This is how you get Discrete BACKGROUND Location in Android 9.0 BUT Android 10.0 returns "NoGPS"

GolfMan 21 Reputation points
2021-01-01T09:30:26.527+00:00
    async Task<string> Loop()
    {
        Location LowLoc = null;

        try
        {
            //await Geolocation.GetLastKnownLocationAsync();
            GeoRequest = new GeolocationRequest(GeolocationAccuracy.High);
            for (int i = 0; i < 5; i++)
            {
                Location Loc = null;
                CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(KGPSTimeout));
                Loc = await Geolocation.GetLocationAsync(GeoRequest, cts.Token);
                if (Loc == null) { continue; }

                if (LowLoc == null) { LowLoc = Loc; }
                else
                {
                    if (Loc.Accuracy < LowLoc.Accuracy) { LowLoc = Loc; }
                    if (LowLoc.Accuracy < 10) { break; }
                }
            }
            GeoRequest = null;

            if (LowLoc != null)
            {
                var s = await CreateMomCookies(LowLoc);
                return s;
            }
            else { return "NoGPS"; }
        }
        catch { return "NoGPS"; }
    }

    async Task<String> CreateMomCookies(Location pos)
    {
        string acc, alt;

        var percentage = Battery.ChargeLevel * 100;

        try { acc = pos.Accuracy?.ToString("0"); }
        catch { acc = "1000"; }

        try { alt = (pos.Altitude * 3.2808399)?.ToString("0"); }
        catch { alt = "N/A"; }

        var s = pos.Latitude.ToString("0.000000") + "," +
            pos.Longitude.ToString("0.000000") + "," +
            pos.Timestamp.ToLocalTime().ToString("hh:mm:ss tt") + "," +
            acc + "," + alt + "," + percentage.ToString("0") + ",MomData";
        await Task.Delay(1);
        return s;
    }
Developer technologies | .NET | Xamarin
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. Anonymous
    2021-01-04T07:07:13.51+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    You can try to use foreground service to get the location. And add location permission.

       <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />  
    
    
    
    
       [assembly: Xamarin.Forms.Dependency(typeof(DependentService))]  
       namespace XamarinA10ForegroundService.Droid  
       {  
           [Service]  
           public class DependentService : Service, IService  
           {  
               public void Start()  
               {  
                   var intent = new Intent(Android.App.Application.Context,  
            typeof(DependentService));  
         
         
                   if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)  
                   {  
                       Android.App.Application.Context.StartForegroundService(intent);  
                   }  
                   else  
                   {  
                       Android.App.Application.Context.StartService(intent);  
                   }  
               }  
         
               public override IBinder OnBind(Intent intent)  
               {  
                   return null;  
               }  
               public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;  
               public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)  
               {  
                   // From shared code or in your PCL  
         
                   CreateNotificationChannel();  
                   string messageBody = "service starting";  
         
                   var notification = new Notification.Builder(this, "10111")  
                   .SetContentTitle("Foreground")  
                   .SetContentText(messageBody)  
                   .SetSmallIcon(Resource.Drawable.main)  
                   .SetOngoing(true)  
                   .Build();  
                   StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);  
         
         
                   MessagingCenter.Subscribe<MainPage, string>(this, "MapIntentReceived", (sender, arg) => {  
                       Toast.MakeText(Android.App.Application.Context, arg, ToastLength.Short).Show();  
         
                       // await SearchForRooms(arg);  
                   });  
         
                   Loop();  
         
         
                   //do you work  
                   return StartCommandResult.Sticky;  
               }  
         
               async Task<string> Loop()  
               {  
                   int KGPSTimeout = 5;  
                   Location LowLoc = null;  
                   try  
                   {  
                       //await Geolocation.GetLastKnownLocationAsync();  
                     var  GeoRequest = new GeolocationRequest(GeolocationAccuracy.High);  
                       for (int i = 0; i < 5; i++)  
                       {  
                           Location Loc = null;  
                           CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(KGPSTimeout));  
                           Loc = await Geolocation.GetLocationAsync(GeoRequest, cts.Token);  
                           if (Loc == null) { continue; }  
                           if (LowLoc == null) { LowLoc = Loc; }  
         
                           
                           else  
                           {  
                               if (Loc.Accuracy < LowLoc.Accuracy) { LowLoc = Loc; }  
                               if (LowLoc.Accuracy < 10) { break; }  
                           }  
         
                           Console.WriteLine("================" + Loc.Latitude + "=================");  
                       }  
                       GeoRequest = null;  
                       if (LowLoc != null)  
                       {  
                           var s = await CreateMomCookies(LowLoc);  
                           return s;  
                       }  
                       else { return "NoGPS"; }  
                   }  
                   catch { return "NoGPS"; }  
               }  
               async Task<String> CreateMomCookies(Location pos)  
               {  
                   string acc, alt;  
                   var percentage = Battery.ChargeLevel * 100;  
                   try { acc = pos.Accuracy?.ToString("0"); }  
                   catch { acc = "1000"; }  
                   try { alt = (pos.Altitude * 3.2808399)?.ToString("0"); }  
                   catch { alt = "N/A"; }  
                   var s = pos.Latitude.ToString("0.000000") + "," +  
                       pos.Longitude.ToString("0.000000") + "," +  
                       pos.Timestamp.ToLocalTime().ToString("hh:mm:ss tt") + "," +  
                       acc + "," + alt + "," + percentage.ToString("0") + ",MomData";  
                   await Task.Delay(1);  
                 //  Toast.MakeText(Android.App.Application.Context, s, ToastLength.Short).Show();  
                   Console.WriteLine("================"+ s + "=================");  
                   return s;  
               }  
               void CreateNotificationChannel()  
               {  
                   if (Build.VERSION.SdkInt < BuildVersionCodes.O)  
                   {  
                       // Notification channels are new in API 26 (and not a part of the  
                       // support library). There is no need to create a notification  
                       // channel on older versions of Android.  
                       return;  
                   }  
         
                   var channelName = Resources.GetString(Resource.String.channel_name);  
                   var channelDescription = GetString(Resource.String.channel_description);  
                   var channel = new NotificationChannel("10111", channelName, NotificationImportance.Default)  
                   {  
                       Description = channelDescription  
                   };  
         
                   var notificationManager = (NotificationManager)GetSystemService(NotificationService);  
                   notificationManager.CreateNotificationChannel(channel);  
               }  
           }  
       }  
    

    Best Regards,

    Leon Lu


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

  2. Alessandro Caliaro 4,196 Reputation points
    2021-01-01T12:05:59.847+00:00

    On Android 10 (API level 29) and higher, you must declare the ACCESS_BACKGROUND_LOCATION permission in your app's manifest in order to request background location access at runtime. On earlier versions of Android, when your app receives foreground location access, it automatically receives background location access as well.

    https://developer.android.com/training/location/permissions


  3. GolfMan 21 Reputation points
    2021-01-06T05:08:01.653+00:00

    EXCEEDINGLY BRILLIANT solution!!!...complexity however requires clarification because my SMS services are not quite setup the way you have proposed

    To implement, I added Interface

    namespace SendAndReceiveSMS.Interfaces
    {
    public interface ILocationService
    {
    Task<string> Loop();
    }
    }

    then I added a class in Droid and added modified Service...I replaced your Start with OnCreate

    [Service]
    public class LocationService : Service, ILocationService
    {
    //public void Start()
    public override void OnCreate()
    {
    var intent = new Intent(Android.App.Application.Context, typeof(LocationService));
    if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
    {
    Android.App.Application.Context.StartForegroundService(intent);
    }
    else
    {
    Android.App.Application.Context.StartService(intent);
    }
    }

    rest of your service is the same

    then in my MainActivity under OnRequestPermissionsResult I implemented

                   Intent intent = new Intent(this, typeof(LocationService));
                    this.StartForegroundService(intent);
    

    finally I Call the Loop() from

                    var MomCookie = await Xamarin.Forms.DependencyService.Get<ILocationService>().Loop();
    

    So needles to say that I took your BRILLIANT solution into a hodge podege of nonsense.

    I have looked up the Service in sample LocationUpdateForegroundService which is setup differently then my SMS services also.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.