androidxamarin.androidwifi-directgoogle-nearbywifip2p

WiFiP2PManager, OnPeersAvailable, DeviceList.Count zero - always


I've been struggling for days now with 2 Samsung S8 phones running a Xamarin test app, with the bear minimum of WiFiP2PManager code to discover peers. I've poured through community forums and documentation - it can't be this hard, there must be something I'm missing.

I've checked the common mistakes:

Still, OnPeersAvailable is called with an empty collection for DeviceList.

The sequence of calls, in the debug window, turns out to be:

  1. WifiP2pManager.Initialize
  2. MainActivity.RegisterReceiver
  3. WifiP2pManager.DiscoverPeers
  4. WifiP2pManager.RequestPeers
  5. OnPeersAvailable (DeviceList.Count == 0)

Here's my code, maybe you can see something?

using System;

using Android.App;
using Android.OS;
using Android.Support.V7.App;
using Android.Runtime;
using Android.Net.Wifi.P2p;
using Android.Content;
using static Android.Net.Wifi.P2p.WifiP2pManager;

namespace WiFiDirectTest
{
    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
    public class MainActivity : AppCompatActivity, IChannelListener, IPeerListListener
    {
        private WifiP2pManager manager;
        Channel channel;
        MyBroadcastReceiver receiver;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            SetContentView(Resource.Layout.activity_main);

            System.Diagnostics.Debug.WriteLine($"Wifi - initialize");
            manager = (WifiP2pManager)GetSystemService(WifiP2pService);
            channel = manager.Initialize(this, MainLooper, null);
        }


        protected override void OnResume()
        {
            base.OnResume();

            System.Diagnostics.Debug.WriteLine($"Wifi - register receiver");
            receiver = new MyBroadcastReceiver(manager, channel, this);
            receiver.Register(this);

            System.Diagnostics.Debug.WriteLine($"Wifi - discover peers");
            manager.DiscoverPeers(channel, new MyActionListner());
        }


        protected override void OnPause()
        {
            base.OnPause();

            System.Diagnostics.Debug.WriteLine($"Wifi - unregister receiver");
            receiver.Unregister(this);
            receiver = null;
        }

        public void OnPeersAvailable(WifiP2pDeviceList peers)
        {
            var count = peers.DeviceList.Count;
            System.Diagnostics.Debug.WriteLine($"Wifi - peers available: {count}");
        }

        public void OnChannelDisconnected()
        {
            System.Diagnostics.Debug.WriteLine("OnChannelDisconnected");
        }

        private class MyActionListner : Java.Lang.Object, WifiP2pManager.IActionListener
        {
            public MyActionListner()
            {
            }

            public void OnFailure(WifiP2pFailureReason reason)
            {
                // breakpoint placed here, never reached.
            }

            public void OnSuccess()
            {
            }
        }
    }


    public class MyBroadcastReceiver : BroadcastReceiver
    {
        WifiP2pManager manager;
        WifiP2pManager.Channel channel;
        MainActivity activity;

        public MyBroadcastReceiver(WifiP2pManager manager, Channel channel, MainActivity activity)
        {
            this.manager = manager;
            this.channel = channel;
            this.activity = activity;
        }

        public void Register(MainActivity context)
        {
            var intentFilter = new IntentFilter();

            intentFilter.AddAction(WifiP2pManager.WifiP2pStateChangedAction);
            intentFilter.AddAction(WifiP2pManager.WifiP2pPeersChangedAction);
            intentFilter.AddAction(WifiP2pManager.WifiP2pConnectionChangedAction);
            intentFilter.AddAction(WifiP2pManager.WifiP2pThisDeviceChangedAction);

            context.RegisterReceiver(this, intentFilter);
        }

        public void Unregister(MainActivity context)
        {
            context.UnregisterReceiver(this);
        }

        public override void OnReceive(Context context, Intent intent)
        {
            var action = intent.Action;

            if (WifiP2pManager.WifiP2pStateChangedAction.Equals(action))
            {
                 System.Diagnostics.Debug.WriteLine("WifiP2pStateChangedAction");
            }
            else if (WifiP2pManager.WifiP2pPeersChangedAction.Equals(action))
            {
                System.Diagnostics.Debug.WriteLine($"Wifi - request peers");
                manager.RequestPeers(channel, activity);
            }
            else if (WifiP2pManager.WifiP2pConnectionChangedAction.Equals(action))
            {
                System.Diagnostics.Debug.WriteLine("WifiP2pConnectionChangedAction");
            }
            else if (WifiP2pManager.WifiP2pThisDeviceChangedAction.Equals(action))
            {
                System.Diagnostics.Debug.WriteLine("WifiP2pThisDeviceChangedAction");
            }
        }
    }
}

Any ideas?

-John


Solution

  • SOLVED!

    Turns out the WiFiDirectSample I was using was built with an old API, prior to the new runtime permissions features in v6.0 (API 23). When I mimicked the WiFiP2PManager orchestration in my new app I was building for v9 (API 28).

    With that I needed to explicitly request permissions at runtime, despite them being listed in the Android Manifest. None of the documentation I read (over and over) mentioned to request permissions.

            string[] permissions = {
                Manifest.Permission.AccessFineLocation,
                Manifest.Permission.AccessCoarseLocation,
                Manifest.Permission.AccessWifiState,
                Manifest.Permission.ChangeWifiState,
                Manifest.Permission.Internet
            };
            RequestPermissions(permissions, 0);
    

    So I just added this code to my OnCreate() and I now get peers back in my OnPeersAvailable callback!