Marcin Drobik

software journeyman notes

Scanning WiFi networks with Xamarin Android

For my WiFi Locator project I need an app to gather WiFi signal data in different locations. First step is to list IDs of all available networks. Finished app looks like this:

(Screen is updated every couple of seconds with latest data)

Xamarin

I decided to build it with Xamarin - It comes bundled with Visual Studio 2015 installer and has been recently made available to use with all Visual Studio licenses which makes it simple for me to start with.

Activity

First we need an activity that will be our app's starting point:

[Activity(Label = "Wifi Monitor", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        SetContentView(Resource.Layout.Wifi);

Network scanning is asynchronous, so to handle the results Android requires registered broadcast receiver. WifiMonitor is custom made class described later:

        RegisterReceiver(new WifiMonitor(this), new IntentFilter(WifiManager.ScanResultsAvailableAction));    
        ((WifiManager)GetSystemService(WifiService)).StartScan();
    }


    public void DisplayText(string text)
    {
        FindViewById<TextView>(Resource.Id.txtScanResults).Text = "Wifi networks: \r\n" + text;
    }
}

BroadcastReceiver

WifiMonitor will be called when network scan is completed and it's responsible for formating the result and passing it back to MainActivity:

public class WifiMonitor : BroadcastReceiver
{

Reminder: be careful when creating async void methods

    public override async void OnReceive(Context context, Intent intent)
    {
        var mainActivity = (MainActivity)context;

Scan results hold (among other data) identifiers and measured signal levels of available networks:

        var wifiManager = (WifiManager)mainActivity.GetSystemService(Context.WifiService);
        var message = string.Join("\r\n", wifiManager.ScanResults
            .Select(r => $"{r.Bssid} - {r.Level} dB"));

        mainActivity.DisplayText(message);

With use of .NET's async/await it's easy to reschedule another scan after some time:

        await Task.Delay(TimeSpan.FromSeconds(1));    
        wifiManager.StartScan();
    }
}

Layout

The layout is plain simple - it's just TextView used to display the message generated by the WifiMonitor. The only real adjustment I made is change the font to monospace and added small margin:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="25px"
    android:minHeight="25px">

  <TextView
      android:text="Scanning for networks..."
      android:textAppearance="?android:attr/textAppearanceMedium"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_margin="10dp"
      android:id="@+id/txtScanResults"
      android:typeface="monospace" />
</LinearLayout>

comments powered by Disqus