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.
Related
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.
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.
I want to require entering a PIN when connecting two Android devices to ensure they are talking to each other.
There is a sample project in the Android SDK 17 called "WiFiDirectDemo". It establishes a Wi-Fi Direct connection but it lacks the PIN authentication.
I don't know how to specify WiFiP2pConfig.wps.setup in the class DeviceDetailFragment around line 71. Do I specify the action on the current device (I want to show a auto-generated four-digit PIN), i. e. config.wps.setup = WPSInfo.DISPLAY, or should I specify the action on the peer, i. e. config.wps.setup = WPSInfo.KEYPAD?
How can I detect the connection request on the other peer? I guess there is something I can listen to, e. g. in the BroadcastReceiver, but I cannot find it.
I'm an experienced iOS developer but Android is very new to me, maybe the the answer is obvious to you. Thanks for your help.
you need to specify the action on the device which sends the connect request ... and for pin i think this should work
p2pconfig.wps.setup = WpsInfo.DISPLAY;
p2pconfig.wps.pin = "0000";
On connect, PIN is displayed on local device and requests user to enter same PIN on remote device; once PIN is entered, connect completes successfully.
Check this https://groups.google.com/forum/#!topic/android-platform/hN5WfXRzXpI read the 5th post
p2pconfig.wps.setup=WpsInfo.KEYPAD(don't specify p2pconfig.wps.pin) works fine for me.It displays a dynamically generated key on the device from which we are trying to connect to be entered on the other device.
In this case you don't need to listen on any b'cast receiver to detect the connection.The wpa_supplicant takes care of it and prompts you to enter the pin.For a clear picture, look at the logcat(I use adb from ADT(sdk+eclipse) to see the logcat) of wpa_supplicant while connection is in progress.
Need to discover or search for Bluetooth devices of certain "vendor-specific" devices.
"vendor-specific" means all devices will have similar starting bits in their "MAC" address
For example, I want to search only for devices whose MAC address starts with 12:34:56:
It should search only for specific series of MAC addresses and list them.
Perform a full discovery, then filter using BluetoothDevice.getAddress()
// Define Vendor ID Prefix
public static final String VENDOR_ID = "12:34:56:"
// First, do a full discovery...
BluetoothAdapter.getDefaultAdapter().startDiscovery()
//...
// Then, for each device returned from discovery...
if ( device.getAddress().startsWith(VENDOR_ID) ) {
// Do Something
}
My Explanation will be based on the BluetoothChat example from the Android SDK, hopefully this is ok, otherwise I would need to write a lot more. If you haven't seen the BluetoothChat example, go take a look, it's really nice!
If you want to use a device where you don't know the complete adress, you'll have to do a complete discovery with BluetoothAdapter.startDiscovery() and search the received addresses for the ones you want to.
If you know the complete address of the device you want to connect to you can directly connect to this device with BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address)
My android application is in blueotooth SPP server mode and listening for client devices,
my application knows the passcode required for pairing of that devices.
My question is,
Is it possible to handle pairing request through application.
Thanks and Regards.
No - because from a security point of view it is important for the user to be aware of pairing. The idea is that devices are paired and bonded once, then onwards connections happen automatically initiated by applications without need for re-pairing (or user intervention)
Yes, it is possible to do pairing through application. I did pairing in my application.
for this you have to made IBluetooth interface object accessible by this way:
IBluetooth mBluetoothService;
Field fie = Class.forName(bluetoothAdapter.getClass().getName()).getDeclaredField("mService");
fie.setAccessible(true);
mBluetoothService = (IBluetooth) fie.get(bluetoothAdapter);
By using this object you can pair with device using IBluetooth interface functions.
(normal Sequence for Auto Pairing)::
mBluetoothService.setPin(deviceAddress, PIN);
mBluetoothService.setTrust(deviceAddress);
mBluetoothService.createBond(deviceAddress);
mBluetoothService.setPairingConfirmation(deviceAddress, false);
mBluetoothService.cancelPairingUserInput(deviceAddress);
By using those function you can pair with any BT device programmatically.