Friday, 29 October 2021

Xamarin.Android Not Receiving Location Updates in Direct Boot Mode

TLDR: is it possible to access location in Direct Boot mode?

I want to receive location updates for a device (testing on Pixel 3a) when the phone boots. This is a companion feature for a regular app, so assume required permission grants etc are taken care of.

The following code is also taken from components that work fine when invoked from a MainActivity.

The steps to set up the location callbacks are as follows:

Firstly, a DirectBootAware BroadcastReceiver that listens for ACTION_LOCKED_BOOT_COMPLETED means I can run code when the device boot and before the screen is unlocked.

[BroadcastReceiver(Enabled = true, Exported = true, DirectBootAware = true)]
[IntentFilter(new string[] { Intent.ActionLockedBootCompleted })]
public class StartForegroundServiceReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {

From here I can verify that the permissions for Corse and Fine location are granted (which they are!)

var permissionCheckResult = context.CheckSelfPermission(Manifest.Permission.AccessFineLocation);

Android.Util.Log.Info("TestingTag", $"AccessFineLocation CheckSelfPermission {permissionCheckResult.ToString()}");


permissionCheckResult = context.CheckSelfPermission(Manifest.Permission.LocationHardware);

Android.Util.Log.Info("TestingTag", $"LocationHardware CheckSelfPermission {permissionCheckResult.ToString()}");


permissionCheckResult = context.CheckSelfPermission(Manifest.Permission.AccessCoarseLocation);

Android.Util.Log.Info("TestingTag", $"AccessCoarseLocation CheckSelfPermission {permissionCheckResult.ToString()}");

and that the Network, GPS, and Passive Location Providers are enabled (again, they're all enabled!)

var locationManager = (LocationManager)context.GetSystemService(Context.LocationService);

var enabled = locationManager.IsProviderEnabled(LocationManager.PassiveProvider);
Log.Info("TestingTag", $"PassiveProvider IsProviderEnabled {(enabled ? "yes" : "no")}");

enabled = locationManager.IsProviderEnabled(LocationManager.GpsProvider);
Log.Info("TestingTag", $"GpsProvider IsProviderEnabled {(enabled ? "yes" : "no")}");

enabled = locationManager.IsProviderEnabled(LocationManager.NetworkProvider);
Log.Info("TestingTag", $"NetworkProvider IsProviderEnabled {(enabled ? "yes" : "no")}");

If I check GetLastKnownLocation

var location = locationManager.GetLastKnownLocation(LocationManager.GpsProvider);

if (location == null)
{
    location = locationManager.GetLastKnownLocation(LocationManager.NetworkProvider);
}

if (location == null)
{
    location = locationManager.GetLastKnownLocation(LocationManager.PassiveProvider);
}

if (location == null)
    Log.Error("TestingTag", $"Location is null");

This always returns null, perhaps because the device has just booted? Or maybe it's because of the same root cause as not receiving any location updates?

Finally, I register for location updates with the LocationManager

var callback = new LocationCallback();

Log.Info("TestingTag", "Starting RequestLocationUpdates via PassiveProvider..");
locationManager.RequestLocationUpdates(LocationManager.PassiveProvider, 3000, 3, callback);

Log.Info("TestingTag", "Starting RequestLocationUpdates via GpsProvider..");
locationManager.RequestLocationUpdates(LocationManager.GpsProvider, 3000, 3, callback);

Log.Info("TestingTag", "Starting RequestLocationUpdates via NetworkProvider..");
locationManager.RequestLocationUpdates(LocationManager.NetworkProvider, 3000, 3, callback);

Here's the location callback code:

public class LocationCallback : ScanCallback, Android.Locations.ILocationListener
{
    public void OnLocationChanged(Location location)
    {
        Log.Info("TestingTag", $"OnLocationChanged {location.Latitude} ~ {location.Longitude}");
    }

    public void OnProviderDisabled(string provider)
    {
        Log.Info("TestingTag", $"OnProviderDisabled {provider}");
    }

    public void OnProviderEnabled(string provider)
    {
        Log.Info("TestingTag", $"OnProviderEnabled {provider}");
    }

    public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
    {
        Log.Info("TestingTag", $"OnStatusChanged {provider} ~ {status.ToString()}");
    }
}

The callback is never invoked :-(

I've added a BluetoothManager to scan for BLE signals (omitted code for that) and that works, ScanResults are returned fine and the phone / BroadcastReceiver is still alive. So it's not as if the BroadcastReceiver is just dying...

Any tips / suggestions / or confirmation that what I'm trying to do is not possible would be greatly appreciated!

Thanks!



from Xamarin.Android Not Receiving Location Updates in Direct Boot Mode

No comments:

Post a Comment