I used the BluetoothLeGatt example code to write an app that automatically connects to a bonded BLE peripheral upon launching the app. Now i am trying to display the data from one of the peripheral's characteristic in a textView. The BluetoothLeGatt example code only demonstrates this using ExpandableListView.OnChildClickListener, my app should require no user input and simply get he data from the characteristic. This is what i have so far:
private TextView mConnectionState;
private TextView mDataField;
private String mDeviceName;
private String mDeviceAddress;
private ExpandableListView mGattServicesList;
private BluetoothLeService mBluetoothLeService;
private boolean mConnected = false;
private BluetoothGattCharacteristic mNotifyCharacteristic;
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) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
// Automatically connects to the device upon successful start-up initialization.
mBluetoothLeService.connect(mDeviceAddress);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
// Handles various events fired by the Service.
// ACTION_GATT_CONNECTED: connected to a GATT server.
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
// ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read
// or notification operations.
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);
mConnectionState.setTextColor(Color.parseColor("#FF17AA00"));
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
clearUI();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
//displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device_control);
final Intent intent = getIntent();
mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
mConnectionState = (TextView) findViewById(R.id.connection_state);
mDataField = (TextView) findViewById(R.id.data);
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
Log.d(TAG, "Connect request result=" + result);
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mGattUpdateReceiver);
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
mBluetoothLeService = null;
}
private void updateConnectionState(final int resourceId) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mConnectionState.setText(resourceId);
}
});
}
private void displayData(String data) {
if (data != null) {
mDataField.setText(data);
}
}
private void clearUI() {
mGattServicesList.setAdapter((SimpleExpandableListAdapter) null);
mDataField.setText(R.string.no_data);
}
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;
}
Figured it out.
Iterated through the services, then the characteristics after services were discovered.
UUID chara = UUID.fromString("c97433f0-be8f-4dc8-b6f0-5343e6100eb4");
List<BluetoothGattService> servs = mBluetoothLeService.getSupportedGattServices();
for (int i = 0; servs.size() > i; i++) {
List<BluetoothGattCharacteristic> charac = servs.get(i).getCharacteristics();
for (int j = 0; charac.size() > i; i++) {
BluetoothGattCharacteristic ch = charac.get(i);
if (ch.getUuid() == chara) {
mBluetoothLeService.readCharacteristic(ch);
mBluetoothLeService.setCharacteristicNotification(ch, true);
}
}
}
Related
I am struggling through one strange issue that is Command send from android device to BLE dongle. Here i have two buttons Button1 and Button2. On click of each button i am trying to send to different command to BLE dongle. Elaboration of issue is below:
Fragment launch with two buttons Button1 and Button2
Click on Button1
Command send to BLE dongle sucessfully
Then clicked in Button2 command doesn't send to BLE.
Again re-run and Fragment launch now i clicked Buttons2
Command send successfully
Them clicked on Button1 command doesn't send.
*
Concussion- Command send only on first click of first button.
*
Now here is code which i have used
Below is code i am calling at from onCreateView() of Fragment to initialize the services and Broadcast receiver.
if(SingleTon.getInstance().getDeviceAddress() !=null && SingleTon.getInstance().getDeviceName() != null) {
if(!SingleTon.getInstance().isLEServiceGattInit())
settingObj.deviceControl(getActivity(), SingleTon.getInstance().getDeviceAddress(), SingleTon.getInstance().getDeviceName());
}
Now methods which will get call form above code-
public void deviceControl(Context context,String deviceAddress, String devicename ){
progressServices = new ProgressDialog(context);
progressServices = ProgressDialog.show(context, "",
"Looking for Services....", true);
this.mcontext = context;
this.mDeviceAddress = deviceAddress;
this.mDeviceName = devicename;
initServices();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
if(progressServices.isShowing()) {
progressServices.dismiss();
Toast.makeText(mcontext,"Issue in BLE, not able to advertise Services/UUIDs.",Toast.LENGTH_LONG).show();
}
}
}, 6000);
}
private void initServices(){
Intent gattServiceIntent = new Intent(mcontext, BluetoothLeService.class);
mcontext.bindService(gattServiceIntent, mServiceConnection, getActivity().BIND_AUTO_CREATE);
mcontext.registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
}
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize");
}
// Automatically connects to the device upon successful start-up initialization.
mBluetoothLeService.connect(mDeviceAddress);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
SingleTon.getInstance().setLEServiceGattInit(false);
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
displayGattServices(mBluetoothLeService.getSupportedGattServices());
SingleTon.getInstance().setmBluetoothLeService(mBluetoothLeService);
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
}
}
};
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
String uuid;
String unknownServiceString = "Unknown Services";
String unknownCharaString = "Unknown Characteristic";
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<>();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData
= new ArrayList<>();
mGattCharacteristics = new ArrayList<>();
// Loops through available GATT Services.
String LIST_NAME = "NAME";
String LIST_UUID = "UUID";
for (BluetoothGattService gattService : gattServices) {
uuid = gattService.getUuid().toString();
if(uuid.contains("ff02")){
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
if (gattCharacteristic.getUuid().equals(UUID.fromString("0000c002-0000-1000-8000-00805f9b34fb"))) {
SingleTon.getInstance().setListWriteCharecteristic(gattCharacteristic);
progressServices.dismiss();
SingleTon.getInstance().setLEServiceGattInit(true);
}
}
}
}
}
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;
}
Now below is code which we are calling for command send on each button click.
btn_head_up.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
sendHexCommand(CommandListHex.Hex20BIT_ACT_HEAD_UP);
return true;
}
});
private void sendHexCommand(String cmd){
if(SingleTon.getInstance().getDeviceAddress() !=null && SingleTon.getInstance().getDeviceName() != null) {
settingObj.sendCommand(cmd, SingleTon.getInstance().getListWriteCharecteristic(), SingleTon.getInstance().getmBluetoothLeService());
} else{
showDialog(getActivity(), getResources().getString(R.string.dialogtitle), "First do configuration for Bluetooth");
}
}
And now finally code to send command
public void sendCommand(String Control_INST, ArrayList<BluetoothGattCharacteristic> charFromSinglonton ,
BluetoothLeService bleGATTService){
for(BluetoothGattCharacteristic gattChar :charFromSinglonton) {
if (charFromSinglonton != null) {
final BluetoothGattCharacteristic characteristic = gattChar;
boolean status = bleGATTService.writeCharacteristic(characteristic, hexStringToByteArray(Control_INST));
if (status) {
SingleTon.getInstance().setCorrectWriteGattCharecteristic(gattChar);
}
}
}
}
Thanks in advance to all.
If you click the same button twice(like first button) what will happen? Send command twice or only one time ?
I am developing an Android Application that connects to a BLE Device and reads the specific GATT Characteristics and Services that I need to check. I used the BluetoothLeGATT example from the Android Dev site as my reference. I can connect to a predefined Address without problems and read the GATT Attribute updates.
What I want to do next is to be able to connect to two BLE Devices simultaneously. However, this seems to be a challenge.
What I did was to essentially duplicate the code needed to connect to a single BLE Device. I had 2 BluetoothLeServices, 2 ArrayLists for the GattCharacteristics and Gatt Service Data, as well as 2 Service Connections, and 2 Broadcast Receivers for GattCallbacks.
However, in my GattCallback functions, I get the same message -- as if they were connected to the same area. Here is my code:
public class MainActivity extends AppCompatActivity {
/*
UUIDs
Dog Block - 20:CD:39:87:DC:AA
Cat Block - 20:CD:39:87:DF:82
*/
private final String TAG = this.getClass().getSimpleName();
private BluetoothAdapter mBluetoothAdapter;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private static final long SCAN_PERIOD = 10000;
private ArrayList<String> addressID = new ArrayList<>();
private ArrayList<BluetoothDevice> deviceList = new ArrayList<>();
private boolean mScanning = false;
private boolean mConnected = false;
private BluetoothLeService mBluetoothLeService;
private BluetoothLeService mBluetoothLeService1;
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics1 =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
private final String LIST_NAME = "NAME";
private final String LIST_UUID = "UUID";
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData
= new ArrayList<ArrayList<HashMap<String, String>>>();
ArrayList<HashMap<String, String>> gattServiceData1 = new ArrayList<HashMap<String, String>>();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData1
= new ArrayList<ArrayList<HashMap<String, String>>>();
private BluetoothGattCharacteristic mNotifyCharacteristic;
private BluetoothGattCharacteristic mNotifyCharacteristic1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// 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(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
addressID.add("20:CD:39:87:DC:AA");
addressID.add("20:CD:39:87:DF:82");
}
#Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
scanLeDevice(true);
if (mBluetoothLeService != null) {
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
unregisterReceiver(mGattUpdateReceiver);
unregisterReceiver(mGattUpdateReceiver1);
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
mBluetoothLeService = null;
mBluetoothLeService1 = null;
}
private void scanLeDevice(final boolean enable) {
if (enable) {
Log.e(TAG, "scanLeDevice true");
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
Log.e(TAG, "scanLeDevice false");
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
deviceList.add(device);
Log.e(TAG, "deviceList count = " + deviceList.size());
if(deviceList.size() >= 2){
checkDevices();
}
}
});
}
};
private void checkDevices() {
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
Intent gattServiceIntent1 = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent1, mServiceConnection1, BIND_AUTO_CREATE);
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
registerReceiver(mGattUpdateReceiver1, makeGattUpdateIntentFilter());
}
//TODO -- connect functions here
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;
}
// Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
Log.e(TAG, "connecting to " + deviceList.get(0).getAddress());
mBluetoothLeService.connect("20:CD:39:87:DC:AA");
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private final ServiceConnection mServiceConnection1 = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService1 = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService1.initialize()) {
Log.e(TAG, "1Unable to initialize Bluetooth");
finish();
}
// Automatically connects to the device upon successful start-up initialization.
Log.e(TAG, "1connecting to " + deviceList.get(1).getAddress());
mBluetoothLeService1.connect("20:CD:39:87:DF:82");
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
Log.e(TAG, "connected");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
Log.e(TAG, "disconnected");
mConnected = false;
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
Log.e(TAG, "gatt services discovered");
displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.e(TAG, "data available");
String data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);
Log.e(TAG, "data is = " + data);
}
}
};
private final BroadcastReceiver mGattUpdateReceiver1 = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
Log.e(TAG, "1connected");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
Log.e(TAG, "1disconnected");
mConnected = false;
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
Log.e(TAG, "1gatt services discovered");
displayGattServices1(mBluetoothLeService1.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.e(TAG, "1data available");
String data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);
Log.e(TAG, "1data is = " + data);
}
}
};
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
Log.e(TAG, "display gatt services not null.");
String uuid = null;
String unknownServiceString = getResources().getString(R.string.unknown_service);
String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap<String, String>();
uuid = gattService.getUuid().toString();
currentServiceData.put(
LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString));
currentServiceData.put(LIST_UUID, 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) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap<String, String>();
uuid = gattCharacteristic.getUuid().toString();
currentCharaData.put(
LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString));
currentCharaData.put(LIST_UUID, uuid);
gattCharacteristicGroupData.add(currentCharaData);
if(uuid.equals(SampleGattAttributes.DOG_CHARACTERISTIC_CONFIG)){
Log.e(TAG, "uuid characteristic detected");
final int charaProp = gattCharacteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
Log.e(TAG, "gatt characteristics read!");
// If there is an active notification on a characteristic, clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(
mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
mBluetoothLeService.readCharacteristic(gattCharacteristic);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
Log.e(TAG, "gatt characteristics notify!");
mNotifyCharacteristic = gattCharacteristic;
mBluetoothLeService.setCharacteristicNotification(
gattCharacteristic, true);
}
}
}
mGattCharacteristics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
}
}
private void displayGattServices1(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
Log.e(TAG, "1display gatt services not null.");
String uuid = null;
String unknownServiceString = getResources().getString(R.string.unknown_service);
String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
mGattCharacteristics1 = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap<String, String>();
uuid = gattService.getUuid().toString();
currentServiceData.put(
LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString));
currentServiceData.put(LIST_UUID, uuid);
gattServiceData1.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) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap<String, String>();
uuid = gattCharacteristic.getUuid().toString();
currentCharaData.put(
LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString));
currentCharaData.put(LIST_UUID, uuid);
gattCharacteristicGroupData.add(currentCharaData);
if (uuid.equals(SampleGattAttributes.DOG_CHARACTERISTIC_CONFIG)) {
Log.e(TAG, "1uuid characteristic detected");
final int charaProp = gattCharacteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
Log.e(TAG, "1gatt characteristics read!");
// If there is an active notification on a characteristic, clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic1 != null) {
mBluetoothLeService1.setCharacteristicNotification(
mNotifyCharacteristic1, false);
mNotifyCharacteristic1 = null;
}
mBluetoothLeService1.readCharacteristic(gattCharacteristic);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
Log.e(TAG, "1gatt characteristics notify!");
mNotifyCharacteristic1 = gattCharacteristic;
mBluetoothLeService1.setCharacteristicNotification(
gattCharacteristic, true);
}
}
}
mGattCharacteristics1.add(charas);
gattCharacteristicData1.add(gattCharacteristicGroupData);
}
}
}
What I do is that once I get the 2 addresses that I want to connect to, I initialize all the necessary connections, services, and broadcast receivers. However, the bluetoothLeGatt messages I receive are the same. Depending on it connected to the Dog or Cat block, I'd get the lines:
data = dog
1data = dog
From the LogCat. It seems as if they were connected to the same device.
I checked my code and I even hardcoded the addresses in but to no avail.
I've made a connection with multiple devices and it works fine. I also made one Service for scanning and one for each ble communication.
Make sure not to use bound services for the communication part because the disconnection might be a problem (it was in my case).
For the Scanning part I made a List of Strings with the Mac addresses in it. When I found one device in my scanner I send the device via broadcastreceiver to my main activity and there I transmit it to its service. So every connection runs in its own service with its own broadcastreceiver and filtersettings.
To make sure that it's not a problem of your broadcastreceiver, make a console log in each service where you display the output immediately. I doubt that your device has two connections to the same server.
How can I receive external sensor data even when the app is closed or screen is off?
I am currently collecting data via bluetooth low energy using this function:
public void onDataRecieved(BleSensor<?> sensor, String text) {
if (sensor instanceof BleHeartRateSensor) {
final BleSensor hSensor = (BleSensor) sensor;
float[] values = hSensor.getData();
//Start service to write data to a file
viewText.setText(text);
}
Here is the class that is used to implement the BLE sensor listener. It is an activity. I am having trouble trying to convert it to a service.
public abstract class DemoSensorActivity extends Activity {
private final static String TAG = DemoSensorActivity.class.getSimpleName();
public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
public static final String EXTRAS_SENSOR_UUID = "SERVICE_UUID";
private BleService bleService;
private String serviceUuid;
private String deviceAddress;
// Handles various events fired by the Service.
// ACTION_GATT_CONNECTED: connected to a GATT server.
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
// ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read
// or notification operations.
private final BroadcastReceiver gattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BleService.ACTION_GATT_DISCONNECTED.equals(action)) {
//TODO: show toast
finish();
} else if (BleService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
final BleSensor<?> sensor = BleSensors.getSensor(serviceUuid);
bleService.enableSensor(sensor, true);
} else if (BleService.ACTION_DATA_AVAILABLE.equals(action)) {
final BleSensor<?> sensor = BleSensors.getSensor(serviceUuid);
final String text = intent.getStringExtra(BleService.EXTRA_TEXT);
onDataRecieved(sensor, text);
}
}
};
// Code to manage Service lifecycle.
private final ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
bleService = ((BleService.LocalBinder) service).getService();
if (!bleService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
// Automatically connects to the device upon successful start-up initialization.
bleService.connect(deviceAddress);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
bleService = null;
//TODO: show toast
finish();
}
};
public abstract void onDataRecieved(BleSensor<?> sensor, String text);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
deviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
serviceUuid = intent.getStringExtra(EXTRAS_SENSOR_UUID);
getActionBar().setDisplayHomeAsUpEnabled(true);
final Intent gattServiceIntent = new Intent(this, BleService.class);
bindService(gattServiceIntent, serviceConnection, BIND_AUTO_CREATE);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter());
if (bleService != null) {
final boolean result = bleService.connect(deviceAddress);
Log.d(TAG, "Connect request result=" + result);
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(gattUpdateReceiver);
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
bleService = null;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BleService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BleService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BleService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
}
Currently this is only running when the app is open and the screen is turned on. Is there a way to continue to run this data collection when the app is closed and the screen is off?
I am attempting to connect to my XAMPP server and interact with the MySQL database with the classes below. However, the error notes that I receive a NullPointerException at the line:
result = imService.createNewGroup(newGroupName);
In the CreateGroup class. It should be noted that the CreateGroup class is also called right after a user inputs text into a Dialog and the service is started from there. I am fairly new to services and network connections, but is there something I'm missing that should allow to at least verify that the service is connected before trying to send the .createGroup command?
CreateGroup Class:
public class CreateGroup extends Activity {
private static final String SERVER_RES_RES_SIGN_UP_SUCCESFULL = "1";
private static final String SERVER_RES_SIGN_UP_USERNAME_CRASHED = "2";
private Manager imService;
private Handler handler = new Handler();
String newGroupName;
public ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((MessagingService.IMBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(CreateGroup.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService(new Intent(CreateGroup.this, MessagingService.class),
mConnection, Context.BIND_AUTO_CREATE);
// Getting intent and info from the dialog
Intent i = getIntent();
Bundle extras = i.getExtras();
newGroupName = extras.getString("groupName");
Thread thread = new Thread() {
String result = new String();
#Override
public void run() {
// Send group name to the messaging
// service
try {
result = imService.createNewGroup(newGroupName);
} catch (NullPointerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("problem", "The value of result is " + result.toString());
handler.post(new Runnable() {
#Override
public void run() {
if (result == null) {
Toast.makeText(getApplicationContext(),
"It's null, not working", Toast.LENGTH_LONG)
.show();
}
if (result != null
&& result
.equals(SERVER_RES_RES_SIGN_UP_SUCCESFULL)) {
Toast.makeText(getApplicationContext(),
R.string.signup_successfull,
Toast.LENGTH_LONG).show();
// showDialog(SIGN_UP_SUCCESSFULL);
} else if (result != null
&& result
.equals(SERVER_RES_SIGN_UP_USERNAME_CRASHED)) {
Toast.makeText(getApplicationContext(),
R.string.signup_username_crashed,
Toast.LENGTH_LONG).show();
// showDialog(SIGN_UP_USERNAME_CRASHED);
} else // if
// (result.equals(SERVER_RES_SIGN_UP_FAILED))
{
Toast.makeText(getApplicationContext(),
R.string.signup_failed, Toast.LENGTH_LONG)
.show();
// showDialog(SIGN_UP_FAILED);
}
}
});
}
};
thread.start();
}
Server Case for "createGroup" method:
case "createGroup":
$SQLtest = "insert into groups(groupName, uniqueGroup, createTime)
VALUES('TestGroup', 1234567891, NOW())";
error_log("$SQLtest", 3 , "error_log");
if($result = $db -> query($SQLtest))
{
$out = SUCCESSFUL;
}
else
{
$out = FAILED;
}
break;
Messaging Service and createGroup method:
public class MessagingService extends Service implements Manager, Updater {
// private NotificationManager mNM;
public static String USERNAME;
public static final String TAKE_MESSAGE = "Take_Message";
public static final String FRIEND_LIST_UPDATED = "Take Friend List";
public static final String MESSAGE_LIST_UPDATED = "Take Message List";
public ConnectivityManager conManager = null;
private final int UPDATE_TIME_PERIOD = 15000;
private String rawFriendList = new String();
private String rawMessageList = new String();
SocketerInterface socketOperator = new Socketer(this);
private final IBinder mBinder = new IMBinder();
private String username;
private String password;
private boolean authenticatedUser = false;
// timer to take the updated data from server
private Timer timer;
private StorageManipulater localstoragehandler;
private NotificationManager mNM;
public class IMBinder extends Binder {
public Manager getService() {
return MessagingService.this;
}
}
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
localstoragehandler = new StorageManipulater(this);
// Display a notification about us starting. We put an icon in the
// status bar.
// showNotification();
conManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
new StorageManipulater(this);
// Timer is used to take the friendList info every UPDATE_TIME_PERIOD;
timer = new Timer();
Thread thread = new Thread() {
#Override
public void run() {
Random random = new Random();
int tryCount = 0;
while (socketOperator.startListening(10000 + random
.nextInt(20000)) == 0) {
tryCount++;
if (tryCount > 10) {
// if it can't listen a port after trying 10 times, give
// up...
break;
}
}
}
};
thread.start();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public String createNewGroup(String groupName) throws NullPointerException, UnsupportedEncodingException {
String params = "action=createGroup";
String result = socketOperator.sendHttpRequest(params);
return result;
}
}
Because your code has an inherent race condition. And an evil one.
Change to something like this:
public void onCreate(Bundle savedInstanceState) {
bindService(new Intent(CreateGroup.this, MessagingService.class),
mConnection, Context.BIND_AUTO_CREATE);
// but do not start thread here!
}
public ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((MessagingService.IMBinder) service).getService();
startCommunicationThread(); // <----------------------- only here can you start comm. thread
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(CreateGroup.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
void startCommunicationThread() {
Thread thread = new Thread() {
String result = new String();
#Override
public void run() {
try {
result = imService.createNewGroup(newGroupName);
..........
}
If you want your code to be even more secure, use a connection state field:
public ServiceConnection mConnection = new ServiceConnection() {
volatile boolean isConnected;
public void onServiceConnected(ComponentName className, IBinder service) {
isConnected = true; // <---------------------
imService = ((MessagingService.IMBinder) service).getService();
startCommunicationThread();
}
public void onServiceDisconnected(ComponentName className) {
isConnected = false; // <---------------
imService = null;
Toast.makeText(CreateGroup.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
And poll isConnected from within startCommunicationThread to make sure no sudden disconnects.
in my project MessagingService.IMBinder MessagingService gives error is there any java class that I should import.
I'm trying to receive a notification from the device when I write a value on a characteristic, but I donĀ“t receive anything. I enable the notification on the characteristic and then I write the value. I've seen that the characteristic in the device have changed its value but I can't get the notification. Here is my code:
DeviceActivity:
public class DevicesActivity extends Activity {
private BLEService mBluetoothLeService;
private String mDeviceAddress;
private boolean mConnected = false;
private BluetoothGattCharacteristic mNotifyCharacteristic;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BLEService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
finish();
}
mBluetoothLeService.context = DevicesActivity.this;
mBluetoothLeService.connect(mDeviceAddress);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BLEService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
invalidateOptionsMenu();
} else if (BLEService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
invalidateOptionsMenu();
} else if (BLEService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
List<BluetoothGattService> servicesList;
servicesList = mBluetoothLeService.getSupportedGattServices();
Iterator<BluetoothGattService> iter = servicesList.iterator();
while (iter.hasNext()) {
BluetoothGattService bService = (BluetoothGattService) iter.next();
if (bService.getUuid().toString().equals(BLEUUID.SERVICE)){
mService = bService;
}
}
} else if (BLEService.ACTION_DATA_AVAILABLE.equals(action)) {
displayData(intent.getStringExtra(BLEService.EXTRA_DATA));
}
}
};
private static final String TAG = "BLEDevice";
public static final String EXTRA_BLUETOOTH_DEVICE = "BT_DEVICE";
private BluetoothAdapter mBTAdapter;
private BluetoothDevice mDevice;
private BluetoothGatt mConnGatt;
private int mStatus;
BluetoothGattService mService;
private EditText pinTxt;
private Button cancelBtn;
private Button unlockBtn;
private Button changePinBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_devices);
pinTxt = (EditText) findViewById(R.id.pin_txt);
cancelBtn = (Button) findViewById(R.id.cancel_btn);
unlockBtn = (Button) findViewById(R.id.unlock_btn);
changePinBtn = (Button) findViewById(R.id.change_pin_btn);
unlockBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String aux = pinTxt.getText().toString();
mBluetoothLeService.sendCharacteristic(aux, getBTDeviceExtra());
}
});
mDevice = getBTDeviceExtra();
mDeviceAddress = mDevice.getAddress();
if (mServiceConnection == null){
Log.v("NULL", "mServiceConnection NULL");
}
Intent gattServiceIntent = new Intent(this, BLEService.class);
if (gattServiceIntent==null){
Log.v("NULL", "mServiceConnection NULL");
}
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
mStatus = BluetoothProfile.STATE_DISCONNECTED;
}
private void displayData(String data) {
if (data != null) {
Toast.makeText(DevicesActivity.this, data, Toast.LENGTH_LONG);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
mBluetoothLeService = null;
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mGattUpdateReceiver);
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BLEService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BLEService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BLEService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BLEService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
}
}
private BluetoothDevice getBTDeviceExtra() {
Intent intent = getIntent();
if (intent
== null) { return null;
}
Bundle extras = intent.getExtras();
if (extras == null) {
return null;
}
BluetoothDevice aux = extras.getParcelable(EXTRA_BLUETOOTH_DEVICE);
return aux;
}
BLEService:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
for (BluetoothGattService service : gatt.getServices()) {
if ((service == null) || (service.getUuid() == null)) {
continue;
}
if (BLEUUID.SERVICE.equalsIgnoreCase(service.getUuid().toString())) {
mService = service;
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
broadcastUpdate(EXTRA_DATA, characteristic);
Log.i("CARAC","CARACTERISTICA LEIDA onCharacteristicRead()");
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
readCharacteristic(characteristic);
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
Log.i("CARAC","CAMBIO EN CARACTERISTICA");
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void broadcastUpdate(final String action,final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
if (PIN_CHARACTERISTIC.equals(characteristic.getUuid())) {
final String pin = characteristic.getStringValue(0);
intent.putExtra(EXTRA_DATA, String.valueOf(pin));
} 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));
Log.i("RECIBIDO", "RECIBIDOS DATOS");
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
}
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BLEService getService() {
return BLEService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
public boolean initialize() {
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
return false;
}
return true;
}
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.disconnect();
}
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
Log.e("CIERRE", "CONEXION CERRADA");
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
Log.i("READ", "CARACTERISTICA LEIDA");
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if (PIN_CHARACTERISTIC.equals(characteristic.getUuid())){
BluetoothGattDescriptor descriptor =
new BluetoothGattDescriptor(UUID.nameUUIDFromBytes(BLEUUID.PIN_CHARACTERISTIC_CONFIG_DESCRIPTOR.getBytes()),
BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
public void sendCharacteristic(String pin, BluetoothDevice device){
byte[] pinByte = pin.getBytes();
int pinInt = Integer.valueOf(pin);
BluetoothGattCharacteristic ch = (BluetoothGattCharacteristic) mService.getCharacteristic(UUID
.fromString(BLEUUID.PIN_CHARACTERISTIC_UUID));
ch.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
ch.setValue(pin);
Toast.makeText(context, "CARACTERISTICA ASIGNADA", Toast.LENGTH_SHORT).show();
connect(device.getAddress());
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
setCharacteristicNotification(ch, true);
if (mBluetoothGatt.writeCharacteristic(ch)) {
Toast.makeText(context, "CARACTERISTICA ESCRITA", Toast.LENGTH_SHORT).show();
}
}
}
BLEUUID
public class BLEUUID {
// CARACTERISTICA PIN
public static final String SERVICE ="0000fff0-0000-1000-8000-00805f9b34fb";
public static final String PIN_CHARACTERISTIC_UUID="0000fff9-0000-1000-8000-00805f9b34fb";
public static final String PIN_CHARACTERISTIC_CONFIG_DESCRIPTOR="0x2902";
private static HashMap<String, String> attributes = new HashMap();
static {
attributes.put(SERVICE, "Service");
attributes.put(PIN_CHARACTERISTIC_UUID, "Pin");
}
When I debug, onCharacteristicChange() never executes.
Somebody knows where's the problem
Here is the general pattern for how things need to work with BLE on Android:
You try to connect
You get a callback indicating it is connected
You discover services
You are told services are discovered
You get the characteristics
For each characteristic you get the descriptors
For the descriptor you set it to enable notification/indication with BluetoothGattDescriptor.setValue()
You write the descriptor with BluetoothGatt.writeDescriptor()
You enable notifications for the characteristic locally with BluetoothGatt.setCharacteristicNotification(). Without this you won't get called back.
You get notification that the descriptor was written
Now you can write data to the characteristic. All of the characteristic and descriptor configuration has do be done before anything is written to any characteristic.