diff --git a/src/Uno.UWP/Devices/Sensors/Helpers/SensorHelpers.iOS.cs b/src/Uno.UWP/Devices/Sensors/Helpers/SensorHelpers.iOS.cs index 756306c1071c..bb19c307fe38 100644 --- a/src/Uno.UWP/Devices/Sensors/Helpers/SensorHelpers.iOS.cs +++ b/src/Uno.UWP/Devices/Sensors/Helpers/SensorHelpers.iOS.cs @@ -6,12 +6,49 @@ namespace Uno.Devices.Sensors.Helpers { internal static class SensorHelpers { + private static readonly DateTimeOffset NSDateConversionStart = + new DateTimeOffset(2001, 1, 1, 0, 0, 0, TimeSpan.Zero); + public static DateTimeOffset TimestampToDateTimeOffset(double timestamp) { var bootTime = NSDate.FromTimeIntervalSinceNow(-NSProcessInfo.ProcessInfo.SystemUptime); var date = (DateTime)bootTime.AddSeconds(timestamp); return new DateTimeOffset(date); } + + public static DateTimeOffset NSDateToDateTimeOffset(NSDate nsDate) + { + if (nsDate == NSDate.DistantPast) + { + return DateTimeOffset.MinValue; + } + else if (nsDate == NSDate.DistantFuture) + { + return DateTimeOffset.MaxValue; + } + + return NSDateConversionStart.AddSeconds( + nsDate.SecondsSinceReferenceDate); + } + + public static NSDate DateTimeOffsetToNSDate(DateTimeOffset dateTimeOffset) + { + if (dateTimeOffset == DateTime.MinValue) + { + return NSDate.DistantPast; + } + else if (dateTimeOffset == DateTime.MaxValue) + { + return NSDate.DistantFuture; + } + + var dateInSecondsFromStart = dateTimeOffset + .ToUniversalTime() + .Subtract(NSDateConversionStart.UtcDateTime); + + return NSDate.FromTimeIntervalSinceReferenceDate( + dateInSecondsFromStart.TotalSeconds); + } } } #endif diff --git a/src/Uno.UWP/Devices/Sensors/Pedometer.cs b/src/Uno.UWP/Devices/Sensors/Pedometer.cs new file mode 100644 index 000000000000..ec8d50ee4f9a --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/Pedometer.cs @@ -0,0 +1,65 @@ +using System; +using System.Threading.Tasks; +using Windows.Foundation; + +namespace Windows.Devices.Sensors +{ + public partial class Pedometer + { + private readonly static object _syncLock = new object(); + + private static Pedometer _instance; + private static bool _initializationAttempted; + + private TypedEventHandler _readingChanged; + + public static IAsyncOperation GetDefaultAsync() + { + if (_initializationAttempted) + { + return Task.FromResult(_instance).AsAsyncOperation(); + } + lock (_syncLock) + { + if (!_initializationAttempted) + { + _instance = TryCreateInstance(); + _initializationAttempted = true; + } + return Task.FromResult(_instance).AsAsyncOperation(); + } + } + + public event TypedEventHandler ReadingChanged + { + add + { + lock (_syncLock) + { + var isFirstSubscriber = _readingChanged == null; + _readingChanged += value; + if (isFirstSubscriber) + { + StartReading(); + } + } + } + remove + { + lock (_syncLock) + { + _readingChanged -= value; + if (_readingChanged == null) + { + StopReading(); + } + } + } + } + + private void OnReadingChanged(PedometerReading reading) + { + _readingChanged?.Invoke(this, new PedometerReadingChangedEventArgs(reading)); + } + } +} diff --git a/src/Uno.UWP/Devices/Sensors/Pedometer.iOS.cs b/src/Uno.UWP/Devices/Sensors/Pedometer.iOS.cs new file mode 100644 index 000000000000..4407cde3d8ed --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/Pedometer.iOS.cs @@ -0,0 +1,77 @@ +#if __IOS__ +using System; +using System.Collections.Generic; +using System.Threading; +using CoreMotion; +using Foundation; +using Uno.Devices.Sensors.Helpers; + +namespace Windows.Devices.Sensors +{ + public partial class Pedometer + { + private readonly CMPedometer _pedometer; + private readonly EventWaitHandle _currentReadingWaiter = + new EventWaitHandle(false, EventResetMode.AutoReset); + + private CMPedometerData _currentData = null; + + private Pedometer(CMPedometer pedometer) + { + _pedometer = pedometer; + } + + public static Pedometer TryCreateInstance() + { + if (CMPedometer.IsStepCountingAvailable) + { + return new Pedometer(new CMPedometer()); + } + return null; + } + + public IReadOnlyDictionary GetCurrentReadings() + { + var readings = new Dictionary(); + _currentData = null; + _pedometer.QueryPedometerData( + NSDate.FromTimeIntervalSince1970(DateTimeOffset.Now.Subtract(DateTimeOffset.Now.TimeOfDay).ToUnixTimeSeconds()), + NSDate.FromTimeIntervalSince1970(DateTimeOffset.Now.ToUnixTimeSeconds()), HandlePedometerData); + _currentReadingWaiter.WaitOne(); + var timeDifferenceInSeconds = TimeSpan.FromSeconds( + _currentData.EndDate.SecondsSinceReferenceDate - + _currentData.StartDate.SecondsSinceReferenceDate); + if (_currentData != null) + { + readings.Add( + PedometerStepKind.Unknown, + new PedometerReading( + _currentData.NumberOfSteps.Int32Value, + timeDifferenceInSeconds, + PedometerStepKind.Unknown, + SensorHelpers.NSDateToDateTimeOffset(_currentData.EndDate))); + } + + return readings; + } + + private void StartReading() + { + _pedometer.StartPedometerUpdates( + SensorHelpers.DateTimeOffsetToNSDate(DateTimeOffset.Now), + HandlePedometerData); + } + + private void StopReading() + { + _pedometer.StopPedometerUpdates(); + } + + private void HandlePedometerData(CMPedometerData data, NSError err) + { + _currentData = data; + _currentReadingWaiter.Set(); + } + } +} +#endif diff --git a/src/Uno.UWP/Devices/Sensors/PedometerReading.cs b/src/Uno.UWP/Devices/Sensors/PedometerReading.cs new file mode 100644 index 000000000000..64c4285fdbc5 --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/PedometerReading.cs @@ -0,0 +1,27 @@ +using System; + +namespace Windows.Devices.Sensors +{ + public partial class PedometerReading + { + internal PedometerReading( + int cumulativeSteps, + TimeSpan cumulativeStepsDuration, + PedometerStepKind stepKind, + DateTimeOffset timestamp) + { + CumulativeSteps = cumulativeSteps; + CumulativeStepsDuration = cumulativeStepsDuration; + StepKind = stepKind; + Timestamp = timestamp; + } + + public int CumulativeSteps { get; } + + public TimeSpan CumulativeStepsDuration { get; } + + public PedometerStepKind StepKind { get; } + + public DateTimeOffset Timestamp { get; } + } +} diff --git a/src/Uno.UWP/Devices/Sensors/PedometerReadingChangedEventArgs.cs b/src/Uno.UWP/Devices/Sensors/PedometerReadingChangedEventArgs.cs new file mode 100644 index 000000000000..d005eb5546b0 --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/PedometerReadingChangedEventArgs.cs @@ -0,0 +1,13 @@ +namespace Windows.Devices.Sensors +{ + public partial class PedometerReadingChangedEventArgs + { + internal PedometerReadingChangedEventArgs( + PedometerReading reading) + { + Reading = reading; + } + + public PedometerReading Reading { get; } + } +} diff --git a/src/Uno.UWP/Devices/Sensors/PedometerStepKind.cs b/src/Uno.UWP/Devices/Sensors/PedometerStepKind.cs new file mode 100644 index 000000000000..94450ec798ed --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/PedometerStepKind.cs @@ -0,0 +1,9 @@ +namespace Windows.Devices.Sensors +{ + public enum PedometerStepKind + { + Unknown, + Walking, + Running, + } +}