BluetoothAdapter — ce este, metode și gestionarea Bluetooth în Android

Autor: IT Sectr Publicat: 2026-07-16 Timp de citire: 10 min

BluetoothAdapter — clasa de sistem Android care reprezintă adaptorul Bluetooth local al dispozitivului. BluetoothAdapter este punctul de intrare pentru toate operațiile Bluetooth pe Android: activarea radioului (enable), scanarea dispozitivelor, gestionarea vizibilității (setScanMode), obținerea informațiilor despre adaptor (getName, getAddress, getState). Clasa este disponibilă prin BluetoothManager.getAdapter() (API 18+) sau BluetoothAdapter.getDefaultAdapter(). Pe dispozitivele fără modul Bluetooth, getDefaultAdapter() returnează null. Conform Android Developers, 2026, BluetoothAdapter este o componentă obligatorie pentru orice aplicație BLE pe Android, începând cu API 5.

Principalele puncte

  • BluetoothAdapter — clasa de sistem Android pentru gestionarea adaptorului Bluetooth local al dispozitivului
  • getDefaultAdapter() — metodă statică pentru obținerea instanței; returnează null pe dispozitivele fără Bluetooth
  • getBluetoothLeScanner() — metodă de acces la scanerul BLE modern (API 21+)
  • enable/disable — metode de activare și dezactivare a radioului Bluetooth (necesită permisiunea BLUETOOTH_ADMIN)
  • startDiscovery/startLeScan — metode de scanare clasică și BLE (LE Scan este învechit, utilizați BluetoothLeScanner)

Ce este BluetoothAdapter: esența și obținerea instanței

BluetoothAdapter reprezintă adaptorul Bluetooth fizic al dispozitivului Android. Fiecare dispozitiv are exact un adaptor (excepție — Android Automotive cu mai multe cipuri Bluetooth, unde se utilizează BluetoothManager.getAdapterList()). BluetoothAdapter încapsulează starea radioului: STATE_OFF (0), STATE_TURNING_ON (1), STATE_ON (2), STATE_TURNING_OFF (3). Starea este urmărită prin BroadcastReceiver pe ACTION_STATE_CHANGED.

Obținerea instanței BluetoothAdapter este primul pas al oricărei aplicații BLE pe Android. Metoda recomandată — prin BluetoothManager.getAdapter() de la API 18+. Alternativa — metoda statică BluetoothAdapter.getDefaultAdapter(), care funcționează de la API 5, dar este mai puțin flexibilă. Ambele metode returnează null dacă dispozitivul nu are modul Bluetooth (tablete Wi-Fi-only, emulator). Verificarea null este obligatorie: aplicația trebuie să se încheie corect sau să dezactiveze funcțiile BLE.

kotlin
// Obținerea BluetoothAdapter (recomandat)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context

class BluetoothHelper(context: Context) {

    private val bluetoothAdapter: BluetoothAdapter?

    init {
        // Metoda 1: prin BluetoothManager (API 18+)
        val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
                as BluetoothManager?
        bluetoothAdapter = manager?.adapter

        // Metoda 2: prin metoda statică (API 5+)
        // val adapter = BluetoothAdapter.getDefaultAdapter()

        // Verificare null
        if (bluetoothAdapter == null) {
            // Dispozitivul nu suportă Bluetooth
        }
    }

    // Verifică starea Bluetooth
    fun isBluetoothEnabled(): Boolean {
        return bluetoothAdapter?.isEnabled == true
    }

    // Obține informații despre adaptor
    fun getAdapterInfo(): Map<String, String> {
        return mapOf(
            "name" to (bluetoothAdapter?.name ?: "N/A"),
            "address" to (bluetoothAdapter?.address ?: "N/A"),
            "state" to (bluetoothAdapter?.state?.toString() ?: "N/A"),
            "scanMode" to (bluetoothAdapter?.scanMode?.toString() ?: "N/A")
        )
    }
}

Clasa BluetoothHelper demonstrează obținerea BluetoothAdapter prin BluetoothManager cu verificarea ulterioară null. isBluetoothEnabled verifică isEnabled — condiție obligatorie înainte de orice operații BLE. getAdapterInfo returnează numele dispozitivului, adresa MAC, starea și modul de vizibilitate. Important: pe Android 10+ (API 29+) serviciul de sistem returnează o adresă MAC falsă (02:00:00:00:00:00) dacă aplicația nu are permisiunile BLUETOOTH_ADMIN și ACCESS_FINE_LOCATION.

Metodele principale BluetoothAdapter: enable, disable, getState, getAddress

BluetoothAdapter oferă metode de gestionare a radioului Bluetooth. enable() și disable() activează și dezactivează Bluetooth. Ambele metode necesită permisiunea BLUETOOTH_ADMIN și se execută asincron: după apelul enable(), sistemul pornește procesul de activare a radioului, starea este urmărită prin BroadcastReceiver cu acțiunea BluetoothAdapter.ACTION_STATE_CHANGED. De la Android 10+, enable() și disable() necesită o permisiune suplimentară de sistem — aplicațiile obișnuite nu pot gestiona Bluetooth programatic fără dialogul utilizatorului.

getState() returnează starea curentă a adaptorului: STATE_OFF (10), STATE_TURNING_ON (11), STATE_ON (12), STATE_TURNING_OFF (13). getAddress() returnează adresa MAC a adaptorului Bluetooth. Pe Android 6+ pentru solicitarea adresei MAC este necesar ACCESS_FINE_LOCATION (sau ACCESS_COARSE_LOCATION pentru API 31+). Pe Android 10+, getAddress() returnează adresa constantă 02:00:00:00:00:00 — adresa reală nu este disponibilă prin API-ul public.

getScanMode() determină modul de vizibilitate al adaptorului: SCAN_MODE_NONE (invizibil), SCAN_MODE_CONNECTABLE (vizibil pentru conectați), SCAN_MODE_CONNECTABLE_DISCOVERABLE (vizibil pentru toți). Modul de vizibilitate este limitat în timp (de obicei 60–300 de secunde) pentru securitate. Setarea modului prin setScanMode() necesită BLUETOOTH_ADMIN și permisiune de sistem pe Android 10+.

MetodăDescrierePermisiune necesară
enable()Activarea radioului BluetoothBLUETOOTH_ADMIN
disable()Dezactivarea radioului BluetoothBLUETOOTH_ADMIN
getState()Starea curentă a adaptoruluiBLUETOOTH
getAddress()Adresa MAC a adaptoruluiBLUETOOTH + ACCESS_FINE_LOCATION (API 23+)
getScanMode()Modul de vizibilitate al dispozitivuluiBLUETOOTH
setScanMode()Setarea modului de vizibilitateBLUETOOTH_ADMIN

Scanarea dispozitivelor: startDiscovery și BluetoothLeScanner

BluetoothAdapter suportă două tipuri de scanare. Scanarea clasică Bluetooth (BR/EDR) se pornește prin startDiscovery() — detectează dispozitive Bluetooth de toate tipurile, inclusiv telefoane și căști. Rezultatele sunt returnate prin BroadcastReceiver cu acțiunea BluetoothDevice.ACTION_FOUND. startDiscovery() funcționează timp de 12 secunde și poate fi anulat prin apelul cancelDiscovery(). Această metodă este învechită pentru BLE — utilizați BluetoothLeScanner.

Scanarea BLE prin BluetoothAdapter se realizează cu metoda învechită startLeScan(LeScanCallback). Începând cu API 21, Google recomandă utilizarea BluetoothLeScanner, obținut prin BluetoothAdapter.getBluetoothLeScanner(). BluetoothLeScanner oferă un API mai flexibil: configurarea scanării prin ScanSettings (mod, callback type, match mode), filtrarea prin ScanFilter (după UUID-ul serviciului, numele dispozitivului, adresa MAC) și suport pentru PendingIntent pentru scanarea în fundal.

kotlin
// API de scanare BLE vechi (învechit) vs nou
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*

class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {

    // ÎNVECHIT: startLeScan (API 18+, API 21)
    @Suppress("DEPRECATION")
    fun legacyScan() {
        bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
            print("Found (LE Scan): $device.name, RSSI: $rssi")
        }
    }

    // NOU: BluetoothLeScanner (API 21+)
    fun modernScan() {
        val scanner = bluetoothAdapter?.bluetoothLeScanner
            ?: return

        // Setări scanare
        val settings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
            .build()

        // Filtrare după serviciu (UUID puls)
        val filters = listOf(
            ScanFilter.Builder()
                .setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
                .build()
        )

        // Pornește scanarea
        scanner.startScan(filters, settings, object : ScanCallback() {
            override fun onScanResult(callbackType: Int, result: ScanResult) {
                val device = result.device
                val rssi = result.rssi
                print("Found (BLE Scanner): ${device.name}, RSSI: $rssi, address: ${device.address}")
            }

            override fun onScanFailed(errorCode: Int) {
                print("Scan error: $errorCode")
            }
        })
    }
}

Clasa BLEScanner compară startLeScan învechit și BluetoothLeScanner modern. În legacyScan, callback-ul LeScanCallback primește BluetoothDevice, RSSI și scanRecord brut. În modernScan se utilizează ScanSettings cu modul LOW_LATENCY (viteză maximă de detectare) și ScanFilter pentru filtrarea după UUID-ul serviciului de puls (Heart Rate Service 0x180D). ScanCallback oferă onScanResult cu obiectul ScanResult conținând informații extinse: nume, RSSI, date publicitare, tipul conexiunii.

BluetoothManager: API modern pentru acces la BluetoothAdapter

BluetoothManager — serviciul de sistem Android, introdus în API 18 (Android 4.3), pentru gestionarea operațiilor Bluetooth. Înainte de API 18, singura modalitate de a obține BluetoothAdapter era metoda statică getDefaultAdapter(). BluetoothManager oferă: adapter — instanța BluetoothAdapter, getConnectedDevices() — lista dispozitivelor conectate, getDevicesMatchingConnectionStates() — filtrarea după stare. BluetoothManager este, de asemenea, utilizat pentru obținerea BluetoothLeScanner pe API-uri vechi.

Avantajele BluetoothManager față de apelul direct BluetoothAdapter.getDefaultAdapter(): aplicația nu depinde de un singleton static, managerul ia în considerare contextul (Activity/Application), ceea ce este important pentru scenariile multi-cont Android Enterprise. Pe Android Automotive cu mai multe cipuri Bluetooth, BluetoothManager.getAdapterList() returnează toate adaptoarele disponibile — BluetoothAdapter.getDefaultAdapter() returnează doar primul.

kotlin
// Utilizarea BluetoothManager pentru BLE
class BLEConnection(context: Context) {

    private val bluetoothManager: BluetoothManager =
        context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

    private val adapter: BluetoothAdapter? = bluetoothManager.adapter

    // Obține lista dispozitivelor BLE conectate
    fun getConnectedDevices(): List<BluetoothDevice> {
        return bluetoothManager.getConnectedDevices(
            BluetoothProfile.GATT
        )
    }

    // Filtrează dispozitivele după stare
    fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
        return bluetoothManager.getDevicesMatchingConnectionStates(
            BluetoothProfile.GATT, states
        )
    }

    // Verifică suportul BLE pe dispozitiv
    fun isBLESupported(): Boolean {
        return adapter != null && context.packageManager
            .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
    }

    // Solicită activarea Bluetooth prin dialogul de sistem
    fun requestEnableBluetooth(activity: MainActivity) {
        if (adapter?.isEnabled == false) {
            val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
            activity.startActivityForResult(intent, REQUEST_ENABLE_BT)
        }
    }

    companion object {
        const val REQUEST_ENABLE_BT = 1001
    }
}

Clasa BLEConnection utilizează BluetoothManager pentru accesul la BluetoothAdapter și obținerea listei dispozitivelor GATT conectate. isBLESupported verifică prezența radioului BLE prin PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) — verificare importantă pentru dispozitivele cu Bluetooth Classic fără BLE. requestEnableBluetooth afișează dialogul de sistem pentru activarea Bluetooth (ACTION_REQUEST_ENABLE), fără a necesita permisiunea BLUETOOTH_ADMIN — aceasta este singura modalitate legală de activare a Bluetooth pe Android 10+ fără aplicație de sistem.

Permisiunile Android pentru lucrul cu BluetoothAdapter

Permisiunile pentru BluetoothAdapter au evoluat cu fiecare versiune de Android. Pe Android 6–11 (API 23–30) pentru scanarea BLE sunt obligatorii BLUETOOTH, BLUETOOTH_ADMIN și ACCESS_FINE_LOCATION. Pe Android 12+ (API 31+) Google a divizat permisiunile: ACCESS_FINE_LOCATION a fost înlocuit cu BLUETOOTH_SCAN (scanare), BLUETOOTH_CONNECT (conectare), BLUETOOTH_ADVERTISE (publicitate). Pentru căutarea dispozitivelor BLE, BLUETOOTH_SCAN este suficient, locația nu este necesară.

Tabelul permisiunilor pe versiuni de Android:

OperațiuneAPI 23–30API 31+
Scanare BLEACCESS_FINE_LOCATIONBLUETOOTH_SCAN (fără locație)
Conectare la BLEACCESS_FINE_LOCATIONBLUETOOTH_CONNECT
Publicitate BLEACCESS_FINE_LOCATIONBLUETOOTH_ADVERTISE
Activare/dezactivareBLUETOOTH_ADMINBLUETOOTH_ADMIN (sistem)
Obținere adresă MACACCESS_FINE_LOCATIONBLUETOOTH_CONNECT (adresă falsă)

Pe Android 12+, toate permisiunile Bluetooth sunt permisiuni de runtime — trebuie solicitate în runtime prin ActivityResultContracts.RequestMultiplePermissions. BLUETOOTH_SCAN și BLUETOOTH_ADVERTISE aparțin grupului NEARBY_DEVICES, BLUETOOTH_CONNECT — aceluiași grup. Permisiunile BLUETOOTH și BLUETOOTH_ADMIN rămân în manifest pentru compatibilitate cu API < 31, dar pentru API 31+ sunt ignorate — Google cere specificarea explicită a noilor permisiuni.

kotlin
// Solicitarea permisiunilor Bluetooth pe Android 12+
import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat

class PermissionHelper(context: Context) {

    fun getRequiredPermissions(): Array<String> {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            // Android 12+: scanare BLE
            arrayOf(
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.BLUETOOTH_ADVERTISE
            )
        } else {
            // Android 6-11: scanare BLE
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.BLUETOOTH,
                Manifest.permission.BLUETOOTH_ADMIN
            )
        }
    }

    // Verifică toate permisiunile
    fun hasPermissions(context: Context): Boolean {
        return getRequiredPermissions().all { permission ->
            ContextCompat.checkSelfPermission(context, permission)
                    == PackageManager.PERMISSION_GRANTED
        }
    }
}

Clasa PermissionHelper returnează setul corect de permisiuni în funcție de nivelul API. Pe Android 12+ se utilizează BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE fără locație. Pe Android 6–11 pentru scanarea BLE este încă necesar ACCESS_FINE_LOCATION. Dezvoltatorul trebuie să ia în considerare ambele scenarii la solicitarea permisiunilor prin ActivityResultContracts sau RxPermissions.

Exemplu complet de lucru cu BluetoothAdapter în Kotlin

Exemplu complet de aplicație BLE în Kotlin care utilizează BluetoothAdapter pentru scanare, conectare și citirea datelor unui dispozitiv BLE. Exemplul acoperă verificarea permisiunilor, obținerea adaptorului, scanarea prin BluetoothLeScanner și conectarea prin BluetoothDevice.connectGatt.

kotlin
// Manager BLE complet în Kotlin
class BLEManager(private val context: Context) {

    private val bluetoothManager: BluetoothManager =
        context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    private val adapter: BluetoothAdapter? = bluetoothManager.adapter
    private var scanner: BluetoothLeScanner? = adapter?.bluetoothLeScanner
    private var gatt: BluetoothGatt? = null

    // 1. Descoperirea serviciilor
    fun canScan(): Boolean {
        return adapter?.isEnabled == true
                && scanner != null
                && PermissionHelper(context).hasPermissions(context)
    }

    // 2. Scanare cu filtru
    fun startScanning(callback: (BluetoothDevice, Int) -> Unit) {
        if (!canScan()) return

        val settings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setReportDelay(0)
            .build()

        scanner?.startScan(null, settings, object : ScanCallback() {
            override fun onScanResult(callbackType: Int, result: ScanResult) {
                callback(result.device, result.rssi)
            }
        })
    }

    // 3. Oprește scanarea
    fun stopScanning() {
        scanner?.stopScan(object : ScanCallback() {})
    }

    // 4. Conectare la dispozitivul BLE
    fun connectToDevice(device: BluetoothDevice) {
        if (adapter?.isEnabled != true) return

        gatt = device.connectGatt(
            context,
            false,
            object : BluetoothGattCallback() {
                override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
                    if (newState == BluetoothProfile.STATE_CONNECTED) {
                        gatt.discoverServices()
                    }
                }

                override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
                    // Servicii găsite, se pot citi caracteristicile
                }
            },
            BluetoothDevice.TRANSPORT_LE
        )
    }

    // 5. Eliberare resurse
    fun disconnect() {
        gatt?.disconnect()
        gatt?.close()
        gatt = null
    }
}

Managerul BLEManager combină ciclul complet BLE pe Android: verificarea adaptorului și a permisiunilor (canScan), scanarea prin BluetoothLeScanner cu ScanSettings (startScanning), conectarea prin BluetoothDevice.connectGatt cu TRANSPORT_LE (connectToDevice), eliberarea resurselor (disconnect). Toate operațiile BLE se execută pe firul UI — Android apelează callback-urile BluetoothGattCallback pe firul principal. Pentru sarcini BLE performante, se recomandă mutarea operațiilor GATT într-un HandlerThread de fundal.

Întrebări frecvente

Ce este BluetoothAdapter în Android?

BluetoothAdapter — clasa care reprezintă adaptorul Bluetooth local al dispozitivului Android. Se obține prin BluetoothManager.getAdapter() (API 18+) sau BluetoothAdapter.getDefaultAdapter(). Oferă metode de activare/dezactivare Bluetooth, scanare a dispozitivelor, gestionare a vizibilității și obținere a informațiilor despre adaptor. Returnează null pe dispozitivele fără modul Bluetooth.

De ce BluetoothAdapter.getDefaultAdapter() returnează null?

Cauza — absența radioului Bluetooth pe dispozitiv. Caracteristic pentru tabletele Wi-Fi-only, emulatorul Android și Android TV fără Bluetooth. Verificați getDefaultAdapter() pentru null la pornirea aplicației și dezactivați funcțiile BLE dacă adaptorul lipsește. Alternativă — verificarea prin PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) pentru o determinare mai precisă.

Cu ce se deosebește BluetoothLeScanner de startLeScan?

BluetoothLeScanner (API 21+) — API modern pentru scanarea BLE cu suport pentru ScanFilter, ScanSettings și PendingIntent. startLeScan (API 18+) — metodă învechită BluetoothAdapter care acceptă LeScanCallback cu un set limitat de date. BluetoothLeScanner este recomandat de Google pentru toate proiectele noi, permite filtrarea după UUID, configurarea modului de consum energetic și lucrul în fundal prin PendingIntent.

Ce permisiuni sunt necesare pentru BLE pe Android 12+?

Pe Android 12+ (API 31) pentru scanarea BLE este necesar BLUETOOTH_SCAN, pentru conectare — BLUETOOTH_CONNECT, pentru publicitate — BLUETOOTH_ADVERTISE. Permisiunea de locație ACCESS_FINE_LOCATION nu mai este necesară pentru BLE. Pe Android 6–11 este necesar ACCESS_FINE_LOCATION. Toate permisiunile se solicită în runtime prin ActivityResultContracts.

Se poate activa Bluetooth programatic fără dialog?

De la Android 10+, activarea programatică a Bluetooth fără dialogul de sistem este disponibilă doar pentru aplicațiile de sistem cu permisiunea BLUETOOTH_PRIVILEGED. Aplicațiile obișnuite trebuie să utilizeze Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) și startActivityForResult — utilizatorul confirmă activarea în dialogul de sistem. BLUETOOTH_ADMIN în manifest nu oferă dreptul la enable() pe Android 10+.

Concluzii

  • BluetoothAdapter — punctul de intrare pentru toate operațiile Bluetooth pe Android, obținut prin BluetoothManager sau getDefaultAdapter()
  • getState() și isEnabled — verificări de bază ale stării radioului Bluetooth înainte de orice operații BLE
  • BluetoothLeScanner (API 21+) înlocuiește startLeScan învechit cu suport pentru ScanFilter, ScanSettings și PendingIntent
  • BluetoothManager — modalitate modernă de obținere a BluetoothAdapter cu suport pentru scenarii multi-cont și Automotive
  • Permisiunile au evoluat: ACCESS_FINE_LOCATION (API 23-30) → BLUETOOTH_SCAN/CONNECT/ADVERTISE (API 31+)
  • enable()/disable() — pe Android 10+ doar prin dialogul de sistem ACTION_REQUEST_ENABLE pentru aplicațiile obișnuite
  • connectGatt — metoda BluetoothDevice pentru stabilirea conexiunii GATT cu perifericul BLE prin BluetoothGattCallback

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și