Skip to content

Commit

Permalink
feat(sensor_plus): Add support for plateform timestamp
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Now all events have a `DateTime` property `timestamp` as constructor 4th constructor parameter
  • Loading branch information
Ortes committed Jan 9, 2024
1 parent 5e5c9db commit 49f5dfd
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.SystemClock
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.EventChannel.EventSink

Expand All @@ -15,6 +16,8 @@ internal class StreamHandlerImpl(

private var sensor: Sensor? = null

private var timestampMicroAtBoot: Long = System.currentTimeMillis() * 1000 - SystemClock.elapsedRealtimeNanos() / 1000

var samplingPeriod = 200000
set(value) {
field = value
Expand Down Expand Up @@ -64,10 +67,14 @@ internal class StreamHandlerImpl(
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}

override fun onSensorChanged(event: SensorEvent) {
val sensorValues = DoubleArray(event.values.size)
val sensorValues = DoubleArray(event.values.size + 1)
event.values.forEachIndexed { index, value ->
sensorValues[index] = value.toDouble()
}

val timestampMicro = timestampMicroAtBoot + (event.timestamp / 1000)
sensorValues[event.values.size] = timestampMicro.toDouble()

events.success(sensorValues)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public protocol MotionStreamHandler: FlutterStreamHandler {
var samplingPeriod: Int { get set }
}

let timestampMicroAtBoot = (Date().timeIntervalSince1970 - ProcessInfo.processInfo.systemUptime) * 1000000

func _initMotionManager() {
if (_motionManager == nil) {
_motionManager = CMMotionManager()
Expand All @@ -24,14 +26,15 @@ func _initMotionManager() {
}
}

func sendTriplet(x: Float64, y: Float64, z: Float64, sink: @escaping FlutterEventSink) {
func sendFlutter(x: Float64, y: Float64, z: Float64, timestamp: TimeInterval, sink: @escaping FlutterEventSink) {
if _isCleanUp {
return
}
// Even after [detachFromEngineForRegistrar] some events may still be received
// and fired until fully detached.
DispatchQueue.main.async {
let triplet = [x, y, z]
let timestampSince1970Micro = timestampMicroAtBoot + (timestamp * 1000000)
let triplet = [x, y, z, timestampSince1970Micro]
triplet.withUnsafeBufferPointer { buffer in
sink(FlutterStandardTypedData.init(float64: Data(buffer: buffer)))
}
Expand Down Expand Up @@ -67,10 +70,11 @@ class FPPAccelerometerStreamHandlerPlus: NSObject, MotionStreamHandler {
// Multiply by gravity, and adjust sign values to
// align with Android.
let acceleration = data!.acceleration
sendTriplet(
sendFlutter(
x: -acceleration.x * GRAVITY,
y: -acceleration.y * GRAVITY,
z: -acceleration.z * GRAVITY,
timestamp: data!.timestamp,
sink: sink
)
}
Expand Down Expand Up @@ -116,10 +120,11 @@ class FPPUserAccelStreamHandlerPlus: NSObject, MotionStreamHandler {
// Multiply by gravity, and adjust sign values to
// align with Android.
let acceleration = data!.userAcceleration
sendTriplet(
sendFlutter(
x: -acceleration.x * GRAVITY,
y: -acceleration.y * GRAVITY,
z: -acceleration.z * GRAVITY,
timestamp: data!.timestamp,
sink: sink
)
}
Expand Down Expand Up @@ -163,7 +168,13 @@ class FPPGyroscopeStreamHandlerPlus: NSObject, MotionStreamHandler {
return
}
let rotationRate = data!.rotationRate
sendTriplet(x: rotationRate.x, y: rotationRate.y, z: rotationRate.z, sink: sink)
sendFlutter(
x: rotationRate.x,
y: rotationRate.y,
z: rotationRate.z,
timestamp: data!.timestamp,
sink: sink
)
}
return nil
}
Expand Down Expand Up @@ -205,7 +216,13 @@ class FPPMagnetometerStreamHandlerPlus: NSObject, MotionStreamHandler {
return
}
let magneticField = data!.magneticField
sendTriplet(x: magneticField.x, y: magneticField.y, z: magneticField.z, sink: sink)
sendFlutter(
x: magneticField.x,
y: magneticField.y,
z: magneticField.z,
timestamp: data!.timestamp,
sink: sink
)
}
return nil
}
Expand Down
15 changes: 11 additions & 4 deletions packages/sensors_plus/sensors_plus/lib/src/web_sensors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class WebSensorsPlugin extends SensorsPlatform {
accelerometer.x as double,
accelerometer.y as double,
accelerometer.z as double,
DateTime.now(),
),
);
},
Expand All @@ -93,7 +94,8 @@ class WebSensorsPlugin extends SensorsPlatform {
apiName: 'Accelerometer()',
permissionName: 'accelerometer',
onError: () {
_accelerometerStreamController!.add(AccelerometerEvent(0, 0, 0));
_accelerometerStreamController!
.add(AccelerometerEvent(0, 0, 0, DateTime.now()));
},
);
_accelerometerResultStream =
Expand Down Expand Up @@ -131,6 +133,7 @@ class WebSensorsPlugin extends SensorsPlatform {
gyroscope.x as double,
gyroscope.y as double,
gyroscope.z as double,
DateTime.now(),
),
);
},
Expand All @@ -148,7 +151,8 @@ class WebSensorsPlugin extends SensorsPlatform {
apiName: 'Gyroscope()',
permissionName: 'gyroscope',
onError: () {
_gyroscopeEventStreamController!.add(GyroscopeEvent(0, 0, 0));
_gyroscopeEventStreamController!
.add(GyroscopeEvent(0, 0, 0, DateTime.now()));
},
);
_gyroscopeEventResultStream =
Expand Down Expand Up @@ -187,6 +191,7 @@ class WebSensorsPlugin extends SensorsPlatform {
linearAccelerationSensor.x as double,
linearAccelerationSensor.y as double,
linearAccelerationSensor.z as double,
DateTime.now(),
),
);
},
Expand All @@ -205,7 +210,7 @@ class WebSensorsPlugin extends SensorsPlatform {
permissionName: 'accelerometer',
onError: () {
_userAccelerometerStreamController!
.add(UserAccelerometerEvent(0, 0, 0));
.add(UserAccelerometerEvent(0, 0, 0, DateTime.now()));
},
);
_userAccelerometerResultStream =
Expand Down Expand Up @@ -243,6 +248,7 @@ class WebSensorsPlugin extends SensorsPlatform {
magnetometerSensor.x as double,
magnetometerSensor.y as double,
magnetometerSensor.z as double,
DateTime.now(),
),
);
},
Expand All @@ -260,7 +266,8 @@ class WebSensorsPlugin extends SensorsPlatform {
apiName: 'Magnetometer()',
permissionName: 'magnetometer',
onError: () {
_magnetometerStreamController!.add(MagnetometerEvent(0, 0, 0));
_magnetometerStreamController!
.add(MagnetometerEvent(0, 0, 0, DateTime.now()));
},
);
_magnetometerResultStream =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// a particular direction.
class AccelerometerEvent {
/// Constructs an instance with the given [x], [y], and [z] values.
AccelerometerEvent(this.x, this.y, this.z);
AccelerometerEvent(this.x, this.y, this.z, this.timestamp);

/// Acceleration force along the x axis (including gravity) measured in m/s^2.
///
Expand All @@ -30,6 +30,14 @@ class AccelerometerEvent {
/// towards the user and negative mean it is moving away from them.
final double z;

/// timestamp of the event
///
/// This is the timestamp of the event in microseconds, as provided by the
/// underlying platform. For Android, this is the uptimeMillis provided by
/// the SensorEvent. For iOS, this is the timestamp provided by the CMDeviceMotion.
final DateTime timestamp;

@override
String toString() => '[AccelerometerEvent (x: $x, y: $y, z: $z)]';
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// the device in 3D space.
class GyroscopeEvent {
/// Constructs an instance with the given [x], [y], and [z] values.
GyroscopeEvent(this.x, this.y, this.z);
GyroscopeEvent(this.x, this.y, this.z, this.timestamp);

/// Rate of rotation around the x axis measured in rad/s.
///
Expand All @@ -30,6 +30,14 @@ class GyroscopeEvent {
/// on.
final double z;

/// timestamp of the event
///
/// This is the timestamp of the event in microseconds, as provided by the
/// underlying platform. For Android, this is the uptimeMillis provided by
/// the SensorEvent. For iOS, this is the timestamp provided by the CMDeviceMotion.
final DateTime timestamp;

@override
String toString() => '[GyroscopeEvent (x: $x, y: $y, z: $z)]';
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ class MagnetometerEvent {
/// Constructs a new instance with the given [x], [y], and [z] values.
///
/// See [MagnetometerEvent] for more information.
MagnetometerEvent(this.x, this.y, this.z);
MagnetometerEvent(this.x, this.y, this.z, this.timestamp);

/// The ambient magnetic field in this axis surrounding the sensor in
/// microteslas ***μT***.
final double x, y, z;

/// timestamp of the event
///
/// This is the timestamp of the event in microseconds, as provided by the
/// underlying platform. For Android, this is the uptimeMillis provided by
/// the SensorEvent. For iOS, this is the timestamp provided by the CMDeviceMotion.
final DateTime timestamp;

@override
String toString() => '[MagnetometerEvent (x: $x, y: $y, z: $z)]';
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ class MethodChannelSensors extends SensorsPlatform {
.receiveBroadcastStream()
.map((dynamic event) {
final list = event.cast<double>();
return AccelerometerEvent(list[0]!, list[1]!, list[2]!);
return AccelerometerEvent(
list[0]!,
list[1]!,
list[2]!,
DateTime.fromMicrosecondsSinceEpoch(list[3]!.toInt()),
);
});
return _accelerometerEvents!;
}
Expand All @@ -77,7 +82,12 @@ class MethodChannelSensors extends SensorsPlatform {
_gyroscopeEvents ??=
_gyroscopeEventChannel.receiveBroadcastStream().map((dynamic event) {
final list = event.cast<double>();
return GyroscopeEvent(list[0]!, list[1]!, list[2]!);
return GyroscopeEvent(
list[0]!,
list[1]!,
list[2]!,
DateTime.fromMicrosecondsSinceEpoch(list[3]!.toInt()),
);
});
return _gyroscopeEvents!;
}
Expand All @@ -104,7 +114,12 @@ class MethodChannelSensors extends SensorsPlatform {
.receiveBroadcastStream()
.map((dynamic event) {
final list = event.cast<double>();
return UserAccelerometerEvent(list[0]!, list[1]!, list[2]!);
return UserAccelerometerEvent(
list[0]!,
list[1]!,
list[2]!,
DateTime.fromMicrosecondsSinceEpoch(list[3]!.toInt()),
);
});
return _userAccelerometerEvents!;
}
Expand All @@ -129,7 +144,12 @@ class MethodChannelSensors extends SensorsPlatform {
_magnetometerEvents ??=
_magnetometerEventChannel.receiveBroadcastStream().map((dynamic event) {
final list = event.cast<double>();
return MagnetometerEvent(list[0]!, list[1]!, list[2]!);
return MagnetometerEvent(
list[0]!,
list[1]!,
list[2]!,
DateTime.fromMicrosecondsSinceEpoch(list[3]!.toInt()),
);
});
return _magnetometerEvents!;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/// [AccelerometerEvent], this event does not include the effects of gravity.
class UserAccelerometerEvent {
/// Constructs an instance with the given [x], [y], and [z] values.
UserAccelerometerEvent(this.x, this.y, this.z);
UserAccelerometerEvent(this.x, this.y, this.z, this.timestamp);

/// Acceleration force along the x axis (excluding gravity) measured in m/s^2.
///
Expand All @@ -29,6 +29,18 @@ class UserAccelerometerEvent {
/// towards the user and negative mean it is moving away from them.
final double z;

/// timestamp of the event
///
/// This is the timestamp of the event in microseconds, as provided by the
/// underlying platform. For Android, this is the timestamp in the event in
/// nanoseconds from the `android.os.SystemClock.elapsedRealtimeNanos` API,
/// and synchronized with SystemClock.uptimeMillis() to be in the same time.
/// For iOS, this is the TimeInterval in the event synchronized with
/// [NSDate timeIntervalSince1970] to be in the same time.
final DateTime timestamp;

@override
String toString() => '[UserAccelerometerEvent (x: $x, y: $y, z: $z)]';
String toString() =>
'[UserAccelerometerEvent (x: $x, y: $y, z: $z, timestamp: $timestamp)]';
}

0 comments on commit 49f5dfd

Please sign in to comment.