Como saber programaticamente se um dispositivo Bluetooth está conectado?

86

Eu entendo como obter uma lista de dispositivos emparelhados, mas como posso saber se eles estão conectados?

Deve ser possível, pois eu os vejo listados na lista de dispositivos Bluetooth do meu telefone e ele indica o status da conexão.

dchappelle
fonte

Respostas:

155

Adicione permissão de bluetooth ao seu AndroidManifest,

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

Em seguida, use filtros de intenção de ouvir o ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECT_REQUESTEDe ACTION_ACL_DISCONNECTEDtransmissões:

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
        }           
    }
};

Algumas notas:

  • Não há como recuperar uma lista de dispositivos conectados na inicialização do aplicativo. A API Bluetooth não permite que você QUERY, em vez disso, permite que você ouça CHANGES.
  • Uma alternativa complicada para o problema acima seria recuperar a lista de todos os dispositivos conhecidos / emparelhados ... e tentar se conectar a cada um (para determinar se você está conectado).
  • Como alternativa, você pode fazer com que um serviço de segundo plano observe a API do Bluetooth e grave os estados do dispositivo em disco para seu aplicativo usar posteriormente.
Skylar Sutton
fonte
2
Isso é bom enquanto meu aplicativo estiver em execução, mas como posso obter uma lista atual?
dchappelle de
2
Como você planeja executar o código sem seu aplicativo "rodando"? Se você quer dizer que precisa acessar isso de algo diferente de uma Activity ... vá no google Android Services, crie um deles para ouvir as transmissões e persistir em uma lista.
Skylar Sutton
6
Posso ouvir as intenções, MAS como posso obter a lista inicial de dispositivos Bluetooth conectados? Se algum já estiver conectado no momento em que minha atividade ou serviço for iniciado, não saberei. Eu imagino (espero) que esses dados estejam disponíveis em algum lugar? Eu não gostaria de ter que criar um serviço (que funciona constantemente, desde que o telefone esteja ligado) apenas para ouvir essas intenções.
dchappelle
11
Não há como recuperar a lista de dispositivos conectados na inicialização do aplicativo. A API do Bluetooth permitirá apenas que você ouça as alterações de conexão. Então, sim, a única maneira de fazer isso é criar um serviço de longa duração e adicionar / remover de uma lista pública. É uma grande reclamação de muitos desenvolvedores. Dependendo de suas necessidades de desempenho, você pode recuperar a lista de dispositivos emparelhados e tentar se conectar a cada um. Se falhar, não está disponível. Porém, uma advertência: .connect () é uma operação de bloqueio.
Skylar Sutton
1
@skylarsutton +1 Muito obrigado por esta resposta, me ajudou a começar no bluetooth
AgentKnopf
33

No meu caso de uso, eu só queria ver se um fone de ouvido Bluetooth está conectado a um aplicativo VoIP. A seguinte solução funcionou para mim:

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

Claro, você precisará da permissão do Bluetooth:

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

jobbert
fonte
2
Este é o que eu estava procurando. Apenas para verificar no lançamento se o Bluetooth está conectado ou não. Obrigado, funcionou!
sud007
11

Muito obrigado a Skylarsutton por sua resposta. Estou postando isso como uma resposta ao dele, mas como estou postando um código, não posso responder como um comentário. Já votei positivamente em sua resposta, então não estou procurando nenhum ponto. Apenas pagando adiante.

Por algum motivo, BluetoothAdapter.ACTION_ACL_CONNECTED não pôde ser resolvido pelo Android Studio. Talvez tenha sido preterido no Android 4.2.2? Aqui está uma modificação de seu código. O código de registro é o mesmo; o código do receptor é ligeiramente diferente. Eu uso isso em um serviço que atualiza um sinalizador conectado por Bluetooth que outras partes do aplicativo fazem referência.

    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
fonte
1
seu código está correto; não foi descontinuado em 4.2.2. A classe BluetoothAdapter não contém ACTION_ACL_CONNECTED. Essa string está na classe BluetoothDevice.
RobLabs
Obrigado por esclarecer isso!
pmont
4

Há uma função isConnected na API do sistema BluetoothDevice em https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothDevice.java

Se você quiser saber se um dispositivo vinculado (emparelhado) está conectado ou não, a seguinte função funciona bem para mim:

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
fonte
Você viu isso dar um resultado diferente de apenas verificar se bluetoothManager.getConnectionState(device, BluetoothProfile.GATT) == BluetoothProfile.STATE_CONNECTED?
Gumby The Green
Pelo que posso dizer, eles dão o mesmo resultado. Observe que, para usuários do Kotlin, essas duas primeiras linhas são apenas val m: Method = device.javaClass.getMethod("isConnected")e val connected = m.invoke(device).
Gumby The Green
Obrigado, exatamente o que eu precisava! Este é o equivalente 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 é para os perfis de fone de ouvido, provavelmente funcionará para outros perfis também. Primeiro você precisa fornecer um listener 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
        }
    }
}

Em seguida, ao verificar o bluetooth:

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

Demora um pouco até que onSeviceConnected seja chamado. Depois disso, você pode obter a lista dos dispositivos de fone de ouvido conectados em:

mBluetoothHeadset!!.connectedDevices
user5902306
fonte
0

BluetoothAdapter.getDefaultAdapter().isEnabled -> retorna verdadeiro quando o bluetooth está aberto

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

audioManager.isBluetoothScoOn -> retorna verdadeiro quando o dispositivo está conectado

Ravid Rinek
fonte
0

Eu estava realmente procurando uma maneira de obter o status da conexão de um dispositivo, e não ouvir eventos de conexão. Aqui está o que funcionou para mim:

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
}
conorbode
fonte