diff --git a/Mobile/NUI/Location/.gn b/Mobile/NUI/Location/.gn new file mode 100644 index 00000000..26e5e77a --- /dev/null +++ b/Mobile/NUI/Location/.gn @@ -0,0 +1,6 @@ + +arg_file_template = "" +buildconfig = "//build/BUILDCONFIG.gn" +root = "//build:" +script_executable = "" +secondary_source = "//build" \ No newline at end of file diff --git a/Mobile/NUI/Location/Location.sln b/Mobile/NUI/Location/Location.sln new file mode 100644 index 00000000..adb70b47 --- /dev/null +++ b/Mobile/NUI/Location/Location.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31005.135 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Location", "Location\Location.csproj", "{e708c9b1-601b-48fa-9ff2-fe38f37dc2f5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5204eb4c-1913-4de9-93d0-f1e45943f734}" + ProjectSection(SolutionItems) = preProject + tizen_workspace.yaml = tizen_workspace.yaml + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {e708c9b1-601b-48fa-9ff2-fe38f37dc2f5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {e708c9b1-601b-48fa-9ff2-fe38f37dc2f5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {e708c9b1-601b-48fa-9ff2-fe38f37dc2f5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {e708c9b1-601b-48fa-9ff2-fe38f37dc2f5}.Release|Any CPU.Build.0 = Release|Any CPU + + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Mobile/NUI/Location/Location/Behaviors/TextSetter.cs b/Mobile/NUI/Location/Location/Behaviors/TextSetter.cs new file mode 100644 index 00000000..046cdb21 --- /dev/null +++ b/Mobile/NUI/Location/Location/Behaviors/TextSetter.cs @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Tizen.NUI.Binding; +using Tizen.NUI.Components; + +namespace Location.Behaviors +{ + public static class TextSetter + { + public static readonly BindableProperty TextProperty = + BindableProperty.CreateAttached( + "Text", + typeof(string), + typeof(TextSetter), + "", + propertyChanged: OnTextChanged); + + public static string GetText(BindableObject button) => (string)button.GetValue(TextProperty); + + public static void SetText(BindableObject button, string value) => button.SetValue(TextProperty, value); + + public static void OnTextChanged(BindableObject bindable, object oldValue, object newValue) + { + if (newValue is string text && bindable is Button button) + { + button.Text = text; + } + } + } +} \ No newline at end of file diff --git a/Mobile/NUI/Location/Location/Directory.Build.targets b/Mobile/NUI/Location/Location/Directory.Build.targets new file mode 100644 index 00000000..a468954a --- /dev/null +++ b/Mobile/NUI/Location/Location/Directory.Build.targets @@ -0,0 +1,21 @@ + + + + + + + + $([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory))) + + + + + + diff --git a/Mobile/NUI/Location/Location/Location.cs b/Mobile/NUI/Location/Location/Location.cs new file mode 100644 index 00000000..01eddb3a --- /dev/null +++ b/Mobile/NUI/Location/Location/Location.cs @@ -0,0 +1,38 @@ +using System; +using Tizen.NUI; +using Tizen.NUI.BaseComponents; + +namespace Location +{ + public class Program : NUIApplication + { + protected override void OnCreate() + { + base.OnCreate(); + Window window = Window.Instance; + window.BackgroundColor = Color.Blue; + window.KeyEvent += OnKeyEvent; + + MainPage page = new MainPage(); + page.PositionUsesPivotPoint = true; + page.ParentOrigin = ParentOrigin.Center; + page.PivotPoint = PivotPoint.Center; + page.Size = new Size(window.WindowSize); + window.Add(page); + } + + public void OnKeyEvent(object sender, Window.KeyEventArgs e) + { + if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape")) + { + Exit(); + } + } + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/Mobile/NUI/Location/Location/Location.csproj b/Mobile/NUI/Location/Location/Location.csproj new file mode 100644 index 00000000..a2ec4019 --- /dev/null +++ b/Mobile/NUI/Location/Location/Location.csproj @@ -0,0 +1,33 @@ + + + + Exe + tizen10.0 + + + + portable + + + None + + + + + + + + + MSBuild:Compile + + + + + + + + + True + + + diff --git a/Mobile/NUI/Location/Location/MainPage.xaml.cs b/Mobile/NUI/Location/Location/MainPage.xaml.cs new file mode 100644 index 00000000..1bd649eb --- /dev/null +++ b/Mobile/NUI/Location/Location/MainPage.xaml.cs @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using Tizen.NUI; +using Tizen.NUI.Components; +using Tizen.NUI.BaseComponents; + +namespace Location +{ + public partial class MainPage : ContentPage + { + public MainPage() + { + InitializeComponent(); + } + + /// + /// User needs to implement this, if required + /// + /// dispose type + protected override void Dispose(DisposeTypes type) + { + if (Disposed) + { + return; + } + + ExitXaml(); + + if (type == DisposeTypes.Explicit) + { + //Todo: Called by User + //Release your own managed resources here. + //You should release all of your own disposable objects here. + + } + + //Todo: Release your own unmanaged resources here. + //You should not access any managed member here except static instance. + //because the execution order of Finalizes is non-deterministic. + + + base.Dispose(type); + } + } +} diff --git a/Mobile/NUI/Location/Location/ViewModel/MainPageViewModel.cs b/Mobile/NUI/Location/Location/ViewModel/MainPageViewModel.cs new file mode 100644 index 00000000..bb46f36a --- /dev/null +++ b/Mobile/NUI/Location/Location/ViewModel/MainPageViewModel.cs @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System.ComponentModel; +using System.Runtime.CompilerServices; +using Tizen.NUI.Binding; +using System.Windows.Input; +using Tizen.Location; +using Tizen.Security; +using System; +using System.Linq; + +namespace Location.ViewModel +{ + public class MainPageViewModel : INotifyPropertyChanged + { + /// + /// Locator instance + /// + private static Locator locator; + + /// + /// GpsSatellite instance + /// + private static GpsSatellite satellite; + + /// + /// CircleBoundary instance + /// + private static CircleBoundary circle; + + /// + /// Flag indicating is location is trecked + /// + private static bool isTrack; + private static bool isSatellite; + private static bool isBound; + + private string textStatus; + private string textTrack; + private string textMessage; + private bool startLocationServiceButtonEnabled; + private bool stopLocationServiceButtonEnabled; + private bool satelliteInformationButtonEnabled; + private bool trackTheRouteButtonEnabled; + private bool locationBoundaryButtonEnabled; + private bool getLocationButtonEnabled; + private string trackTheRouteButtonLabel; + private string satelliteInformationButtonLabel; + private string locationBoundaryButtonLabel; + public ICommand StartLocationService { get; private set; } + + public ICommand GetLocation { get; private set; } + + public ICommand TrackTheRoute { get; private set; } + + public ICommand SatelliteInformation { get; private set; } + + public ICommand LocationBoundary { get; private set; } + + public ICommand StopLocationService { get; private set; } + + public MainPageViewModel() + { + locator = null; + satellite = null; + circle = null; + isTrack = false; + isSatellite = false; + isBound = false; + textStatus = "[Status]"; + textTrack = ""; + textMessage = ""; + startLocationServiceButtonEnabled = true; + stopLocationServiceButtonEnabled = false; + satelliteInformationButtonEnabled = false; + trackTheRouteButtonEnabled = false; + locationBoundaryButtonEnabled = false; + getLocationButtonEnabled = false; + trackTheRouteButtonLabel = "Track the route"; + satelliteInformationButtonLabel = "Satellite information"; + locationBoundaryButtonLabel = "Location boundary"; + StartLocationService = new Command(() => ExecuteStartLocationService()); + GetLocation = new Command(() => ExecuteGetLocation()); + TrackTheRoute = new Command(() => ExecuteTrackTheRoute()); + SatelliteInformation = new Command(() => ExecuteSatelliteInformation()); + LocationBoundary = new Command(() => ExecuteLocationBoundary()); + StopLocationService = new Command(() => ExecuteStopLocationService()); + PrivilegeCheck(); + } + + public string TextStatus + { + get => textStatus; + set + { + if (textStatus != value) + { + textStatus = value; + RaisePropertyChanged(); + } + } + } + + public string TextTrack + { + get => textTrack; + set + { + if (textTrack != value) + { + textTrack = value; + RaisePropertyChanged(); + } + } + } + + public string TextMessage + { + get => textMessage; + set + { + if (textMessage != value) + { + textMessage = value; + RaisePropertyChanged(); + } + } + } + + public bool StartLocationServiceButtonEnabled + { + get => startLocationServiceButtonEnabled; + set + { + if (startLocationServiceButtonEnabled != value) + { + startLocationServiceButtonEnabled = value; + RaisePropertyChanged(); + } + } + } + + public bool StopLocationServiceButtonEnabled + { + get => stopLocationServiceButtonEnabled; + set + { + if (stopLocationServiceButtonEnabled != value) + { + stopLocationServiceButtonEnabled = value; + RaisePropertyChanged(); + } + } + } + + public bool SatelliteInformationButtonEnabled + { + get => satelliteInformationButtonEnabled; + set + { + if (satelliteInformationButtonEnabled != value) + { + satelliteInformationButtonEnabled = value; + RaisePropertyChanged(); + } + } + } + + public bool TrackTheRouteButtonEnabled + { + get => trackTheRouteButtonEnabled; + set + { + if (trackTheRouteButtonEnabled != value) + { + trackTheRouteButtonEnabled = value; + RaisePropertyChanged(); + } + } + } + + public bool LocationBoundaryButtonEnabled + { + get => locationBoundaryButtonEnabled; + set + { + if (locationBoundaryButtonEnabled != value) + { + locationBoundaryButtonEnabled = value; + RaisePropertyChanged(); + } + } + } + + public bool GetLocationButtonEnabled + { + get => getLocationButtonEnabled; + set + { + if (getLocationButtonEnabled != value) + { + getLocationButtonEnabled = value; + RaisePropertyChanged(); + } + } + } + + public string TrackTheRouteButtonLabel + { + get => trackTheRouteButtonLabel; + set + { + if (trackTheRouteButtonLabel != value) + { + trackTheRouteButtonLabel = value; + RaisePropertyChanged(); + } + } + } + + public string SatelliteInformationButtonLabel + { + get => satelliteInformationButtonLabel; + set + { + if (satelliteInformationButtonLabel != value) + { + satelliteInformationButtonLabel = value; + RaisePropertyChanged(); + } + } + } + + public string LocationBoundaryButtonLabel + { + get => locationBoundaryButtonLabel; + set + { + if (locationBoundaryButtonLabel != value) + { + locationBoundaryButtonLabel = value; + RaisePropertyChanged(); + } + } + } + + /// + /// Button event to start location service + /// + public void ExecuteStartLocationService() + { + if (locator == null) + { + try + { + /// + /// Create Locator instance, sets LocationType to GPS + /// + /// This method selects the best method available at the moment. + /// This method uses Global Positioning System. + /// This method uses WiFi Positioning System. + /// This method uses passive mode. + locator = new Locator(LocationType.Gps); + + /// Create GpsSatellite instance + satellite = new GpsSatellite(locator); + + if (locator != null) + { + /// Starts the Locator which has been created using the specified method. + locator.Start(); + TextStatus = "[Status] Start location service, GPS searching ..."; + + /// Add ServiceStateChanged event to receive the event regarding service state + locator.ServiceStateChanged += Locator_ServiceStateChanged; + + /// Disable start button to avoid duplicated call. + StartLocationServiceButtonEnabled = false; + + // Enable available buttons + SatelliteInformationButtonEnabled = true; + StopLocationServiceButtonEnabled = true; + } + else + { + /// Locator creation failed + TextStatus = "[Status] Location initialize .. Failed"; + } + } + catch (Exception ex) + { + /// Exception handling + TextStatus = "[Status] Location Initialize : " + ex.Message; + } + } + } + + /// + /// Button event to get current location + /// + public void ExecuteGetLocation() + { + try + { + /// + /// Gets the details of the location. + /// + /// The current latitude [-90.0 ~ 90.0] (degrees). + /// The current longitude [-180.0 ~ 180.0] (degrees). + /// The current altitude (meters). + /// The device speed (km/h). + /// The direction and degrees from the north. + /// The accuracy. + /// The time value when the measurement was done. + Tizen.Location.Location l = locator.GetLocation(); + TextMessage = "[GetLocation]" + "\n Timestamp : " + l.Timestamp + "\n Latitude : " + l.Latitude + "\n Longitude : " + l.Longitude; + } + catch (Exception ex) + { + /// Exception when location service is not available + TextMessage = "[GetLocation]" + "\n Exception : " + ex.Message; + } + } + /// + /// Event : ServiceStateChanged + /// + /// object + /// An enumeration of type LocationServiceState. + private void Locator_ServiceStateChanged(object sender, ServiceStateChangedEventArgs e) + { + /// Service is disabled. + /// Service is enabled. + if (e.ServiceState == ServiceState.Enabled) + { + /// Service state changed to Enabled + TextStatus = "[Status] Location service enabled"; + + /// Update button status + StartLocationServiceButtonEnabled = false; + + /// Enable buttons to show available method + TrackTheRouteButtonEnabled = true; + GetLocationButtonEnabled = true; + LocationBoundaryButtonEnabled = true; + } + else + { + /// Service state changed to Disabled + TextStatus = "[Status] Service disabled, GPS searching ..."; + } + } + + /// + /// Event : LocationChanged + /// + /// object + /// Object of the Location class. + private void Locator_LocationChanged(object sender, LocationChangedEventArgs e) + { + /// LocationChanged event invoked, + /// Available values : Latitude, Longitude, Altitude, Speed, Direction, Accuracy, Timestamp + TextTrack = "[Tracking] " + "\n Latitude : " + e.Location.Latitude + "\n Longitude : " + e.Location.Longitude; + } + + /// + /// Remove LocationChanged event + /// + private void CancelTrack() + { + /// Remove LocationChanged event + locator.LocationChanged -= Locator_LocationChanged; + TrackTheRouteButtonLabel = "Track the route"; + isTrack = false; + } + + /// + /// Button event for location tracking + /// + public void ExecuteTrackTheRoute() + { + if (isTrack == true) + { + CancelTrack(); + TextTrack = ""; + } + else + { + /// Add LocationChanged event + locator.LocationChanged += Locator_LocationChanged; + TrackTheRouteButtonLabel = "Cancel route tracking"; + isTrack = true; + } + } + + /// + /// Event : SatelliteStatusUpdated + /// If InViewCount is bigger than 0, SatelliteInformation is available + /// + /// object + /// SatelliteStatusChangedEventArgs + private void Satellite_SatelliteStatusUpdated(object sender, SatelliteStatusChangedEventArgs e) + { + try + { + /// The number of active satellites. + /// The number of satellites in view. + /// The time at which the data has been extracted. + if (e.InViewCount > 0) + { + /// + /// Satellites returns values + /// ElementAt(0) used to check one of SatelliteInformation + /// + /// The azimuth value of the satellite in degrees. + /// The elevation of the satellite in meters. + /// The PRN value of the satellite. + /// The SNR value of the satellite in dB. + /// The flag signaling if the satellite is in use. + SatelliteInformation s = satellite.Satellites.ElementAt(0); + TextMessage = "[Satellite]" + "\n Timestamp : " + e.Timestamp + "\n Active : " + e.ActiveCount + " , Inview : " + e.InViewCount + "\n azimuth[" + s.Azimuth + "] elevation[" + s.Elevation + "] prn[" + s.Prn + "]\n snr[" + s.Snr + "] active[" + s.Active + "]"; + } + else + { + /// ActiveCount and InViewCount are available when SatelliteSttatusUpdated event invoked. + TextMessage = "[Satellite]" + "\n Timestamp : " + e.Timestamp + "\n Active : " + e.ActiveCount + " , Inview : " + e.InViewCount; + } + } + catch (Exception ex) + { + /// Exception when location service is not available + TextMessage = "[Satellite]\n Exception : " + ex.Message; + } + } + + /// Cancel satellite information + private void CancelSatellite() + { + /// Remove SatelliteStatusUpdated event + satellite.SatelliteStatusUpdated -= Satellite_SatelliteStatusUpdated; + SatelliteInformationButtonLabel = "Satellite information"; + isSatellite = false; + } + + /// + /// Button event to receive satellite information + /// + public void ExecuteSatelliteInformation() + { + if (isSatellite == true) + { + /// Cancel satellite information + CancelSatellite(); + TextMessage = ""; + } + else + { + /// Add SatelliteStatusUpdated event + try + { + satellite.SatelliteStatusUpdated += Satellite_SatelliteStatusUpdated; + SatelliteInformationButtonLabel = "Cancel satellite information"; + isSatellite = true; + } + catch (Exception ex) + { + /// Exception handling + TextMessage = "[Satellite]\n Exception : " + ex.Message; + } + } + } + + /// + /// Event : ZoneChanged + /// + /// object + /// ZoneChangedEventArgs + private void Locator_ZoneChanged(object sender, ZoneChangedEventArgs e) + { + /// An enumeration of type BoundaryState. + /// The latitude value [-90.0 ~ 90.0] (degrees). + /// The longitude value [-180.0 ~ 180.0] (degrees). + /// The altitude value. + /// The timestamp value. + TextMessage = "[Boundary]\n Timestamp : " + e.Timestamp + "\n BoundState : " + e.BoundState + "\n Latitude : " + e.Latitude + "\n Longitude : " + e.Longitude; + } + + /// Cancel boundary + private void CancelBoundary() + { + /// Remove ZoneChanged event + locator.ZoneChanged -= Locator_ZoneChanged; + LocationBoundaryButtonLabel = "Location boundary"; + isBound = false; + + /// RemoveBoundary to remove boundary method + locator.RemoveBoundary(circle); + + /// Dispose to release circle instance. + circle.Dispose(); + circle = null; + } + + /// + /// Button event to set location boundary + /// + public void ExecuteLocationBoundary() + { + /// Set initial position + Coordinate center; + center.Latitude = 10.1234; + center.Longitude = 20.1234; + + /// Set radius value to detect out of boundary + double radius = 50.0; + + try + { + if (isBound == true) + { + /// Cancel boundary + CancelBoundary(); + TextMessage = ""; + } + else + { + LocationBoundaryButtonLabel = "Cancel location boundary"; + isBound = true; + + /// Create circle boundary + /// The coordinates which constitute the center of the circular boundary. + /// The radius value of the circular boundary. + circle = new CircleBoundary(center, radius); + + /// Add circle boundary to detect zone changed + locator.AddBoundary(circle); + + /// Add ZoneChanged event + locator.ZoneChanged += Locator_ZoneChanged; + } + } + catch (Exception ex) + { + /// Exception handling + TextMessage = "[Boundary]\n Exception : " + ex.Message; + } + } + + /// + /// Button event to stop location service + /// + public void ExecuteStopLocationService() + { + try + { + if (circle != null) + { + /// Cancel boundary when stop button clicked + CancelBoundary(); + } + + if (isTrack == true) + { + /// Cancel tracking when stop button clicked + CancelTrack(); + } + + if (isSatellite == true) + { + /// Cancel satellite when stop button clicked + CancelSatellite(); + } + + /// Remove text messages + TextMessage = ""; + TextTrack = ""; + + /// Stop to location service + locator.Stop(); + + /// Dispose to release location resource + locator.Dispose(); + locator = null; + satellite = null; + + /// Enable location button after Stop() method called. + StartLocationServiceButtonEnabled = true; + + /// Disable buttons when location in not available. + TrackTheRouteButtonEnabled = false; + LocationBoundaryButtonEnabled = false; + GetLocationButtonEnabled = false; + SatelliteInformationButtonEnabled = false; + StopLocationServiceButtonEnabled = false; + TextStatus = "[Status] Stop location service"; + } + catch (Exception ex) + { + /// Exception handling + TextMessage = "[Stop]\n Exception : " + ex.Message; + } + } + + /// + /// Permission check + /// + private void PrivilegeCheck() + { + try + { + /// Check location permission + CheckResult result = PrivacyPrivilegeManager.CheckPermission("http://tizen.org/privilege/location"); + + switch (result) + { + case CheckResult.Allow: + break; + case CheckResult.Deny: + break; + case CheckResult.Ask: + /// Request to privacy popup + PrivacyPrivilegeManager.RequestPermission("http://tizen.org/privilege/location"); + break; + } + } + catch (Exception ex) + { + /// Exception handling + TextStatus = "[Status] Privilege : " + ex.Message; + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + private void RaisePropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/Mobile/NUI/Location/Location/res/layout/MainPage.xaml b/Mobile/NUI/Location/Location/res/layout/MainPage.xaml new file mode 100644 index 00000000..24d7279b --- /dev/null +++ b/Mobile/NUI/Location/Location/res/layout/MainPage.xaml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +