The Android Developer Challenge is back! Submit your idea before December 2.

Visão geral do Bluetooth

A plataforma Android é compatível com a pilha de rede Bluetooth, o que permite a um dispositivo trocar dados em comunicação sem fios com outros dispositivos Bluetooth. A biblioteca do aplicativo oferece acesso à funcionalidade do Bluetooth por meio das APIs Bluetooth do Android. Essas APIs permitem a conexão sem fio de aplicativos a outros dispositivos Bluetooth, permitindo recursos sem fio ponto a ponto e multiponto.

Ao usar as APIs Bluetooth, um aplicativo Android pode executar as seguintes atividades:

  • Procurar outros dispositivos Bluetooth
  • Consultar o adaptador Bluetooth local para verificar a existência de dispositivos Bluetooth pareados
  • Estabelecer canais RFCOMM
  • Conectar-se a outros dispositivos por meio da descoberta de serviços
  • Transferir dados de e para outros dispositivos
  • Gerenciar várias conexões

Esta página tem como foco o Classic Bluetooth. O Classic Bluetooth é a escolha certa para operações com maior consumo de bateria, como streaming e comunicação entre dispositivos Android. Para dispositivos Bluetooth com baixos requisitos de energia, o Android 4.3 (API de nível 18) introduz APIs compatíveis com o Bluetooth de baixa energia. Para saber mais, consulte Bluetooth de baixa energia.

Este documento descreve diferentes perfis de Bluetooth, inclusive o Perfil Health Device. Este documento explica como usar a API Bluetooth do Android para executar as quatro principais tarefas necessárias para a comunicação usando Bluetooth: configurar o Bluetooth, encontrar dispositivos pareados ou disponíveis na área local, conectar dispositivos e transferir dados entre dispositivos.

Conceitos básicos

Para que dispositivos com Bluetooth ativado transmitam dados entre si, eles precisam primeiro formar um canal de comunicação por meio de um processo de pareamento. Um dispositivo detectável fica disponível para futuras solicitações de conexão. Outro dispositivo encontra o dispositivo detectável usando um processo de descoberta de serviços. Após o dispositivo detectável aceitar a solicitação de pareamento, os dois dispositivos concluem um processo de vínculo, onde trocam chaves de segurança. Eles armazenam essas chaves em cache para uso posterior. Após a finalização dos processos de pareamento e vínculo, os dois dispositivos trocam informações. Quando a sessão é concluída, o dispositivo que iniciou a solicitação de pareamento libera o canal que o vinculava ao dispositivo detectável. No entanto, ambos permanecem vinculados para que possam se reconectar automaticamente durante uma sessão futura, desde que estejam ao alcance um do outro e nenhum dos dois tenha removido o vínculo.

Permissões do Bluetooth

Para usar recursos do Bluetooth no aplicativo, você precisa declarar duas permissões. A primeira delas é BLUETOOTH. Você precisa dessa permissão para executar todas as comunicações do Bluetooth, como solicitar ou aceitar uma conexão e transferir dados.

A outra permissão que precisa ser declarada é ACCESS_FINE_LOCATION. Seu aplicativo precisa dessa permissão porque uma verificação Bluetooth pode ser usada para coletar informações sobre o local do usuário. Essa informação pode vir do próprio dispositivo do usuário, assim como de sensores Bluetooth em uso em locais como centros comerciais e de grande circulação.

Observação: caso seu aplicativo seja direcionado ao Android 9 (API de nível 28) ou posteriores, você pode declarar a permissão ACCESS_COARSE_LOCATION em vez da permissão ACCESS_FINE_LOCATION.

Se você quiser que o aplicativo inicie a descoberta de dispositivos ou manipule configurações do Bluetooth, será necessário declarar também a permissão BLUETOOTH_ADMIN, além da permissão BLUETOOTH. A maioria dos aplicativos precisa dessa permissão somente para poder descobrir dispositivos Bluetooth locais. Os outros recursos concedidos por essa permissão não devem ser usados, a menos que o aplicativo seja um “gerenciador de energia” que modifique configurações do Bluetooth mediante solicitações do usuário.

Declare as permissões do Bluetooth no arquivo de manifesto do aplicativo. Por exemplo:

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

  <!-- If your app targets Android 9 or lower, you can declare
       ACCESS_COARSE_LOCATION instead. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  ...
</manifest>

Consulte a referência <uses-permission> para mais informações sobre a declaração de permissões do aplicativo.

Trabalhar com perfis

A partir do Android 3.0, a API Bluetooth permite trabalhar com perfis Bluetooth. O perfil Bluetooth é uma especificação de interface sem fio para comunicação com base em Bluetooth entre dispositivos. Um exemplo é o perfil Hands-Free. Para um smartphone se conectar a um fone de ouvido sem fio, os dois dispositivos precisam ser compatíveis com o perfil Hands-Free.

A API Bluetooth do Android oferece implementações para os seguintes perfis Bluetooth:

  • Headset. O perfil Headset permite usar fones de ouvido Bluetooth com smartphones. O Android oferece a classe BluetoothHeadset, que é um proxy para controlar o Bluetooth Headset Service. Isso abrange os perfis Bluetooth Headset e Hands-Free (v1.5). A classe BluetoothHeadset é compatível com comandos AT. Para ver uma discussão mais detalhada desse tópico, consulte Comandos AT específicos de fornecedores
  • A2DP. O perfil Advanced Audio Distribution Profile (A2DP) define como fazer streaming de áudio de alta qualidade de um dispositivo para outro usando uma conexão Bluetooth. O Android oferece a classe BluetoothA2dp, que é um proxy para controlar o Bluetooth A2DP Service.
  • Health Device. O Android 4.0 (API de nível 14) introduz a compatibilidade com o perfil Health Device (HDP) do Bluetooth. Esse perfil permite criar aplicativos que usam o Bluetooth para comunicação com dispositivos de saúde compatíveis com Bluetooth, como monitores de frequência cardíaca, medidores de sangue, termômetros, balanças etc. Para ter acesso a uma lista de dispositivos compatíveis e os códigos de especialização de dados de dispositivo correspondentes, consulte as Especializações de dados do dispositivo HDP do Bluetooth. Esses valores também são referenciados na especificação ISO/IEEE 11073-20601 [7] como MDC_DEV_SPEC_PROFILE_* no Anexo de Códigos de Nomenclatura. Para ver uma discussão mais detalhada do HDP, consulte Perfil Health Device.

Veja a seguir as etapas básicas para trabalhar com um perfil:

  1. Tenha acesso ao adaptador padrão conforme descrito em Configurar o Bluetooth.
  2. Configure um BluetoothProfile.ServiceListener. Esse listener notifica os clientes de BluetoothProfile quando são conectados ou desconectados do serviço.
  3. Use getProfileProxy() para estabelecer uma conexão ao objeto de proxy de perfil associado ao perfil. No exemplo abaixo, o objeto de proxy de perfil é uma instância de BluetoothHeadset.
  4. Em onServiceConnected(), acesse um manipulador para o objeto de proxy de perfil.
  5. Após ter o objeto de proxy de perfil, você pode usá-lo para monitorar o estado da conexão e executar outras operações relevantes para esse perfil.

Por exemplo, este snippet de código mostra como conectar-se a um objeto de proxy de BluetoothHeadset para poder controlar o perfil Headset:

Kotlin

var bluetoothHeadset: BluetoothHeadset? = null

// Get the default adapter
val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()

private val profileListener = object : BluetoothProfile.ServiceListener {

    override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
        if (profile == BluetoothProfile.HEADSET) {
            bluetoothHeadset = proxy as BluetoothHeadset
        }
    }

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

// Establish connection to the proxy.
bluetoothAdapter?.getProfileProxy(context, profileListener, BluetoothProfile.HEADSET)

// ... call functions on bluetoothHeadset

// Close proxy connection after use.
bluetoothAdapter?.closeProfileProxy(BluetoothProfile.HEADSET, bluetoothHeadset)

Java

BluetoothHeadset bluetoothHeadset;

// Get the default adapter
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

private BluetoothProfile.ServiceListener profileListener = new BluetoothProfile.ServiceListener() {
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEADSET) {
            bluetoothHeadset = (BluetoothHeadset) proxy;
        }
    }
    public void onServiceDisconnected(int profile) {
        if (profile == BluetoothProfile.HEADSET) {
            bluetoothHeadset = null;
        }
    }
};

// Establish connection to the proxy.
bluetoothAdapter.getProfileProxy(context, profileListener, BluetoothProfile.HEADSET);

// ... call functions on bluetoothHeadset

// Close proxy connection after use.
bluetoothAdapter.closeProfileProxy(bluetoothHeadset);

Comandos AT específicos de fornecedores

A partir do Android 3.0 (API de nível 11), os aplicativos podem registrar-se para receber transmissões de sistema de comandos AT predefinidos específicos de fornecedor, enviados por fones de ouvido (como um comando +XEVENT da Plantronics). Por exemplo, um aplicativo pode receber transmissões que indicam o nível de bateria de um dispositivo conectado, bem como notificar o usuário ou executar outra ação necessária. Crie um broadcast receiver para o intent ACTION_VENDOR_SPECIFIC_HEADSET_EVENT para processar comandos AT específicos de fornecedor para o fone de ouvido.

Perfil Health Device

O Android 4.0 (API de nível 14) introduz a compatibilidade com o perfil Health Device (HDP) do Bluetooth. Esse perfil permite criar aplicativos que usam o Bluetooth para comunicação com dispositivos de saúde compatíveis com Bluetooth, como monitores de frequência cardíaca, medidores de sangue, termômetros e balanças. A Bluetooth Health API contém as classes BluetoothHealth, BluetoothHealthCallback e BluetoothHealthAppConfiguration, descritas em Classes principais e interfaces.

A compreensão destes conceitos principais do HDP pode ajudar a usar a API Bluetooth Health:

Fonte
É um dispositivo de saúde — como uma balança, um medidor de glicose ou um termômetro — que transmite dados médicos para um dispositivo inteligente como um smartphone ou tablet Android.
Coletor
É o dispositivo inteligente que recebe dados médicos. Em aplicativos HDP do Android, o coletor é representado por um objeto .BluetoothHealthAppConfiguration
Registro
É o processo usado para registrar um coletor para se comunicar com um dispositivo de saúde em particular.
Conexão
É o processo usado para abrir um canal entre um dispositivo de saúde (fonte) e um dispositivo inteligente (coletor).

Criar um aplicativo HDP

Veja a seguir as etapas básicas envolvidas na criação de um aplicativo HDP do Android:

  1. Tenha uma referência ao objeto de proxy de BluetoothHealth.

    Da mesma forma que nos dispositivos com perfil Headset e A2DP, você precisa chamar getProfileProxy() com um BluetoothProfile.ServiceListener e o tipo de perfil HEALTH para estabelecer uma conexão com o objeto de proxy de perfil.

  2. Crie um BluetoothHealthCallback e registre uma configuração de aplicativo (BluetoothHealthAppConfiguration) que atue como um coletor de saúde.
  3. Estabeleça uma conexão a um dispositivo de saúde.

    Observação: alguns dispositivos iniciam a conexão automaticamente. Não é necessário executar esta etapa para esses dispositivos.

  4. Quando conectado a um dispositivo de saúde, leia/grave dados nele usando o descritor de arquivo. Os dados recebidos precisam ser interpretados usando um gerenciador de saúde que implemente as especificações IEEE 11073.
  5. Quando terminar, feche o canal de saúde e cancele a inscrição do aplicativo. O canal também se fechará quando houver um longo período de inatividade.

Configurar o Bluetooth

Antes que o aplicativo se comunique usando o Bluetooth, é necessário verificar se o dispositivo permite Bluetooth e, caso permita, se o Bluetooth está ativado.

Se o dispositivo não permitir o Bluetooth, desative todos os recursos do Bluetooth de forma ordenada. Se o dispositivo for compatível com Bluetooth, mas estiver desativado, você poderá solicitar que o usuário ative o Bluetooth sem sair do aplicativo. Essa configuração é efetuada em duas etapas, usando o BluetoothAdapter:

  1. Tenha o BluetoothAdapter.

    O BluetoothAdapter é necessário para todas as atividades do Bluetooth. Para ter o BluetoothAdapter, chame o método estático getDefaultAdapter(). Um BluetoothAdapter será retornado para representar o próprio adaptador Bluetooth do dispositivo (o rádio Bluetooth). Há um adaptador Bluetooth para todo o sistema, e o aplicativo pode usar esse objeto para interagir com ele. Se getDefaultAdapter() retornar null, significa que o dispositivo não é compatível com Bluetooth. Por exemplo:

    Kotlin

    val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
    if (bluetoothAdapter == null) {
        // Device doesn't support Bluetooth
    }
    

    Java

    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter == null) {
        // Device doesn't support Bluetooth
    }
    
  2. Ative o Bluetooth.

    Em seguida, é necessário garantir a ativação do Bluetooth. Chame isEnabled() para verificar se o Bluetooth está ativado. Se o método retornar “false”, o Bluetooth está desativado. Para solicitar a ativação do Bluetooth, chame startActivityForResult(), passando em uma ação de intent ACTION_REQUEST_ENABLE. Essa chamada envia uma solicitação para ativar o Bluetooth por meio das configurações do sistema (sem que o aplicativo seja interrompido). Por exemplo:

    Kotlin

    if (bluetoothAdapter?.isEnabled == false) {
        val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
    }
    

    Java

    if (!bluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }
    

    Será exibida uma caixa de diálogo para solicitar ao usuário permissão de ativação do Bluetooth, conforme visto na Figura 1. Se o usuário responder “Yes”, o sistema começará a ativar o Bluetooth e o foco retornará ao seu aplicativo após a conclusão (ou falha) do processo.

    Figura 1. A caixa de diálogo de ativação do Bluetooth.

    A constante REQUEST_ENABLE_BT passada a startActivityForResult() é um número inteiro definido localmente (que precisa ser maior que 0) passado pelo sistema para a implementação de onActivityResult() como o parâmetro requestCode.

    Se a ativação do Bluetooth for bem-sucedida, a atividade receberá o código de resultado RESULT_OK no callback .onActivityResult() Se o Bluetooth não foi ativado devido a um erro (ou à resposta “No” do usuário), o código de resultado será RESULT_CANCELED.

Opcionalmente, o aplicativo também pode ouvir o intent de transmissão ACTION_STATE_CHANGED, transmitido pelo sistema sempre que o estado do Bluetooth for alterado. Essa transmissão contém os campos adicionais EXTRA_STATE e EXTRA_PREVIOUS_STATE, que contêm respectivamente os estados novo e anterior do Bluetooth. Os valores possíveis dos campos adicionais são STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF e STATE_OFF. Pode ser útil ouvir essa transmissão se o aplicativo precisar detectar alterações do estado do Bluetooth no ambiente de execução.

Dica: ativar a detecção do dispositivo automaticamente ativa o Bluetooth. Se você planeja sempre ativar a detecção do dispositivo antes de executar as atividades do Bluetooth, pule a etapa 2 acima. Para mais informações, leia a seção ativar a detecção do dispositivo nesta página.

Encontrar dispositivos

Use o BluetoothAdapter para encontrar dispositivos remotos Bluetooth por meio da descoberta de dispositivos ou consultando a lista de dispositivos pareados vinculados.

A descoberta de dispositivos é um procedimento de análise que procura dispositivos com Bluetooth ativado na área local e solicita algumas informações de cada um deles. Às vezes, esse processo é denominado descoberta, consulta ou análise. No entanto, os dispositivos Bluetooth próximos responderão a solicitações de descoberta somente se estiverem configurados como detectáveis. Se o dispositivo estiver detectável, responderá à solicitação de descoberta compartilhando algumas informações, como o nome, a classe e o endereço MAC único do dispositivo. Com essas informações, o dispositivo que executa a descoberta pode optar por iniciar uma conexão com o dispositivo descoberto.

Após a conexão com um dispositivo remoto pela primeira vez, uma solicitação de pareamento será automaticamente apresentada ao usuário. Quando um dispositivo é pareado, as informações básicas sobre esse dispositivo — como nome, classe e endereço MAC do dispositivo — são salvas e podem ser lidas usando as APIs Bluetooth. Com o endereço MAC conhecido de um dispositivo remoto, é possível iniciar uma conexão com ele a qualquer momento sem executar a descoberta, desde que o dispositivo esteja dentro do alcance.

Lembre-se de que há uma diferença entre estar pareado e estar conectado:

  • Estar pareado significa que os dois dispositivos estão cientes da existência um do outro, têm um link-chave compartilhado que pode ser usado para autenticação e podem estabelecer uma conexão criptografada entre si.
  • Estar conectado significa que os dispositivos compartilham no momento um canal RFCOMM e podem transmitir dados entre si. A API Bluetooth atual do Android exige que os dispositivos estejam pareados antes de estabelecer uma conexão RFCOMM. O pareamento é executado automaticamente na inicialização de uma conexão criptografada com as APIs do Bluetooth.

As sessões a seguir descrevem como encontrar dispositivos que já foram pareados ou descobrir novos dispositivos usando a descoberta de dispositivos.

Observação: por padrão, dispositivos Android não são detectáveis. O usuário pode tornar o dispositivo detectável por tempo limitado por meio das configurações do sistema ou o aplicativo pode solicitar que o usuário ative a detecção do dispositivo sem sair do aplicativo. Para mais informações, consulte a seção ativar detecção do dispositivo nesta página.

Consultar dispositivos pareados

Antes de executar a descoberta de dispositivos, vale a pena consultar o conjunto de dispositivos pareados para verificar se o dispositivo desejado já é conhecido. Para isso, chame getBondedDevices(). Isso retorna um conjunto de objetos BluetoothDevice que representam dispositivos pareados. Por exemplo, você pode consultar todos os dispositivos pareados e mostrar o nome e o endereço MAC de cada dispositivo, como demonstrado no snippet de código a seguir:

Kotlin

val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
    val deviceName = device.name
    val deviceHardwareAddress = device.address // MAC address
}

Java

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) {
    // There are paired devices. Get the name and address of each paired device.
    for (BluetoothDevice device : pairedDevices) {
        String deviceName = device.getName();
        String deviceHardwareAddress = device.getAddress(); // MAC address
    }
}

Para iniciar uma conexão com um dispositivo Bluetooth, só é necessário o endereço MAC do objeto BluetoothDevice associado, que você pode recuperar chamando getAddress(). Para saber mais sobre a criação de uma conexão, veja a seção Conectar dispositivos.

Atenção: a realização de descoberta de dispositivos consome muitos recursos do adaptador de Bluetooth. Assim que você encontrar um dispositivo para conexão, certifique-se de interromper a descoberta com cancelDiscovery() antes de tentar a conexão. Além disso, a realização da descoberta durante a conexão não é recomendada, uma vez que esse processo reduz significativamente a largura de banda disponível para as conexões atuais.

Descobrir dispositivos

Para começar a descobrir dispositivos, basta chamar startDiscovery(). Esse processo é assíncrono e retorna um valor booleano que indica se a descoberta foi iniciada corretamente. Normalmente, o processo de descoberta envolve uma análise de consulta de cerca de 12 segundos, seguida por uma análise de página de cada dispositivo encontrado para recuperar o nome do Bluetooth.

Para descobrir informações sobre cada dispositivo descoberto, o aplicativo precisa registrar um BroadcastReceiver para o intent ACTION_FOUND. O sistema transmite esse intent para cada dispositivo. O intent contém os campos extras EXTRA_DEVICE e EXTRA_CLASS, que por sua vez contêm um BluetoothDevice e um BluetoothClass, respectivamente. O snippet de código a seguir mostra como é possível registrar-se para processar a transmissão quando dispositivos são descobertos:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...

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

// Create a BroadcastReceiver for ACTION_FOUND.
private val receiver = object : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val action: String = intent.action
        when(action) {
            BluetoothDevice.ACTION_FOUND -> {
                // Discovery has found a device. Get the BluetoothDevice
                // object and its info from the Intent.
                val device: BluetoothDevice =
                        intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
                val deviceName = device.name
                val deviceHardwareAddress = device.address // MAC address
            }
        }
    }
}

override fun onDestroy() {
    super.onDestroy()
    ...

    // Don't forget to unregister the ACTION_FOUND receiver.
    unregisterReceiver(receiver)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    // 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)) {
            // Discovery has found a device. Get the BluetoothDevice
            // object and its info from the Intent.
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            String deviceName = device.getName();
            String deviceHardwareAddress = device.getAddress(); // MAC address
        }
    }
};

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

    // Don't forget to unregister the ACTION_FOUND receiver.
    unregisterReceiver(receiver);
}

Para iniciar uma conexão com um dispositivo Bluetooth, só é necessário o endereço MAC do objeto BluetoothDevice associado, que você pode recuperar chamando getAddress(). Para saber mais sobre a criação de uma conexão, veja a seção Conectar dispositivos.

Atenção: a realização de descoberta de dispositivos consome muitos recursos do adaptador de Bluetooth. Assim que você encontrar um dispositivo para conexão, certifique-se de interromper a descoberta com cancelDiscovery() antes de tentar a conexão. Além disso, a realização da descoberta durante a conexão não é recomendada, uma vez que esse processo reduz significativamente a largura de banda disponível para as conexões atuais.

Ativar a detecção do dispositivo

Se você quer que o dispositivo local seja detectável por outros dispositivos, chame startActivityForResult(Intent, int) com o Intent de ação ACTION_REQUEST_DISCOVERABLE. Com isso, uma solicitação será enviada para ativar o modo detectável do sistema, sem que haja necessidade de navegar até o app Configurações, o que interromperia seu próprio aplicativo. Por padrão, o dispositivo torna-se detectável durante 120 segundos (2 minutos). Ao adicionar o extra EXTRA_DISCOVERABLE_DURATION, é possível definir uma duração diferente, de até 3.600 segundos (1 hora).

Atenção: se você definir o valor do extra EXTRA_DISCOVERABLE_DURATION como 0, o dispositivo ficará sempre detectável. Não recomendamos essa configuração, uma vez que ela não é segura.

O snippet de código a seguir define o dispositivo como detectável durante 300 segundos (5 minutos):

Kotlin

val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
    putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivity(discoverableIntent)

Java

Intent discoverableIntent =
        new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
Figura 2: Caixa de diálogo de ativação da detecção do dispositivo.

Será exibida uma caixa de diálogo que solicitará a permissão do usuário para tornar o dispositivo detectável, como mostrado na Figura 2. Se o usuário responder “Yes”, o dispositivo se tornará detectável pelo tempo especificado. A atividade receberá então uma chamada para o callback onActivityResult(), com o código de resultado igual à duração do período em que o dispositivo permanecerá detectável. Se o usuário responder “No” ou se ocorrer um erro, o código de resultado será RESULT_CANCELED.

Observação: se o Bluetooth não foi ativado no dispositivo, ele será ativado automaticamente pela ativação da detecção do dispositivo.

O dispositivo permanecerá silenciosamente no modo detectável pelo tempo especificado. Se você quiser ser notificado quando o modo detectável mudar, registre um BroadcastReceiver para o intent .ACTION_SCAN_MODE_CHANGED. Esse intent contém os campos extras EXTRA_SCAN_MODE e EXTRA_PREVIOUS_SCAN_MODE, que fornecem respectivamente os modos de análise novo e anterior. Veja possíveis valores para cada extra:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
O dispositivo está no modo detectável.
SCAN_MODE_CONNECTABLE
O dispositivo não está no modo detectável, mas ainda pode receber conexões.
SCAN_MODE_NONE
O dispositivo não está no modo detectável e não pode receber conexões.

Se você estiver iniciando a conexão a um dispositivo remoto, não será necessário ativar a detecção do dispositivo. A ativação da detecção do dispositivo só é necessária se você quiser que o aplicativo hospede um soquete de servidor que aceite as conexões recebidas, uma vez que os dispositivos remotos precisam ser capazes de descobrir o dispositivo antes de iniciar a conexão.

Conectar dispositivos

Para criar uma conexão entre dois dispositivos, você precisa implementar os mecanismos do lado do cliente e do servidor, porque um dispositivo precisa abrir um soquete de servidor e o outro precisa iniciar a conexão (usando o endereço MAC do dispositivo servidor para iniciar a conexão). O dispositivo servidor e o dispositivo cliente recebem o BluetoothSocket necessário de formas diferentes. O servidor recebe a informação do soquete quando uma conexão de entrada é aceita. O cliente fornece a informação do soquete quando abre um canal RFCOMM para o servidor.

O servidor e o cliente serão considerados conectados entre si quando cada um deles tiver um BluetoothSocket conectado no mesmo canal RFCOMM. Nesse momento, cada dispositivo pode ter streams de entrada e saída e a transferência de dados pode começar, o que é discutido na seção Gerenciar uma conexão. Esta seção descreve como iniciar a conexão entre dois dispositivos.

Técnicas de conexão

Uma das técnicas de implementação é preparar automaticamente cada dispositivo como servidor para que cada um tenha um soquete de servidor aberto e ouça conexões. Nesse caso, qualquer um dos dispositivos pode iniciar a conexão com o outro e se tornar o cliente. Como alternativa, um dispositivo pode hospedar explicitamente a conexão e abrir um soquete de servidor sob demanda e o outro dispositivo pode simplesmente iniciar a conexão.

Figura 3. Caixa de diálogo de pareamento do Bluetooth.

Observação: se os dois dispositivos não foram pareados previamente, a biblioteca do Android mostrará automaticamente uma notificação ou caixa de diálogo de solicitação de pareamento ao usuário durante o procedimento de conexão, como mostrado na Figura 3. Portanto, ao tentar conectar dispositivos, o aplicativo não precisa se preocupar com o pareamento deles. A tentativa de conexão RFCOMM ficará bloqueada até que o usuário execute o pareamento entre os dois dispositivos corretamente. Ela falhará se o usuário rejeitar o pareamento ou se o pareamento falhar ou esgotar-se o tempo limite.

Conectar como servidor

Para conectar dois dispositivos, um precisa atuar como servidor, mantendo um BluetoothServerSocket aberto. O objetivo do soquete do servidor é ouvir solicitações de conexão de entrada e, quando uma for aceita, fornecer um BluetoothSocket conectado. Quando o BluetoothSocket é adquirido do BluetoothServerSocket, o BluetoothServerSocket pode — e precisa — ser descartado, a menos que você queria aceitar mais conexões.

Veja a seguir o procedimento básico para configurar um soquete de servidor e aceitar uma conexão:

  1. Chame um listenUsingRfcommWithServiceRecord() e receba um BluetoothServerSocket.

    A string é um nome identificável do serviço e será gravada automaticamente pelo sistema em uma nova entrada de banco de dados do Service Discovery Protocol (SDP) no dispositivo. O nome é arbitrário e pode ser simplesmente o nome do aplicativo. O identificador universalmente único (UUID, na sigla em inglês) também está incluído na entrada SDP e será a base para o acordo de conexão com o dispositivo cliente. Ou seja, quando o cliente tentar se conectar com este dispositivo, ele terá um UUID que identifica unicamente o serviço com que quer se conectar. Esses UUIDs precisam corresponder para que a conexão seja aceita.

    O UUID é um formato padronizado de 128 bits para um código de string usado para identificar unicamente informações. A vantagem de um UUID é que é grande o suficiente para permitir a seleção aleatória de qualquer código sem conflitos com outros. Nesse caso, ele é usado para identificar unicamente o serviço Bluetooth do aplicativo. Para ter um UUID para uso no aplicativo, você pode usar um dos diversos geradores de UUID aleatórios na Web e inicializar um UUID com fromString(String).

  2. Comece a ouvir solicitações de conexão chamando accept().

    Essa é uma chamada de bloqueio. Ela retornará quando uma conexão for aceita ou ocorrer uma exceção. A conexão só será aceita quando um dispositivo remoto enviar uma solicitação de conexão com um UUID correspondente ao registrado nesse soquete do servidor ouvinte. Quando bem-sucedido, accept() retornará um BluetoothSocket conectado.

  3. A menos que você queira aceitar mais conexões, chame close().

    Com isso, o soquete do servidor e todos os seus recursos serão liberados, mas o BluetoothSocket conectado retornado por accept() não será fechado. Ao contrário do TCP/IP, o RFCOMM somente permite um cliente conectado por canal em um determinado momento. Portanto, na maioria dos casos, faz sentido chamar close() no BluetoothServerSocket imediatamente depois de aceitar um soquete conectado.

Como a chamada accept() é de bloqueio, ela não deve ser executada no thread de IU da atividade principal. Assim, o aplicativo ainda poderá responder a outras interações do usuário. Normalmente, faz sentido fazer todo o trabalho que envolve um BluetoothServerSocket ou BluetoothSocket em um novo thread, gerenciado pelo aplicativo. Para cancelar uma chamada bloqueada como accept(), chame close() no BluetoothServerSocket ou BluetoothSocket de outro thread. Todos os métodos em um BluetoothServerSocket ou BluetoothSocket podem ser usados com segurança no thread.

Exemplo

Veja a seguir um thread simplificado do componente de servidor que aceita conexões de entrada:

Kotlin

private inner class AcceptThread : Thread() {
    
    private val mmServerSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE) {
        bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID)
    }

    override fun run() {
        // Keep listening until exception occurs or a socket is returned.
        var shouldLoop = true
        while (shouldLoop) {
            val socket: BluetoothSocket? = try {
                mmServerSocket?.accept()
            } catch (e: IOException) {
                Log.e(TAG, "Socket's accept() method failed", e)
                shouldLoop = false
                null
            }
            socket?.also {
                manageMyConnectedSocket(it)
                mmServerSocket?.close()
                shouldLoop = false
            }
        }
    }

    // Closes the connect socket and causes the thread to finish.
    fun cancel() {
        try {
            mmServerSocket?.close()
        } catch (e: IOException) {
            Log.e(TAG, "Could not close the connect socket", e)
        }
    }
}

Java

private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;

    public AcceptThread() {
        // Use a temporary object that is later assigned to mmServerSocket
        // because mmServerSocket is final.
        BluetoothServerSocket tmp = null;
        try {
            // MY_UUID is the app's UUID string, also used by the client code.
            tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException e) {
            Log.e(TAG, "Socket's listen() method failed", e);
        }
        mmServerSocket = tmp;
    }

    public void run() {
        BluetoothSocket socket = null;
        // Keep listening until exception occurs or a socket is returned.
        while (true) {
            try {
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                Log.e(TAG, "Socket's accept() method failed", e);
                break;
            }

            if (socket != null) {
                // A connection was accepted. Perform work associated with
                // the connection in a separate thread.
                manageMyConnectedSocket(socket);
                mmServerSocket.close();
                break;
            }
        }
    }

    // Closes the connect socket and causes the thread to finish.
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Could not close the connect socket", e);
        }
    }
}

Nesse exemplo, só se quer uma conexão de entrada. Portanto, assim que uma conexão for aceita e o BluetoothSocket for adquirido, o aplicativo passará o BluetoothSocket adquirido a um thread separado, fechará o BluetoothServerSocket e interromperá o loop.

Quando accept() retorna o BluetoothSocket, o soquete já está conectado. Portanto, não chame connect(), como é feito no lado do cliente.

O método manageMyConnectedSocket() específico do aplicativo é projetado para iniciar o thread para transferência de dados. Isso é discutido na seção sobre Gerenciar uma conexão.

Normalmente, é necessário fechar o BluetoothServerSocket assim que acabar de ouvir conexões de entrada. Nesse exemplo, close() é chamado assim que o BluetoothSocket é adquirido. Também pode ser necessário fornecer um método público no thread que possa fechar o BluetoothSocket privado se for preciso parar de ouvir no soquete do servidor.

Conectar como cliente

Para iniciar uma conexão com um dispositivo remoto que aceite conexões com um soquete de servidor aberto, é necessário antes ter um objeto BluetoothDevice que representa o dispositivo remoto. Para saber como criar um BluetoothDevice, consulte Encontrar dispositivos. Em seguida, use BluetoothDevice para adquirir um BluetoothSocket e iniciar a conexão.

Este é o procedimento básico:

  1. Usando o BluetoothDevice, chame createRfcommSocketToServiceRecord(UUID) para ter um BluetoothSocket.

    Esse método inicializa um objeto BluetoothSocket que permite que o cliente se conecte a um BluetoothDevice. O UUID passado aqui precisa corresponder ao UUID usado pelo dispositivo servidor quando chamou listenUsingRfcommWithServiceRecord(String, UUID) para abrir o BluetoothServerSocket. Para usar o UUID correspondente, codifique a string UUID no seu aplicativo e a referencie no código do servidor e do cliente.

  2. Chame connect() para iniciar a conexão. Esse método é uma chamada de bloqueio.

    Após esse método ser chamado pelo cliente, o sistema realizará uma pesquisa SDP para encontrar dispositivos remotos com o UUID correspondente. Se a pesquisa for bem-sucedida e o dispositivo remoto aceitar a conexão, ele compartilhará o canal RFCOMM para uso durante a conexão e o método connect() retornará. Caso a conexão falhe ou o tempo do método connect() se encerrar (após cerca de 12 segundos), o método lançará uma IOException.

    Como connect() é uma chamada de bloqueio, sempre realize o procedimento de conexão em um thread separado do thread (IU) da atividade principal.

    Observação: sempre chame cancelDiscovery() para garantir que o dispositivo não faça descoberta de dispositivos antes de o connect() ser chamado. Se houver uma descoberta em andamento, a tentativa de conexão terá a velocidade substancialmente reduzida e provavelmente falhará.

Exemplo

Veja um exemplo básico de um thread de cliente que inicia uma conexão Bluetooth:

Kotlin

private inner class ConnectThread(device: BluetoothDevice) : Thread() {

    private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
        device.createRfcommSocketToServiceRecord(MY_UUID)
    }

    public override fun run() {
        // Cancel discovery because it otherwise slows down the connection.
        bluetoothAdapter?.cancelDiscovery()

        mmSocket?.use { socket ->
            // Connect to the remote device through the socket. This call blocks
            // until it succeeds or throws an exception.
            socket.connect()

            // The connection attempt succeeded. Perform work associated with
            // the connection in a separate thread.
            manageMyConnectedSocket(socket)
        }
    }

    // Closes the client socket and causes the thread to finish.
    fun cancel() {
        try {
            mmSocket?.close()
        } catch (e: IOException) {
            Log.e(TAG, "Could not close the client socket", e)
        }
    }
}

Java

private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device) {
        // Use a temporary object that is later assigned to mmSocket
        // because mmSocket is final.
        BluetoothSocket tmp = null;
        mmDevice = device;

        try {
            // Get a BluetoothSocket to connect with the given BluetoothDevice.
            // MY_UUID is the app's UUID string, also used in the server code.
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            Log.e(TAG, "Socket's create() method failed", e);
        }
        mmSocket = tmp;
    }

    public void run() {
        // Cancel discovery because it otherwise slows down the connection.
        bluetoothAdapter.cancelDiscovery();

        try {
            // Connect to the remote device through the socket. This call blocks
            // until it succeeds or throws an exception.
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and return.
            try {
                mmSocket.close();
            } catch (IOException closeException) {
                Log.e(TAG, "Could not close the client socket", closeException);
            }
            return;
        }

        // The connection attempt succeeded. Perform work associated with
        // the connection in a separate thread.
        manageMyConnectedSocket(mmSocket);
    }

    // Closes the client socket and causes the thread to finish.
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Could not close the client socket", e);
        }
    }
}

Nesse snippet, cancelDiscovery() é chamado antes que a tentativa de conexão ocorra. Sempre chame cancelDiscovery() antes de connect(), principalmente porque cancelDiscovery() será bem-sucedido, independentemente de a descoberta do dispositivo estar em progresso. No entanto, se o aplicativo precisar determinar se a descoberta do dispositivo está em progresso, é possível conferir usando isDiscovering().

O método manageMyConnectedSocket() específico do aplicativo é projetado para iniciar o thread para transferência de dados. Isso é discutido na seção sobre Gerenciar uma conexão.

Ao concluir o BluetoothSocket, sempre chame close(). Ao fazer isso, o soquete conectado automaticamente se fecha e libera todos os recursos internos relacionados.

Gerenciar uma conexão

Após você ter conectado corretamente vários dispositivos, cada um deles terá um BluetoothSocket conectado. É aí que começa a ficar interessante: você pode compartilhar dados entre dispositivos. Ao usar o BluetoothSocket, o procedimento geral para transferência de dados é este:

  1. Acesse o InputStream e o OutputStream que processam transmissões pelo soquete por meio de getInputStream() e getOutputStream(), respectivamente.
  2. Leia e grave dados nos streams com read(byte[]) e write(byte[]).

Naturalmente, é necessário considerar detalhes de implementação. Em particular, é necessário usar um thread dedicado para ler a partir do stream e registrar nele. Isso é importante, já que os métodos read(byte[]) e write(byte[]) são chamadas de bloqueio. O método read(byte[]) bloqueia até que haja algo a ser lido do stream. O método write(byte[]) não costuma bloquear, mas pode fazer isso para controle de fluxo, se o dispositivo remoto não estiver chamando read(byte[]) rápido o suficiente e os buffers intermediários ficarem cheios como resultado. Portanto, o loop principal do thread precisa ser dedicado à leitura do InputStream. Pode-se usar um método público separado no thread para iniciar gravações no OutputStream.

Exemplo

Veja um exemplo de como transferir dados entre dois dispositivos conectados por Bluetooth:

Kotlin

private const val TAG = "MY_APP_DEBUG_TAG"

// Defines several constants used when transmitting messages between the
// service and the UI.
const val MESSAGE_READ: Int = 0
const val MESSAGE_WRITE: Int = 1
const val MESSAGE_TOAST: Int = 2
// ... (Add other message types here as needed.)

class MyBluetoothService(
        // handler that gets info from Bluetooth service
        private val handler: Handler) {

    private inner class ConnectedThread(private val mmSocket: BluetoothSocket) : Thread() {

        private val mmInStream: InputStream = mmSocket.inputStream
        private val mmOutStream: OutputStream = mmSocket.outputStream
        private val mmBuffer: ByteArray = ByteArray(1024) // mmBuffer store for the stream

        override fun run() {
            var numBytes: Int // bytes returned from read()

            // Keep listening to the InputStream until an exception occurs.
            while (true) {
                // Read from the InputStream.
                numBytes = try {
                    mmInStream.read(mmBuffer)
                } catch (e: IOException) {
                    Log.d(TAG, "Input stream was disconnected", e)
                    break
                }

                // Send the obtained bytes to the UI activity.
                val readMsg = handler.obtainMessage(
                        MESSAGE_READ, numBytes, -1,
                        mmBuffer)
                readMsg.sendToTarget()
            }
        }

        // Call this from the main activity to send data to the remote device.
        fun write(bytes: ByteArray) {
            try {
                mmOutStream.write(bytes)
            } catch (e: IOException) {
                Log.e(TAG, "Error occurred when sending data", e)

                // Send a failure message back to the activity.
                val writeErrorMsg = handler.obtainMessage(MESSAGE_TOAST)
                val bundle = Bundle().apply {
                    putString("toast", "Couldn't send data to the other device")
                }
                writeErrorMsg.data = bundle
                handler.sendMessage(writeErrorMsg)
                return
            }

            // Share the sent message with the UI activity.
            val writtenMsg = handler.obtainMessage(
                    MESSAGE_WRITE, -1, -1, mmBuffer)
            writtenMsg.sendToTarget()
        }

        // Call this method from the main activity to shut down the connection.
        fun cancel() {
            try {
                mmSocket.close()
            } catch (e: IOException) {
                Log.e(TAG, "Could not close the connect socket", e)
            }
        }
    }
}

Java

public class MyBluetoothService {
    private static final String TAG = "MY_APP_DEBUG_TAG";
    private Handler handler; // handler that gets info from Bluetooth service

    // Defines several constants used when transmitting messages between the
    // service and the UI.
    private interface MessageConstants {
        public static final int MESSAGE_READ = 0;
        public static final int MESSAGE_WRITE = 1;
        public static final int MESSAGE_TOAST = 2;

        // ... (Add other message types here as needed.)
    }

    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;
        private byte[] mmBuffer; // mmBuffer store for the stream

        public ConnectedThread(BluetoothSocket socket) {
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // Get the input and output streams; using temp objects because
            // member streams are final.
            try {
                tmpIn = socket.getInputStream();
            } catch (IOException e) {
                Log.e(TAG, "Error occurred when creating input stream", e);
            }
            try {
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "Error occurred when creating output stream", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            mmBuffer = new byte[1024];
            int numBytes; // bytes returned from read()

            // Keep listening to the InputStream until an exception occurs.
            while (true) {
                try {
                    // Read from the InputStream.
                    numBytes = mmInStream.read(mmBuffer);
                    // Send the obtained bytes to the UI activity.
                    Message readMsg = handler.obtainMessage(
                            MessageConstants.MESSAGE_READ, numBytes, -1,
                            mmBuffer);
                    readMsg.sendToTarget();
                } catch (IOException e) {
                    Log.d(TAG, "Input stream was disconnected", e);
                    break;
                }
            }
        }

        // Call this from the main activity to send data to the remote device.
        public void write(byte[] bytes) {
            try {
                mmOutStream.write(bytes);

                // Share the sent message with the UI activity.
                Message writtenMsg = handler.obtainMessage(
                        MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
                writtenMsg.sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "Error occurred when sending data", e);

                // Send a failure message back to the activity.
                Message writeErrorMsg =
                        handler.obtainMessage(MessageConstants.MESSAGE_TOAST);
                Bundle bundle = new Bundle();
                bundle.putString("toast",
                        "Couldn't send data to the other device");
                writeErrorMsg.setData(bundle);
                handler.sendMessage(writeErrorMsg);
            }
        }

        // Call this method from the main activity to shut down the connection.
        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Could not close the connect socket", e);
            }
        }
    }
}

Após o construtor adquirir os streams necessários, o thread espera a chegada dos dados por meio do InputStream. Quando read(byte[]) retorna com dados do stream, eles são enviados à atividade principal usando um Handler de membros da classe pai. O thread espera que mais bytes sejam lidos do InputStream.

Para enviar dados de saída, basta chamar o método write() do thread da atividade principal e passar os bytes a enviar. Esse método chama write(byte[]) para enviar os dados ao dispositivo remoto. Se uma IOException for lançada ao chamar write(byte[]), o thread enviará um toast à atividade principal, explicando ao usuário que o dispositivo não pôde enviar os bytes a outro dispositivo conectado.

O método cancel() do thread permite que a conexão seja finalizada a qualquer momento por meio do fechamento do BluetoothSocket. Chame esse método sempre que acabar de usar a conexão Bluetooth.

Para ver uma demonstração do uso das APIs Bluetooth, consulte o aplicativo de amostra Bluetooth Chat.

Classes principais e interfaces

Todas as APIs Bluetooth estão disponíveis no pacote .android.bluetooth Veja a seguir um resumo das classes e interfaces necessárias para criar conexões Bluetooth:

BluetoothAdapter
Representa o adaptador Bluetooth local (rádio Bluetooth). O BluetoothAdapter é o ponto de entrada para toda a interação com o Bluetooth. Use-o para descobrir outros dispositivos Bluetooth, consultar uma lista de dispositivos vinculados (pareados), instanciar um BluetoothDevice usando um endereço MAC conhecido e criar um BluetoothServerSocket para ouvir comunicações de outros dispositivos.
BluetoothDevice
Representa um dispositivo remoto Bluetooth. Use-o para solicitar uma conexão com um dispositivo remoto por meio de um BluetoothSocket ou consultar informações sobre o dispositivo, como nome, endereço, classe e estado de vinculação.
BluetoothSocket
Representa a interface de um soquete Bluetooth (semelhante a um Socket TCP). É o ponto de conexão que permite que um aplicativo troque dados com outro dispositivo Bluetooth por meio de InputStream e OutputStream.
BluetoothServerSocket
Representa um soquete de servidor aberto que ouve solicitações recebidas (semelhante a um ServerSocket TCP). Para conectar dois dispositivos Android, um dispositivo precisa abrir um soquete de servidor com esta classe. Quando um dispositivo remoto Bluetooth estabelecer uma solicitação de conexão com esse dispositivo, o dispositivo aceitará a conexão e retornará um BluetoothSocket conectado.
BluetoothClass
Descreve as características e os recursos gerais de um dispositivo Bluetooth. Essa descrição é um conjunto de propriedades somente para leitura que definem as classes e os serviços do dispositivo. Embora essa informação forneça uma dica útil com relação ao tipo de dispositivo, os atributos dessa classe não descrevem necessariamente todos os serviços e perfis Bluetooth compatíveis com o dispositivo.
BluetoothProfile
É uma interface que representa um perfil Bluetooth. O perfil Bluetooth é uma especificação de interface sem fio para comunicação com base em Bluetooth entre dispositivos. Um exemplo é o perfil Hands-Free. Para ver uma discussão mais detalhada dos perfis, consulte Trabalho com perfis.
BluetoothHeadset
Permite o uso de fones de ouvido Bluetooth com smartphones. Inclui os perfis Bluetooth Headset e Hands-Free (v1.5).
BluetoothA2dp
Define como fazer streaming de áudio de alta qualidade de um dispositivo para outro por meio de uma conexão Bluetooth usando o perfil Advanced Audio Distribution Profile (A2DP).
BluetoothHealth
Representa um proxy do perfil Health Device que controla o serviço Bluetooth.
BluetoothHealthCallback
Classe abstrata usada para implementar callbacks de BluetoothHealth. É necessário estender essa classe e implementar os métodos de callback para receber atualizações sobre as alterações no estado do registro do aplicativo e no estado do canal Bluetooth.
BluetoothHealthAppConfiguration
Representa uma configuração de aplicativo registrada pelo aplicativo de saúde de terceiros do Bluetooth para comunicação com um dispositivo de saúde remoto do Bluetooth.
BluetoothProfile.ServiceListener
É uma interface que notifica clientes de comunicação entre processos (IPC, na sigla em inglês) do BluetoothProfile quando eles se conectam ou desconectam do serviço interno que executa um perfil em particular.