Search code examples
javaandroidarduinobluetoothbluetooth-lowenergy

How to get BLE devices' names list by android app?


Hello I am making a bluetooth connecting android app. I followed the instruction from developer.android.com while I am testing my app, I look forward to it works properly, but it didn't. I tried to get detected BLE devices names, but don't know the reason why it doesn't show me the devices name...

Arduino nano 33 IOT is adverstising bluetooth next to my android phone, and I am trying to detect it and get the Adrduino's BLE device name and address.

here is my MainActivity.java

public class MainActivity extends AppCompatActivity {

    //View Contents Elements
    public Button btnActivateBluetooth;
    public Button btnSearchBluetooth;
    public Button btnSendData;
    public ListView lvSearchedDevice;
    public ListView lvLog;
    public TextView tvStatus;
    public EditText etData;

    //etc values
    public ArrayAdapter<String> logAdapter;
    private final int REQUEST_ENABLE_BT = 1;
    private boolean mScanning = true;

    //bluetooth values
    public BluetoothAdapter btAdapter;
    public BluetoothManager btManager;
    private Handler handler;


    @SuppressLint("MissingPermission")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //View Elements
        btnSearchBluetooth = (Button) findViewById(R.id.btnSearchBluetooth);
        btnSendData = (Button) findViewById(R.id.btnSendData);
        lvSearchedDevice = (ListView) findViewById(R.id.lvSearchedDevice);
        lvLog = (ListView) findViewById(R.id.log);
        tvStatus = (TextView) findViewById(R.id.tvStatus);
        etData = (EditText) findViewById(R.id.etData);

        //etc
        logAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
        lvLog.setAdapter(logAdapter);
        handler = new Handler();

        // Initializes Bluetooth adapter.
        btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
        btAdapter = btManager.getAdapter();

        // displays a dialog requesting user permission to enable Bluetooth.
        if (btAdapter == null || !btAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        btnSearchBluetooth.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                scanLeDevice(true);
            }
        });
    }

    //Scan devices
    @SuppressLint("MissingPermission")
    private void scanLeDevice(final boolean enable){
        if(enable){
            handler.postDelayed(new Runnable() {
                @SuppressLint("MissingPermission")
                @Override
                public void run() {
                    btAdapter.stopLeScan(leScanCallback);
                }
            },5000);
            btAdapter.startLeScan(leScanCallback);
        }
        else
        {
            btAdapter.stopLeScan(leScanCallback);
        }
    }

    //Callback method
    private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
            runOnUiThread(new Runnable() {
                @SuppressLint("MissingPermission")
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, device.getName(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    };
}

and this is my Arduino nano 33 IOT's code.

#include <ArduinoBLE.h>
BLEService Toothbrush("00001101-0000-1000-8000-00805F9B34FB");
BLEStringCharacteristic ToothbrushChar("00001101-0000-1000-8000-00805F9B34FB",BLEWrite|BLERead | BLENotify, 10);

void setup() {
  Serial.begin(9600);
  if(!BLE.begin()){
    Serial.println("Starting BLE failed.");
    while(1);
  }
  BLE.setLocalName("HayanToothbrush");
  BLE.setAdvertisedService(Toothbrush);
  Toothbrush.addCharacteristic(ToothbrushChar);
  BLE.addService(Toothbrush);
  BLE.advertise();

  Serial.println("Bluetooth device active, wating for connections...");
}

void loop() {
  BLEDevice central = BLE.central();
  
  if(central) {
    Serial.print("Connected to central : ");
    Serial.println(central.address());

    while(central.connected()){
      
    }
    Serial.print("Disconnected from central:");
    Serial.println(central.address());
  }
}

I add permissions in the Mainfest as below.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.bluetooth0523">

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Bluetooth0523"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

But it still doesn't find me scanned device name. I think it's on LeScanCallBack problem. When running startLeScan, It seems not running callback method. in addition, I am running this app on SDK_VERSION_30 and Arduino nano IOT 33 is discoverable If I use the Bluetooth function that my phone has, not my application, it will be displayed in the scan result list. Phone's own Bluetooth I want to get scan result on my own app. but don't know where is the problem.


Solution

  • Permissions must be declared and requested depending on Android version. Main differences are:

    Target Android 12 or higher

    BLUETOOTH_SCAN
    

    Target Android 11 or lower

    ACCESS_FINE_LOCATION
    

    See Bluetooth permissions for details.