First, sorry for my english, second, I have a problem with a BluetoothGattCallback in Android studio for ble, the app runs, I go in research and connection and it's ok, but the method in the callback never starts, my principal interest is rssi.
This is my gattcallback:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
Toast.makeText(MainActivity.this, "fin qui tutto ok", Toast.LENGTH_LONG).show();
TextView Rssitext = (TextView) findViewById(R.id.textView8);
Rssitext.setText("RSSI"+ "null");
if (status == gatt.STATE_CONNECTED) {
Toast.makeText(MainActivity.this,rssi, Toast.LENGTH_LONG).show();
Rssitext.setText("RSSI"+ rssi);
}
else {
Toast.makeText(MainActivity.this,"fail read rssi", Toast.LENGTH_LONG).show();
Rssitext.setText("RSSI"+ "null");
}
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
boolean rssiStatus = mBluetoothGatt.readRemoteRssi();
broadcastUpdate(intentAction);
Toast.makeText(MainActivity.this, "Connected to GATT server." , Toast.LENGTH_LONG).show();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Toast.makeText(MainActivity.this,"Disconnected from GATT server.", Toast.LENGTH_LONG).show();
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Toast.makeText(MainActivity.this,"onServicesDiscovered received: " + status, Toast.LENGTH_LONG).show();
}
}
and now when I call, I use has for automatic connect to specific device when are found
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
Toast.makeText(MainActivity.this, device.getName() + " " + device.hashCode(), Toast.LENGTH_LONG).show();
if ((device.hashCode() == 676210690)|| (device.hashCode() == -1001190065))
{
mBluetoothGatt= device.connectGatt(context, false, mGattCallback);
Toast.makeText(MainActivity.this,
"sought after device found", Toast.LENGTH_LONG).show();
mBluetoothGatt.readRemoteRssi();
}
}
}
};
Related
I am trying to connect to the i-phone via Android Bluetooth + BLE.
My goal is to read iOS notifications via Android Bluetooth + BLE.
I am able to show the i-phone Bluetooth in the android app and was able to connect to the i-phone but I am unable to found the Notification characteristic.
I got notification characteristic UUID from this link I am using Notification Source: UUID
Here is my BluetoothGattCallback:
public BluetoothGattCallback mCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
final BluetoothGatt mGatt = gatt;
Handler handler;
handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
mGatt.discoverServices();
}
});
//gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
try
{
Log.i("no_conn", "Connection unsuccessful with status"+status);
//mGatt.disconnect();
mGatt.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.i("Not success", "Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattService> matchingServices = gatt.getServices();
gatt.getService(UUID.fromString(SERVICE_STRING));
List<BluetoothGattCharacteristic> matchingCharacteristics = BluetoothUtils.findCharacteristics(gatt);
if (matchingCharacteristics.isEmpty()) {
Log.i("No characteristics", "Unable to find characteristics.");
showToast("No characteristic found");
return;
}else {
showToast("characteristic found");
}
}
};
Here is my findCharacteristics function:
public static List<BluetoothGattCharacteristic> findCharacteristics1(BluetoothGatt bluetoothGatt) {
List<BluetoothGattCharacteristic> matchingCharacteristics = new ArrayList<>();
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = null;
for (BluetoothGattService bgservice : serviceList) {
String serviceIdString = bgservice.getUuid()
.toString();
if (matchesServiceUuidString(serviceIdString)) {
service = bgservice;
}
}
if (service == null) {
Log.i("Null service", "Null service.");
return matchingCharacteristics;
}
return matchingCharacteristics;
}
Here I am matching with serviceIdString with the Notification Source: UUID.
Am I missing anything?
I call on my bluetooth adapter mBluetoothAdapter.startDiscovery(); which then returns me a list of BluetoothDevices. When I press on 1 of those devices, I do this:
mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, mGattCallback);
Where my callback is:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("","list size: " + listBGS.size());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onServicesDiscovered GATT_SUCCESS: " + status);
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("","list size: " + listBGS.size());
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onCharacteristicRead GATT_SUCCESS: " + status + " / char: " + characteristic);
}
}
};
Now, when I try it on phones, I get STATE_CONNECTED on onConnectionStateChange , and I then call discoverServices, and I get back a GATT_SUCCESS onServicesDiscoveres. So I can take the uuids from my services.
BUT when I try it on a beacon, I get back STATE_CONNECTED and when I call discoverServices, I get back an status code: 129 -> GATT_INTERNAL_ERROR
Why is this happening for my beacons? Is there another way, how I can take the devices uuid?
I just need the UUID to be able to do this after, for the beaconManager:
try {
beaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId", null, null, null));
} catch (RemoteException e) { }
EDIT
I know that the beacon should ask me for a code to pair, but it doesn't. Why?
I tried adding this code:
final IntentFilter pairingRequestFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingRequestFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
registerReceiver(mPairingRequestRecevier, pairingRequestFilter);
But still I don't get a request to pair and input my passkey
This is my pairingRequestReceiver:
private final BroadcastReceiver mPairingRequestRecevier = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction()))
{
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if (type == BluetoothDevice.PAIRING_VARIANT_PIN)
{
device.setPin(intToByteArray(123456));
abortBroadcast();
}
else
{
Log.e("","Unexpected pairing type: " + type);
}
}
}
};
After hours of trial and error I did manage to find a way to make it work like this:
1.I start the discovery the same, but when I select an bluetooth device, I ask to bond (pair) with it like this:
private void pairDevice(BluetoothDevice device) {
try {
Method method = device.getClass().getMethod("createBond", (Class[]) null);
method.invoke(device, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
}
}
I have a ACTION_BOND_STATE_CHANGED receiver:
private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
if (state == BluetoothDevice.BOND_BONDED && prevState == BluetoothDevice.BOND_BONDING) {
Log.i("","Paired");
mBluetoothGatt = btDevice.connectGatt(MainActivity.this, false, mGattCallback);
} else if (state == BluetoothDevice.BOND_NONE && prevState == BluetoothDevice.BOND_BONDED){
Log.i("","Unpaired");
}
}
}
};
Which I register like this:
IntentFilter intent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mPairReceiver, intent);
And only after this, I try to connect with my BluetoothGattCallback. Hence, I can discover the services, and so on
How do I notify users if the device they are trying to connect to does not connect, besides waiting and testing for a connection. There does not seem to be any callback for a failed connection after trying connectGatt().
Thanks!
The method: connGATT() has 3 parameters. The third one is a callback:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
if you want to know the connection is success or not, you should add override the method:
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState)
Here is the link.https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
The whole callback looks like this:
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
// New services discovered
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
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
...
};
...
}
I am new to android development and currently I am trying to modify the sample code for Bluetooth LE interfacing found here https://developer.android.com/samples/BluetoothLeGatt/index.html .
This demo project is divided into two activities but I want to reduce it to one activity; the DeviceControlActivity is changed into a 'regular' Java class.
After a few attempts I made the BluetoothLeService run with this constructor of my Device Control class:
public DeviceControl (BluetoothDevice device, Context context) {
mDeviceName = device.getName();
mDeviceAddress = device.getAddress();
this.context = context;
Log.d(TAG, "DeviceControl construktor");
Log.d(TAG, "Context = " + context);
Intent gattServiceIntent = new Intent(context, BluetoothLeService.class);
context.bindService(gattServiceIntent, mServiceConnection, context.BIND_AUTO_CREATE);
}
The BluetoothLeService class is ridden with Log.d()'s and seems to work fine; however, the broadcasts it emits here:
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) {
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);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
Log.d(TAG, "Methode broadcastUpdate aufgerufen. Action = " + action);
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
However, they never arrive in the DeviceControl Class I originally bound the service to:
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Broadcast received");
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
System.out.println("GATT-services discovered");
displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
}
}
};
What's wrong here?
I cannot comment yet, but is it registered?
You have to register the broadcast receiver with the registerReceiver method.
P.S. If you are using the AppCompat library and do not need the broadcasts to leave your app, also look into the LocalBroadcastManager.
Thanks RobK,
Indeed I didn't register the broadcast. The code for registering wasn't in the onCreate() method in the sample project activity where I expectet everything necessary to set up the Service, but in the onResume() method.
Adding
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
Log.d(TAG, "Connect request result=" + result);
}
to the constructor and an additional custom intent filter
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;
}
solved it for me.
i have two problem.I want connect my ble service .I can connect but i cant disconnect serive when i use mService.disconnect(); my app will crash.and other problem is i cant send value to RXchar......
All problem are dispaly on a null object reference
this is disconnect error
RxChar error
my code _ble_fragment
switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
try {
//send data to service
if (isChecked) {
message = "1";
} else {
message = "0";
}
value = message.getBytes("UTF-8");
sendText.setText(message);
mService.writeRXCharacteristic(value);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
scanButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("click", "按下去了");
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onClick - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else {
if (scanButton.getText().equals("Connect")) {
Log.i("scan", "open device");
switch1.setEnabled(true);
//Connect button pressed, open DeviceListActivity class, with popup windows that scan for devices
Intent newIntent = new Intent(getActivity(), DeviceListActivity.class);
startActivity(newIntent);
} else {
//Disconnect button pressed
mService.disconnect();
Log.i("Diconnect", "Disconnect Ble");
// mHandler.removeCallbacks(runnable);
}
}
}
});
DeviceList & UartService code:
public void writeGatt(BluetoothDevice dev){
byte[] msgBuffer; //bluetooth send alway byte
String message = "1"; //ON
msgBuffer = message.getBytes();
mBtGatt = dev.connectGatt(this,false,GattCallback);//call Gattcallback
}
private final BluetoothGattCallback GattCallback = new BluetoothGattCallback() { //
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBtGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
// New services discovered
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
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
};
public void disconnect() { //deisconnect
if (mBtGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBtGatt.close();
mBtGatt = null;
// mBluetoothGatt.close();
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Log.i("broadcastUpdate", "run broadcastUpdate send " + intent);
}
public void close() {
if (mBtGatt == null) {
return;
}
Log.w(TAG, "mBluetoothGatt closed");
;
mBtGatt.close();
mBtGatt = null;
}
public void writeRXCharacteristic(byte[] value)
{
/* BluetoothGattService RxService = mBtGatt.getService(RX_SERVICE_UUID);
//showMessage("mBluetoothGatt null"+ mBluetoothGatt);
if (RxService == null) {
//showMessage("Rx service not found!");
// broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
Log.i("RxService is null!!","RxService is null!!");
return;
}
BluetoothGattCharacteristic RxChar = RxService.getCharacteristic(RX_CHAR_UUID);
if (RxChar == null) {
// showMessage("Rx charateristic not found!");
//broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
Log.i("RxCHAR is null!!","RxCHAR is null!!");
return;
}
RxChar.setValue(value);
boolean status = mBtGatt.writeCharacteristic(RxChar);
Log.d(TAG, "write TXchar - status=" + status);*/
BluetoothGattService RxService=null;
while( RxService==null) {
try{
RxService = mBtGatt.getService(RX_SERVICE_UUID);}
catch(Exception e){
Log.d(TAG, e.toString());}
}
if (RxService == null) {
Log.d(TAG, "1");
return;
}BluetoothGattCharacteristic RxChar=null;
while( RxChar ==null){
try{
RxChar = RxService.getCharacteristic(RX_CHAR_UUID);}
catch(Exception e)
{Log.d(TAG, e.toString());}
}
if (RxChar == null) {
Log.d(TAG, "2");
return;
}
RxChar.setValue(value);
mBtGatt.writeCharacteristic(RxChar);
}
what can i do?
you can try this:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter.isEnabled()){
bluetoothAdapter.disable();
}
you need add two permission bellow:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>