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:
ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, CHANGE_NETWORK_STATE, INTERNET
)Still, OnPeersAvailable is called with an empty collection for DeviceList.
The sequence of calls, in the debug window, turns out to be:
WifiP2pManager.Initialize
MainActivity.RegisterReceiver
WifiP2pManager.DiscoverPeers
WifiP2pManager.RequestPeers
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
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!