I am new to android and BLE. I am working on BLE android application. In the application, we are checking battery percentage and distance between 2 devices. We need to capture these details and save it to the file.
Currently we are able to do the task but only for few seconds. After few seconds, it fails with following error. Also please find below code for your reference.
Android version : 10 Testing on Samsung A31
Error : ERROR:bta_gattc_utils.cc(434)] bta_gattc_mark_bg_conn unable to find the bg connection mask for bd_addr=a4:c1:38:a2:c1:f9
Code :
**MainActivity.java**
package com.renesas.socialband;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.Menu;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.navigation.NavigationView;
import com.google.gson.Gson;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity implements devicedata, SettingFragment.OnHeadlineSelectedListener,
DataDisplayFragment.onDisplayFragmentPause {
private static final int REQUEST_ENABLE_BT = 1;
public static final int BLE_INIT_CMD = 7;
public static final int BLE_INIT_IND = 8;
public static final int BLE_INIT_COMPLETE = 9;
public static final int BLE_NULL = 10;
public static final int BLE_SCAN_CMD = 2;
private static final int BLE_SCANNING = 11;
public static final int BLE_SCAN_DEV_IND = 3;
public static final int BLE_SCAN_COMPLETE_IND = 4;
public static final int BLE_SCAN_CANCEL_CMD = 5;
private static final int BLE_SCAN_CANCEL_IND = 6;
public static final int BLE_CONNECT_CMD = 12;
public static final int BLE_CONNECTING = 17;
public static final int BLE_CONNECTED = 22;
public static final int BLE_CONNECTION_SUCCESS = 13;
public static final int BLE_DISCONNECT_CMD = 20;
public static final int BLE_DISCONNECTING = 28;
public static final int BLE_DISCONNECTED = 18;
public static final int BLE_NOTIFICATION_DISTANCE_DATA = 14;
public static final int BLE_NOTIFICATION_DEVICE_INFORMATION = 15;
public static final int BLE_WRITE_DEVICE_CONFIG_DATA = 16;
private BluetoothLeScanner bluetoothLeScanner;
private int myBleState = BLE_NULL;
private String mydeviceSettings;
BluetoothGatt gatt;
List<BluetoothGattService> mygattservices;
myBluetoothhandler p;
BluetoothAdapter bluetoothAdapter;
BluetoothDevice connectedDevice;
private Boolean SettingFragmentDisplayed = false;
@Override
public void onArticleSelected( String config ) {
Log.e("BLE", "Receiving settings data = " + config);
myBleDispatcher(BLE_WRITE_DEVICE_CONFIG_DATA, null, config);
}
@Override
public void onmyDisplayFragmentPause() {
Log.e("BLE", "DisplayFragment paused");
}
public static class myBluetoothMessage {
int state;
int command;
String mydata;
String myAddress;
ArrayList<BluetoothDevice> mDevices;
BluetoothDevice device;
}
// private ScanCallback leScanCallback;
private AppBarConfiguration mAppBarConfiguration;
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
private ProgressBar simpleProgressBar;
private MenuItem mySettings;
private MenuItem myDevice;
private ArrayList<BluetoothDevice> mDevices = new ArrayList<>();
private static final int BLUETOOTH_PERMISSION_CODE = 100;
private BluetoothGatt mBluetoothGatt;
Gson gson;
static String BATTERY_SERVICE_UUID = "0000180f-0000-1000-8000-00805f9b34fb";
static String BATTERY_LEVEL_UUID = "00002a19-0000-1000-8000-00805f9b34fb";
static String CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID = "00002902-0000-1000-8000-00805f9b34fb";
// fragment handling
DataDisplayFragment firstFragment;
SettingFragment mySettingFragment;
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.findViewById(R.id.action_settings);
setSupportActionBar(toolbar);
final FloatingActionButton fab = findViewById(R.id.fab);
simpleProgressBar = (ProgressBar) findViewById(R.id.progressBar); // initiate the progress bar
simpleProgressBar.setVisibility(View.GONE);
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences(getString(R.string.connectedDevice), Context.MODE_PRIVATE);
String mTest = sharedPreferences.getString(getString(R.string.connectedDevice), null);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick( View view ) {
if((connectedDevice != null) && (myBleState != BLE_CONNECTING))
{
Log.e("BLE","Reconnecting to device");
myBleState = BLE_CONNECTING;
myBleDispatcher(BLE_CONNECT_CMD, connectedDevice, null);
return;
}
if (myBleState == BLE_INIT_COMPLETE) {
myBleState = BLE_SCANNING;
mDevices.clear();
mAdapter.notifyDataSetChanged();
simpleProgressBar.setVisibility(View.VISIBLE);
myBleDispatcher(BLE_SCAN_CMD, null, null);
Toast.makeText(MainActivity.this, "Scanning bluetooth devices",
Toast.LENGTH_LONG).show();
} else if (myBleState == BLE_SCANNING) {
myBleDispatcher(BLE_SCAN_CANCEL_CMD, null, null);
simpleProgressBar.setVisibility(View.GONE);
myBleState = BLE_INIT_COMPLETE;
Toast.makeText(MainActivity.this, "Scanning cancelled",
Toast.LENGTH_LONG).show();
}else if (myBleState == BLE_CONNECTING) {
myBleDispatcher(BLE_CONNECT_CMD, connectedDevice, null);
}
}
});
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
recyclerView = (RecyclerView) findViewById(R.id.myRecyclerView);
recyclerView.setHasFixedSize(true);
// use a linear layout manager
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
// specify an adapter (see also next example)
mAdapter = new myAdapter(mDevices, this);
recyclerView.setAdapter(mAdapter);
firstFragment = new DataDisplayFragment();
mySettingFragment = new SettingFragment();
if (this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
} else {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, BLUETOOTH_PERMISSION_CODE);
}
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
if (mTest != null)
connectedDevice = bluetoothAdapter.getRemoteDevice(mTest);
BleUiHandler myUihandler = new BleUiHandler();
p = new myBluetoothhandler(this, myUihandler, bluetoothAdapter);
new Thread(p).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
myBleDispatcher(BLE_INIT_CMD, null, null);
}
BluetoothGattCallback gattCallback =
new BluetoothGattCallback() {
@Override
public void onConnectionStateChange( BluetoothGatt gatt, int status,
int newState ) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.e("BLE", "Connected to GATT server.");
Log.e("BLE", "Attempting to start service discovery:");
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.e("BLE", "Disconnected from GATT server.");
}
}
;
@Override
public void onServicesDiscovered( BluetoothGatt gatt, int status ) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
Log.e("BLE", "onServicesDiscovered Success received: " + status);
mygattservices = gatt.getServices();
BluetoothGattService batteryService = gatt.getService(UUID.fromString(BATTERY_SERVICE_UUID));
if (batteryService == null) {
Log.e("BLE", "Battery service not found!");
} else
Log.e("BLE", "Battery service found!");
BluetoothGattCharacteristic batteryLevel = batteryService.getCharacteristic(UUID.fromString(BATTERY_LEVEL_UUID));
if (batteryLevel == null) {
Log.e("BLE", "Battery characteristic not found!");
return;
} else {
Log.e("BLE", "Battery characteristic found!");
Log.e("BLE", String.valueOf(gatt.readCharacteristic(batteryLevel)));
// setCharacteristicNotification(gatt,batteryLevel,true);
}
} else {
Log.e("BLE", "onServicesDiscovered received: " + status);
}
}
@Override
public void onCharacteristicRead( BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status ) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e("BLE", "onCharacteristicRead: " + status);
Log.e("BLE", "onCharacteristicRead: " + status);
}
}
@Override
public void onDescriptorWrite( BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status ) {
Log.e("BLE", "Write Descriptor Status = " + status);
}
@Override
public void onCharacteristicChanged( BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic ) {
Log.e("BLE", "FINALLY SOMETHING CHANGED ");
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.e("BLE", " format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.e("BLE", " format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 0);
Log.e("BLE", String.format("FINALLY SOMETHING CHANGED %x", heartRate));
}
};
@Override
public void onClick( BluetoothDevice mDevice ) {
Log.e("BLE", "OOPS FINALLY");
if (firstFragment.isAdded())
return;
getSupportFragmentManager().beginTransaction()
.add(R.id.listcontainer, firstFragment).addToBackStack("devicedetails").commit();
connectedDevice = mDevice;
myBleState = BLE_CONNECTING;
myBleDispatcher(BLE_CONNECT_CMD, mDevice, null);
}
public boolean setCharacteristicNotification( BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic characteristic, boolean enable ) {
boolean setstate;
byte[] value = new byte[0];
bluetoothGatt.setCharacteristicNotification(characteristic, enable);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID));
int properties = characteristic.getProperties();
if ((properties & 0x00000010) > 0) {
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
} else if ((properties & 0x00000020) > 0) {
value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
}
descriptor.setValue(value);
setstate = bluetoothGatt.writeDescriptor(descriptor); //descriptor write operation successfully started?
Log.e("BLE", "SET STATE" + setstate);
return setstate;
}
@Override
public boolean onOptionsItemSelected( MenuItem item ) {
switch (item.getItemId()) {
case R.id.action_settings:
Log.e("SETTING", "SELECTED");
if (mySettingFragment.isAdded())
return true;
getSupportFragmentManager().beginTransaction()
.add(R.id.listcontainer, mySettingFragment).addToBackStack("settings").commit();
SettingFragmentDisplayed = true;
return true;
case R.id.action_delete:
SharedPreferences sharedPref = getApplicationContext().getSharedPreferences(getString(R.string.connectedDevice), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.clear();
editor.commit();
getSupportFragmentManager().popBackStack();
if((myBleState == BLE_CONNECTING) || (myBleState == BLE_CONNECTED) ) {
myBleDispatcher(BLE_DISCONNECT_CMD, connectedDevice, null);
myBleState = BLE_DISCONNECTING;
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public class BleUiHandler extends Handler {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void handleMessage( Message msg ) {
// Log.e("BLE","Received UI Event");
myBluetoothMessage myUiMessage = (myBluetoothMessage) msg.obj;
switch (myUiMessage.command) {
case BLE_INIT_IND:
myBleState = BLE_INIT_COMPLETE;
if (connectedDevice != null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.listcontainer, firstFragment).addToBackStack("devicedetails").commit();
myBleState = BLE_CONNECTING;
// mySettings.setEnabled(true);
simpleProgressBar.setVisibility(View.VISIBLE);
myBleDispatcher(BLE_CONNECT_CMD, connectedDevice, null);
}
break;
case BLE_SCAN_DEV_IND:
mDevices.add(myUiMessage.device);
mAdapter.notifyDataSetChanged();
break;
case BLE_SCAN_COMPLETE_IND:
Log.e("BLE", "BLE_SCAN_COMPLETE_IND");
simpleProgressBar.setVisibility(View.GONE);
myBleState = BLE_INIT_COMPLETE;
break;
case BLE_CONNECTION_SUCCESS:
Log.e("BLE", "BLE connection success storing device");
if(myBleState == BLE_DISCONNECTING)
{
myBleDispatcher(BLE_DISCONNECT_CMD, connectedDevice, null);
return;
}
myBleState= BLE_CONNECTED;
if(connectedDevice != null) {
SharedPreferences sharedPref = getApplicationContext().getSharedPreferences(getString(R.string.connectedDevice), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(getString(R.string.connectedDevice), connectedDevice.getAddress());
editor.apply();
}
// mySettings.setEnabled(true);
// firstFragment.onDataChage("32,32.33");
break;
case BLE_DISCONNECTED:
// Toast.makeText(getApplicationContext(),"DISCONNECTED",Toast.LENGTH_LONG);
if(connectedDevice != null)
{
return;
}
myBleState= BLE_INIT_COMPLETE;
getSupportFragmentManager().popBackStack();
//firstFragment.ongattDisconnected();
connectedDevice = null;
break;
case BLE_NOTIFICATION_DEVICE_INFORMATION:
mydeviceSettings = myUiMessage.mydata;
mySettingFragment.fragmentInitData(mydeviceSettings);
break;
case BLE_NOTIFICATION_DISTANCE_DATA:
try {
firstFragment.onDataChage(myUiMessage.mydata);
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
**DataDisplayFragment.java**
package com.renesas.socialband;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DataDisplayFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class DataDisplayFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private View myFragView;
ProgressBar PB;
onDisplayFragmentPause myFragmentcallBack;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public String FILE_NAME = "socialbandlogs.txt";
public DataDisplayFragment() {
// Required empty public constructor
}
@RequiresApi(api = Build.VERSION_CODES.O)
public void FileLoggermessage(View v, String aLogMessage) throws IOException {
Log.e("FileLogger","Inside File Logger");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
Log.e("FileLogger", String.valueOf(now));
String Final_Message= now + " : " + aLogMessage + "\n";
FileOutputStream fos = null;
try {
// Context context = null;
fos = v.getContext().openFileOutput(FILE_NAME, Context.MODE_APPEND);
fos.write(Final_Message.getBytes() );
//Toast.makeText(this, "Saved to " + getFilesDir() + "/" + FILE_NAME, Toast.LENGTH_LONG).show();
// Toast.makeText(this, now + ": Saved to \" + getFilesDir() + \"/\" + FILE_NAME",Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
User contributions licensed under CC BY-SA 3.0