Bluetooth socket connection - android

How can i know if a BluetoothSocket is still connected to the endpoint? How can i detect if the socket has been disconnected by the endpoint?
Thanks

In my apps, I keep track of I/O errors. If a successful read() takes place, then I reset the counters. If the error counters go up high enough (4-5 is usually a good number) then I consider the connection dead, and proceed to tear it down and re-build it.
The SDK talks about a state change intent, but I'm not clear whether it's referring to a specific connection, or the bluetooth adapter itself here:
Optionally, your application can also
listen for the ACTION_STATE_CHANGED
broadcast Intent, which the system
will broadcast whenever the Bluetooth
state has changed. This broadcast
contains the extra fields EXTRA_STATE
and EXTRA_PREVIOUS_STATE, containing
the new and old Bluetooth states,
respectively. Possible values for
these extra fields are
STATE_TURNING_ON, STATE_ON,
STATE_TURNING_OFF, and STATE_OFF.
Listening for this broadcast can be
useful to detect changes made to the
Bluetooth state while your app is
running.

Related

Ble device is not pairing consistently to phone

I have a ble device that I need to regularly extract data from securely and constantly. So on startup I want to make sure to bond the device if it is not already. I have the Mac address of the device in this case.
public void startApp(){
remoteDevice = bluetoothManager.getAdapter().getRemoteDevice(MAC_AD);
if(remoteDevice.getBondState()!=12){
remoteDevice.createBond();
}
}
What ends up happening is that the bond state will alternate between unbonded and currently_bonding but not fully bond.
The strange thing is that sometimes it will work, but usually not, particularly on my google pixel. Bonding through the settings is also very inconsistent.
Is there any way to retry this or some kind of Bluetooth reset that should be done so that I can bond consistently?
I've tried calling createBond() in intervals;
I've often found that calling createBond() directly can have hit-and-miss results depending on the platform (both ends). Logically it should use the same mechanism internally, but I've tended to get better results by calling read on a simple characteristic which has bonded requirements.
It either successes - meaning your connection is bonded - and you can continue. Or it fails, which internally triggers the bonding, and then you can try again after a short delay, at which point it should now be bonded.

What is causing multicast messages not to flow immediately after wifi restart

I have an Android app that creates a MulticastSocket, joins a MC group and receives messages from another machine on the local wifi network.
MulticastSocket socket = new MulticastSocket(null); // Create an unbound socket.
socket.setSoTimeout(LISTEN_TIMEOUT_MILLIS);
socket.setReuseAddress(true);
socket.bind(new InetSocketAddress(listenPort)); // Bind to the configured multicast port
final WifiManager.MulticastLock lock = wifiManager.createMulticastLock("my_lock");
lock.acquire();
socket.setNetworkInterface(networkInterface);
socket.joinGroup(multicastGroup);
while (true) {
socket.receive(packet);
// Do something with the packet
// Handle timeout etc.
// Handle change of network interface by leaving group, setting netIntf and joining group again.
}
socket.leaveGroup(multicastGroup);
socket.close();
lock.release();
Works well on most Android devices (Huawei, Samsung), but on some (Pixel3), if the WiFi on the device is switched off and then back on again, while the app sees the Wifi connection come live, it can take up to 14 mins (it is extremely variable) before the MC messages start being received again.
Even throwing away the Socket and creating a fresh MCSocket doesn't alleviate the delay.
But it has to be some state that is held within the JVM, because a restart of the app causes it to connect immediately.
It feels like there is some lease that is being held for the MC connection that is only being renewed on a clock cycle.
So my questions are:
What is causing the MC messages to not flow immediately after the
WiFi connection comes back up and a new MCSocket is created to
listen to it.
What can I do to ensure timely resumption of the message flow?
I notice you've updated your question to include WifiManager.MulticastLock
I wonder if you are you reacquiring the lock when the Wifi connection comes back, some posts here on SO imply this is necessary.
I note the comment on the following post:
Re: https://stackoverflow.com/a/4002084/1015289
it turns out that your multicast lock is destroyed when the connectivity goes away (the long delay was me rewriting my code three times before I figured this out). So, you have to reacquire the lock every time the connection comes back

How to find Wifip2p groups in android

I'm trying to use WiFi-Direct for connecting multiple devices over wifi in a master-slave style (one to many)- one client creates a group using the "createGroup" function, and all the other clients should connect to the group (manually).
when a client press on a "Discover peers" button, i want to give him a list of all the master peers.
And here is the problem- I can't find a way to differentiate between slave peers and the master peer (the one who initiate the createGroup request).
is there any way to filter out all the slave peers and keep only the master peers?
You should be discovering services rather than peers, though the API does work better if you also do peer discovery, thus here's my proposal for your logic:
With slave:
Start peerDiscovery
When you get Peers changed event, start service discovery (for service_type defined by your master)
Add the discovered services into a selection list as they come (note that they come one by one, and I've seen max 5 seconds between discovered services)
With Master
createGroup
Add local service to advertise that you are the master
Start Peer discovery, and make sure by monitoring the Discovery state changes that it stays on (if it goes off, your service advertisement likely will not be seen by the slaves)
A simple way to achieve this is to do the following: You can set which device to be Group Owner (Master device) by setting the groupOwnerIntent to 15.
WifiP2pConfig config = new WifiP2pConfig();
config.groupOwnerIntent = 15; //Value between 0-15
You also need to change the master's device name to something like "Master"+itsCurrentName. (To change the WiFi Direct device name, check my answer on how to set interface device name of wifi direct)
Now, whenever a new device scans for peers, the results will show which devices are GroupOwners from their name that starts with the word "Master".
This is a simple way to filter out master from slave peers.

How can I avoid or dismiss Android's Bluetooth pairing notification when I am doing programmatic pairing?

I have an app where I am programmatically controlling Bluetooth pairing and unpairing. I can pair before connection and unpair afterwards. The reason I need to do this is specific to my application and not in the scope of my question.
Basically what I am doing is:
Get a reference ib to IBluetooth object as described in this answer
Register a BroadcastReceiver for android.bluetooth.device.action.PAIRING_REQUEST
Call ib.createBond(address)
Wait for BroadcastReceiver to trigger
Convert user pin into bytes with convertPinToBytes()
Call ib.setPin(address, pinBytes) from within BroadcastReceiver
Anyways, this approach works great, except for the fact that when I do the pairing, I get a notification in the Status bar requesting that the user enter a PIN to complete the pairing. But this is in fact unnecessary, because by the time the user sees this, my app has already used setPin(). I'd really like for that notification to either a) not appear at all, or b) be dismissed automatically somehow.
I realize this may not even be possible, but I thought I would ask in case someone has a creative idea.
Try setting the confirmation first in the PAIRING_REQUEST
BluetoothDevice device = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
device.getClass().getMethod("cancelPairingUserInput").invoke(device);
This worked for me between two Android devices using RFCOMM but I'm not entering any PINs
Since Android API 19 Google switched these Methods to public Methods, so there is no need for Reflection any more. :)
Do this in the PAIRING_REQUEST notification event:
BluetoothDevice localBluetoothDevice = (BluetoothDevice)intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
Class localClass = localBluetoothDevice.getClass();
Class[] arrayOfClass = new Class[0];
localClass.getMethod("cancelPairingUserInput", arrayOfClass).invoke(paramBluetoothDevice, null)).booleanValue();
But you gotta tell me how did you pair your remote device without the user to enter Passkey/PIN? off course, you know the PIN for the remote device which is trying to pair to your device but how did you provide that PIN to the remote device.

Android bluetooth: how to poll for connections/disconnections

I need to continuously poll for getting bluetooth devices connections/disconnections in my activity to update a listView with the currenctly available devices.
I use btAdapter.startDiscovery() but it is not permanent ... how can i correctly get the on/off events for the devices?
I would suggest using a broadcastreceiver to listen for the specific events you are talking about. You could even fire off another discovery mode after it comes out of its current discovery mode to have it keep scanning
BluetoothAdapter.ACTION_DISCOVERY_FINISHED
BluetoothDevice.ACTION_ACL_CONNECTED
BluetoothDevice.ACTION_ACL_DISCONNECTED
You can use the intent extra's to be able to get the name (ect) from the device that connects
I would read http://developer.android.com/guide/topics/wireless/bluetooth.html and
http://developer.android.com/reference/android/content/BroadcastReceiver.html

Categories

Resources