¿Cómo saber mediante programación si un dispositivo Bluetooth está conectado?

86

Entiendo cómo obtener una lista de dispositivos emparejados, pero ¿cómo puedo saber si están conectados?

Debe ser posible ya que los veo en la lista de dispositivos Bluetooth de mi teléfono e indica su estado de conexión.

dchappelle
fuente

Respuestas:

155

Agregue permiso de bluetooth a su AndroidManifest,

<uses-permission android:name="android.permission.BLUETOOTH" />

A continuación, utilice filtros intención de escuchar el ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECT_REQUESTEDy ACTION_ACL_DISCONNECTEDtransmisiones:

public void onCreate() {
    ...
    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    this.registerReceiver(mReceiver, filter);
}

//The BroadcastReceiver that listens for bluetooth broadcasts
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           ... //Device found
        }
        else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
           ... //Device is now connected
        }
        else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
           ... //Done searching
        }
        else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
           ... //Device is about to disconnect
        }
        else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
           ... //Device has disconnected
        }           
    }
};

Algunas notas:

  • No hay forma de recuperar una lista de dispositivos conectados al inicio de la aplicación. La API de Bluetooth no le permite CONSULTAR, sino que le permite escuchar CAMBIOS.
  • Una solución tonta para solucionar el problema anterior sería recuperar la lista de todos los dispositivos conocidos / emparejados ... luego intentar conectarse a cada uno (para determinar si está conectado).
  • Alternativamente, puede hacer que un servicio en segundo plano observe la API de Bluetooth y escriba los estados del dispositivo en el disco para que su aplicación los use en una fecha posterior.
Skylar Sutton
fuente
2
Esto es bueno mientras mi aplicación se esté ejecutando, pero ¿cómo puedo obtener una lista actual?
dchappelle
2
¿Cómo planea ejecutar código sin que su aplicación "se ejecute"? Si quiere decir que necesita acceder a esto desde algo que no sea una Actividad ... vaya a Google Android Services, cree uno de esos para escuchar las transmisiones y manténgalo en una lista.
Skylar Sutton
6
Puedo escuchar las intenciones, PERO, ¿cómo puedo obtener la lista inicial de dispositivos Bluetooth conectados? Si alguno ya está conectado al momento de iniciar mi Actividad o Servicio, no lo sabré. Me imagino (espero) que estos datos estén disponibles en alguna parte. No me gustaría tener que crear un servicio (que se ejecute constantemente mientras el teléfono esté encendido) solo para escuchar estas intenciones.
dchappelle
11
No hay forma de recuperar la lista de dispositivos conectados al inicio de la aplicación. La API de Bluetooth solo le permitirá escuchar los cambios de conexión. Entonces, sí, la única forma de hacerlo es crear un servicio de larga duración y agregar / eliminar a una lista pública. Es una gran queja de muchos desarrolladores. Dependiendo de sus necesidades de rendimiento, puede recuperar la lista de dispositivos emparejados e intentar conectarse a cada uno. Si falla, no está disponible. Sin embargo, una advertencia: .connect () es una operación de bloqueo.
Skylar Sutton
1
@skylarsutton +1 Muchas gracias por esta respuesta, me ayudó a comenzar con bluetooth
AgentKnopf
33

En mi caso de uso, solo quería ver si hay un auricular Bluetooth conectado para una aplicación de VoIP. La siguiente solución funcionó para mí:

public static boolean isBluetoothHeadsetConnected() {
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()
            && mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED;
} 

Por supuesto, necesitará el permiso de Bluetooth:

<uses-permission android:name="android.permission.BLUETOOTH" />

jobbert
fuente
2
Este es el que estaba buscando. Solo para verificar al iniciar que el Bluetooth esté conectado o no. ¡Gracias funcionó!
sud007
11

Muchas gracias a Skylarsutton por su respuesta. Estoy publicando esto como una respuesta a la suya, pero como estoy publicando un código no puedo responder como comentario. Ya voté a favor de su respuesta, así que no estoy buscando ningún punto. Solo pagando por adelantado.

Por alguna razón, Android Studio no pudo resolver BluetoothAdapter.ACTION_ACL_CONNECTED. ¿Quizás quedó obsoleto en Android 4.2.2? Aquí hay una modificación de su código. El código de registro es el mismo; el código del receptor difiere ligeramente. Lo uso en un servicio que actualiza una marca de conexión Bluetooth a la que hacen referencia otras partes de la aplicación.

    public void onCreate() {
        //...
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        this.registerReceiver(BTReceiver, filter);
    }

    //The BroadcastReceiver that listens for bluetooth broadcasts
    private final BroadcastReceiver BTReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
            //Do something if connected
            Toast.makeText(getApplicationContext(), "BT Connected", Toast.LENGTH_SHORT).show();
        }
        else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
            //Do something if disconnected
            Toast.makeText(getApplicationContext(), "BT Disconnected", Toast.LENGTH_SHORT).show();
        }
        //else if...
    }
};
pmont
fuente
1
su código es correcto; no estaba en desuso en 4.2.2. La clase BluetoothAdapter no contiene ACTION_ACL_CONNECTED. Esa cadena está en la clase BluetoothDevice.
RobLabs
¡Gracias por aclarar eso!
pmont
4

Hay una función isConnected en la API del sistema BluetoothDevice en https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothDevice.java

Si desea saber si un dispositivo delimitado (emparejado) está conectado actualmente o no, la siguiente función funciona bien para mí:

public static boolean isConnected(BluetoothDevice device) {
    try {
        Method m = device.getClass().getMethod("isConnected", (Class[]) null);
        boolean connected = (boolean) m.invoke(device, (Object[]) null);
        return connected;
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
}
LW
fuente
¿Has visto que esto da un resultado diferente de simplemente comprobar si bluetoothManager.getConnectionState(device, BluetoothProfile.GATT) == BluetoothProfile.STATE_CONNECTED?
Gumby The Green
Por lo que puedo decir, dan el mismo resultado. Tenga en cuenta que para los usuarios de Kotlin, esas dos primeras líneas son solo val m: Method = device.javaClass.getMethod("isConnected")y val connected = m.invoke(device).
Gumby The Green
¡Gracias, exactamente lo que necesitaba! Este es el equivalente de Kotlin para este método:fun isConnected(device: BluetoothDevice): Boolean { return try { val m: Method = device.javaClass.getMethod( "isConnected" ) m.invoke(device) as Boolean } catch (e: Exception) { throw IllegalStateException(e) } }
Takeya
1

Este código es para los perfiles de auriculares, probablemente también funcione para otros perfiles. Primero debe proporcionar un escucha de perfil (código Kotlin):

private val mProfileListener = object : BluetoothProfile.ServiceListener {
    override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
        if (profile == BluetoothProfile.HEADSET) 
            mBluetoothHeadset = proxy as BluetoothHeadset            
    }

    override fun onServiceDisconnected(profile: Int) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = null
        }
    }
}

Luego, mientras verifica el bluetooth:

mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET)
if (!mBluetoothAdapter.isEnabled) {
    return Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
}

Se necesita un poco de tiempo hasta que se llama a onSeviceConnected. Después de eso, puede obtener la lista de dispositivos de auriculares conectados en:

mBluetoothHeadset!!.connectedDevices
usuario5902306
fuente
0

BluetoothAdapter.getDefaultAdapter().isEnabled -> devuelve verdadero cuando bluetooth está abierto

val audioManager = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager

audioManager.isBluetoothScoOn -> devuelve verdadero cuando el dispositivo está conectado

ravid rinek
fuente
0

Realmente estaba buscando una forma de obtener el estado de conexión de un dispositivo, no escuchar los eventos de conexión. Esto es lo que funcionó para mí:

BluetoothManager bm = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bm.getConnectedDevices(BluetoothGatt.GATT);
int status = -1;

for (BluetoothDevice device : devices) {
  status = bm.getConnectionState(device, BLuetoothGatt.GATT);
  // compare status to:
  //   BluetoothProfile.STATE_CONNECTED
  //   BluetoothProfile.STATE_CONNECTING
  //   BluetoothProfile.STATE_DISCONNECTED
  //   BluetoothProfile.STATE_DISCONNECTING
}
connorbode
fuente