Bluetooth discovery issue in Android versions above 12

194 Views Asked by At

I am programming a very simple test Android application that makes a discovery of bluetooth devices and displays them on screen. This application works correctly on Android 9, but does not work correctly on Android 12. I have no problems requesting permissions, and it detects them correctly. In fact, it successfully runs bluetoothAdapter.startDiscovery(), but the BroadcastReceiver does not show me any device. I have not been able to find the cause, and I don't know what could be the problem. Please can anyone help me, or does anyone know a code example that does this function in versions higher than Android 12?

Here is the Android Logcat after executing the blueetoothAdapter.startDiscovery() method

2023-06-22 13:33:16.317 10495-10495 BluetoothAdapter com.example.discoverydevicestest I startDiscovery 2023-06-22 13:33:16.322 10495-10495 DiscoveryTest com.example.discoverydevicestest E Discovery devices start 2023-06-22 13:33:16.327 10495-10495 Toast com.example.discoverydevicestest V show: caller = com.example.discoverydevicestest.DiscoveryAndroid12.startDiscovery:199 2023-06-22 13:33:16.327 10495-10495 Toast com.example.discoverydevicestest V show: focusDisplayId = 0, isFocusInDesktop = false mCustomDisplayId=-1 isDexDualMode=false 2023-06-22 13:33:16.327 10495-10495 Toast com.example.discoverydevicestest V show: isActivityContext = true

My code

public class DiscoveryAndroid12 extends AppCompatActivity {

    private static final String TAG = "DiscoveryTest";
    private static final int REQUEST_ENABLE_BLUETOOTH = 1;
    private static final int REQUEST_PERMISSION_LOCATION = 2;
    private static final int REQUEST_BLUETOOTH_SCAN_PERMISSION = 3;
    private static final int REQUEST_BLUETOOTH_CONNECT_PERMISSION = 4;
    private static final int REQUEST_BLUETOOTH_A12_PERMISSIONS = 5;

    private BluetoothAdapter bluetoothAdapter;
    private ArrayAdapter<String> deviceListAdapter;
    private List<BluetoothDevice> discoveredDevices;

    private Button discoverButton;
    private ListView deviceListView;

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

        discoverButton = findViewById(R.id.discoverButton);
        deviceListView = findViewById(R.id.deviceListView);

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        discoveredDevices = new ArrayList<>();
        deviceListAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
        deviceListView.setAdapter(deviceListAdapter);

        discoverButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                discoverDevices();
            }
        });

        deviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                connectToDevice(position);
            }
        });

        // Check if the device has bluetooth
        if (bluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not supported on this device", Toast.LENGTH_SHORT).show();
            finish();
        }

        // Register for broadcasts when a device is discovered.
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        registerReceiver(receiver, filter);

    }

    // Create a BroadcastReceiver for ACTION_FOUND.
    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                Log.e(TAG, "Device detected!");
                // Discovery has found a device. Get the BluetoothDevice
                // object and its info from the Intent.
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    // TODO: Consider calling
                    //    ActivityCompat#requestPermissions
                }
                String deviceName = device.getName();
                String deviceHardwareAddress = device.getAddress(); // MAC address
                Log.e(TAG, "Device found: " + deviceName + ": " + deviceHardwareAddress);

                discoveredDevices.add(device);
                String show = (deviceName != null) ? deviceName + ": " + deviceHardwareAddress : "Unknown name: " + deviceHardwareAddress;
                deviceListAdapter.add(show);

            }
        }
    };

    private void discoverDevices() {
        Log.e(TAG, "Starting process to search devices...");
        boolean isGranted = true;

        //Check permissions
        if (Build.VERSION.SDK_INT >= 31) {
            isGranted = checkBTScanAndConnectPermissions();
        } else {
            isGranted = checkLocationPermission();
        }

        if (isGranted) { //If permissions are granted
            // Check if bluetooth is enabled
            if (!bluetoothAdapter.isEnabled()) {
                Log.e(TAG, "BT disabled, requesting user to enable it");
                Intent enableBluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BLUETOOTH);
            } else {
                Log.e(TAG, "BT enabled, starting dicovery");
                startDiscovery();
            }
        }

    }

    private boolean checkLocationPermission() {

        Log.e(TAG, "Checking LOCATION permissions...");
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_LOCATION);
            return false;
        } else {
            Log.e(TAG, "Location permission granted");
            return true;
        }
    }

    private boolean checkScanPermission() {

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN)
                != PackageManager.PERMISSION_GRANTED) {
            Log.e(TAG, "BLUETOOTH_SCAN permission is not granted, requesting it...");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_SCAN}, REQUEST_BLUETOOTH_SCAN_PERMISSION);
            return false;
        } else {
            Log.e(TAG, "BLUETOOTH_SCAN  permission granted");
            return true;
        }
    }



    @RequiresApi(api = Build.VERSION_CODES.S)
    private boolean checkBTScanAndConnectPermissions() {

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}, REQUEST_BLUETOOTH_A12_PERMISSIONS);
            return false;
        } else {
            Log.e(TAG, "BLUETOOTH SCAN and CONNECT permissions granted");
            return true;
        }
    }

    private void startDiscovery() {
        boolean isGranted = true;
        deviceListAdapter.clear();
        discoveredDevices.clear();
        // Starting BT devices discovery
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= 31) {
                isGranted = checkScanPermission();
            }
        }

        if (isGranted) {
            Log.e(TAG, "BT scan permissions already granted");
            bluetoothAdapter.startDiscovery();
            Log.e(TAG, "Discovery devices start");
            Toast.makeText(this, "Discovering devices...", Toast.LENGTH_SHORT).show();
        }

    }

    private void connectToDevice(int position) {
        BluetoothDevice device = discoveredDevices.get(position);

        // Actions to connect to BT device

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
        }

        Toast.makeText(this, "Connecting to device: " + device.getName(), Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
            if (resultCode == RESULT_OK) {
                startDiscovery();
                Toast.makeText(this, "Bluetooth enabled", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "Bluetooth activation was canceled", Toast.LENGTH_SHORT).show();
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {


        if (requestCode == REQUEST_PERMISSION_LOCATION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                discoverDevices();
            } else {
                Toast.makeText(this, "Location permission denied", Toast.LENGTH_SHORT).show();
            }
        }

        if (requestCode == REQUEST_BLUETOOTH_SCAN_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startDiscovery();
                Toast.makeText(this, "Scan permission granted", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "Scan permission denied", Toast.LENGTH_SHORT).show();
            }
        }

        if (requestCode == REQUEST_BLUETOOTH_A12_PERMISSIONS) {
            boolean isgranted = true;
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "Scan permission granted");
                Toast.makeText(this, "Scan permission granted", Toast.LENGTH_SHORT).show();
            } else {
                Log.d(TAG, "Scan permission denied");
                Toast.makeText(this, "Scan permission denied", Toast.LENGTH_SHORT).show();
                isgranted = false;
            }

            if (grantResults.length > 0 && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "Connect permission granted");
                Toast.makeText(this, "Connect permission granted", Toast.LENGTH_SHORT).show();
            } else {
                Log.d(TAG, "Connect permission denied");
                Toast.makeText(this, "Connect permission denied", Toast.LENGTH_SHORT).show();
                isgranted = false;
            }

            if (isgranted){
                discoverDevices();
            }
        }


        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions

        }
        bluetoothAdapter.cancelDiscovery();
    }
}

The AndroidManifest.xml file

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

    <!-- Request legacy Bluetooth permissions on older devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>

    <!-- Needed only if your app looks for Bluetooth devices.
     You must add an attribute to this permission, or declare the
     ACCESS_FINE_LOCATION permission, depending on the results when you
     check location usage in your app. -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

    <!-- Needed only if your app makes the device discoverable to Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- Needed only if your app communicates with already-paired Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />


    <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:supportsRtl="true"
        android:theme="@style/Theme.DiscoveryDevicesTest"
        tools:targetApi="31">
        <activity
            android:name=".DiscoveryAndroid12"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.bluetooth.device.action.FOUND" />
            </intent-filter>

        </activity>
    </application>

</manifest>

Are there any considerations to keep in mind when using BroadcastReceiver in Android 12?

Thank you in advance for any contribution!

0

There are 0 best solutions below