How to programmatically check connection state of a Bluetooth device in Android? - android

I can enumerate the paired Bluetooth devices, and I need to check their current connection state on app startup.
But, I found no way of getting the connection state ?!
Here are some efforts I've tried but failed:
android.bluetooth.BluetoothDevice
It has the method to get the bond state of the remote device, and possible values for the bond state are: BOND_NONE, BOND_BONDING, BOND_BONDED. But it's not the connection state.
android.bluetooth.BluetoothProfile
The method can be used to get the connection state, but the BluetoothProfile object must be obtained first.
public abstract int getConnectionState (BluetoothDevice device);
As describe in doc: "Clients should call getProfileProxy(Context, BluetoothProfile.ServiceListener, int), to get the Profile Proxy.", it can ONLY be retrieve in a ServiceListener called when state changes.
What if I query the state on startup without any state changes happen yet?
android.bluetooth.BluetoothManager
It provides a method:
public int getConnectionState (BluetoothDevice device, int profile);
But it cannot be used to detect connection state of a Bluetooth speaker, as the profile argument only accepts GATT or GATT_SERVER (for low energy device), other profiles (HEADSET, HEALTH, A2DP) are not supported.
android.bluetooth.BluetoothAdapter
It provides a method:
public int getProfileConnectionState (int profile);
This function can be used to check whether the local Bluetooth adapter is connected to any remote device for a specific profile. It can be used to check a specified profile. But it cannot be used to check a given device.
Does anyone know how to get the connection state of a given Bluetooth device?
Thanks in advance.

See the notes in the answer from similar question How to programmatically tell if a Bluetooth device is connected? (Android 2.2):
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 work around 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.

Related

how to make BLE autoconnect to Bluetooth of android phone without pairing

I am having a Arduino with BLE which has to send some data to any/all android phones over Bluetooth in it's range. My android phone should have a app which i intend to make will notify about data received.
How can i make such android app which auto-connects to any nearby BLE , if found without pairing even for first time and exchange data. I mean how in any application i can implement auto-connect without key pairing.I found that setting autoconnect=true will do this task , but i am not sure.
Any help, even some resource i will refer and clear my doubts.
The pre-requisites and steps are (code snippets in Java):
HC-XX module or similar BLE-device on the Arduino-side set to security mode 1 and security level 1 (no security AND no pairing)
Android 4.3 (API level 18) with built-in platform support for Bluetooth Low Energy (BLE)
Check on the device (mobile) that BLE is enabled
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Find the BLE device(s). You use the startLeScan() method. This method takes a BluetoothAdapter.LeScanCallback as a parameter. You must implement this callback, because that is how scan results are returned. Because scanning is battery-intensive, you should observe the following guidelines:
As soon as you find the desired device, stop scanning.
Never scan on a loop, and set a time limit on your scan. A device that was previously available may have moved out of range, and continuing to scan drains the battery.
If you want to scan for only specific types of peripherals, you can instead call startLeScan(UUID[], BluetoothAdapter.LeScanCallback), providing an array of UUID objects that specify the GATT services your app supports.
The first step in interacting with a BLE device is connecting to it— more specifically, connecting to the GATT server on the device. To connect to a GATT server on a BLE device, you use the connectGatt() method. This method takes three parameters: a Context object, autoConnect (boolean indicating whether to automatically connect to the BLE device as soon as it becomes available), and a reference to a BluetoothGattCallback.
// Here we set autoconnect to true
bluetoothGatt = device.connectGatt(this, true, gattCallback);
To sum up auto connect alone will not do the job as you want no pairing. So security mode 1 and security level 1 (no security at all) has to be set. So make sure by using software sided encryption/auto sign-in that no unauthorized persons use your device
Read more about BLE in Android in detail here
Read more about BLE security in detail here

BLE: Bonding initiated with already bonded device

I have two BLE devices configured to work as peripheral(s) with simple static pass pairing program and Android phone as client.
1) peripheral_1 address = 0xCECECECECE with static passkey 123456, Device name = Garden, appearance = generic tag.
2) peripheral_2 address = 0xC1C1C1C1C1 with static passkey 123456, Device name = Garden, appearance = generic tag.
Both peripherals IO configured as display only.
I try to connect to peripheral_1 through nrfConnect app, I get pop-up to feed passkey, after giving correct passkey the devices are bonded and all good.
repeated the same procedure with peripheral_2 and all good as well.
Now the real problem comes in. After disconnecting with peripheral_2, I tried to connect to peripheral_1, I get pop again to feed in passkey for already bonded device, why?
Also, after feeding in the passkey I can't read any of the characteristics values unless I disconnect and re-connect to peripheral_1. Why?
Now I repeat with peripheral_2 and I see the same behaviour(client asks to feed in passkey again).
I believe the STK/LTK should be uniquely generated based on the BT address and store in client's database.
Suppose if I change the appearance of one of the peripheral to "unknown" then I see the client does not ask for passkey to re-enter again after bonding. Only with this combination
appearance it works("unknown" vs "").
Any inputs, suggestions are greatly appreciated.

How to get Device name of your PEER using WifiP2P in Android

I am connecting two devices using wifi p2p from Android. I would like to know if there is any way for both devices to know the name of each other when the connection is established. When the device is starting the connection request, it is easy because you choose the peer from the list so you see the name. The question is focus to the device that receives the connection request!!!
I guess it has to be possible since the first time you try to connect you see a pop up with the name of the peer to accept the connection. But I don't know where this information can be found when programming an app.
I guess it has to be stored either in NetworkInfo (when you received a change of state) or in WifiP2pInfo (when the connection info is available).
When you receive the WIFI_P2P_CONNECTION_CHANGED_ACTION broadcast, if you are on API level 18 or higher, there is an extra in the intent, called EXTRA_WIFI_P2P_GROUP.
EXTRA_WIFI_P2P_GROUP
This returns a WifiP2pGroup on which you can call getClientList(). This gives you a collection of WifiP2pDevices. Once you have a WifiP2pDevice you can just get the field "deviceName".
Getting peer name is straight forward. Once you get the device list
public String getName(WifiP2pDevice device){
return device.deviceName;
}
Not sure if this is what you are asking for, pardon me if this is not the answer.
There is requestConnectionInfo method by this you can get all information about connected deivce simply implement this after connection is made like below
wifiManager.requestConnectionInfo(wifichannel, new WifiP2pManager.ConnectionInfoListener() {
#Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
//by info you can get host address and isGroupowner or else information you to
implement your code after this
}

How many devices can i connect with Wi-Fi P2P?

I need to connect 20+ android devices in a client-server network. Each client Android device will be communicating with the server Android device and vice versa. The client devices do not need to communicate with each other.
The server device would need access to internet for a brief period while connected to the clients.
My question is, can Wi-Fi P2P support that many connections reliably? And if yes, how do I go about implementing them?
Or will I have to ensure that all devices are on the same WLAN?
From experience, in a real-world deployment of an Android Wi-Fi Direct application, 20 devices should not be an issue.
Theoretically, the maximum number of devices in a Wi-Fi P2P group, where the GO is an Android device, is 254. The group owner is assigned the IP, 192.168.49.1. Clients are assigned an IP from the range, 192.168.49.2 to 192.168.49.254.
The group owner address is defined by the following in WifiP2pServiceImpl.java:
/* Is chosen as a unique address to avoid conflict with
the ranges defined in Tethering.java */
private static final String SERVER_ADDRESS = "192.168.49.1";
Determining the range for the clients is done as follows:
In WifiP2pServiceImpl.java, the startDhcpServer(String intf) method will start the DHCP server for a given interface - not a surprise. This method is called when the group has started and the device is the group owner.
Taking a closer look at this code, we can see that on the InterfaceConfiguration object, the link address is set to 192.168.49.1 and the prefix length is 24 (prefix length is the number of bits set in a subnet mask, here equivalent to 255.255.255.0) - this implies the answer, but we can dig a little further.
ifcg = mNwService.getInterfaceConfig(intf);
ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
SERVER_ADDRESS), 24));
ifcg.setInterfaceUp();
mNwService.setInterfaceConfig(intf, ifcg);
Next, the following commands will restart tethering with the DHCP range specified by the String[], tetheringDhcpRanges. The calls of mNwService (Network Management Service) methods will execute the appropriate netd commands.
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges();
if (mNwService.isTetheringStarted()) {
if (DBG) logd("Stop existing tethering and restart it");
mNwService.stopTethering();
}
mNwService.tetherInterface(intf);
mNwService.startTethering(tetheringDhcpRanges);
And cm.getTetheredDhcpRanges() is ultimately a reference to the following (ConnectivityManager.getTetheredDhcpRanges() -> ConnectivityService.getTetheredDhcpRanges() -> Tethering.getTetheredDhcpRanges()):
// USB is 192.168.42.1 and 255.255.255.0
// Wifi is 192.168.43.1 and 255.255.255.0
// BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
// with 255.255.255.0
// P2P is 192.168.49.1 and 255.255.255.0
private String[] mDhcpRange;
private static final String[] DHCP_DEFAULT_RANGE = {
"192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
"192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
"192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
"192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
}
and:
mDhcpRange = context.getResources().getStringArray(
com.android.internal.R.array.config_tether_dhcp_range);
if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
mDhcpRange = DHCP_DEFAULT_RANGE;
}
in com.android.server.connectivity.Tethering.
Of course, it is possible for the device manufacturer to change this code, so this is also worth considering.
For those planning to deploy applications where there will be many users, a mechanism to allow a more than one device to be GO is required. If data needs to be synchronised between devices, it is simple to simulate "churn" and have GOs only be a GO for a time period before becoming a client to another GO and synchronising any data.
The max number as far as I know is not specified, so you would need to test that out to be certain. Also there could be differences between hardware.
Anyway, the basic implementation would be rather simple. The server would call GreateGroup, so it would be the Groupowner in all cases. And then start locals service advertising. Clients then would simply look for the advertisement and once they see it, they would start connection process to the server. One the server connection is made over Wifi direct you would simply start socket communications from the client to the server (server would have listening socket on all times).
Note that connection would require user to click on the dialog showed when client tries to connect to the group owner. And if you want to get rid of this. Then you could actually use the Accesspoint created by GreateGroup, and add the access point name as well as the password to the advertising. Then your clients could actually use the accesspoint to connect (like to any Wlan accesspoint)
Note though that the Wifi Direct way, would not interfere with Wifi connections, not would it require it. But the accesspoint way would mean that any existing Wifi connection from the client would be disconnected, and the device thinks that the connection made to the server would provide normal internet connectivity.
Remember that devices don't need to be connected to a network to connect to each other. Wi-Fi Direct allows them to connect directly.
Here is a list of Wi-Fi Direct resources that you may find useful: https://groups.google.com/forum/#!topic/wi-fi-direct/uWpuOzHY6y0
I'd recommend following Android's Service Discovery Demo and try implementing it yourself. And here is the source code for the demo.

get bluetooth device leave the connection

I have a bluetooth device , I want to know how to obtain the method when connected Bluetooth device is out of range
like code
//if bluetooth is Not in the range of connection
{
}
Please give me some solution
To check whether a bluetooth device is connected or not you can use intent filters to listen to the ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECT_REQUESTED, and ACTION_ACL_DISCONNECTED broadcasts. For more details please check this post How to programmatically tell if a Bluetooth device is connected? (Android 2.2)
There is no internal method like DeviceNotInRange() {} hence you need to work it out by creating your customized method. You need to create a method that keep searching on a regular interval and when device is not in range, you can raise an Alert or sound for intimation.

Categories

Resources