| File: Gyroscope\Gyroscope.shared.cs | Web Access |
| Project: src\src\Essentials\src\Essentials.csproj (Microsoft.Maui.Essentials) |
#nullable enable using System; using System.Numerics; using Microsoft.Maui.ApplicationModel; namespace Microsoft.Maui.Devices.Sensors { /// <summary> /// The Gyroscope API lets you monitor the device's gyroscope sensor which is the rotation around the device's three primary axes. /// </summary> public interface IGyroscope { /// <summary> /// Gets a value indicating whether reading the gyroscope is supported on this device. /// </summary> bool IsSupported { get; } /// <summary> /// Gets a value indicating whether the gyroscope is actively being monitored. /// </summary> bool IsMonitoring { get; } /// <summary> /// Start monitoring for changes to the gyroscope. /// </summary> /// <param name="sensorSpeed">The speed to listen for changes.</param> void Start(SensorSpeed sensorSpeed); /// <summary> /// Stop monitoring for changes to the gyroscope. /// </summary> void Stop(); /// <summary> /// Occurs when the gyroscope reading changes. /// </summary> event EventHandler<GyroscopeChangedEventArgs> ReadingChanged; } /// <summary> /// The Gyroscope API lets you monitor the device's gyroscope sensor which is the rotation around the device's three primary axes. /// </summary> public static partial class Gyroscope { /// <summary> /// Occurs when the gyroscope reading changes. /// </summary> public static event EventHandler<GyroscopeChangedEventArgs> ReadingChanged { add => Current.ReadingChanged += value; remove => Current.ReadingChanged -= value; } /// <summary> /// Gets a value indicating whether the gyroscope is actively being monitored. /// </summary> public static bool IsMonitoring => Current.IsMonitoring; /// <summary> /// Gets a value indicating whether reading the gyroscope is supported on this device. /// </summary> public static bool IsSupported => Current.IsSupported; /// <summary> /// Start monitoring for changes to the gyroscope. /// </summary> /// <param name="sensorSpeed">The speed to listen for changes.</param> public static void Start(SensorSpeed sensorSpeed) => Current.Start(sensorSpeed); /// <summary> /// Stop monitoring for changes to the gyroscope. /// </summary> public static void Stop() => Current.Stop(); static IGyroscope Current => Devices.Sensors.Gyroscope.Default; static IGyroscope? defaultImplementation; /// <summary> /// Provides the default implementation for static usage of this API. /// </summary> public static IGyroscope Default => defaultImplementation ??= new GyroscopeImplementation(); internal static void SetDefault(IGyroscope? implementation) => defaultImplementation = implementation; } /// <summary> /// Contains the current axis reading information from the <see cref="IGyroscope.ReadingChanged"/> event. /// </summary> public class GyroscopeChangedEventArgs : EventArgs { /// <summary> /// Initializes a new instance of the <see cref="GyroscopeChangedEventArgs"/> class. /// </summary> /// <param name="reading">The gyroscope data reading.</param> public GyroscopeChangedEventArgs(GyroscopeData reading) => Reading = reading; /// <summary> /// The current values of the gyroscope. /// </summary> public GyroscopeData Reading { get; } } /// <summary> /// Contains the axis readings measured by the device's gyroscope. /// </summary> public readonly struct GyroscopeData : IEquatable<GyroscopeData> { /// <summary> /// Initializes a new instance of the <see cref="GyroscopeData"/> class. /// </summary> /// <param name="x">X axis data.</param> /// <param name="y">Y axis data.</param> /// <param name="z">Z axis data.</param> public GyroscopeData(double x, double y, double z) : this((float)x, (float)y, (float)z) { } /// <summary> /// Initializes a new instance of the <see cref="GyroscopeData"/> class. /// </summary> /// <param name="x">X axis data.</param> /// <param name="y">Y axis data.</param> /// <param name="z">Z axis data.</param> public GyroscopeData(float x, float y, float z) => AngularVelocity = new Vector3(x, y, z); /// <summary> /// Gets the angular velocity vector in radians per second. /// </summary> public Vector3 AngularVelocity { get; } /// <summary> /// Compares the underlying <see cref="GyroscopeData"/> instances. /// </summary> /// <param name="obj">Object to compare with.</param> /// <returns><see langword="true"/> if they are equal, otherwise <see langword="false"/>.</returns> public override bool Equals(object? obj) => (obj is GyroscopeData data) && Equals(data); /// <summary> /// Compares the underlying <see cref="GyroscopeData.AngularVelocity"/> instances. /// </summary> /// <param name="other"><see cref="GyroscopeData"/> object to compare with.</param> /// <returns><see langword="true"/> if they are equal, otherwise <see langword="false"/>.</returns> public bool Equals(GyroscopeData other) => AngularVelocity.Equals(other.AngularVelocity); /// <summary> /// Equality operator for equals. /// </summary> /// <param name="left">Left to compare.</param> /// <param name="right">Right to compare.</param> /// <returns><see langword="true"/> if objects are equal, otherwise <see langword="false"/>.</returns> public static bool operator ==(GyroscopeData left, GyroscopeData right) => left.Equals(right); /// <summary> /// Inequality operator. /// </summary> /// <param name="left">Left to compare.</param> /// <param name="right">Right to compare.</param> /// <returns><see langword="true"/> if objects are not equal, otherwise <see langword="false"/>.</returns> public static bool operator !=(GyroscopeData left, GyroscopeData right) => !left.Equals(right); /// <inheritdoc cref="ValueType.GetHashCode"/> public override int GetHashCode() => AngularVelocity.GetHashCode(); /// <summary> /// Returns a string representation of the current values of <see cref="AngularVelocity"/>. /// </summary> /// <returns>A string representation of this instance in the format of <c>AngularVelocity.X: {value}, AngularVelocity.Y: {value}, AngularVelocity.Z: {value}</c>.</returns> public override string ToString() => $"{nameof(AngularVelocity.X)}: {AngularVelocity.X}, " + $"{nameof(AngularVelocity.Y)}: {AngularVelocity.Y}, " + $"{nameof(AngularVelocity.Z)}: {AngularVelocity.Z}"; } partial class GyroscopeImplementation : IGyroscope { bool UseSyncContext => SensorSpeed == SensorSpeed.Default || SensorSpeed == SensorSpeed.UI; SensorSpeed SensorSpeed { get; set; } = SensorSpeed.Default; public event EventHandler<GyroscopeChangedEventArgs>? ReadingChanged; public bool IsMonitoring { get; private set; } public bool IsSupported => PlatformIsSupported; public void Start(SensorSpeed sensorSpeed) { if (!PlatformIsSupported) throw new FeatureNotSupportedException(); if (IsMonitoring) throw new InvalidOperationException("Gyroscope has already been started."); IsMonitoring = true; try { PlatformStart(sensorSpeed); } catch { IsMonitoring = false; throw; } } public void Stop() { if (!PlatformIsSupported) throw new FeatureNotSupportedException(); if (!IsMonitoring) return; IsMonitoring = false; try { PlatformStop(); } catch { IsMonitoring = true; throw; } } void RaiseReadingChanged(GyroscopeData data) { var args = new GyroscopeChangedEventArgs(data); if (UseSyncContext) MainThread.BeginInvokeOnMainThread(() => ReadingChanged?.Invoke(null, args)); else ReadingChanged?.Invoke(null, args); } } }