diff --git a/src/MobileApps/MyDriving.sln b/src/MobileApps/MyDriving.sln index f923683e..549a52b4 100644 --- a/src/MobileApps/MyDriving.sln +++ b/src/MobileApps/MyDriving.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyDriving.iOS", "MyDriving\MyDriving.iOS\MyDriving.iOS.csproj", "{DE56E591-0655-43D7-A1B9-B3280F78B667}" EndProject @@ -43,12 +43,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObdLibiOS", "..\OBDLibrary\ EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution - MyDriving\MyDriving.DataObjects\MyDriving.DataObjects.projitems*{bd4403c0-6cd5-4030-b1a3-7ad98b9b80ca}*SharedItemsImports = 13 MyDriving\MyDriving.Shared\MyDriving.Shared.projitems*{219edca6-56bb-4ebd-ae46-c691f0aed767}*SharedItemsImports = 4 MyDriving\MyDriving.DataObjects\MyDriving.DataObjects.projitems*{649300ce-70ea-4606-983f-f4476fdd6c7e}*SharedItemsImports = 4 - MyDriving\MyDriving.Shared\MyDriving.Shared.projitems*{efa3478d-88c0-41a8-ad5e-5878e42fe3e2}*SharedItemsImports = 13 MyDriving\MyDriving.Shared\MyDriving.Shared.projitems*{b09661c2-82a6-4d16-b4fd-7b23d0ffe1fe}*SharedItemsImports = 4 + MyDriving\MyDriving.DataObjects\MyDriving.DataObjects.projitems*{bd4403c0-6cd5-4030-b1a3-7ad98b9b80ca}*SharedItemsImports = 13 MyDriving\MyDriving.Shared\MyDriving.Shared.projitems*{de56e591-0655-43d7-a1b9-b3280f78b667}*SharedItemsImports = 4 + MyDriving\MyDriving.Shared\MyDriving.Shared.projitems*{efa3478d-88c0-41a8-ad5e-5878e42fe3e2}*SharedItemsImports = 13 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution AppStore|Any CPU = AppStore|Any CPU @@ -216,7 +216,6 @@ Global {219EDCA6-56BB-4EBD-AE46-C691F0AED767}.Debug|iPhone.Deploy.0 = Debug|x86 {219EDCA6-56BB-4EBD-AE46-C691F0AED767}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86 {219EDCA6-56BB-4EBD-AE46-C691F0AED767}.Debug|iPhoneSimulator.Build.0 = Debug|x86 - {219EDCA6-56BB-4EBD-AE46-C691F0AED767}.Debug|iPhoneSimulator.Deploy.0 = Debug|x86 {219EDCA6-56BB-4EBD-AE46-C691F0AED767}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {219EDCA6-56BB-4EBD-AE46-C691F0AED767}.Debug|Mixed Platforms.Build.0 = Debug|x86 {219EDCA6-56BB-4EBD-AE46-C691F0AED767}.Debug|Mixed Platforms.Deploy.0 = Debug|x86 diff --git a/src/MobileApps/MyDriving/MyDriving.Android/Resources/Resource.designer.cs b/src/MobileApps/MyDriving/MyDriving.Android/Resources/Resource.designer.cs index 0ab60145..f7e16a86 100644 --- a/src/MobileApps/MyDriving/MyDriving.Android/Resources/Resource.designer.cs +++ b/src/MobileApps/MyDriving/MyDriving.Android/Resources/Resource.designer.cs @@ -5271,145 +5271,154 @@ public partial class String public const int hockeyapp_feedback_failed_title = 2131099730; // aapt resource value: 0x7f060053 - public const int hockeyapp_feedback_generic_error = 2131099731; + public const int hockeyapp_feedback_fetching_feedback_text = 2131099731; // aapt resource value: 0x7f060054 - public const int hockeyapp_feedback_last_updated_text = 2131099732; + public const int hockeyapp_feedback_generic_error = 2131099732; // aapt resource value: 0x7f060055 - public const int hockeyapp_feedback_max_attachments_allowed = 2131099733; + public const int hockeyapp_feedback_last_updated_text = 2131099733; // aapt resource value: 0x7f060056 - public const int hockeyapp_feedback_message_hint = 2131099734; + public const int hockeyapp_feedback_max_attachments_allowed = 2131099734; // aapt resource value: 0x7f060057 - public const int hockeyapp_feedback_name_hint = 2131099735; + public const int hockeyapp_feedback_message_hint = 2131099735; // aapt resource value: 0x7f060058 - public const int hockeyapp_feedback_refresh_button_text = 2131099736; + public const int hockeyapp_feedback_name_hint = 2131099736; // aapt resource value: 0x7f060059 - public const int hockeyapp_feedback_response_button_text = 2131099737; + public const int hockeyapp_feedback_refresh_button_text = 2131099737; // aapt resource value: 0x7f06005a - public const int hockeyapp_feedback_select_file = 2131099738; + public const int hockeyapp_feedback_response_button_text = 2131099738; // aapt resource value: 0x7f06005b - public const int hockeyapp_feedback_select_picture = 2131099739; + public const int hockeyapp_feedback_select_file = 2131099739; // aapt resource value: 0x7f06005c - public const int hockeyapp_feedback_send_button_text = 2131099740; + public const int hockeyapp_feedback_select_picture = 2131099740; // aapt resource value: 0x7f06005d - public const int hockeyapp_feedback_send_generic_error = 2131099741; + public const int hockeyapp_feedback_send_button_text = 2131099741; // aapt resource value: 0x7f06005e - public const int hockeyapp_feedback_send_network_error = 2131099742; + public const int hockeyapp_feedback_send_generic_error = 2131099742; // aapt resource value: 0x7f06005f - public const int hockeyapp_feedback_subject_hint = 2131099743; + public const int hockeyapp_feedback_send_network_error = 2131099743; // aapt resource value: 0x7f060060 - public const int hockeyapp_feedback_title = 2131099744; + public const int hockeyapp_feedback_sending_feedback_text = 2131099744; // aapt resource value: 0x7f060061 - public const int hockeyapp_feedback_validate_email_empty = 2131099745; + public const int hockeyapp_feedback_subject_hint = 2131099745; // aapt resource value: 0x7f060062 - public const int hockeyapp_feedback_validate_email_error = 2131099746; + public const int hockeyapp_feedback_title = 2131099746; // aapt resource value: 0x7f060063 - public const int hockeyapp_feedback_validate_name_error = 2131099747; + public const int hockeyapp_feedback_validate_email_empty = 2131099747; // aapt resource value: 0x7f060064 - public const int hockeyapp_feedback_validate_subject_error = 2131099748; + public const int hockeyapp_feedback_validate_email_error = 2131099748; // aapt resource value: 0x7f060065 - public const int hockeyapp_feedback_validate_text_error = 2131099749; + public const int hockeyapp_feedback_validate_name_error = 2131099749; // aapt resource value: 0x7f060066 - public const int hockeyapp_login_email_hint = 2131099750; + public const int hockeyapp_feedback_validate_subject_error = 2131099750; // aapt resource value: 0x7f060067 - public const int hockeyapp_login_headline_text = 2131099751; + public const int hockeyapp_feedback_validate_text_error = 2131099751; // aapt resource value: 0x7f060068 - public const int hockeyapp_login_headline_text_email_only = 2131099752; + public const int hockeyapp_login_email_hint = 2131099752; // aapt resource value: 0x7f060069 - public const int hockeyapp_login_login_button_text = 2131099753; + public const int hockeyapp_login_headline_text = 2131099753; // aapt resource value: 0x7f06006a - public const int hockeyapp_login_missing_credentials_toast = 2131099754; + public const int hockeyapp_login_headline_text_email_only = 2131099754; // aapt resource value: 0x7f06006b - public const int hockeyapp_login_password_hint = 2131099755; + public const int hockeyapp_login_login_button_text = 2131099755; // aapt resource value: 0x7f06006c - public const int hockeyapp_paint_dialog_message = 2131099756; + public const int hockeyapp_login_missing_credentials_toast = 2131099756; // aapt resource value: 0x7f06006d - public const int hockeyapp_paint_dialog_negative_button = 2131099757; + public const int hockeyapp_login_password_hint = 2131099757; // aapt resource value: 0x7f06006e - public const int hockeyapp_paint_dialog_neutral_button = 2131099758; + public const int hockeyapp_paint_dialog_message = 2131099758; // aapt resource value: 0x7f06006f - public const int hockeyapp_paint_dialog_positive_button = 2131099759; + public const int hockeyapp_paint_dialog_negative_button = 2131099759; // aapt resource value: 0x7f060070 - public const int hockeyapp_paint_indicator_toast = 2131099760; + public const int hockeyapp_paint_dialog_neutral_button = 2131099760; // aapt resource value: 0x7f060071 - public const int hockeyapp_paint_menu_clear = 2131099761; + public const int hockeyapp_paint_dialog_positive_button = 2131099761; // aapt resource value: 0x7f060072 - public const int hockeyapp_paint_menu_save = 2131099762; + public const int hockeyapp_paint_indicator_toast = 2131099762; // aapt resource value: 0x7f060073 - public const int hockeyapp_paint_menu_undo = 2131099763; + public const int hockeyapp_paint_menu_clear = 2131099763; // aapt resource value: 0x7f060074 - public const int hockeyapp_permission_dialog_negative_button = 2131099764; + public const int hockeyapp_paint_menu_save = 2131099764; // aapt resource value: 0x7f060075 - public const int hockeyapp_permission_dialog_positive_button = 2131099765; + public const int hockeyapp_paint_menu_undo = 2131099765; // aapt resource value: 0x7f060076 - public const int hockeyapp_permission_update_message = 2131099766; + public const int hockeyapp_permission_dialog_negative_button = 2131099766; // aapt resource value: 0x7f060077 - public const int hockeyapp_permission_update_title = 2131099767; + public const int hockeyapp_permission_dialog_positive_button = 2131099767; // aapt resource value: 0x7f060078 - public const int hockeyapp_update_button = 2131099768; + public const int hockeyapp_permission_update_message = 2131099768; // aapt resource value: 0x7f060079 - public const int hockeyapp_update_dialog_message = 2131099769; + public const int hockeyapp_permission_update_title = 2131099769; // aapt resource value: 0x7f06007a - public const int hockeyapp_update_dialog_negative_button = 2131099770; + public const int hockeyapp_update_button = 2131099770; // aapt resource value: 0x7f06007b - public const int hockeyapp_update_dialog_positive_button = 2131099771; + public const int hockeyapp_update_dialog_message = 2131099771; // aapt resource value: 0x7f06007c - public const int hockeyapp_update_dialog_title = 2131099772; + public const int hockeyapp_update_dialog_negative_button = 2131099772; // aapt resource value: 0x7f06007d - public const int hockeyapp_update_mandatory_toast = 2131099773; + public const int hockeyapp_update_dialog_positive_button = 2131099773; + + // aapt resource value: 0x7f06007e + public const int hockeyapp_update_dialog_title = 2131099774; + + // aapt resource value: 0x7f06007f + public const int hockeyapp_update_mandatory_toast = 2131099775; + + // aapt resource value: 0x7f060080 + public const int hockeyapp_update_version_details_label = 2131099776; // aapt resource value: 0x7f060037 public const int library_name = 2131099703; - // aapt resource value: 0x7f06007e - public const int login_facebook = 2131099774; + // aapt resource value: 0x7f060081 + public const int login_facebook = 2131099777; - // aapt resource value: 0x7f060080 - public const int login_microsoft = 2131099776; + // aapt resource value: 0x7f060083 + public const int login_microsoft = 2131099779; - // aapt resource value: 0x7f06007f - public const int login_twitter = 2131099775; + // aapt resource value: 0x7f060082 + public const int login_twitter = 2131099778; // aapt resource value: 0x7f060034 public const int status_bar_notification_info_overflow = 2131099700; diff --git a/src/MobileApps/MyDriving/MyDriving.UITests/MyDriving.UITests.csproj b/src/MobileApps/MyDriving/MyDriving.UITests/MyDriving.UITests.csproj index 64ec21e0..c6fd1744 100644 --- a/src/MobileApps/MyDriving/MyDriving.UITests/MyDriving.UITests.csproj +++ b/src/MobileApps/MyDriving/MyDriving.UITests/MyDriving.UITests.csproj @@ -84,9 +84,8 @@ + - - - + \ No newline at end of file diff --git a/src/MobileApps/MyDriving/MyDriving.UWP/MyDriving.UWP.csproj b/src/MobileApps/MyDriving/MyDriving.UWP/MyDriving.UWP.csproj index d3f341a4..a21d813f 100644 --- a/src/MobileApps/MyDriving/MyDriving.UWP/MyDriving.UWP.csproj +++ b/src/MobileApps/MyDriving/MyDriving.UWP/MyDriving.UWP.csproj @@ -400,7 +400,7 @@ Visual C++ 2015 Runtime for Universal Windows Platform Apps - + SQLite for Universal Windows Platform diff --git a/src/MobileApps/MyDriving/MyDriving.UWP/Views/CurrentTripView.xaml.cs b/src/MobileApps/MyDriving/MyDriving.UWP/Views/CurrentTripView.xaml.cs index 7cabb0dd..c3c2a899 100644 --- a/src/MobileApps/MyDriving/MyDriving.UWP/Views/CurrentTripView.xaml.cs +++ b/src/MobileApps/MyDriving/MyDriving.UWP/Views/CurrentTripView.xaml.cs @@ -211,7 +211,7 @@ private async Task BeginExtendedExecution() { case ExtendedExecutionResult.Allowed: session = newSession; - ViewModel.Geolocator.AllowsBackgroundUpdates = true; + ViewModel.Locator.AllowsBackgroundUpdates = true; ViewModel.StartTrackingTripCommand.Execute(null); break; diff --git a/src/MobileApps/MyDriving/MyDriving.iOS/Screens/Trips/CurrentTripViewController.cs b/src/MobileApps/MyDriving/MyDriving.iOS/Screens/Trips/CurrentTripViewController.cs index e6e96865..816b19d8 100644 --- a/src/MobileApps/MyDriving/MyDriving.iOS/Screens/Trips/CurrentTripViewController.cs +++ b/src/MobileApps/MyDriving/MyDriving.iOS/Screens/Trips/CurrentTripViewController.cs @@ -59,7 +59,7 @@ await CurrentTripViewModel.ExecuteStartTrackingTripCommandAsync().ContinueWith(a await PromptPermissionsChangeDialog(); }); - if (!CurrentTripViewModel.Geolocator.IsGeolocationEnabled) + if (!CurrentTripViewModel.Locator.IsGeolocationEnabled) { tripMapView.Camera.CenterCoordinate = new CLLocationCoordinate2D(47.6204, -122.3491); tripMapView.Camera.Altitude = 5000; @@ -95,7 +95,7 @@ async Task ConfigureCurrentTripUserInterface() ResetTripInfoView(); CurrentTripViewModel = new CurrentTripViewModel(); - CurrentTripViewModel.Geolocator.PositionChanged += Geolocator_PositionChanged; + CurrentTripViewModel.Locator.PositionChanged += Geolocator_PositionChanged; } @@ -179,7 +179,7 @@ async Task PromptPermissionsChangeDialog() async void RecordButton_TouchUpInside(object sender, EventArgs e) { - if (!CurrentTripViewModel.Geolocator.IsGeolocationEnabled) + if (!CurrentTripViewModel.Locator.IsGeolocationEnabled) { Acr.UserDialogs.UserDialogs.Instance.Alert( "Please ensure that geolocation is enabled and permissions are allowed for MyDriving to start a recording.", diff --git a/src/MobileApps/MyDriving/MyDriving/MyDriving.csproj b/src/MobileApps/MyDriving/MyDriving/MyDriving.csproj index 6894a1f1..aed40f1c 100644 --- a/src/MobileApps/MyDriving/MyDriving/MyDriving.csproj +++ b/src/MobileApps/MyDriving/MyDriving/MyDriving.csproj @@ -46,8 +46,11 @@ + + + diff --git a/src/MobileApps/MyDriving/MyDriving/Services/FakeLocationProvider.cs b/src/MobileApps/MyDriving/MyDriving/Services/FakeLocationProvider.cs new file mode 100644 index 00000000..d99a1e98 --- /dev/null +++ b/src/MobileApps/MyDriving/MyDriving/Services/FakeLocationProvider.cs @@ -0,0 +1,59 @@ +using Plugin.Geolocator.Abstractions; +using System; +using System.Threading.Tasks; + +namespace MyDriving.Services +{ + public class FakeLocationProvider : ILocationProvider + { + bool running; + Position lastPosition; + + public event EventHandler PositionChanged; + + public FakeLocationProvider(Position initalPosition) + { + lastPosition = initalPosition; + } + + public bool IsListening { get { return running; } } + public bool IsGeolocationEnabled { get { return true; } } + public bool AllowsBackgroundUpdates { get; set; } // TODO unset running when app goes into background if this is false + + public async Task TryStartAsync() + { + if (running) + throw new InvalidOperationException("already started"); + + running = true; + + while (true) + { + var pos = new Position(lastPosition); + pos.Longitude += 0.00085720162; + PositionChanged?.Invoke(this, new PositionEventArgs(lastPosition)); + lastPosition = pos; + + await Task.Delay(3000); + + if (!running) + { + return true; + }; + } + } + + public async Task TryStopAsync() + { + running = false; + await Task.Delay(1000); // fake work + return true; + } + + public async Task GetPositionAsync(TimeSpan timeout) + { + await Task.Delay(100); // fake work + return new Position(lastPosition); + } + } +} diff --git a/src/MobileApps/MyDriving/MyDriving/Services/ILocationProvider.cs b/src/MobileApps/MyDriving/MyDriving/Services/ILocationProvider.cs new file mode 100644 index 00000000..70798cdf --- /dev/null +++ b/src/MobileApps/MyDriving/MyDriving/Services/ILocationProvider.cs @@ -0,0 +1,17 @@ +using Plugin.Geolocator.Abstractions; +using System; +using System.Threading.Tasks; + +namespace MyDriving.Services +{ + public interface ILocationProvider + { + event EventHandler PositionChanged; + bool IsListening { get; } + bool IsGeolocationEnabled { get; } + bool AllowsBackgroundUpdates { get; set; } + Task TryStartAsync(); + Task TryStopAsync(); + Task GetPositionAsync(TimeSpan timeout); + } +} diff --git a/src/MobileApps/MyDriving/MyDriving/Services/PlatformLocationProvider.cs b/src/MobileApps/MyDriving/MyDriving/Services/PlatformLocationProvider.cs new file mode 100644 index 00000000..cec07006 --- /dev/null +++ b/src/MobileApps/MyDriving/MyDriving/Services/PlatformLocationProvider.cs @@ -0,0 +1,60 @@ +using Plugin.DeviceInfo; +using Plugin.Geolocator; +using Plugin.Geolocator.Abstractions; +using System; +using System.Threading.Tasks; + +namespace MyDriving.Services +{ + public class PlatformLocationProvider : ILocationProvider + { + public static readonly PlatformLocationProvider Instance = new PlatformLocationProvider(); + + private readonly IGeolocator geolocator; + + public event EventHandler PositionChanged; + + private PlatformLocationProvider() + { + geolocator = CrossGeolocator.Current; + } + + public bool IsListening { get { return geolocator.IsListening; } } + public bool IsGeolocationEnabled { get { return geolocator.IsGeolocationEnabled; } } + public bool AllowsBackgroundUpdates { get { return geolocator.AllowsBackgroundUpdates; } set { geolocator.AllowsBackgroundUpdates = value; }} + + public async Task TryStartAsync() + { + if (geolocator.IsGeolocationAvailable + && (CrossDeviceInfo.Current.Platform == Plugin.DeviceInfo.Abstractions.Platform.iOS || geolocator.IsGeolocationEnabled)) + { + geolocator.AllowsBackgroundUpdates = true; + geolocator.DesiredAccuracy = 25; + + geolocator.PositionChanged += Geolocator_PositionChanged; + + //every 3 second, 5 meters + return await geolocator.StartListeningAsync(3000, 5); + } + else + { + return false; + } + } + + public async Task TryStopAsync() + { + return await geolocator.StopListeningAsync(); + } + + public async Task GetPositionAsync(TimeSpan timeout) + { + return await geolocator.GetPositionAsync((int)timeout.TotalMilliseconds); + } + + private void Geolocator_PositionChanged(object sender, PositionEventArgs e) + { + PositionChanged?.Invoke(this, e); + } + } +} diff --git a/src/MobileApps/MyDriving/MyDriving/ViewModel/CurrentTripViewModel.cs b/src/MobileApps/MyDriving/MyDriving/ViewModel/CurrentTripViewModel.cs index c050935b..41bbae55 100644 --- a/src/MobileApps/MyDriving/MyDriving/ViewModel/CurrentTripViewModel.cs +++ b/src/MobileApps/MyDriving/MyDriving/ViewModel/CurrentTripViewModel.cs @@ -27,6 +27,8 @@ public class CurrentTripViewModel : ViewModelBase { readonly OBDDataProcessor obdDataProcessor; readonly List photos; + static ILocationProvider locationProvider; + string distance = "0.0"; string distanceUnits = "miles"; @@ -51,6 +53,15 @@ public class CurrentTripViewModel : ViewModelBase ICommand takePhotoCommand; + static CurrentTripViewModel() + { + // Initally set this to PlatformLocationProvider which wraps CrossGeolocator.Current, however if + // we are simulated swap it for a fake one when trip starts so position changed event raised. + // (Otherwise when simulate position changed events never raised). + // + locationProvider = PlatformLocationProvider.Instance; + } + public CurrentTripViewModel() { CurrentTrip = new Trip @@ -120,7 +131,7 @@ public string EngineLoad } public bool NeedSave { get; set; } - public IGeolocator Geolocator => CrossGeolocator.Current; + public ILocationProvider Locator => locationProvider; public IMedia Media => CrossMedia.Current; public TripSummaryViewModel TripSummary { get; set; } @@ -170,8 +181,18 @@ public async Task StartRecordingTrip() if (obdDataProcessor != null) { await obdDataProcessor.ConnectToObdDevice(true); - + CurrentTrip.HasSimulatedOBDData = obdDataProcessor.IsObdDeviceSimulated; + + if (obdDataProcessor.IsObdDeviceSimulated) + { + // Create fake location provider to raise position changed event.. + var fakeLocationProvider = new FakeLocationProvider(CurrentPosition); + fakeLocationProvider.PositionChanged += Geolocator_PositionChanged; + fakeLocationProvider.TryStartAsync(); // NOTE: we cannot await this as it never returns untill stopped (yes its not great but easier than creating periodic timer in a PCL) + + locationProvider = fakeLocationProvider; + } } CurrentTrip.RecordedTimeStamp = DateTime.UtcNow; @@ -342,21 +363,14 @@ public async Task ExecuteStartTrackingTripCommandAsync() try { - if (Geolocator.IsListening) + if (locationProvider.IsListening) { - await Geolocator.StopListeningAsync(); + await locationProvider.TryStopAsync(); } - if (Geolocator.IsGeolocationAvailable && (CrossDeviceInfo.Current.Platform == Plugin.DeviceInfo.Abstractions.Platform.iOS || Geolocator.IsGeolocationEnabled)) - { - Geolocator.AllowsBackgroundUpdates = true; - Geolocator.DesiredAccuracy = 25; - - Geolocator.PositionChanged += Geolocator_PositionChanged; - //every 3 second, 5 meters - await Geolocator.StartListeningAsync(3000, 5); - } - else + locationProvider.PositionChanged += Geolocator_PositionChanged; + var started = await locationProvider.TryStartAsync(); + if (!started) { Acr.UserDialogs.UserDialogs.Instance.Alert( "Please ensure that geolocation is enabled and permissions are allowed for MyDriving to start a recording.", @@ -377,8 +391,8 @@ public async Task ExecuteStopTrackingTripCommandAsync() try { //Unsubscribe because we were recording and it is alright - Geolocator.PositionChanged -= Geolocator_PositionChanged; - await Geolocator.StopListeningAsync(); + Locator.PositionChanged -= Geolocator_PositionChanged; + await Locator.TryStopAsync(); } catch (Exception ex) { @@ -592,7 +606,7 @@ async Task ExecuteTakePhotoCommandAsync() return; } - var locationTask = Geolocator.GetPositionAsync(2500); + var locationTask = Locator.GetPositionAsync(TimeSpan.FromMilliseconds(2500)); var photo = await Media.TakePhotoAsync(new StoreCameraMediaOptions { DefaultCamera = CameraDevice.Rear,