Reputation: 563
I'm trying to get notifications for custom device. I know the device is working because in iOS with the Lightblue app I do get the notifications. I have tried with both a nexus 5 and a samsung s4 (both kitkats). Nothing seems to work. My "onCharacteristicChanged" is not getting called.
MainActivity.java
package com.foo.ble;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
public class MainActivity extends Activity implements BluetoothAdapter.LeScanCallback {
private BluetoothAdapter adapter;
final private static char[] hexArray = "0123456789ABCDEF".toCharArray();
private Callback callback;
/**
* Converts 0xfe to "FE"
* @return hex representation of the adScanned
*/
public static String getPayload(final byte[] adScanned) {
if (adScanned == null) return "N/A";
final char[] hexChars = new char[adScanned.length * 2];
for (int j = 0; j < adScanned.length; j++) {
final int v = adScanned[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
adapter = manager.getAdapter();
callback = new Callback();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
adapter.stopLeScan(MainActivity.this);
}
}, 3*10000);
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.startLeScan(MainActivity.this);
}
});
}
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
if (device.getAddress().equals("CE:AD:09:F2:BB:DC")) {
Log.d("foo", "onLeScan payload:" + getPayload(scanRecord));
adapter.stopLeScan(this);
runOnUiThread(new Runnable() {
@Override
public void run() {
device.connectGatt(MainActivity.this, true, callback);
}
});
}
}
@Override
protected void onDestroy() {
callback.close();
}
}
Callback.java
package com.foo.ble;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
import android.util.Log;
import java.util.UUID;
public class Callback extends BluetoothGattCallback {
final static UUID SERVICE = UUID.fromString("something1");
final static UUID ADV_CHAR = UUID.fromString("something2");
final static UUID ADV_DESCRIPTOR = UUID.fromString("something3");
BluetoothGatt gatt;
public void close() {
if (gatt == null) return;
Log.d("foo", "close with gatt");
gatt.disconnect();
gatt.close();
gatt = null;
}
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status,
final int newState) {
Log.d("foo", "onConnectionStateChange");
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d("foo", "status connected");
this.gatt = gatt;
gatt.discoverServices();
}
}
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
Log.d("foo", "onServicesDiscovered");
if (status == BluetoothGatt.GATT_SUCCESS) {
final BluetoothGattCharacteristic characteristic =
gatt.getService(SERVICE).getCharacteristic(ADV_CHAR);
final BluetoothGattDescriptor descriptor =
characteristic.getDescriptor(ADV_DESCRIPTOR);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.setCharacteristicNotification(characteristic, true);
gatt.writeDescriptor(descriptor);
}
}
@Override
public void onCharacteristicRead(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
final int status) {
Log.d("foo", "onCharacteristicRead status:" + status + " payload: " +
MainActivity.getPayload(characteristic.getValue()));
}
@Override
public void onCharacteristicWrite(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
final int status) {
Log.d("foo", "onCharacteristicWrite");
}
@Override
public void onCharacteristicChanged(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic) {
Log.d("foo", "onCharacteristicChanged payload:" +
MainActivity.getPayload(characteristic.getValue()));
}
@Override
public void onDescriptorWrite(final BluetoothGatt gatt,
final BluetoothGattDescriptor descriptor,
final int status) {
Log.d("foo", "onDescriptorWrite status: " + status);
final BluetoothGattCharacteristic characteristic =
gatt.getService(SERVICE).getCharacteristic(ADV_CHAR);
if (characteristic.getValue() != null) {
Log.d("foo", "value: " + MainActivity.getPayload(characteristic.getValue()));
} else {
gatt.readCharacteristic(characteristic);
}
}
}
My AndroidManifest.xml has:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
The log looks like this:
11-05 12:17:13.314 3683-3683/com.foo.ble D/BluetoothAdapter﹕ startLeScan(): null
11-05 12:17:13.364 3683-3695/com.foo.ble D/BluetoothAdapter﹕ onClientRegistered() - status=0 clientIf=5
11-05 12:17:13.394 3683-3683/com.foo.ble I/Adreno-EGL﹕ <qeglDrvAPI_eglInitialize:320>: EGL 1.4 QUALCOMM Build: I0404c4692afb8623f95c43aeb6d5e13ed4b30ddbDate: 11/06/13
11-05 12:17:13.414 3683-3683/com.foo.ble D/OpenGLRenderer﹕ Enabling debug mode 0
11-05 12:17:13.454 3683-3683/com.foo.ble D/dalvikvm﹕ GC_FOR_ALLOC freed 238K, 2% free 16971K/17240K, paused 14ms, total 14ms
11-05 12:17:15.174 3683-3694/com.foo.ble D/foo﹕ onLeScan payload:02010517FF0000000000000005000000000000000000395401001207086C6976656C7911072E9AB04DB9790F857A4CF0634C7AB94A000000000000000000
11-05 12:17:15.174 3683-3694/com.foo.ble D/BluetoothAdapter﹕ stopLeScan()
11-05 12:17:15.184 3683-3683/com.foo.ble D/BluetoothGatt﹕ connect() - device: CE:AD:09:F2:BB:DC, auto: true
11-05 12:17:15.184 3683-3683/com.foo.ble D/BluetoothGatt﹕ registerApp()
11-05 12:17:15.184 3683-3683/com.foo.ble D/BluetoothGatt﹕ registerApp() - UUID=605cbd6f-6080-4fd8-97ff-1f97b406258e
11-05 12:17:15.194 3683-3695/com.foo.ble D/BluetoothGatt﹕ onClientRegistered() - status=0 clientIf=5
11-05 12:17:43.344 3683-3683/com.foo.ble D/BluetoothAdapter﹕ stopLeScan()
11-05 12:23:59.194 3683-3694/com.foo.ble D/BluetoothGatt﹕ onClientConnectionState() - status=0 clientIf=5 device=CE:AD:09:F2:BB:DC
11-05 12:23:59.194 3683-3694/com.foo.ble D/foo﹕ onConnectionStateChange
11-05 12:23:59.204 3683-3694/com.foo.ble D/foo﹕ status connected
11-05 12:23:59.204 3683-3694/com.foo.ble D/BluetoothGatt﹕ discoverServices() - device: CE:AD:09:F2:BB:DC
11-05 12:24:00.754 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetService() - Device=CE:AD:09:F2:BB:DC UUID=randomService1
11-05 12:24:00.764 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetService() - Device=CE:AD:09:F2:BB:DC UUID=randomService2
11-05 12:24:00.784 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetService() - Device=CE:AD:09:F2:BB:DC UUID=something1
11-05 12:24:00.794 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID1
11-05 12:24:00.804 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID2
11-05 12:24:00.804 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID3
11-05 12:24:00.814 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID4
11-05 12:24:00.814 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID5
11-05 12:24:00.814 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID6
11-05 12:24:00.814 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID7
11-05 12:24:00.814 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=something2
11-05 12:24:00.824 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetDescriptor() - Device=CE:AD:09:F2:BB:DC UUID=something3
11-05 12:24:00.824 3683-3695/com.foo.ble D/BluetoothGatt﹕ onSearchComplete() = Device=CE:AD:09:F2:BB:DC Status=0
11-05 12:24:00.824 3683-3695/com.foo.ble D/foo﹕ onServicesDiscovered
11-05 12:24:00.824 3683-3695/com.foo.ble D/BluetoothGatt﹕ setCharacteristicNotification() - uuid: something2 enable: true
11-05 12:24:00.834 3683-3695/com.foo.ble D/BluetoothGatt﹕ writeDescriptor() - uuid: something3
11-05 12:24:00.894 3683-3694/com.foo.ble D/BluetoothGatt﹕ onDescriptorWrite() - Device=CE:AD:09:F2:BB:DC UUID=something3
11-05 12:24:00.894 3683-3694/com.foo.ble D/foo﹕ onDescriptorWrite status: 0
11-05 12:24:00.894 3683-3694/com.foo.ble D/BluetoothGatt﹕ readCharacteristic() - uuid: something2
11-05 12:24:00.994 3683-3695/com.foo.ble D/BluetoothGatt﹕ onCharacteristicRead() - Device=CE:AD:09:F2:BB:DC UUID=something2 Status=0
11-05 12:24:00.994 3683-3695/com.foo.ble D/foo﹕ onCharacteristicRead status:0 payload: 0000000000050000000000000000005154010012
Any help will be appreciated!
Upvotes: 1
Views: 1645
Reputation: 427
I have observed notifications either not working with certain phone/peripheral/environment combinations, or stop working after having worked in the same connection session, with no apparent reason. All calls return success but notifications just don't come through. Regardless of if you solve the immediate problem at hand, you should consider doing a read poll for your characteristic value as a back-up solution.
The various calls in your onServicesDiscovered()
method should also be gated by conditional checks on the return values of the various gatt methods you're calling.
Anyway, some things you can try:
Finally, I'll act like technical support asking if the computer is plugged in: make certain that the characteristic value on the peripheral is indeed changing.
Upvotes: 2