I've followed the guide listed at https://developer.android.com/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html
I can't figure out how to trigger a notify when the characteristic value changes. The method onCharacteristicChanged is never called but I know for a fact the value changes every 2 seconds. I am getting around this fact by calling readCharacteristic when I discover the service and then repeatedly afterwards. I don't believe this is the correct way rather I should only read when the onCharacteristicChanged method sends a broadcast. Is it possible to get notify to work or is this the best method?
Device Controller:
public class WarningActivity extends AppCompatActivity {
private static final String TAG = "WarningActivity Class";
private BluetoothLeService mBluetoothLeService;
public static WarningActivity wInstance;
private boolean mConnected = false;
private String mDeviceAddress;
private boolean quitService;
private TextView connectStatus;
private Button connectButton;
private Button cameraButton;
private BluetoothManager mBluetoothManager;
private Vibrator vib;
private Uri notification;
private Ringtone ring;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
mBluetoothLeService.connect(mDeviceAddress);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
Log.i("Data: ", mBluetoothLeService.getSupportedGattService().toString());
BluetoothGattService mService = mBluetoothLeService.getSupportedGattService();
BluetoothGattCharacteristic characteristic = mService.getCharacteristic(mBluetoothLeService.ALERT_UUID);
mBluetoothLeService.setCharacteristicNotification(characteristic, true);
mBluetoothLeService.readCharacteristic(characteristic);
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
BluetoothGattService mService = mBluetoothLeService.getSupportedGattService();
BluetoothGattCharacteristic characteristic = mService.getCharacteristic(mBluetoothLeService.ALERT_UUID);
byte[] temp = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);
String tempString = Arrays.toString(temp);
Log.i("Data: ", Arrays.toString(temp));
mBluetoothLeService.readCharacteristic(characteristic);
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor("#268011"));
getSupportActionBar().setBackgroundDrawable(colorDrawable);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
connectButton = (Button) findViewById(R.id.connectButton);
connectButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.connected_logo, 0, 0);
connectButton.setClickable(false);
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
Intent intent = getIntent();
mDeviceAddress = intent.getStringExtra("EXTRA_DEVICE_ADDRESS");
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
ring = RingtoneManager.getRingtone(getApplicationContext(), notification);
wInstance = this;
quitService = false;
connectStatus = (TextView) findViewById(R.id.connectMessage);
connectStatus.setText("Connected to: \n " + mDeviceAddress);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
Log.d(TAG, "Connect request result=" + result);
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mGattUpdateReceiver);
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
mBluetoothLeService = null;
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
}
BluetoothLeService
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED = "ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED = "ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = "ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA = "EXTRA_DATA";
public final static UUID SERVICE_UUID = UUID.fromString(GattAttributes.BLE_SERVICE);
public final static UUID ALERT_UUID = UUID.fromString(GattAttributes.BLE_ALERT_CHARACTERISTIC);
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.i("BlueToothService: ", "onCharacteristicRead " + characteristic.toString());
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i("BlueToothService: ", "onCharacteristicChanged " + characteristic.toString());
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
Log.i("BlueToothService: ", "BroadcastUpdate ActionOnly: " + action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
Log.i("BlueToothService: ", "BroadcastUpdateLong " + characteristic.toString() + " Action:" + action);
intent.putExtra(EXTRA_DATA, characteristic.getValue());
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if (SERVICE_UUID.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(ALERT_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
public BluetoothGattService getSupportedGattService() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getService(SERVICE_UUID);
}
}
Solution Found: Classic Case of mistyping and wrong descriptor UUID. Where I found the answer BLE GATT onCharacteristicChanged not called after subscribing to notification. The mistype was in setCharacteristicNotification method. Changed to ALERT_UUID and to what article has me assuming the correct descriptor UUID
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if (ALERT_UUID.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
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();
}
}
}
hi everyone i am working on android app which requires connecting to ble device and sending data over ble. i have tried scanning and displaying the scanned devices on a list which works fine. the problem is with connecting to the scanned device. here is the part of my main activity code.
public class main_activity extends Activity implements BluetoothLeUart.Callback{
public ImageButton fabbutton;
Activity activity;
private ArrayAdapter<String> adapter;
private ArrayList<String> liste,devicedata;
private ListView list;
public EditText input;
String name,address,Devicename,Deviceaddress,datadevicename;
private BluetoothGatt mBluetoothGatt;
public static String SelectedDeviceName;
private BluetoothAdapter mBluetoothAdapter;
public ArrayList<BluetoothDevice> dev;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private static final long SCAN_PERIOD = 10000;
BluetoothLeUart uart = new BluetoothLeUart(this);
public static BluetoothDevice device;
private BluetoothGatt mGatt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity);
fabbutton = (ImageButton) findViewById(R.id.fabbutton);
activity = this;
mHandler = new Handler();
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
scanLeDevice(true);
mActionBar.setTitle(Html.fromHtml("<font color='#727272'>Board List</font>"));
list = (ListView) findViewById(R.id.list);
liste = new ArrayList<String>();
liste.clear();
adapter = new ArrayAdapter<String>(list.getContext(), android.R.layout.simple_list_item_1, liste);
list.setAdapter(adapter);
// On Click Listener for Paired BLE Device List
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SelectedDeviceName = list.getItemAtPosition(position).toString();
String[] splitString = SelectedDeviceName.split(" ");
Devicename = splitString[0];
Deviceaddress = splitString[1];
device = mBluetoothAdapter.getRemoteDevice(Deviceaddress);
Toast.makeText(getApplicationContext(),device.toString(),Toast.LENGTH_SHORT).show();
//device.connectGatt(getApplicationContext(), true, gattCallback);
uart.connectFirstAvailable();// this is where i start connecting process.
}
});
here is the code of my BluetoothLeUart class
public class BluetoothLeUart extends BluetoothGattCallback implements BluetoothAdapter.LeScanCallback {
public String mDeviceAddress;
// UUIDs for UART service and associated characteristics.
public static UUID UART_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
public static UUID TX_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
public static UUID RX_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
// UUID for the UART BTLE client characteristic which is necessary for notifications.
public static UUID CLIENT_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
// UUIDs for the Device Information service and associated characeristics.
public static UUID DIS_UUID = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb");
public static UUID DIS_MANUF_UUID = UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb");
public static UUID DIS_MODEL_UUID = UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb");
public static UUID DIS_HWREV_UUID = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb");
public static UUID DIS_SWREV_UUID = UUID.fromString("00002a28-0000-1000-8000-00805f9b34fb");
// Internal UART state.
private Context context;
private WeakHashMap<Callback, Object> callbacks;
private BluetoothAdapter adapter;
private BluetoothGatt gatt;
private BluetoothGattCharacteristic tx;
private BluetoothGattCharacteristic rx;
private boolean connectFirst;
private boolean writeInProgress; // Flag to indicate a write is currently in progress
// Device Information state.
private BluetoothGattCharacteristic disManuf;
private BluetoothGattCharacteristic disModel;
private BluetoothGattCharacteristic disHWRev;
private BluetoothGattCharacteristic disSWRev;
private boolean disAvailable;
// Queues for characteristic read (synchronous)
private Queue<BluetoothGattCharacteristic> readQueue;
// Interface for a BluetoothLeUart client to be notified of UART actions.
public interface Callback {
public void onConnected(BluetoothLeUart uart);
public void onConnectFailed(BluetoothLeUart uart);
public void onDisconnected(BluetoothLeUart uart);
public void onReceive(BluetoothLeUart uart, BluetoothGattCharacteristic rx);
public void onDeviceFound(BluetoothDevice device);
public void onDeviceInfoAvailable();
}
public BluetoothLeUart(Context context) {
super();
this.context = context;
this.callbacks = new WeakHashMap<Callback, Object>();
this.adapter = BluetoothAdapter.getDefaultAdapter();
this.gatt = null;
this.tx = null;
this.rx = null;
this.disManuf = null;
this.disModel = null;
this.disHWRev = null;
this.disSWRev = null;
this.disAvailable = false;
this.connectFirst = false;
this.writeInProgress = false;
this.readQueue = new ConcurrentLinkedQueue<BluetoothGattCharacteristic>();
}
// Return instance of BluetoothGatt.
public BluetoothGatt getGatt() {
return gatt;
}
// Return true if connected to UART device, false otherwise.
public boolean isConnected() {
return (tx != null && rx != null);
}
public String getDeviceInfo() {
if (tx == null || !disAvailable ) {
// Do nothing if there is no connection.
return "";
}
StringBuilder sb = new StringBuilder();
sb.append("Manufacturer : " + disManuf.getStringValue(0) + "\n");
sb.append("Model : " + disModel.getStringValue(0) + "\n");
sb.append("Firmware : " + disSWRev.getStringValue(0) + "\n");
return sb.toString();
};
public boolean deviceInfoAvailable() { return disAvailable; }
// Send data to connected UART device.
public void send(byte[] data) {
if (tx == null || data == null || data.length == 0) {
// Do nothing if there is no connection or message to send.
return;
}
// Update TX characteristic value. Note the setValue overload that takes a byte array must be used.
tx.setValue(data);
writeInProgress = true; // Set the write in progress flag
gatt.writeCharacteristic(tx);
// ToDo: Update to include a timeout in case this goes into the weeds
while (writeInProgress); // Wait for the flag to clear in onCharacteristicWrite
}
public void registerCallback(Callback callback) {
callbacks.put(callback, null);
}
public void unregisterCallback(Callback callback) {
callbacks.remove(callback);
}
// Disconnect to a device if currently connected.
public void disconnect() {
if (gatt != null) {
gatt.disconnect();
}
gatt = null;
tx = null;
rx = null;
}
// Stop any in progress UART device scan.
public void stopScan() {
if (adapter != null) {
adapter.stopLeScan(this);
}
}
// Start scanning for BLE UART devices. Registered callback's onDeviceFound method will be called
// when devices are found during scanning.
public void startScan() {
if (adapter != null) {
adapter.startLeScan(this);
Toast.makeText(context,"Entered",Toast.LENGTH_SHORT).show();
}
}
// Connect to the first available UART device.
public void connectFirstAvailable() {
// Disconnect to any connected device.
disconnect();
// Stop any in progress device scan.
stopScan();
// Start scan and connect to first available device.
connectFirst = true;
startScan();
}
// Handlers for BluetoothGatt and LeScan events.
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// Connected to device, start discovering services.
if (!gatt.discoverServices()) {
// Error starting service discovery.
connectFailure();
}
}
else {
// Error connecting to device.
connectFailure();
}
}
else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
// Disconnected, notify callbacks of disconnection.
rx = null;
tx = null;
notifyOnDisconnected(this);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
// Notify connection failure if service discovery failed.
if (status == BluetoothGatt.GATT_FAILURE) {
connectFailure();
return;
}
// Save reference to each UART characteristic.
tx = gatt.getService(UART_UUID).getCharacteristic(TX_UUID);
rx = gatt.getService(UART_UUID).getCharacteristic(RX_UUID);
// Setup notifications on RX characteristic changes (i.e. data received).
// First call setCharacteristicNotification to enable notification.
if (!gatt.setCharacteristicNotification(rx, true)) {
// Stop if the characteristic notification setup failed.
connectFailure();
return;
}
// Next update the RX characteristic's client descriptor to enable notifications.
BluetoothGattDescriptor desc = rx.getDescriptor(CLIENT_UUID);
if (desc == null) {
// Stop if the RX characteristic has no client descriptor.
connectFailure();
return;
}
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
if (!gatt.writeDescriptor(desc)) {
// Stop if the client descriptor could not be written.
connectFailure();
return;
}
// Notify of connection completion.
notifyOnConnected(this);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
notifyOnReceive(this, characteristic);
}
#Override
public void onCharacteristicRead (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
//Log.w("DIS", characteristic.getStringValue(0));
// Check if there is anything left in the queue
BluetoothGattCharacteristic nextRequest = readQueue.poll();
if(nextRequest != null){
// Send a read request for the next item in the queue
gatt.readCharacteristic(nextRequest);
}
else {
// We've reached the end of the queue
disAvailable = true;
notifyOnDeviceInfoAvailable();
}
}
else {
//Log.w("DIS", "Failed reading characteristic " + characteristic.getUuid().toString());
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// Log.d(TAG,"Characteristic write successful");
}
writeInProgress = false;
}
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
Toast.makeText(context, "onLe Entered", Toast.LENGTH_SHORT).show();
if (!parseUUIDs(scanRecord).contains(UART_UUID)) {
return;
}
// Notify registered callbacks of found device.
notifyOnDeviceFound(device);
// Connect to first found device if required.
if (connectFirst) {
// Stop scanning for devices.
// Prevent connections to future found devices.
if (mDeviceAddress.equals(device.getAddress())) {
stopScan();
connectFirst = false;
// Connect to device.
gatt = device.connectGatt(context, true, this);
}
}
}
// Private functions to simplify the notification of all callbacks of a certain event.
private void notifyOnConnected(BluetoothLeUart uart) {
for (Callback cb : callbacks.keySet()) {
if (cb != null) {
cb.onConnected(uart);
}
}
}
private void notifyOnConnectFailed(BluetoothLeUart uart) {
for (Callback cb : callbacks.keySet()) {
if (cb != null) {
cb.onConnectFailed(uart);
}
}
}
private void notifyOnDisconnected(BluetoothLeUart uart) {
for (Callback cb : callbacks.keySet()) {
if (cb != null) {
cb.onDisconnected(uart);
}
}
}
private void notifyOnReceive(BluetoothLeUart uart, BluetoothGattCharacteristic rx) {
for (Callback cb : callbacks.keySet()) {
if (cb != null ) {
cb.onReceive(uart, rx);
}
}
}
private void notifyOnDeviceFound(BluetoothDevice device) {
for (Callback cb : callbacks.keySet()) {
if (cb != null) {
cb.onDeviceFound(device);
}
}
}
private void notifyOnDeviceInfoAvailable() {
for (Callback cb : callbacks.keySet()) {
if (cb != null) {
cb.onDeviceInfoAvailable();
}
}
}
// Notify callbacks of connection failure, and reset connection state.
private void connectFailure() {
rx = null;
tx = null;
notifyOnConnectFailed(this);
}
private List<UUID> parseUUIDs(final byte[] advertisedData) {
List<UUID> uuids = new ArrayList<UUID>();
int offset = 0;
while (offset < (advertisedData.length - 2)) {
int len = advertisedData[offset++];
if (len == 0)
break;
int type = advertisedData[offset++];
switch (type) {
case 0x02: // Partial list of 16-bit UUIDs
case 0x03: // Complete list of 16-bit UUIDs
while (len > 1) {
int uuid16 = advertisedData[offset++];
uuid16 += (advertisedData[offset++] << 8);
len -= 2;
uuids.add(UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", uuid16)));
}
break;
case 0x06:// Partial list of 128-bit UUIDs
case 0x07:// Complete list of 128-bit UUIDs
// Loop through the advertised 128-bit UUID's.
while (len >= 16) {
try {
// Wrap the advertised bits and order them.
ByteBuffer buffer = ByteBuffer.wrap(advertisedData, offset++, 16).order(ByteOrder.LITTLE_ENDIAN);
long mostSignificantBit = buffer.getLong();
long leastSignificantBit = buffer.getLong();
uuids.add(new UUID(leastSignificantBit,
mostSignificantBit));
} catch (IndexOutOfBoundsException e) {
// Defensive programming.
//Log.e(LOG_TAG, e.toString());
continue;
} finally {
// Move the offset to read the next uuid.
offset += 15;
len -= 16;
}
}
break;
default:
offset += (len - 1);
break;
}
}
return uuids;
}
}
here is the code of my BluetoothLeService class
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
public 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";
// UUIDs for UART service and associated characteristics.
public static UUID UART_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
public static UUID TX_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
public static UUID RX_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
// UUID for the UART BTLE client characteristic which is necessary for notifications.
public static UUID CLIENT_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
// UUIDs for the Device Information service and associated characeristics.
public static UUID DIS_UUID = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb");
public static UUID DIS_MANUF_UUID = UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb");
public static UUID DIS_MODEL_UUID = UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb");
public static UUID DIS_HWREV_UUID = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb");
public static UUID DIS_SWREV_UUID = UUID.fromString("00002a28-0000-1000-8000-00805f9b34fb");
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
public final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("STATE CONNECTED", "OK");
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i("STATE CONNECTED BROADCAST SENT - DISCOVERING SERVICES", "OK");
// Attempts to discover services after successful connection.
mBluetoothGatt.discoverServices();
Log.i("AFTER DISCOVER SERVICES", "OK");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("STATE DISCONNECTED", "OK");
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
Log.i("STATE DISCONNECTED BROADCAST SENT", "OK");
}
if(mConnectionState==123334){
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
Log.i("GATT SUCCESS - SERVICES DISCOVERED", "OK");
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
Log.i("INTENT SENT", "OK");
}
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.
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 {
public 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) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.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;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to 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);
}
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
}
What is the target version of targetSdkVersion. I had similar issue and changed build.gradle to
defaultConfig {
applicationId "com.XXX.XXXr"
minSdkVersion 21
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
It solved the problem, but I have some others needs to be solved...
In my case (Adafruit Feather BLE) the following worked
public static String LOG_TAG = "Adafruit Ind";
public static UUID UART_UUID = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
public static UUID TX_UUID = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
public static UUID RX_UUID = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
public static UUID CLIENT_UUID = UUID.fromString("00002902-0000-1000-8000-00805F9B34FB");
public static UUID DIS_UUID = UUID.fromString("000001530-1212-EFDE-1523-785FEABCD123");
public static UUID DIS_MANUF_UUID = UUID.fromString("00002A29-0000-1000-8000-00805F9B34FB");
public static UUID DIS_MODEL_UUID = UUID.fromString("00002A24-0000-1000-8000-00805F9B34FB");
public static UUID DIS_HWREV_UUID = UUID.fromString("00002A26-0000-1000-8000-00805F9B34FB");
public static UUID DIS_SWREV_UUID = UUID.fromString("00002A28-0000-1000-8000-00805F9B34FB");
My goal in this question is push the rssilevel from one .java file to the other.
I tried to push from class 1 to class 2, as well as pulling data dfrom class 1 to class 2 and i have always had my app crash.
I tried
ProximityManager temp = new ProximityManager();
int temp = temp.rssilevel;
The above code is in a class in the same package, but different .java file and class. They are linked.
and it would not work, any other ideas please!
EDIT: Also how would i call the function playSound() in another class?
i would normaly do something like Public ProximityManager mProximityManager;
then call mProximityManager.playSound(); but i get an app crash when i do this.
public class ProximityManager implements BleManager<ProximityManagerCallbacks> {
private final String TAG = "ProximityManager";
private ProximityManagerCallbacks mCallbacks;
private BluetoothGattServer mBluetoothGattServer;
private BluetoothGatt mBluetoothGatt;
private BluetoothDevice mDeviceToConnect;
private Context mContext;
private Handler mHandler;
private LogSession mLogSession;
private Ringtone mRingtoneNotification;
private Ringtone mRingtoneAlarm;
public int rssilevel;
public final static UUID IMMEIDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb");
private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb");
private final static UUID TX_POWER_UUID = UUID.fromString("00001804-0000-1000-8000-00805f9b34fb");
private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change";
private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services";
private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information";
private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic";
private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic";
private final static int HIGH_ALERT = 2;
private final static int MID_ALERT = 1;
private final static int NO_ALERT = 0;
private BluetoothGattCharacteristic mAlertLevelCharacteristic, mLinklossCharacteristic, mBatteryCharacteristic;
private boolean userDisconnectedFlag = false;
public void getrssi( int rssilevel) {
this.rssilevel = rssilevel;
}
public ProximityManager(Context context) {
initializeAlarm(context);
mHandler = new Handler();
// Register bonding broadcast receiver
final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
context.registerReceiver(mBondingBroadcastReceiver, filter);
}
private void openGattServer(Context context, BluetoothManager manager) {
mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks);
}
private void closeGattServer() {
if (mBluetoothGattServer != null) {
// mBluetoothGattServer.cancelConnection(mBluetoothGatt.getDevice()); // FIXME this method does not cancel the connection
mBluetoothGattServer.close(); // FIXME This method does not cause BluetoothGattServerCallback#onConnectionStateChange(newState=DISCONNECTED) to be called on Nexus phones.
mBluetoothGattServer = null;
}
}
private void addImmediateAlertService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app.
*/
BluetoothGattCharacteristic alertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
alertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
BluetoothGattService immediateAlertService = new BluetoothGattService(IMMEIDIATE_ALERT_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
immediateAlertService.addCharacteristic(alertLevel);
mBluetoothGattServer.addService(immediateAlertService);
}
private void addLinklossService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app.
*/
BluetoothGattCharacteristic linklossAlertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE
| BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_WRITE);
linklossAlertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
BluetoothGattService linklossService = new BluetoothGattService(LINKLOSS_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
linklossService.addCharacteristic(linklossAlertLevel);
mBluetoothGattServer.addService(linklossService);
}
private BluetoothGattServerCallback mGattServerCallbacks = new BluetoothGattServerCallback() {
#Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
DebugLogger.d(TAG, "[Proximity Server] onCharacteristicReadRequest " + device.getName());
}
#Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset,
byte[] value) {
DebugLogger.d(TAG, "[Proximity Server] onCharacteristicWriteRequest " + device.getName());
final int receivedValue = value[0];
if (receivedValue != NO_ALERT) {
Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: ON");
playAlarm();
} else {
Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: OFF");
stopAlarm();
}
}
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
DebugLogger.d(TAG, "[Proximity Server] onConnectionStateChange " + device.getName() + " status: " + status + " new state: " + newState);
}
#Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
DebugLogger.d(TAG, "[Proximity Server] onDescriptorReadRequest " + device.getName());
}
#Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
DebugLogger.d(TAG, "[Proximity Server] onDescriptorWriteRequest " + device.getName());
}
#Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
DebugLogger.d(TAG, "[Proximity Server] onExecuteWrite " + device.getName());
}
#Override
public void onServiceAdded(final int status, final BluetoothGattService service) {
DebugLogger.d(TAG, "[Proximity Server] onServiceAdded " + service.getUuid());
mHandler.post(new Runnable() {
#Override
public void run() {
// adding another service from callback thread fails on Samsung S4 with Android 4.3
if (IMMEIDIATE_ALERT_SERVICE_UUID.equals(service.getUuid()))
addLinklossService();
else {
DebugLogger.d(TAG, "[Proximity Server] Gatt server started");
Logger.i(mLogSession, "[Proximity Server] Gatt server started");
if (mBluetoothGatt == null) {
mBluetoothGatt = mDeviceToConnect.connectGatt(mContext, false, mGattCallback);
mDeviceToConnect = null;
} else {
mBluetoothGatt.connect();
}
}
}
});
}
};
/**
* Callbacks for activity {HTSActivity} that implements HTSManagerCallbacks interface activity use this method to register itself for receiving callbacks
*/
#Override
public void setGattCallbacks(ProximityManagerCallbacks callbacks) {
mCallbacks = callbacks;
}
/**
* Sets the log session that can be used to log events
*
* #param logSession
*/
public void setLogger(LogSession logSession) {
mLogSession = logSession;
}
#Override
public void connect(Context context, BluetoothDevice device) {
mContext = context;
// save the device that we want to connect to
mDeviceToConnect = device;
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (preferences.getBoolean(ProximityActivity.PREFS_GATT_SERVER_ENABLED, true)) {
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
try {
DebugLogger.d(TAG, "[Proximity Server] Starting Gatt server...");
Logger.v(mLogSession, "[Proximity Server] Starting Gatt server...");
openGattServer(context, bluetoothManager);
addImmediateAlertService();
// the BluetoothGattServerCallback#onServiceAdded callback will proceed further operations
} catch (final Exception e) {
// On Nexus 4&7 with Android 4.4 (build KRT16S) sometimes creating Gatt Server fails. There is a Null Pointer Exception thrown from addCharacteristic method.
Logger.e(mLogSession, "[Proximity Server] Gatt server failed to start");
Log.e(TAG, "Creating Gatt Server failed", e);
}
} else {
if (mBluetoothGatt == null) {
mBluetoothGatt = mDeviceToConnect.connectGatt(context, false, mGattCallback);
mDeviceToConnect = null;
} else {
mBluetoothGatt.connect();
}
}
}
#Override
public void disconnect() {
if (mBluetoothGatt != null) {
userDisconnectedFlag = true;
mBluetoothGatt.disconnect();
stopAlarm();
closeGattServer();
}
}
private void initializeAlarm(Context context) {
final Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
mRingtoneAlarm = RingtoneManager.getRingtone(context, alarmUri);
mRingtoneAlarm.setStreamType(AudioManager.STREAM_ALARM);
final Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mRingtoneNotification = RingtoneManager.getRingtone(context, notification);
}
private void playNotification() {
DebugLogger.d(TAG, "playNotification");
mRingtoneNotification.play();
}
private void playAlarm() {
DebugLogger.d(TAG, "playAlarm");
final AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
mRingtoneAlarm.play();
}
private void stopAlarm() {
DebugLogger.d(TAG, "stopAlarm");
mRingtoneAlarm.stop();
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc
*/
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
DebugLogger.d(TAG, "Device connected");
mBluetoothGatt.discoverServices();
//This will send callback to ProximityActivity when device get connected
mCallbacks.onDeviceConnected();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
DebugLogger.d(TAG, "Device disconnected");
if (userDisconnectedFlag) {
mCallbacks.onDeviceDisconnected();
userDisconnectedFlag = false;
} else {
playNotification();
mCallbacks.onLinklossOccur();
}
}
} else {
mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
final List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
if (service.getUuid().equals(IMMEIDIATE_ALERT_SERVICE_UUID)) {
DebugLogger.d(TAG, "Immediate Alert service is found");
mAlertLevelCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
} else if (service.getUuid().equals(LINKLOSS_SERVICE_UUID)) {
DebugLogger.d(TAG, "Linkloss service is found");
mLinklossCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
} else if (service.getUuid().equals(BATTERY_SERVICE_UUID)) {
DebugLogger.d(TAG, "Battery service is found");
mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID);
}
}
if (mLinklossCharacteristic == null) {
mCallbacks.onDeviceNotSupported();
gatt.disconnect();
} else {
mCallbacks.onServicesDiscovered(mAlertLevelCharacteristic != null);
writeLinklossAlertLevel(HIGH_ALERT);
}
} else {
mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status);
}
mBluetoothGatt.readRemoteRssi();
DebugLogger.d(TAG, "Finished READING THE RSSI");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
if (rssi != 0) {
rssilevel = rssi; }
else {
rssilevel = 0; }
DebugLogger.d(TAG, "READING THE RSSI");
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC_UUID)) {
int batteryValue = characteristic.getValue()[0];
mCallbacks.onBatteryValueReceived(batteryValue);
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (characteristic.getUuid().equals(ALERT_LEVEL_CHARACTERISTIC_UUID)) {
if (mBatteryCharacteristic != null) {
readBatteryLevel();
}
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
mCallbacks.onError(ERROR_WRITE_CHARACTERISTIC, status);
}
}
};
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
// skip other devices
if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
return;
DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState);
if (bondState == BluetoothDevice.BOND_BONDING) {
mCallbacks.onBondingRequired();
return;
}
if (bondState == BluetoothDevice.BOND_BONDED) {
if (mLinklossCharacteristic != null) {
writeLinklossAlertLevel(HIGH_ALERT);
}
mCallbacks.onBonded();
}
}
};
private void readBatteryLevel() {
if (mBatteryCharacteristic != null) {
DebugLogger.d(TAG, "reading battery characteristic");
mBluetoothGatt.readCharacteristic(mBatteryCharacteristic);
} else {
DebugLogger.w(TAG, "Battery Level Characteristic is null");
}
}
#SuppressWarnings("unused")
private void readLinklossAlertLevel() {
if (mLinklossCharacteristic != null) {
DebugLogger.d(TAG, "reading linkloss alert level characteristic");
mBluetoothGatt.readCharacteristic(mLinklossCharacteristic);
} else {
DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is null");
}
}
private void writeLinklossAlertLevel(int alertLevel) {
if (mLinklossCharacteristic != null) {
DebugLogger.d(TAG, "writing linkloss alert level characteristic");
mLinklossCharacteristic.setValue(alertLevel, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mLinklossCharacteristic);
} else {
DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is not found");
}
}
public void writeImmediateAlertOn() {
if (mAlertLevelCharacteristic != null) {
DebugLogger.d(TAG, "writing Immediate alert characteristic On");
mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mAlertLevelCharacteristic.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic);
} else {
DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found");
}
}
public void writeImmediateAlertOff() {
if (mAlertLevelCharacteristic != null) {
DebugLogger.d(TAG, "writing Immediate alert characteristic Off");
mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mAlertLevelCharacteristic.setValue(NO_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic);
} else {
DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found");
}
}
#Override
public void closeBluetoothGatt() {
try {
mContext.unregisterReceiver(mBondingBroadcastReceiver);
} catch (Exception e) {
// the receiver must have been not registered or unregistered before
}
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
mBluetoothGatt = null;
}
if (mBluetoothGattServer != null) {
mBluetoothGattServer.close();
mBluetoothGattServer = null;
}
mCallbacks = null;
mLogSession = null;
mRingtoneAlarm = mRingtoneNotification = null;
}
}
I'm getting the next exception, when I called a method in a Service, and when debug, I see that onServiceConnected never executes. I've tried to put Logs inside it, but it never executes, I get tired of waiting for it.
05-18 19:31:13.998 7031-7031/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.geochildfragment.app, PID: 7031
java.lang.NullPointerException
at com.geochildfragment.app.ActivityMain.sendPin(ActivityMain.java:249)
at com.geochildfragment.app.FragmentLinkDevice$4.onClick(FragmentLinkDevice.java:224)
at android.view.View.performClick(View.java:4626)
at android.view.View$PerformClick.run(View.java:19293)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5293)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)
This is my activity, I call the sendPin method, that it's throwing the exception, from a fragment:
int bStatus;
Boolean connected = false;
BluetoothDevice bDevice;
private BLEService bleService;
BluetoothGattService gattService;
public static final String EXTRA_BLUETOOTH_DEVICE = "BT_DEVICE";
BluetoothAdapter bAdapter;
Context context;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
bleService = ((BLEService.LocalBinder) service).getService();
if (!bleService.initialize()){
finish();
}
bleService.context = context;
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
bleService=null;
}
};
private final BroadcastReceiver serviceUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BLEService.ACTION_GATT_CONNECTED.equals(action)) {
connected = true;
//invalidateOptionsMenu();
} else if (BLEService.ACTION_GATT_DISCONNECTED.equals(action)) {
connected = false;
//invalidateOptionsMenu();
} else if (BLEService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
List<BluetoothGattService> servicesList;
servicesList = bleService.getSupportedGattServices();
Iterator<BluetoothGattService> iter = servicesList.iterator();
while (iter.hasNext()) {
BluetoothGattService bService = (BluetoothGattService) iter.next();
if (bService.getUuid().toString().equals(BLEUUID.SERVICE)){
gattService = bService;
}
}
} else if (BLEService.ACTION_DATA_AVAILABLE.equals(action)) {
........
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
Bundle extra = this.getIntent().getExtras();
getConnectedDevices(extra);
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);
bStatus = BluetoothProfile.STATE_DISCONNECTED;
}
#Override
public void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
bleService = null;
}
#Override
public void onResume() {
super.onResume();
registerReceiver(serviceUpdateReceiver, makeGattUpdateIntentFilter());
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(serviceUpdateReceiver);
}
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
public void sendPin(BluetoothDevice bDevice, String pin) {
String deviceAddress = bDevice.getAddress();
bleService.connect(deviceAddress);
bleService.sendPINCharacteristic(pin, bDevice);
}
public void verifyPIN(String data){
FragmentLinkDevice f = (FragmentLinkDevice) getSupportFragmentManager().findFragmentById(R.id.link_device_fragment);
if (data.contains(BroadcastIDs.OK)){
f.launchDeviceConfigActivity()
} else if (data.contains(BroadcastIDs.FAIL)){
f.launchAlertDialog();
}
}
}
In the manifest I've declared it by:
<service android:name="Bluetooth.BLEService" android:enabled="true"/>
This is the service:
public class BLEService extends Service {
private static int DELAY = 3000;
private final static String TAG = BLEService.class.getSimpleName();
public Context context;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
BluetoothGattService mService;
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 SERVICE = BLEUUID.SERVICE;
public final static UUID PIN_CHARACTERISTIC = UUID.fromString(BLEUUID.PIN_CHARACTERISTIC_UUID);
public final static UUID PUK_CHARACTERISTIC = UUID.fromString(BLEUUID.PUK_UUID);
public final static UUID INTERVAL_CHARACTERISTIC = UUID.fromString(BLEUUID.INTERVAL_UUID);
public final static UUID ROUTE_INTERVAL_CHARACTERISTIC = UUID.fromString(BLEUUID.ROUTE_INTERVAL_UUID);
public final static UUID ON_OFF_CHARACTERISTIC = UUID.fromString(BLEUUID.ON_OFF_UUID);
public final static UUID GPS1_CHARACTERISTIC= UUID.fromString(BLEUUID.GPS1_UUID);
public final static UUID GPS2_CHARACTERISTIC= UUID.fromString(BLEUUID.GPS2_UUID);
public final static UUID BATTERY_CHARACTERISTIC = UUID.fromString(BLEUUID.BATTERY_LEVEL_UUID);
public final static UUID DEVICE_NAME_CHARACTERISTIC = UUID.fromString(BLEUUID.DEVICE_NAME_UUID);
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);
Devices device = new Devices();
device = device.FindByDeviceAddress(mBluetoothDeviceAddress);
//showPerimeterNotification(device);
}
}
#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);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
readCharacteristic(characteristic);
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status){
if (status== BluetoothGatt.GATT_SUCCESS){
Toast.makeText(context, "onDescriptorWrite: SUCCESS", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(context, "onDescriptorWrite: FAILURE", Toast.LENGTH_LONG).show();
}
}
};
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, BroadcastIDs.PIN + String.valueOf(pin));
disconnect();
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
public BLEService getService() {
return BLEService.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) {
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;
}
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 = characteristic.getDescriptor
(UUID.nameUUIDFromBytes(BLEUUID.fromHexToString(BLEUUID.PIN_CHARACTERISTIC_CONFIG_DESCRIPTOR)));*/
BluetoothGattDescriptor descriptor =
new BluetoothGattDescriptor(UUID.fromString(BLEUUID.CONFIG_UUID),BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED);
//descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
public void sendPINCharacteristic(String pin, BluetoothDevice device){
byte[] pinByte = pin.getBytes();
int pinInt = Integer.valueOf(pin);
connect(device.getAddress());
final BluetoothGattCharacteristic ch = (BluetoothGattCharacteristic) mService.getCharacteristic(UUID
.fromString(BLEUUID.PIN_CHARACTERISTIC_UUID));
ch.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
ch.setValue(pin);
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
setCharacteristicNotification(ch, true);
mBluetoothGatt.writeCharacteristic(ch);
}
}
Does somebody know what's the problem?
Try to declare the complete package path for the BLEService class in your AndroidManifest.xml. For example
<service android:name="com.example.bluetooth.le.BLEService" android:enabled="true"/>
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.