In my app I need pairing bluetooth device and immediately connect with it.
I have the following function in order to pairing devices:
public boolean createBond(BluetoothDevice btDevice)
{
try {
Log.d("pairDevice()", "Start Pairing...");
Method m = btDevice.getClass().getMethod("createBond", (Class[]) null);
Boolean returnValue = (Boolean) m.invoke(btDevice, (Object[]) null);
Log.d("pairDevice()", "Pairing finished.");
return returnValue;
} catch (Exception e) {
Log.e("pairDevice()", e.getMessage());
}
return false;
}
And I use it as the following way:
Boolean isBonded = false;
try {
isBonded = createBond(bdDevice);
if(isBonded)
{
//Connect with device
}
}
And it show me the dialog to pairing devices and enter the pin.
The problem is that createBond functions always return true, and it doen's wait until I enter the pin and paired with device, so I don't use correctly:
isBonded = createBond(bdDevice);
if(isBonded) {...}
So the question is How can I paired with device and when it is paired connect to it?
P.D My code is based in the first answer of the following thread: Android + Pair devices via bluetooth programmatically
I found the solution.
First I need a BroadcastReceiver like:
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
// CONNECT
}
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Discover new device
}
}
};
And then I need register the receiver as follow:
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
context.registerReceiver(myReceiver, intentFilter);
In this way the receiver is listening for ACTION_FOUND (Discover new device) and ACTION_BOND_STATE_CHANGED (Device change its bond state), then I check if the new state is BOND_BOUNDED and if it is I connect with device.
Now when I call createBond Method (described in the question) and enter the pin, ACTION_BOND_STATE_CHANGED will fire and device.getBondState() == BluetoothDevice.BOND_BONDED will be True and it will connect.
Related
I'm trying to check if my BluetoothDevice is connected to something.
If it is connected, obtain the data of the other device
I want to implement this function to my application since I need to monitor if the connection was lost or is still connected and add a visual indicator in case the connection changes.
Tried with this function but the toast shows nearby devices (not connected) constantly:
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String name = device.getName();
Toast.makeText(getApplicationContext(),name,Toast.LENGTH_SHORT).show();
}
AFAIK there is no way to view the state of the connection. Instead you monitor for changes in the state of the bluetooth connection. So you can register a receiver and then receive a broadcast when the device is disconnected.
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
this.registerReceiver(rec, filter);
private BroadcastReceiver rec = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_DISCONNECTED.equals(action)) {
// Bluetooth is now disconnected
}
}
I'm mantaining an app that runs on an Android 6.0 tablet that uses a Zebra iMZ220 bluetooth printer. The app requires the printer to be paired to the tablet, of course.
From time to time, the printer appears to receive a new pairing request from the tablet to which it is already paired, with the end result of breaking the bond.
I've been unable to determine the exact cause of it, for there are no errors in the log and it appears to happen randomly.
I've found these lines which I think is supposed to pair the printer:
Method method = device.getClass().getMethod("createBond", (Class[]) null);
method.invoke(device, (Object[]) null);
in the sequence
String printerMac = settings.getString("printerMac","");
if (!stampante.isEmpty()) {
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(stampante);
try {
Method method = device.getClass().getMethod("createBond", (Class[]) null);
method.invoke(device, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
}
}
Could it, for some reason, remove the bond on the printer even though it is supposed to do the opposite?
I couldn't reproduce this error on a Android 8 device.
From my experience (since i am also developing and maintaining an app that connects to a bluetooth printer) the pairing between the device and the bluetooth device can sometimes be lost although it is really rare. It is a bug that spreads amongst various devices and Android versions.
What i ended up doing is accept the possibility that it might sometime happen and implement a broadcast receiver to be notified that the pairing has been lost. At that time i create the bond again programmatically and also connect the printer.
When trying to create the bond, a default dialog will appear for the user to input the PIN the printer uses.However, since i know the PIN, i input this PIN progrmmatically so the dialog just appears for a split second and then dissapears.
After months battling with this issue this ended up to be the most elegant solution i could find.Hope it helps you as well.
In onCreate create the filter and register the receiver:
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(mReceiver, filter);
Method to call when you want to pair with the device:
private void pairDevice(BluetoothDevice device) {
try {
//Log.d("AutoPairing", "Start Pairing... with: " + device.getName());
device.createBond();
Log.d("AutoPairing", "Pairing finished.");
} catch (Exception e) {
Log.e("AutoPairing", e.getMessage());
}
}
Broadcast Receiver :
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
}else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
}else if (BluetoothDevice.ACTION_FOUND.equals(action)){
}else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
}else if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
try {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If you want to auto_insert the pin, uncomment the following lines
//String PinNew = "HereIsThePinThePrinterUses";
//device.setPin(PinNew.getBytes());
} catch (Exception e) {
Log.e("AutoPairing", "Error occurs when trying to auto pair");
e.printStackTrace();
}
}else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == 12) {
// Pairing was succesful. Do what you would normally do after that. Perhaps connect the printer now.
} else {
// Pairing was unsuccesful. **This is also what get's triggered when the pairing is getting lost**. Let's pair the device then.
pairDevice(device);
}
}
}
};
Hope i am not forgetting something.
PM: All those empty if statements are there in case you want to connect the printer as well. If you do it some other way then you can delete them and remove those actions from the filter.
When device gets paired to any device i should get a notification and also if it finds any paired device aroud i should get notified .
How to achieve this using Broadcast reciever
Based on your comment i understand that you want to show if there is a nearby paired bluetooth device after bluetooth is connected..
so first after your BluetoothDevice.ACTION_ACL_CONNECTED you need to start scan for paired Bluetooth devices and display them in a list. In the context of a mobile device, a Bluetooth device can either be:
1)unknown
2)paired
3)connected
It is important to know the difference between a paired and a connected Bluetooth device. Paired devices are aware of each other’s existence and share a link key, which can be used to authenticate, resulting in a connection. Devices are automatically paired once an encrypted connection is established.
Bluetooth devices are represented by the BluetoothDevice object. A list of paired devices can be obtained by invoking the getBondedDevices() method.
In your activity class
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BTAdapter = BluetoothAdapter.getDefaultAdapter();
if (!BTAdapter.isEnabled()) {
Intent enableBT = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBT, REQUEST_BLUETOOTH);
}
Log.d("DEVICELIST", "Super called for DeviceListFragment onCreate\n");
deviceItemList = new ArrayList<DeviceItem>();
Set<BluetoothDevice> pairedDevices = bTAdapter.getBondedDevices();
}
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
DeviceItem newDevice= new DeviceItem(device.getName(),device.getAddress(),"false");
deviceItemList.add(newDevice);
}
}
then create a new clsss DevicelistFragment to make a BroadcastReceiver and override the onReceive() method. The onReceive() method is invoked whenever a Bluetooth device is found.
public class DeviceListFragment extends Fragment implements AbsListView.OnItemClickListener{
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_deviceitem_list, container, false);
ToggleButton scan = (ToggleButton) view.findViewById(R.id.scan);
...
scan.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
if (isChecked) {
mAdapter.clear();
getActivity().registerReceiver(bReciever, filter);
bTAdapter.startDiscovery();
} else {
getActivity().unregisterReceiver(bReciever);
bTAdapter.cancelDiscovery();
}
}
});
}
...
private final BroadcastReceiver bReciever = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Create a new device item
DeviceItem newDevice = new DeviceItem(device.getName(), device.getAddress(), "false");
// Add it to our adapter
mAdapter.add(newDevice);
}
}
};
}
For full project see https://github.com/tutsplus/Android-BluetoothScannerFinishedProject
Also see: http://www.londatiga.net/it/programming/android/how-to-programmatically-scan-or-discover-android-bluetooth-device/
//Try this snippet and handle the
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
//or handle here with notification.....
}
}
//you can get notified when a new device is connected using Broadcast receiver
BroadcastReceiver btReceive=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)) {
//the device is found
}
}
};
I understand how to get a list of paired devices, but how can I tell if they are connected?
It must be possible since I see them listed in my phone's Bluetooth device list and it states their connection status.
Add the Bluetooth permission to your AndroidManifest,
<uses-permission android:name="android.permission.BLUETOOTH" />
Then use intent filters to listen to the ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECT_REQUESTED, and ACTION_ACL_DISCONNECTED broadcasts:
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
}
}
};
A few notes:
There is no way to retrieve a list of connected devices at application startup. The Bluetooth API does not allow you to query, instead it allows you to listen to changes.
A hoaky workaround to the above problem would be to retrieve the list of all known/paired devices... then trying to connect to each one (to determine if you're connected).
Alternatively, you could have a background service watch the Bluetooth API and write the device states to disk for your application to use at a later date.
In my use case I only wanted to see if a Bluetooth headset is connected for a VoIP app. The following solution worked for me.
Kotlin:
fun isBluetoothHeadsetConnected(): Boolean {
val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
return (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled
&& mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED)
}
Java:
public static boolean isBluetoothHeadsetConnected() {
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()
&& mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED;
}
Of course you'll need the Bluetooth permission:
<uses-permission android:name="android.permission.BLUETOOTH" />
There is an isConnected function in the BluetoothDevice system API in https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothDevice.java.
If you want to know if a bounded (paired) device is currently connected or not, the following function works fine for me:
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);
}
}
For some reason, BluetoothAdapter.ACTION_ACL_CONNECTED could not be resolved by Android Studio. Perhaps it was deprecated in Android 4.2.2?
Here is a modification of Skylarsutton's code (Big thanks to Skylarsutton for his answer.) . The registration code is the same; the receiver code differs slightly. I use this in a service which updates a Bluetooth-connected flag that other parts of the app reference.
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...
}
};
This code is for the headset profiles, and probably it will work for other profiles too.
First you need to provide a profile listener (Kotlin code):
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
}
}
}
Then while checking Bluetooth:
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET)
if (!mBluetoothAdapter.isEnabled) {
return Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
}
It takes a bit of time until onSeviceConnected is called. After that you may get the list of the connected headset devices from:
mBluetoothHeadset!!.connectedDevices
BluetoothAdapter.getDefaultAdapter().isEnabled ->
returns true when Bluetooth is open.
val audioManager = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.isBluetoothScoOn ->
returns true when a device connected
I was really looking for a way to fetch the connection status of a device, not listen to connection events. Here's what worked for me:
BluetoothManager bm = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bm.getConnectedDevices(BluetoothProfile.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
}
In android how can my Activity will get to know if a Bluetooth A2DP device is connected to my device.
Is there any broadcast receiver for that?
How to write this broadcast receiver?
Starting from API 11 (Android 3.0) you can use BluetoothAdapter to discover devices connected to a specific bluetooth profile. I used the code below to discover a device by its name:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.A2DP) {
boolean deviceConnected = false;
BluetoothA2dp btA2dp = (BluetoothA2dp) proxy;
List<BluetoothDevice> a2dpConnectedDevices = btA2dp.getConnectedDevices();
if (a2dpConnectedDevices.size() != 0) {
for (BluetoothDevice device : a2dpConnectedDevices) {
if (device.getName().contains("DEVICE_NAME")) {
deviceConnected = true;
}
}
}
if (!deviceConnected) {
Toast.makeText(getActivity(), "DEVICE NOT CONNECTED", Toast.LENGTH_SHORT).show();
}
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, btA2dp);
}
}
public void onServiceDisconnected(int profile) {
// TODO
}
};
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.A2DP);
You can do that for every bluetooth profile. Take a look at Working with profiles in Android's guide.
However, as written in other answers, you can register a BroadcastReceiver to listen to connection events (like when you're working on android < 3.0).
You cannot get the list of connected devices by calling any API.
You need instead to listen to the intents ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECTED that notifies about devices being connected or disconnected.
No way to get the initial list of connected devices.
I had this problem in my app and the way I handle it (didn't find better...) is to bounce off/on the Bluetooth at application start to be sure to start with an empty list of connected devices, and then listen to the above intents.
muslidrikk's answer is broadly correct; however you can alternatively use fetchUUIDsWithSDP() and see what you get back... it's a bit of a hack though -- you'd have to know what UUIDs (capabilities) you could expect from the device, if it were turned on. And that might be difficult to guarantee.
For BluetoothHeadset specifically, you can call getConnectedDevices() to get connected devices for this specific profile.
Reference: http://developer.android.com/reference/android/bluetooth/BluetoothHeadset.html
Other cases you need to register a receiver for that.
In your activity, define broadcast receiver...
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy