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 ddc9a3c
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 24 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
36 changes: 32 additions & 4 deletions packages/sensors_plus/sensors_plus/test/sensors_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ void main() {

test('accelerometerEvents are streamed', () async {
const channelName = 'dev.fluttercommunity.plus/sensors/accelerometer';
const sensorData = <double>[1.0, 2.0, 3.0];
final date = DateTime.now();
final sensorData = <double>[
1.0,
2.0,
3.0,
date.microsecondsSinceEpoch.toDouble(),
];
_initializeFakeMethodChannel('setAccelerationSamplingPeriod');
_initializeFakeSensorChannel(channelName, sensorData);

Expand All @@ -22,11 +28,18 @@ void main() {
expect(event.x, sensorData[0]);
expect(event.y, sensorData[1]);
expect(event.z, sensorData[2]);
expect(event.timestamp, date);
});

test('gyroscopeEvents are streamed', () async {
const channelName = 'dev.fluttercommunity.plus/sensors/gyroscope';
const sensorData = <double>[3.0, 4.0, 5.0];
final date = DateTime.now();
final sensorData = <double>[
3.0,
4.0,
5.0,
date.microsecondsSinceEpoch.toDouble(),
];
_initializeFakeMethodChannel('setGyroscopeSamplingPeriod');
_initializeFakeSensorChannel(channelName, sensorData);

Expand All @@ -35,11 +48,18 @@ void main() {
expect(event.x, sensorData[0]);
expect(event.y, sensorData[1]);
expect(event.z, sensorData[2]);
expect(event.timestamp, date);
});

test('userAccelerometerEvents are streamed', () async {
const channelName = 'dev.fluttercommunity.plus/sensors/user_accel';
const sensorData = <double>[6.0, 7.0, 8.0];
final date = DateTime.now();
final sensorData = <double>[
6.0,
7.0,
8.0,
date.microsecondsSinceEpoch.toDouble(),
];
_initializeFakeMethodChannel('setUserAccelerometerSamplingPeriod');
_initializeFakeSensorChannel(channelName, sensorData);

Expand All @@ -48,11 +68,18 @@ void main() {
expect(event.x, sensorData[0]);
expect(event.y, sensorData[1]);
expect(event.z, sensorData[2]);
expect(event.timestamp, date);
});

test('magnetometerEvents are streamed', () async {
const channelName = 'dev.fluttercommunity.plus/sensors/magnetometer';
const sensorData = <double>[8.0, 9.0, 10.0];
final date = DateTime.now();
final sensorData = <double>[
8.0,
9.0,
10.0,
date.microsecondsSinceEpoch.toDouble(),
];
_initializeFakeMethodChannel('setMagnetometerSamplingPeriod');
_initializeFakeSensorChannel(channelName, sensorData);

Expand All @@ -61,6 +88,7 @@ void main() {
expect(event.x, sensorData[0]);
expect(event.y, sensorData[1]);
expect(event.z, sensorData[2]);
expect(event.timestamp, date);
});
}

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

0 comments on commit ddc9a3c

Please sign in to comment.