Search code examples
androidandroid-studiowifi-directservice-discoverywifip2p

WiFi Direct (P2P) for Service Discovery not responding to discoverService available listeners


I have been trying to create some simple WiFi Direct prototype apps and have been unable to get WiFi Direct (P2P) for Service Discovery working. (Android docs here: https://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct)

I started with a barebones Android Studio project based on the empty activity template. My target version of Android is 10 (level 29). I have tried several different arrangements of code similar to what is found on the above Android web page, which basically consist of the following basic parts:

<?xmlversion="1.0"encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
    <uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permissionandroid:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permissionandroid:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permissionandroid:name="android.permission.INTERNET"/>
    <uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permissionandroid:name="android.permission.NEARBY_WIFI_DEVICES"/>
    <uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"tools:ignore="CoarseFineLocation"/>
    
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.app_name"
        tools:targetApi="31">
        
        
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <actionandroid:name="android.intent.action.MAIN"/>
                
                <categoryandroid:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

private static final String SERVICE_NAME="WiFiD_DemoService";
private static final String SERVICE_TYPE="_presence._tcp";

private WifiP2pManager manager;
private WifiP2pManager.Channel channel;

@Override
protectedvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if(!initP2p()){
        finish();
    }

    if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M
        &&checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
        !=PackageManager.PERMISSION_GRANTED){
    requestPermissions(newString[]{Manifest.permission.ACCESS_FINE_LOCATION},
        MainActivity.PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION);
    }
}

privatebooleaninitP2p(){
    //Devicecapabilitydefinitioncheck
    if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)){
        Log.e(TAG,"Wi-FiDirectisnotsupportedbythisdevice.");
        returnfalse;
    }
    //Hardwarecapabilitycheck
    WifiManagerwifiManager=(WifiManager)getApplicationContext().getSystemService(WIFI_SERVICE);
    if(wifiManager==null){
        Log.e(TAG,"CannotgetWi-Fisystemservice.");
        returnfalse;
    }
    if(!wifiManager.isP2pSupported()){
        Log.e(TAG,"Wi-FiDirectisnotsupportedbythehardwareorWi-Fiisoff.");
        returnfalse;
    }
    manager=(WifiP2pManager)getApplicationContext().getSystemService(WIFI_P2P_SERVICE);
    if(manager==null){
        Log.e(TAG,"CannotgetWi-FiDirectsystemservice.");
        returnfalse;
    }
    channel=manager.initialize(this,getMainLooper(),null);
    if(channel==null){
        Log.e(TAG,"CannotinitializeWi-FiDirect.");
        returnfalse;
    }
    returntrue;
}


privatevoidstartRegistration(){
    //Createastringmapcontaininginformationaboutyourservice.
    Map<String,String>record=newHashMap<String,String>();
    record.put("listenport",String.valueOf(SERVER_PORT));
    record.put("buddyname","ExperienceHost"+(int)(Math.random()*1000));
    record.put("available","visible");

    //Serviceinformation.Passitaninstancename,servicetype
    //_protocol._transportlayer,andthemapcontaining
    //informationotherdeviceswillwantoncetheyconnecttothisone.
    WifiP2pDnsSdServiceInfoserviceInfo=WifiP2pDnsSdServiceInfo.newInstance(SERVICE_NAME,SERVICE_TYPE,record);

    //Addthelocalservice,sendingtheserviceinfo,networkchannel,
    //andlistenerthatwillbeusedtoindicatesuccessorfailureof
    //therequest.
    manager.addLocalService(channel,serviceInfo,newWifiP2pManager.ActionListener(){
        @Override
        publicvoidonSuccess(){
            //Commandsuccessful! Codeisn'tnecessarilyneededhere,
            //UnlessyouwanttoupdatetheUIoraddloggingstatements.
            outputLog("Service:"+SERVICE_NAME+"Started.");
        }

        @Override
        publicvoidonFailure(intarg0){
            //Commandfailed.CheckforP2P_UNSUPPORTED,ERROR,orBUSY
            outputLog("Warning,Service:"+SERVICE_NAME+"FailedtoStart.");
        }
    });
}


privatevoiddiscoverService(){

    manager.setDnsSdResponseListeners(channel,
        newWifiP2pManager.DnsSdServiceResponseListener(){
        
        @Override
        publicvoidonDnsSdServiceAvailable(StringinstanceName,StringregistrationType,WifiP2pDeviceresourceType){
        
            outputLog("Servicediscovered:"+instanceName);
        
            if(instanceName==SERVICE_NAME){
                //shouldconnecttoservice
                outputLog("JoiningService:"+instanceName);
            }
            Log.d(TAG,"onBonjourServiceAvailable"+instanceName);
        }
        },newWifiP2pManager.DnsSdTxtRecordListener(){
        
        /*Callbackincludes:
        *fullDomain:fulldomainname:e.g"printer._ipp._tcp.local."
        *record:TXTrecorddtaasamapofkey/valuepairs.
        *device:Thedevicerunningtheadvertisedservice.
        */
        @Override
        publicvoidonDnsSdTxtRecordAvailable(StringfullDomain,Map<String,String>record,WifiP2pDevicedevice){
            Log.d(TAG,"DnsSdTxtRecordavailable-"+record.toString());
            outputLog("Found service on device: " + device.deviceAddress + " with idenity of: "+ (String)record.get("buddyname"));
        }
    });

    serviceRequest=WifiP2pDnsSdServiceRequest.newInstance();
    manager.addServiceRequest(channel,serviceRequest,
        newWifiP2pManager.ActionListener(){
        
            @Override
            publicvoidonSuccess(){
                //Success!
                outputLog("ServiceRequestadded");
            }
        
            @Override
            publicvoidonFailure(intcode){
                //Commandfailed.CheckforP2P_UNSUPPORTED,ERROR,orBUSY
                outputLog("ServiceRequestaddfailed");
            }
    });

    manager.discoverServices(channel,
        newWifiP2pManager.ActionListener(){
    
        @Override
        publicvoidonSuccess(){
            //Success!
            outputLog("DiscoverServicesinitsucceeded");
        }
        
        @Override
        publicvoidonFailure(intcode){
            //Commandfailed.CheckforP2P_UNSUPPORTED,ERROR,orBUSY
            if(code==WifiP2pManager.P2P_UNSUPPORTED){
                Log.d(TAG,"Wi-FiDirectisn'tsupportedonthisdevice.");
            }
            outputLog("DiscoverServicesinitfailed"+code);
        }
    });
}

publicvoidonClickButHostService(Viewview){
    startRegistration();
}

publicvoidonClickButDiscoverService(Viewview){
    discoverService();
}

publicvoidoutputLog(Stringmsg){
    Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}

If I run the app on one device, and click the Host Service button, then deploy the app in debug mode on another device, and click the DiscoverService button, testing with break points shows the discovery service initializing successfully, but neither the onDnsSdServiceAvailable nor the onDnsSdTxtRecordAvailable listeners ever seem to fire. I have also used break points to confirm when clicking on the HostService that the addLocalService launches successfully.

I have not been able to find a current, and buildable sample project of a WiFi Direct P2P Service Discovery app anywhere, and therefore unable to walk through, and test a working sample.

Is there anyone that has been able to recently get this API to work who can shed some light or offer some pointers on why this code is not discovering and firing with the detection of WiFi Direct P2P Services registered on either the same app running on another device, or even 3rd party services from some of the many devices in the local area?

Is there something else, or more required to discover this type of service?


Solution

  • I don't see any glaring issues with your code as it is roughly what lies in the docs, but here is a sample from the Android repo that I have cloned into a Github repo here and verified is working as expected.