Why is discovering peers for Android Wi-Fi Direct so unreliable?
I've been recently developing an application with a connection system based on WiFi Direct (with WiFi P2P Service Discovery) and the one thing I can most certainly say is that the whole thing is a huge pain in the ... . Mostly because of the lack of documentation but also because when developing a wifi-direct-based solution you need to pay attention to basically everything (especially to all callbacks from listeners) before making any method call.
Two most annoying things were I guess:
An undocumented
UNKNOWN_ERROR
(I think itsint
code was-3
) that is being thrown inActionListener
onFailure
method. It seems to be some sort of issue with the wifi daemon itself. The only thing that seems to work to prevent it from happening is resetting WiFi before you even start messing around with WiFi direct.Something being in the wrong state for your method call - for example if
WIFI_P2P_STATE_CHANGED_ACTION
has not been received in your broadcast receiver with theWIFI_P2P_STATE_ENABLED
or if 'your_device' has not received a properstatus
in theWIFI_P2P_THIS_DEVICE_CHANGED_ACTION
. This usually results inonFailure
call in one of yourActionListener
s (with for exampleERROR
orBUSY
failure reason).
From my experience it's reliable. After tons of trying, I got the robust workable flow like this:
...
wifiP2pManager.clearLocalServices(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
HashMap<String, String> record = new HashMap<>();
record.put("name", "Amos");
WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(AppConfig.DNS_SD_SERVICE_NAME, AppConfig.DNS_SD_SERVICE_TYPE, record);
wifiP2pManager.addLocalService(wifiP2pChannel, serviceInfo, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.setDnsSdResponseListeners(wifiP2pChannel, WifiDirectFragment.this, WifiDirectFragment.this);
wifiP2pManager.clearServiceRequests(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.addServiceRequest(wifiP2pChannel, WifiP2pDnsSdServiceRequest.newInstance(), new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.discoverPeers(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.discoverServices(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// this is my recursive discovery approach
handler.postDelayed(discoveryRunnable, AppConfig.DNS_SD_SERVICE_DISCOVERABLE_DURATION_S * 1000);
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
I was able to "solve" the problems of some phones not appearing by requesting peer discovery every 10 seconds. I think I was running into this because one phone was always the host and I didn't bother to have it discover peers (because it doesn't try to join them), and the Wifi Direct was going to sleep on the host phone. I don't do anything with the peer results, but it wakes up the Wifi Direct system. There's probably a better method to call but I'm not sure what it is. If I had to guess I'd say I'm wasting some battery life.