Bluetooth

Android's Bluetooth APIs let an app discover nearby Bluetooth devices and exchange data with them — everything from headphones to fitness bands to, as we'll use for our example, a kitchen scale.

Imagine a future RecipeBox feature: instead of typing "200g flour" by hand while entering ingredients, the user places a bowl on a Bluetooth kitchen scale and RecipeBox reads the weight directly. It's not a core feature of the app today, but it's a realistic, motivating example for these APIs.

Permissions on Android 12+ (API 31+)

Older Android versions used a single blanket BLUETOOTH permission. Starting with Android 12 (API 31), Google split Bluetooth access into more granular, purpose-specific runtime permissions — the same runtime permission model covered in Runtime Permissions:

PermissionNeeded for
BLUETOOTH_SCANDiscovering nearby devices (scanning)
BLUETOOTH_CONNECTConnecting to and communicating with an already-known device
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

Requesting them at runtime works exactly the same way as any other dangerous permission:

if (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);
}
Why the change? The old blanket BLUETOOTH permission granted an app broad access whether it just wanted to connect to a paired headset or actively scan for every device nearby. Splitting it into BLUETOOTH_SCAN and BLUETOOTH_CONNECT lets the user (and the system) understand precisely what an app is doing with Bluetooth.

Checking and Enabling Bluetooth

BluetoothManager btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter adapter = btManager.getAdapter();

if (adapter == null) {
    // Device has no Bluetooth radio at all
} else if (!adapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Explanation: ACTION_REQUEST_ENABLE shows the user a system dialog asking to turn Bluetooth on — apps cannot silently flip the radio on themselves.

Discovering Nearby Devices

Scanning for devices is asynchronous: you start discovery, then listen for a broadcast per device found — the same BroadcastReceiver pattern from Broadcast Receivers:

private final BroadcastReceiver deviceFoundReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            String name = device.getName();
            String address = device.getAddress();
            // Add to a "nearby devices" list, e.g. for picking the kitchen scale
        }
    }
};

// Register once, e.g. in onCreate()
registerReceiver(deviceFoundReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));

// Start scanning (requires BLUETOOTH_SCAN permission granted)
adapter.startDiscovery();
Explanation: startDiscovery() doesn't return the device list directly — it kicks off a scan, and the system broadcasts ACTION_FOUND once per nearby device as it's detected, which the receiver collects over the following seconds.

Bluetooth Low Energy (BLE)

Everything above describes "classic" Bluetooth. Most modern smart kitchen devices — scales included — actually use Bluetooth Low Energy (BLE) instead, a more battery-efficient variant designed for small, infrequent bursts of data rather than continuous audio-style streaming. BLE communication revolves around GATT services and characteristics, which is a meaningfully different (and deeper) API surface than classic Bluetooth sockets.

Honest scope note: Bluetooth — and BLE especially — is a genuinely deep topic. This lesson is an overview of the moving parts (permissions, discovery, connecting), not exhaustive coverage of GATT profiles, characteristics, or BLE advertising. Treat it as a starting map, not the full territory.
Next up is another hardware-adjacent, narrow-scope topic: letting an Android device act as a USB host in USB Host.