I've been trying to discover multiple peers - multiple times in a background service instead of an activity. Broadly based on this: http://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct.html
Since, an advertised service of a peer once received doesn't reappear if that peer goes away and comes back in range. The reason why I need to re-discover the same peers is I'm changing the TXT record value depending on the app usage. Which needs to be re-advertised and the receiving device updates a local file with the new values.
Even though, I've managed to get this to work in a kind of an unreliable manner. By, removing the localservice and serviceRequest and re-initiate the registration and discovery by using a handler.
But, what I've noticed is some of the earlier advertisements are pooled and keep showing even when the advertising device has stopped advertising, and the TXT Listeners do not attach and at times. Which causes a WifiP2pManager ignored warning while adding both the local service as well as the service discovery request. Hence, the listener doesn't get the advertisement at times, while keeps getting advertisements at times when even Wifi is disabled.
01-06 17:14:34.324 26591-26591/com.cutting.chai.wifi D/WifiP2pManager﹕ Ignored { when=-25ms what=139313 target=android.net.wifi.p2p.WifiP2pManager$Channel$P2pHandler }
[ 01-06 17:14:34.324 26591:26591 D/Status] Added Local Service
01-06 17:14:34.324 26591-26591/com.cutting.chai.wifi D/WifiP2pManager﹕ Ignored { when=-25ms what=139313 target=android.net.wifi.p2p.WifiP2pManager$Channel$P2pHandler }
01-06 17:14:34.324 26591-26591/com.cutting.chai.wifi D/WifiP2pManager﹕ Ignored { when=-26ms what=139313 target=android.net.wifi.p2p.WifiP2pManager$Channel$P2pHandler }
[ 01-06 17:14:34.324 26591:26591 D/Status] Added service discovery request
And below is my code:
public class WifiDirectDiscoverService extends Service{
public static final String TAG = "wifidirectservicedemo";
// TXT RECORD properties
public static final String TXTRECORD_PROP_AVAILABLE = "available";
public static final String SERVICE_INSTANCE = "_ccwifidirect";
public static final String SERVICE_REG_TYPE = "_presence._tcp";
private WifiP2pManager manager;
private final IntentFilter intentFilter = new IntentFilter();
private WifiP2pManager.Channel channel;
private BroadcastReceiver mReceiver;
private WifiP2pDnsSdServiceRequest serviceRequest;
WifiP2pDnsSdServiceInfo service;
/* Preferences to get user data to set the advertisement record */
private ccSharedPreferences sharedPreferences;
private String[] interestCodes;
private String[] hobbyCodes;
Handler mHandler = new Handler();
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public void onCreate() {
super.onCreate();
Log.d("Server", ">>>onCreate()");
}
final Runnable ToastRunnable = new Runnable(){
public void run(){
Toast.makeText(getApplicationContext(), "discover service",
Toast.LENGTH_LONG).show();
manager.removeLocalService(channel, service, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess () {
appendStatus("Remove Local Service");
}
@Override
public void onFailure ( int error){
appendStatus("Failed to remove a service "+error);
}
});
manager.removeServiceRequest(channel, serviceRequest, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
appendStatus("Clear Service Requests");
}
@Override
public void onFailure(int error) {
appendStatus("Failed to clear Service Requests "+error);
}
});
startRegistration();
setupListener();
initiateDiscovery();
mHandler.postDelayed(ToastRunnable, 15000);
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, startId, startId);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(getApplicationContext(), getMainLooper(), null);
mReceiver = new WiFiDirectBroadcastReceiver(manager, channel, WifiDirectDiscoverService.this);
registerReceiver(mReceiver, intentFilter);
startRegistration();
setupListener();
initiateDiscovery();
mHandler.postDelayed(ToastRunnable, 10000);
return START_STICKY;
}
/**
* Registers a local service and then initiates a service discovery
*/
private void startRegistration() {
sharedPreferences = new ccSharedPreferences();
Map<String, String> record = new HashMap<>();
record.put(TXTRECORD_PROP_AVAILABLE, "visible");
int size = record.toString().length();
Toast.makeText(getApplicationContext(), size + " bytes record ", Toast.LENGTH_LONG).show();
service = WifiP2pDnsSdServiceInfo.newInstance(
SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
manager.addLocalService(channel, service, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
appendStatus("Added Local Service");
}
@Override
public void onFailure(int error) {
appendStatus("Failed to add a service "+error);
}
});
}
private void setupListener() {
/*
* Register listeners for DNS-SD services. These are callbacks invoked
* by the system when a service is actually discovered.
*/
WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {
/**
* A new TXT record is available. Pick up the advertised
* buddy name.
*/
@Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
if (record.get(TXTRECORD_PROP_AVAILABLE) != null) {
Log.d(TAG,
device.deviceName + " is "
+ record.get(TXTRECORD_PROP_AVAILABLE));
Toast.makeText(getApplicationContext(), device.deviceName + " is " + record.get(TXTRECORD_PROP_AVAILABLE), Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "Advertised Service is " + record.toString(), Toast.LENGTH_LONG).show();
Log.d("Record", record.toString());
}
}
};
WifiP2pManager.DnsSdServiceResponseListener servListener = new WifiP2pManager.DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// A service has been discovered. Is this our app?
if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
// update the UI and add the item the discovered
// device.
WiFiP2pService service = new WiFiP2pService();
service.device = srcDevice;
service.instanceName = instanceName;
service.serviceRegistrationType = registrationType;
Log.d(TAG, "onBonjourServiceAvailable "
+ instanceName);
Toast.makeText(getApplicationContext(), service.device + " is around ", Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), instanceName + " is the instance name ", Toast.LENGTH_LONG).show();
}
}
};
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
}
public void initiateDiscovery(){
// After attaching listeners, create a service request and initiate
// discovery.
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
appendStatus("Added service discovery request");
}
@Override
public void onFailure(int arg0) {
appendStatus("Failed adding service discovery request "+arg0);
}
});
manager.discoverServices(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
appendStatus("Service discovery initiated");
}
@Override
public void onFailure(int arg0) {
appendStatus("Service discovery failed "+arg0);
}
});
}
public void appendStatus(String status) {
Log.d("Status" + "\n", status);
}
@Override
public void onDestroy() {
Toast.makeText(this, "service onDestroy", Toast.LENGTH_LONG).show();
mHandler.removeCallbacksAndMessages(null);
}
}
I've also read this: Sending data in Android WiFi Direct service discovery instead of connecting
While, I understand the unreliability of using multicast-DNS discovery is essentially meant for service discovery and not messaging scenarios. In my case, the record value doesn't change very often. But, I need to ensure the advertisement and discovery and multiple peers happens without an erratic behavior as described.
Any assistance with this is much appreciated!
Thanks!
Arnab