Пример #1
0
        static async Task <FileResult> PlatformMediaAsync(MediaPickerOptions options, bool photo)
        {
            Permissions.EnsureDeclared <Permissions.LaunchApp>();

            await Permissions.EnsureGrantedAsync <Permissions.StorageRead>();

            var tcs = new TaskCompletionSource <FileResult>();

            var appControl = new AppControl();

            appControl.Operation  = photo ? AppControlOperations.ImageCapture : AppControlOperations.VideoCapture;
            appControl.LaunchMode = AppControlLaunchMode.Group;

            var appId = AppControl.GetMatchedApplicationIds(appControl)?.FirstOrDefault();

            if (!string.IsNullOrEmpty(appId))
            {
                appControl.ApplicationId = appId;
            }

            AppControl.SendLaunchRequest(appControl, (request, reply, result) =>
            {
                if (result == AppControlReplyResult.Succeeded && reply.ExtraData.Count() > 0)
                {
                    var file = reply.ExtraData.Get <IEnumerable <string> >(AppControlData.Selected)?.FirstOrDefault();
                    tcs.TrySetResult(new FileResult(file));
                }
                else
                {
                    tcs.TrySetCanceled();
                }
            });

            return(await tcs.Task);
        }
Пример #2
0
        static async Task <IEnumerable <FilePickerResult> > PlatformPickAsync(PickOptions options, bool allowMultiple = false)
        {
            Permissions.EnsureDeclared <Permissions.LaunchApp>();
            await Permissions.EnsureGrantedAsync <Permissions.StorageRead>();

            var tcs = new TaskCompletionSource <IEnumerable <FilePickerResult> >();

            var appControl = new AppControl();

            appControl.Operation = AppControlOperations.Pick;
            appControl.ExtraData.Add(AppControlData.SectionMode, allowMultiple ? "multiple" : "single");
            appControl.LaunchMode = AppControlLaunchMode.Single;

            var fileType = options?.FileTypes?.Value?.FirstOrDefault();

            appControl.Mime = fileType ?? "*/*";

            var fileResults = new List <FilePickerResult>();

            AppControl.SendLaunchRequest(appControl, (request, reply, result) =>
            {
                if (result == AppControlReplyResult.Succeeded)
                {
                    if (reply.ExtraData.Count() > 0)
                    {
                        var selectedFiles = reply.ExtraData.Get <IEnumerable <string> >(AppControlData.Selected).ToList();
                        fileResults.AddRange(selectedFiles.Select(f => new FilePickerResult(f)));
                    }
                }

                tcs.TrySetResult(fileResults);
            });

            return(await tcs.Task);
        }
Пример #3
0
        static async Task <Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
        {
            await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>();

            var geolocator = new Geolocator
            {
                DesiredAccuracyInMeters = request.PlatformDesiredAccuracy
            };

            CheckStatus(geolocator.LocationStatus);

            cancellationToken = Utils.TimeoutToken(cancellationToken, request.Timeout);

            var location = await geolocator.GetGeopositionAsync().AsTask(cancellationToken);

            return(location?.Coordinate?.ToLocation());

            void CheckStatus(PositionStatus status)
            {
                switch (status)
                {
                case PositionStatus.Disabled:
                case PositionStatus.NotAvailable:
                    throw new FeatureNotEnabledException("Location services are not enabled on device.");
                }
            }
        }
Пример #4
0
        static async Task <FileResult> PlatformPickAsync(MediaPickerOptions options, bool photo)
        {
            // We only need the permission when accessing the file, but it's more natural
            // to ask the user first, then show the picker.
            await Permissions.EnsureGrantedAsync <Permissions.StorageRead>();

            var intent = new Intent(Intent.ActionGetContent);

            intent.SetType(photo ? FileSystem.MimeTypes.ImageAll : FileSystem.MimeTypes.VideoAll);

            var pickerIntent = Intent.CreateChooser(intent, options?.Title);

            try
            {
                string path = null;
                void OnResult(Intent intent)
                {
                    // The uri returned is only temporary and only lives as long as the Activity that requested it,
                    // so this means that it will always be cleaned up by the time we need it because we are using
                    // an intermediate activity.

                    path = FileSystem.EnsurePhysicalPath(intent.Data);
                }

                await IntermediateActivity.StartAsync(pickerIntent, Platform.requestCodeMediaPicker, onResult : OnResult);

                return(new FileResult(path));
            }
            catch (OperationCanceledException)
            {
                return(null);
            }
        }
Пример #5
0
        static async Task <FileResult> PlatformCaptureAsync(MediaPickerOptions options, bool photo)
        {
            await Permissions.EnsureGrantedAsync <Permissions.Camera>();

            await Permissions.EnsureGrantedAsync <Permissions.StorageWrite>();

            var capturePhotoIntent = new Intent(photo ? MediaStore.ActionImageCapture : MediaStore.ActionVideoCapture);

            if (capturePhotoIntent.ResolveActivity(Platform.AppContext.PackageManager) != null)
            {
                try
                {
                    var activity = Platform.GetCurrentActivity(true);

                    var storageDir = Platform.AppContext.ExternalCacheDir;
                    var tmpFile    = Java.IO.File.CreateTempFile(Guid.NewGuid().ToString(), photo ? ".jpg" : ".mp4", storageDir);
                    tmpFile.DeleteOnExit();

                    capturePhotoIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
                    capturePhotoIntent.AddFlags(ActivityFlags.GrantWriteUriPermission);

                    var result = await IntermediateActivity.StartAsync(capturePhotoIntent, Platform.requestCodeMediaCapture, tmpFile);

                    var outputUri = result.GetParcelableExtra(IntermediateActivity.OutputUriExtra) as global::Android.Net.Uri;

                    return(new FileResult(outputUri));
                }
                catch (OperationCanceledException)
                {
                    return(null);
                }
            }

            return(null);
        }
Пример #6
0
        static async Task <IEnumerable <FileResult> > PlatformPickAsync(PickOptions options, bool allowMultiple = false)
        {
            // we only need the permission when accessing the file, but it's more natural
            // to ask the user first, then show the picker.
            await Permissions.EnsureGrantedAsync <Permissions.StorageRead>();

            // Essentials supports >= API 19 where this action is available
            var action = Intent.ActionOpenDocument;

            var intent = new Intent(action);

            intent.SetType(FileSystem.MimeTypes.All);
            intent.PutExtra(Intent.ExtraAllowMultiple, allowMultiple);

            var allowedTypes = options?.FileTypes?.Value?.ToArray();

            if (allowedTypes?.Length > 0)
            {
                intent.PutExtra(Intent.ExtraMimeTypes, allowedTypes);
            }

            var pickerIntent = Intent.CreateChooser(intent, options?.PickerTitle ?? "Select file");

            try
            {
                var resultList = new List <FileResult>();
                void OnResult(Intent intent)
                {
                    // The uri returned is only temporary and only lives as long as the Activity that requested it,
                    // so this means that it will always be cleaned up by the time we need it because we are using
                    // an intermediate activity.

                    if (intent.ClipData == null)
                    {
                        var path = FileSystem.EnsurePhysicalPath(intent.Data);
                        resultList.Add(new FileResult(path));
                    }
                    else
                    {
                        for (var i = 0; i < intent.ClipData.ItemCount; i++)
                        {
                            var uri  = intent.ClipData.GetItemAt(i).Uri;
                            var path = FileSystem.EnsurePhysicalPath(uri);
                            resultList.Add(new FileResult(path));
                        }
                    }
                }

                await IntermediateActivity.StartAsync(pickerIntent, Platform.requestCodeFilePicker, onResult : OnResult);

                return(resultList);
            }
            catch (OperationCanceledException)
            {
                return(null);
            }
        }
Пример #7
0
        static async Task CheckSupportAsync()
        {
            if (!IsSupported)
            {
                throw new FeatureNotSupportedException();
            }

            await Permissions.EnsureGrantedAsync <Permissions.Flashlight>();
        }
Пример #8
0
        public static async Task <Contact> PickContactAsync()
        {
            // iOS does not require permissions for the picker
            if (DeviceInfo.Platform != DevicePlatform.iOS)
            {
                await Permissions.EnsureGrantedAsync <Permissions.ContactsRead>();
            }

            return(await PlatformPickContactAsync());
        }
Пример #9
0
        static async Task <FileResult> PlatformCaptureAsync(MediaPickerOptions options, bool photo)
        {
            await Permissions.EnsureGrantedAsync <Permissions.Camera>();

            await Permissions.EnsureGrantedAsync <Permissions.StorageWrite>();

            var capturePhotoIntent = new Intent(photo ? MediaStore.ActionImageCapture : MediaStore.ActionVideoCapture);

            if (!Platform.IsIntentSupported(capturePhotoIntent))
            {
                throw new FeatureNotSupportedException($"Either there was no camera on the device or '{capturePhotoIntent.Action}' was not added to the <queries> element in the app's manifest file. See more: https://developer.android.com/about/versions/11/privacy/package-visibility");
            }

            capturePhotoIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
            capturePhotoIntent.AddFlags(ActivityFlags.GrantWriteUriPermission);

            try
            {
                var activity = Platform.GetCurrentActivity(true);

                // Create the temporary file
                var ext = photo
                    ? FileSystem.Extensions.Jpg
                    : FileSystem.Extensions.Mp4;
                var fileName = Guid.NewGuid().ToString("N") + ext;
                var tmpFile  = FileSystem.GetEssentialsTemporaryFile(Platform.AppContext.CacheDir, fileName);

                // Set up the content:// uri
                AndroidUri outputUri = null;
                void OnCreate(Intent intent)
                {
                    // Android requires that using a file provider to get a content:// uri for a file to be called
                    // from within the context of the actual activity which may share that uri with another intent
                    // it launches.

                    outputUri ??= FileProvider.GetUriForFile(tmpFile);

                    intent.PutExtra(MediaStore.ExtraOutput, outputUri);
                }

                // Start the capture process
                await IntermediateActivity.StartAsync(capturePhotoIntent, Platform.requestCodeMediaCapture, OnCreate);

                // Return the file that we just captured
                return(new FileResult(tmpFile.AbsolutePath));
            }
            catch (OperationCanceledException)
            {
                return(null);
            }
        }
Пример #10
0
        static async Task <Location> PlatformLastKnownLocationAsync()
        {
            if (!CLLocationManager.LocationServicesEnabled)
            {
                throw new FeatureNotEnabledException("Location services are not enabled on device.");
            }

            await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>();

            var manager  = new CLLocationManager();
            var location = manager.Location;

            return(location?.ToLocation());
        }
Пример #11
0
        static async Task <Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
        {
            if (!CLLocationManager.LocationServicesEnabled)
            {
                throw new FeatureNotEnabledException("Location services are not enabled on device.");
            }

            await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>();

            // the location manager requires an active run loop
            // so just use the main loop
            CLLocationManager manager = null;

            NSRunLoop.Main.InvokeOnMainThread(() => manager = new CLLocationManager());

            var tcs = new TaskCompletionSource <CLLocation>(manager);

            var listener = new SingleLocationListener();

            listener.LocationHandler += HandleLocation;

            cancellationToken = Utils.TimeoutToken(cancellationToken, request.Timeout);
            cancellationToken.Register(Cancel);

            manager.DesiredAccuracy = request.PlatformDesiredAccuracy;
            manager.Delegate        = listener;

#if __IOS__
            // we're only listening for a single update
            manager.PausesLocationUpdatesAutomatically = false;
#endif

            manager.StartUpdatingLocation();

            var clLocation = await tcs.Task;

            return(clLocation?.ToLocation());

            void HandleLocation(CLLocation location)
            {
                manager.StopUpdatingLocation();
                tcs.TrySetResult(location);
            }

            void Cancel()
            {
                manager.StopUpdatingLocation();
                tcs.TrySetResult(null);
            }
        }
Пример #12
0
        static async Task <Location> PlatformLastKnownLocationAsync()
        {
            await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>();

            var             lm           = Platform.LocationManager;
            AndroidLocation bestLocation = null;

            foreach (var provider in lm.GetProviders(true))
            {
                var location = lm.GetLastKnownLocation(provider);

                if (location != null && IsBetterLocation(location, bestLocation))
                {
                    bestLocation = location;
                }
            }

            return(bestLocation?.ToLocation());
        }
Пример #13
0
        static async Task <Contact> PlatformPickContactAsync()
        {
            Permissions.EnsureDeclared <Permissions.ContactsRead>();
            Permissions.EnsureDeclared <Permissions.LaunchApp>();
            await Permissions.EnsureGrantedAsync <Permissions.ContactsRead>();

            var tcs = new TaskCompletionSource <Contact>();

            var appControl = new AppControl();

            appControl.Operation = AppControlOperations.Pick;
            appControl.ExtraData.Add(AppControlData.SectionMode, "single");
            appControl.LaunchMode = AppControlLaunchMode.Single;
            appControl.Mime       = "application/vnd.tizen.contact";

            AppControl.SendLaunchRequest(appControl, (request, reply, result) =>
            {
                Contact contact = null;

                if (result == AppControlReplyResult.Succeeded)
                {
                    var contactId = reply.ExtraData.Get <IEnumerable <string> >(AppControlData.Selected)?.FirstOrDefault();

                    if (int.TryParse(contactId, out var contactInt))
                    {
                        var record = manager.Database.Get(TizenContact.Uri, contactInt);
                        if (record != null)
                        {
                            contact = ToContact(record);
                        }
                    }
                }
                tcs.TrySetResult(contact);
            });

            return(await tcs.Task);
        }
Пример #14
0
        static async Task <FileResult> PhotoAsync(MediaPickerOptions options, bool photo, bool pickExisting)
        {
            var sourceType = pickExisting ? UIImagePickerControllerSourceType.PhotoLibrary : UIImagePickerControllerSourceType.Camera;
            var mediaType  = photo ? UTType.Image : UTType.Movie;

            if (!UIImagePickerController.IsSourceTypeAvailable(sourceType))
            {
                throw new FeatureNotSupportedException();
            }
            if (!UIImagePickerController.AvailableMediaTypes(sourceType).Contains(mediaType))
            {
                throw new FeatureNotSupportedException();
            }

            // microphone only needed if video will be captured
            if (!photo && !pickExisting)
            {
                await Permissions.EnsureGrantedAsync <Permissions.Microphone>();
            }

            // Check if picking existing or not and ensure permission accordingly as they can be set independently from each other
            if (pickExisting && !Platform.HasOSVersion(11, 0))
            {
                await Permissions.EnsureGrantedAsync <Permissions.Photos>();
            }

            if (!pickExisting)
            {
                await Permissions.EnsureGrantedAsync <Permissions.Camera>();
            }

            var vc = Platform.GetCurrentViewController(true);

            picker               = new UIImagePickerController();
            picker.SourceType    = sourceType;
            picker.MediaTypes    = new string[] { mediaType };
            picker.AllowsEditing = false;
            if (!photo && !pickExisting)
            {
                picker.CameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Video;
            }

            if (!string.IsNullOrWhiteSpace(options?.Title))
            {
                picker.Title = options.Title;
            }

            if (DeviceInfo.Idiom == DeviceIdiom.Tablet && picker.PopoverPresentationController != null && vc.View != null)
            {
                picker.PopoverPresentationController.SourceRect = vc.View.Bounds;
            }

            var tcs = new TaskCompletionSource <FileResult>(picker);

            picker.Delegate = new PhotoPickerDelegate
            {
                CompletedHandler = async info =>
                {
                    GetFileResult(info, tcs);
                    await vc.DismissViewControllerAsync(true);
                }
            };

            if (picker.PresentationController != null)
            {
                picker.PresentationController.Delegate = new PhotoPickerPresentationControllerDelegate
                {
                    CompletedHandler = info => GetFileResult(info, tcs)
                };
            }

            await vc.PresentViewControllerAsync(picker, true);

            var result = await tcs.Task;

            picker?.Dispose();
            picker = null;

            return(result);
        }
Пример #15
0
        static async Task <Contact> PlatformPickContactAsync()
        {
            Permissions.EnsureDeclared <Permissions.ContactsRead>();
            await Permissions.EnsureGrantedAsync <Permissions.ContactsRead>();

            var tcs = new TaskCompletionSource <Contact>();

            var appControl = new AppControl();

            appControl.Operation = AppControlOperations.Pick;
            appControl.ExtraData.Add(AppControlData.SectionMode, "single");
            appControl.LaunchMode = AppControlLaunchMode.Single;
            appControl.Mime       = "application/vnd.tizen.contact";

            AppControl.SendLaunchRequest(appControl, (request, reply, result) =>
            {
                Contact contact = null;

                if (result == AppControlReplyResult.Succeeded)
                {
                    var contactId = reply.ExtraData.Get <IEnumerable <string> >(AppControlData.Selected)?.FirstOrDefault();

                    if (int.TryParse(contactId, out var contactInt))
                    {
                        var mgr = new ContactsManager();

                        var record = mgr.Database.Get(TizenContact.Uri, contactInt);

                        if (record != null)
                        {
                            string name = null;
                            var emails  = new List <ContactEmail>();
                            var phones  = new List <ContactPhone>();

                            var recordName = record.GetChildRecord(TizenContact.Name, 0);
                            if (recordName != null)
                            {
                                var first = recordName.Get <string>(TizenName.First) ?? string.Empty;
                                var last  = recordName.Get <string>(TizenName.Last) ?? string.Empty;

                                name = $"{first} {last}".Trim();
                            }

                            var emailCount = record.GetChildRecordCount(TizenContact.Email);
                            for (var i = 0; i < emailCount; i++)
                            {
                                var item = record.GetChildRecord(TizenContact.Email, i);
                                var addr = item.Get <string>(TizenEmail.Address);
                                var type = (TizenEmail.Types)item.Get <int>(TizenEmail.Type);

                                emails.Add(new ContactEmail(addr, GetContactType(type)));
                            }

                            var phoneCount = record.GetChildRecordCount(TizenContact.Number);
                            for (var i = 0; i < phoneCount; i++)
                            {
                                var item   = record.GetChildRecord(TizenContact.Number, i);
                                var number = item.Get <string>(TizenNumber.NumberData);
                                var type   = (TizenNumber.Types)item.Get <int>(TizenNumber.Type);

                                phones.Add(new ContactPhone(number, GetContactType(type)));
                            }

                            contact = new Contact(name, phones, emails, ContactType.Unknown);
                        }
                    }
                }

                tcs.TrySetResult(contact);
            });

            return(await tcs.Task);
        }
Пример #16
0
        static async Task <Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
        {
            await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>();

            var locationManager = Platform.LocationManager;

            var enabledProviders = locationManager.GetProviders(true);
            var hasProviders     = enabledProviders.Any(p => !ignoredProviders.Contains(p));

            if (!hasProviders)
            {
                throw new FeatureNotEnabledException("Location services are not enabled on device.");
            }

            // get the best possible provider for the requested accuracy
            var providerInfo = GetBestProvider(locationManager, request.DesiredAccuracy);

            // if no providers exist, we can't get a location
            // let's punt and try to get the last known location
            if (string.IsNullOrEmpty(providerInfo.Provider))
            {
                return(await GetLastKnownLocationAsync());
            }

            var tcs = new TaskCompletionSource <AndroidLocation>();

            var allProviders = locationManager.GetProviders(false);

            var providers = new List <string>();

            if (allProviders.Contains(LocationManager.GpsProvider))
            {
                providers.Add(LocationManager.GpsProvider);
            }
            if (allProviders.Contains(LocationManager.NetworkProvider))
            {
                providers.Add(LocationManager.NetworkProvider);
            }

            if (providers.Count == 0)
            {
                providers.Add(providerInfo.Provider);
            }

            var listener = new SingleLocationListener(locationManager, providerInfo.Accuracy, providers);

            listener.LocationHandler = HandleLocation;

            cancellationToken = Utils.TimeoutToken(cancellationToken, request.Timeout);
            cancellationToken.Register(Cancel);

            // start getting location updates
            // make sure to use a thread with a looper
            var looper = Looper.MyLooper() ?? Looper.MainLooper;

            foreach (var provider in providers)
            {
                locationManager.RequestLocationUpdates(provider, 0, 0, listener, looper);
            }

            var androidLocation = await tcs.Task;

            if (androidLocation == null)
            {
                return(null);
            }

            return(androidLocation.ToLocation());

            void HandleLocation(AndroidLocation location)
            {
                RemoveUpdates();
                tcs.TrySetResult(location);
            }

            void Cancel()
            {
                RemoveUpdates();
                tcs.TrySetResult(listener.BestLocation);
            }

            void RemoveUpdates()
            {
                for (var i = 0; i < providers.Count; i++)
                {
                    locationManager.RemoveUpdates(listener);
                }
            }
        }
Пример #17
0
        static async Task <FileResult> PhotoAsync(MediaPickerOptions options, bool photo, bool pickExisting)
        {
            var sourceType = pickExisting ? UIImagePickerControllerSourceType.PhotoLibrary : UIImagePickerControllerSourceType.Camera;
            var mediaType  = photo ? UTType.Image : UTType.Movie;

            if (!UIImagePickerController.IsSourceTypeAvailable(sourceType))
            {
                throw new FeatureNotSupportedException();
            }
            if (!UIImagePickerController.AvailableMediaTypes(sourceType).Contains(mediaType))
            {
                throw new FeatureNotSupportedException();
            }

            if (!photo)
            {
                await Permissions.EnsureGrantedAsync <Permissions.Microphone>();
            }

            // permission is not required on iOS 11 for the picker
            if (!Platform.HasOSVersion(11, 0))
            {
                await Permissions.EnsureGrantedAsync <Permissions.Photos>();
            }

            var vc = Platform.GetCurrentViewController(true);

            picker               = new UIImagePickerController();
            picker.SourceType    = sourceType;
            picker.MediaTypes    = new string[] { mediaType };
            picker.AllowsEditing = false;
            if (!photo && !pickExisting)
            {
                picker.CameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Video;
            }

            if (!string.IsNullOrWhiteSpace(options?.Title))
            {
                picker.Title = options.Title;
            }

            if (DeviceInfo.Idiom == DeviceIdiom.Tablet && picker.PopoverPresentationController != null && vc.View != null)
            {
                picker.PopoverPresentationController.SourceRect = vc.View.Bounds;
            }

            var tcs = new TaskCompletionSource <FileResult>(picker);

            picker.Delegate = new PhotoPickerDelegate
            {
                CompletedHandler = info =>
                                   tcs.TrySetResult(DictionaryToMediaFile(info))
            };

            await vc.PresentViewControllerAsync(picker, true);

            var result = await tcs.Task;

            await vc.DismissViewControllerAsync(true);

            picker?.Dispose();
            picker = null;

            return(result);
        }
Пример #18
0
        static async Task <Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
        {
            await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>();

            Locator service = null;
            var     gps     = Platform.GetFeatureInfo <bool>("location.gps");
            var     wps     = Platform.GetFeatureInfo <bool>("location.wps");

            if (gps)
            {
                if (wps)
                {
                    service = new Locator(LocationType.Hybrid);
                }
                else
                {
                    service = new Locator(LocationType.Gps);
                }
            }
            else
            {
                if (wps)
                {
                    service = new Locator(LocationType.Wps);
                }
                else
                {
                    service = new Locator(LocationType.Passive);
                }
            }

            var tcs = new TaskCompletionSource <bool>();

            cancellationToken = Utils.TimeoutToken(cancellationToken, request.Timeout);
            cancellationToken.Register(() =>
            {
                service?.Stop();
                tcs.TrySetResult(false);
            });

            double KmToMetersPerSecond(double km) => km * 0.277778;

            service.LocationChanged += (s, e) =>
            {
                if (e.Location != null)
                {
                    lastKnownLocation.Accuracy  = e.Location.Accuracy;
                    lastKnownLocation.Altitude  = e.Location.Altitude;
                    lastKnownLocation.Course    = e.Location.Direction;
                    lastKnownLocation.Latitude  = e.Location.Latitude;
                    lastKnownLocation.Longitude = e.Location.Longitude;
                    lastKnownLocation.Speed     = KmToMetersPerSecond(e.Location.Speed);
                    lastKnownLocation.Timestamp = e.Location.Timestamp;
                }
                service?.Stop();
                tcs.TrySetResult(true);
            };
            service.Start();

            await tcs.Task;

            return(lastKnownLocation);
        }