diff --git a/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/SensorsPlugin.kt b/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/SensorsPlugin.kt index 85cec3e245..52c4da1890 100644 --- a/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/SensorsPlugin.kt +++ b/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/SensorsPlugin.kt @@ -7,50 +7,78 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.MethodChannel /** SensorsPlugin */ class SensorsPlugin : FlutterPlugin { + private lateinit var methodChannel: MethodChannel + private lateinit var accelerometerChannel: EventChannel private lateinit var userAccelChannel: EventChannel private lateinit var gyroscopeChannel: EventChannel private lateinit var magnetometerChannel: EventChannel - private lateinit var accelerationStreamHandler: StreamHandlerImpl - private lateinit var linearAccelerationStreamHandler: StreamHandlerImpl - private lateinit var gyroScopeStreamHandler: StreamHandlerImpl + private lateinit var accelerometerStreamHandler: StreamHandlerImpl + private lateinit var userAccelStreamHandler: StreamHandlerImpl + private lateinit var gyroscopeStreamHandler: StreamHandlerImpl private lateinit var magnetometerStreamHandler: StreamHandlerImpl override fun onAttachedToEngine(binding: FlutterPluginBinding) { + setupMethodChannel(binding.binaryMessenger) setupEventChannels(binding.applicationContext, binding.binaryMessenger) } override fun onDetachedFromEngine(binding: FlutterPluginBinding) { + teardownMethodChannel() teardownEventChannels() } + private fun setupMethodChannel(messenger: BinaryMessenger) { + methodChannel = MethodChannel(messenger, METHOD_CHANNEL_NAME) + methodChannel.setMethodCallHandler { call, result -> + val streamHandler = when (call.method) { + "setAccelerationSamplingPeriod" -> accelerometerStreamHandler + "setUserAccelerometerSamplingPeriod" -> userAccelStreamHandler + "setGyroscopeSamplingPeriod" -> gyroscopeStreamHandler + "setMagnetometerSamplingPeriod" -> magnetometerStreamHandler + else -> null + } + streamHandler?.samplingPeriod = call.arguments as Int + if (streamHandler != null) { + result.success(null) + } else { + result.notImplemented() + } + } + } + + private fun teardownMethodChannel() { + methodChannel.setMethodCallHandler(null) + } + private fun setupEventChannels(context: Context, messenger: BinaryMessenger) { val sensorsManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager accelerometerChannel = EventChannel(messenger, ACCELEROMETER_CHANNEL_NAME) - accelerationStreamHandler = StreamHandlerImpl( + accelerometerStreamHandler = StreamHandlerImpl( sensorsManager, Sensor.TYPE_ACCELEROMETER ) - accelerometerChannel.setStreamHandler(accelerationStreamHandler) + accelerometerChannel.setStreamHandler(accelerometerStreamHandler) userAccelChannel = EventChannel(messenger, USER_ACCELEROMETER_CHANNEL_NAME) - linearAccelerationStreamHandler = StreamHandlerImpl( + userAccelStreamHandler = StreamHandlerImpl( sensorsManager, Sensor.TYPE_LINEAR_ACCELERATION ) - userAccelChannel.setStreamHandler(linearAccelerationStreamHandler) + userAccelChannel.setStreamHandler(userAccelStreamHandler) gyroscopeChannel = EventChannel(messenger, GYROSCOPE_CHANNEL_NAME) - gyroScopeStreamHandler = StreamHandlerImpl( + gyroscopeStreamHandler = StreamHandlerImpl( sensorsManager, Sensor.TYPE_GYROSCOPE ) - gyroscopeChannel.setStreamHandler(gyroScopeStreamHandler) + gyroscopeChannel.setStreamHandler(gyroscopeStreamHandler) magnetometerChannel = EventChannel(messenger, MAGNETOMETER_CHANNEL_NAME) magnetometerStreamHandler = StreamHandlerImpl( @@ -66,16 +94,19 @@ class SensorsPlugin : FlutterPlugin { gyroscopeChannel.setStreamHandler(null) magnetometerChannel.setStreamHandler(null) - accelerationStreamHandler.onCancel(null) - linearAccelerationStreamHandler.onCancel(null) - gyroScopeStreamHandler.onCancel(null) + accelerometerStreamHandler.onCancel(null) + userAccelStreamHandler.onCancel(null) + gyroscopeStreamHandler.onCancel(null) magnetometerStreamHandler.onCancel(null) } companion object { + private const val METHOD_CHANNEL_NAME = + "dev.fluttercommunity.plus/sensors/method" private const val ACCELEROMETER_CHANNEL_NAME = "dev.fluttercommunity.plus/sensors/accelerometer" - private const val GYROSCOPE_CHANNEL_NAME = "dev.fluttercommunity.plus/sensors/gyroscope" + private const val GYROSCOPE_CHANNEL_NAME = + "dev.fluttercommunity.plus/sensors/gyroscope" private const val USER_ACCELEROMETER_CHANNEL_NAME = "dev.fluttercommunity.plus/sensors/user_accel" private const val MAGNETOMETER_CHANNEL_NAME = diff --git a/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/StreamHandlerImpl.kt b/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/StreamHandlerImpl.kt index ad645ac07d..54669e2b39 100644 --- a/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/StreamHandlerImpl.kt +++ b/packages/sensors_plus/sensors_plus/android/src/main/kotlin/dev/fluttercommunity/plus/sensors/StreamHandlerImpl.kt @@ -15,15 +15,17 @@ internal class StreamHandlerImpl( private var sensor: Sensor? = null + var samplingPeriod = 200000 + set(value) { + field = value + updateRegistration() + } + override fun onListen(arguments: Any?, events: EventSink) { sensor = sensorManager.getDefaultSensor(sensorType) if (sensor != null) { sensorEventListener = createSensorEventListener(events) - sensorManager.registerListener( - sensorEventListener, - sensor, - SensorManager.SENSOR_DELAY_NORMAL - ) + sensorManager.registerListener(sensorEventListener, sensor, samplingPeriod) } else { events.error( "NO_SENSOR", @@ -36,6 +38,14 @@ internal class StreamHandlerImpl( override fun onCancel(arguments: Any?) { if (sensor != null) { sensorManager.unregisterListener(sensorEventListener) + sensorEventListener = null + } + } + + private fun updateRegistration() { + if (sensorEventListener != null) { + sensorManager.unregisterListener(sensorEventListener) + sensorManager.registerListener(sensorEventListener, sensor, samplingPeriod) } } diff --git a/packages/sensors_plus/sensors_plus/example/integration_test/sensors_plus_test.dart b/packages/sensors_plus/sensors_plus/example/integration_test/sensors_plus_test.dart index 33fd4ca165..602a896218 100644 --- a/packages/sensors_plus/sensors_plus/example/integration_test/sensors_plus_test.dart +++ b/packages/sensors_plus/sensors_plus/example/integration_test/sensors_plus_test.dart @@ -15,7 +15,8 @@ void main() { (WidgetTester tester) async { final completer = Completer(); late StreamSubscription subscription; - subscription = accelerometerEvents.listen((AccelerometerEvent event) { + subscription = + accelerometerEventStream().listen((AccelerometerEvent event) { completer.complete(event); subscription.cancel(); }); diff --git a/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/project.pbxproj b/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/project.pbxproj index 7ac2cd026c..8c1e4018bd 100644 --- a/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/project.pbxproj @@ -87,6 +87,13 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 18B7D72A2ABD9B4F006A0D55 /* Recovered References */ = { + isa = PBXGroup; + children = ( + ); + name = "Recovered References"; + sourceTree = ""; + }; 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -105,7 +112,6 @@ 178BE122EE4A7CE24B05D8AC /* Pods-RunnerTests.release.xcconfig */, 101AB93329D02192F269FF15 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -129,6 +135,7 @@ 331C8082294A63A400263BE5 /* RunnerTests */, 9643F7DAEAB1D555F9F2E496 /* Pods */, E9DC5051924EC6D7963378C9 /* Frameworks */, + 18B7D72A2ABD9B4F006A0D55 /* Recovered References */, ); sourceTree = ""; }; @@ -215,7 +222,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { @@ -452,6 +459,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_KEY_NSMotionUsageDescription = ""; IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; @@ -470,6 +478,7 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -490,6 +499,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.sensorsplus.example.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -508,6 +518,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.sensorsplus.example.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -524,6 +535,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.sensorsplus.example.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -579,6 +591,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_KEY_NSMotionUsageDescription = ""; IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -628,6 +641,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_KEY_NSMotionUsageDescription = ""; IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; @@ -648,6 +662,7 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -670,6 +685,7 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e42adcb34c..87131a09be 100644 --- a/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/sensors_plus/sensors_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ { + static const Duration _ignoreDuration = Duration(milliseconds: 20); + static const int _snakeRows = 20; static const int _snakeColumns = 20; static const double _snakeCellSize = 10.0; - List? _userAccelerometerValues; - List? _accelerometerValues; - List? _gyroscopeValues; - List? _magnetometerValues; + UserAccelerometerEvent? _userAccelerometerEvent; + AccelerometerEvent? _accelerometerEvent; + GyroscopeEvent? _gyroscopeEvent; + MagnetometerEvent? _magnetometerEvent; + + DateTime? _userAccelerometerUpdateTime; + DateTime? _accelerometerUpdateTime; + DateTime? _gyroscopeUpdateTime; + DateTime? _magnetometerUpdateTime; + + int? _userAccelerometerLastInterval; + int? _accelerometerLastInterval; + int? _gyroscopeLastInterval; + int? _magnetometerLastInterval; final _streamSubscriptions = >[]; + Duration sensorInterval = SensorInterval.normalInterval; + @override Widget build(BuildContext context) { - final userAccelerometer = _userAccelerometerValues - ?.map((double v) => v.toStringAsFixed(1)) - .toList(); - final accelerometer = - _accelerometerValues?.map((double v) => v.toStringAsFixed(1)).toList(); - final gyroscope = - _gyroscopeValues?.map((double v) => v.toStringAsFixed(1)).toList(); - final magnetometer = - _magnetometerValues?.map((double v) => v.toStringAsFixed(1)).toList(); - return Scaffold( appBar: AppBar( title: const Text('Sensors Plus Example'), @@ -97,40 +101,118 @@ class _MyHomePageState extends State { ), ), Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('UserAccelerometer: $userAccelerometer'), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Accelerometer: $accelerometer'), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Gyroscope: $gyroscope'), + padding: const EdgeInsets.all(20.0), + child: Table( + columnWidths: const { + 0: FlexColumnWidth(4), + 4: FlexColumnWidth(2), + }, + children: [ + const TableRow( + children: [ + SizedBox.shrink(), + Text('X'), + Text('Y'), + Text('Z'), + Text('Interval'), + ], + ), + TableRow( + children: [ + const Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Text('UserAccelerometer'), + ), + Text(_userAccelerometerEvent?.x.toStringAsFixed(1) ?? '?'), + Text(_userAccelerometerEvent?.y.toStringAsFixed(1) ?? '?'), + Text(_userAccelerometerEvent?.z.toStringAsFixed(1) ?? '?'), + Text( + '${_userAccelerometerLastInterval?.toString() ?? '?'} ms'), + ], + ), + TableRow( + children: [ + const Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Text('Accelerometer'), + ), + Text(_accelerometerEvent?.x.toStringAsFixed(1) ?? '?'), + Text(_accelerometerEvent?.y.toStringAsFixed(1) ?? '?'), + Text(_accelerometerEvent?.z.toStringAsFixed(1) ?? '?'), + Text('${_accelerometerLastInterval?.toString() ?? '?'} ms'), + ], + ), + TableRow( + children: [ + const Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Text('Gyroscope'), + ), + Text(_gyroscopeEvent?.x.toStringAsFixed(1) ?? '?'), + Text(_gyroscopeEvent?.y.toStringAsFixed(1) ?? '?'), + Text(_gyroscopeEvent?.z.toStringAsFixed(1) ?? '?'), + Text('${_gyroscopeLastInterval?.toString() ?? '?'} ms'), + ], + ), + TableRow( + children: [ + const Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Text('Magnetometer'), + ), + Text(_magnetometerEvent?.x.toStringAsFixed(1) ?? '?'), + Text(_magnetometerEvent?.y.toStringAsFixed(1) ?? '?'), + Text(_magnetometerEvent?.z.toStringAsFixed(1) ?? '?'), + Text('${_magnetometerLastInterval?.toString() ?? '?'} ms'), + ], + ), ], ), ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Magnetometer: $magnetometer'), - ], - ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text('Update Interval:'), + SegmentedButton( + segments: [ + ButtonSegment( + value: SensorInterval.gameInterval, + label: Text('Game\n' + '(${SensorInterval.gameInterval.inMilliseconds}ms)'), + ), + ButtonSegment( + value: SensorInterval.uiInterval, + label: Text('UI\n' + '(${SensorInterval.uiInterval.inMilliseconds}ms)'), + ), + ButtonSegment( + value: SensorInterval.normalInterval, + label: Text('Normal\n' + '(${SensorInterval.normalInterval.inMilliseconds}ms)'), + ), + const ButtonSegment( + value: Duration(milliseconds: 500), + label: Text('500ms'), + ), + const ButtonSegment( + value: Duration(seconds: 1), + label: Text('1s'), + ), + ], + selected: {sensorInterval}, + showSelectedIcon: false, + onSelectionChanged: (value) { + setState(() { + sensorInterval = value.first; + userAccelerometerEventStream( + samplingPeriod: sensorInterval); + accelerometerEventStream(samplingPeriod: sensorInterval); + gyroscopeEventStream(samplingPeriod: sensorInterval); + magnetometerEventStream(samplingPeriod: sensorInterval); + }); + }, + ), + ], ), ], ), @@ -149,11 +231,19 @@ class _MyHomePageState extends State { void initState() { super.initState(); _streamSubscriptions.add( - userAccelerometerEvents.listen( + userAccelerometerEventStream(samplingPeriod: sensorInterval).listen( (UserAccelerometerEvent event) { + final now = DateTime.now(); setState(() { - _userAccelerometerValues = [event.x, event.y, event.z]; + _userAccelerometerEvent = event; + if (_userAccelerometerUpdateTime != null) { + final interval = now.difference(_userAccelerometerUpdateTime!); + if (interval > _ignoreDuration) { + _userAccelerometerLastInterval = interval.inMilliseconds; + } + } }); + _userAccelerometerUpdateTime = now; }, onError: (e) { showDialog( @@ -162,7 +252,7 @@ class _MyHomePageState extends State { return const AlertDialog( title: Text("Sensor Not Found"), content: Text( - "It seems that your device doesn't support Accelerometer Sensor"), + "It seems that your device doesn't support User Accelerometer Sensor"), ); }); }, @@ -170,11 +260,19 @@ class _MyHomePageState extends State { ), ); _streamSubscriptions.add( - accelerometerEvents.listen( + accelerometerEventStream(samplingPeriod: sensorInterval).listen( (AccelerometerEvent event) { + final now = DateTime.now(); setState(() { - _accelerometerValues = [event.x, event.y, event.z]; + _accelerometerEvent = event; + if (_accelerometerUpdateTime != null) { + final interval = now.difference(_accelerometerUpdateTime!); + if (interval > _ignoreDuration) { + _accelerometerLastInterval = interval.inMilliseconds; + } + } }); + _accelerometerUpdateTime = now; }, onError: (e) { showDialog( @@ -183,7 +281,7 @@ class _MyHomePageState extends State { return const AlertDialog( title: Text("Sensor Not Found"), content: Text( - "It seems that your device doesn't support Gyroscope Sensor"), + "It seems that your device doesn't support Accelerometer Sensor"), ); }); }, @@ -191,11 +289,19 @@ class _MyHomePageState extends State { ), ); _streamSubscriptions.add( - gyroscopeEvents.listen( + gyroscopeEventStream(samplingPeriod: sensorInterval).listen( (GyroscopeEvent event) { + final now = DateTime.now(); setState(() { - _gyroscopeValues = [event.x, event.y, event.z]; + _gyroscopeEvent = event; + if (_gyroscopeUpdateTime != null) { + final interval = now.difference(_gyroscopeUpdateTime!); + if (interval > _ignoreDuration) { + _gyroscopeLastInterval = interval.inMilliseconds; + } + } }); + _gyroscopeUpdateTime = now; }, onError: (e) { showDialog( @@ -204,7 +310,7 @@ class _MyHomePageState extends State { return const AlertDialog( title: Text("Sensor Not Found"), content: Text( - "It seems that your device doesn't support User Accelerometer Sensor"), + "It seems that your device doesn't support Gyroscope Sensor"), ); }); }, @@ -212,11 +318,19 @@ class _MyHomePageState extends State { ), ); _streamSubscriptions.add( - magnetometerEvents.listen( + magnetometerEventStream(samplingPeriod: sensorInterval).listen( (MagnetometerEvent event) { + final now = DateTime.now(); setState(() { - _magnetometerValues = [event.x, event.y, event.z]; + _magnetometerEvent = event; + if (_magnetometerUpdateTime != null) { + final interval = now.difference(_magnetometerUpdateTime!); + if (interval > _ignoreDuration) { + _magnetometerLastInterval = interval.inMilliseconds; + } + } }); + _magnetometerUpdateTime = now; }, onError: (e) { showDialog( diff --git a/packages/sensors_plus/sensors_plus/example/lib/snake.dart b/packages/sensors_plus/sensors_plus/example/lib/snake.dart index 0b4d18b66b..dfb677a502 100644 --- a/packages/sensors_plus/sensors_plus/example/lib/snake.dart +++ b/packages/sensors_plus/sensors_plus/example/lib/snake.dart @@ -84,7 +84,7 @@ class SnakeState extends State { void initState() { super.initState(); _streamSubscription = - accelerometerEvents.listen((AccelerometerEvent event) { + accelerometerEventStream().listen((AccelerometerEvent event) { setState(() { acceleration = event; }); diff --git a/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.h b/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.h deleted file mode 100644 index 357a2cd18e..0000000000 --- a/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import - -@interface FPPSensorsPlusPlugin : NSObject -@end - -@interface FPPUserAccelStreamHandlerPlus : NSObject -@end - -@interface FPPAccelerometerStreamHandlerPlus : NSObject -@end - -@interface FPPGyroscopeStreamHandlerPlus : NSObject -@end - -@interface FPPMagnetometerStreamHandlerPlus : NSObject -@end diff --git a/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.m b/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.m deleted file mode 100644 index efb4adbbb7..0000000000 --- a/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.m +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "FPPSensorsPlusPlugin.h" -#import - -@implementation FPPSensorsPlusPlugin - -NSMutableDictionary *_eventChannels; -NSMutableDictionary *> - *_streamHandlers; -BOOL _isCleanUp = NO; - -+ (void)registerWithRegistrar:(NSObject *)registrar { - _eventChannels = [NSMutableDictionary dictionary]; - _streamHandlers = [NSMutableDictionary dictionary]; - - FPPAccelerometerStreamHandlerPlus *accelerometerStreamHandler = - [[FPPAccelerometerStreamHandlerPlus alloc] init]; - NSString *accelerometerStreamHandlerName = - @"dev.fluttercommunity.plus/sensors/accelerometer"; - FlutterEventChannel *accelerometerChannel = - [FlutterEventChannel eventChannelWithName:accelerometerStreamHandlerName - binaryMessenger:[registrar messenger]]; - [accelerometerChannel setStreamHandler:accelerometerStreamHandler]; - [_eventChannels setObject:accelerometerChannel - forKey:accelerometerStreamHandlerName]; - [_streamHandlers setObject:accelerometerStreamHandler - forKey:accelerometerStreamHandlerName]; - - FPPUserAccelStreamHandlerPlus *userAccelerometerStreamHandler = - [[FPPUserAccelStreamHandlerPlus alloc] init]; - NSString *userAccelerometerStreamHandlerName = - @"dev.fluttercommunity.plus/sensors/user_accel"; - FlutterEventChannel *userAccelerometerChannel = [FlutterEventChannel - eventChannelWithName:userAccelerometerStreamHandlerName - binaryMessenger:[registrar messenger]]; - [userAccelerometerChannel setStreamHandler:userAccelerometerStreamHandler]; - [_eventChannels setObject:userAccelerometerChannel - forKey:userAccelerometerStreamHandlerName]; - [_streamHandlers setObject:userAccelerometerStreamHandler - forKey:userAccelerometerStreamHandlerName]; - - FPPGyroscopeStreamHandlerPlus *gyroscopeStreamHandler = - [[FPPGyroscopeStreamHandlerPlus alloc] init]; - NSString *gyroscopeStreamHandlerName = - @"dev.fluttercommunity.plus/sensors/gyroscope"; - FlutterEventChannel *gyroscopeChannel = - [FlutterEventChannel eventChannelWithName:gyroscopeStreamHandlerName - binaryMessenger:[registrar messenger]]; - [gyroscopeChannel setStreamHandler:gyroscopeStreamHandler]; - [_eventChannels setObject:gyroscopeChannel forKey:gyroscopeStreamHandlerName]; - [_streamHandlers setObject:gyroscopeStreamHandler - forKey:gyroscopeStreamHandlerName]; - - FPPMagnetometerStreamHandlerPlus *magnetometerStreamHandler = - [[FPPMagnetometerStreamHandlerPlus alloc] init]; - NSString *magnetometerStreamHandlerName = - @"dev.fluttercommunity.plus/sensors/magnetometer"; - FlutterEventChannel *magnetometerChannel = - [FlutterEventChannel eventChannelWithName:magnetometerStreamHandlerName - binaryMessenger:[registrar messenger]]; - [magnetometerChannel setStreamHandler:magnetometerStreamHandler]; - [_eventChannels setObject:magnetometerChannel - forKey:magnetometerStreamHandlerName]; - [_streamHandlers setObject:magnetometerStreamHandler - forKey:magnetometerStreamHandlerName]; - - _isCleanUp = NO; -} - -- (void)detachFromEngineForRegistrar: - (NSObject *)registrar { - _cleanUp(); -} - -static void _cleanUp(void) { - _isCleanUp = YES; - for (FlutterEventChannel *channel in _eventChannels.allValues) { - [channel setStreamHandler:nil]; - } - [_eventChannels removeAllObjects]; - for (NSObject *handler in _streamHandlers.allValues) { - [handler onCancelWithArguments:nil]; - } - [_streamHandlers removeAllObjects]; -} - -@end - -const double GRAVITY = 9.81; -CMMotionManager *_motionManager; - -void _initMotionManager(void) { - if (!_motionManager) { - _motionManager = [[CMMotionManager alloc] init]; - } -} - -static void sendTriplet(Float64 x, Float64 y, Float64 z, - FlutterEventSink sink) { - if (_isCleanUp) { - return; - } - // Even after [detachFromEngineForRegistrar] some events may still be received - // and fired until fully detached. - @try { - NSMutableData *event = [NSMutableData dataWithCapacity:3 * sizeof(Float64)]; - [event appendBytes:&x length:sizeof(Float64)]; - [event appendBytes:&y length:sizeof(Float64)]; - [event appendBytes:&z length:sizeof(Float64)]; - - sink([FlutterStandardTypedData typedDataWithFloat64:event]); - } @catch (NSException *e) { - NSLog(@"Error: %@ %@", e, [e userInfo]); - } @finally { - } -} - -@implementation FPPAccelerometerStreamHandlerPlus - -- (FlutterError *)onListenWithArguments:(id)arguments - eventSink:(FlutterEventSink)eventSink { - _initMotionManager(); - [_motionManager - startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init] - withHandler:^(CMAccelerometerData *accelerometerData, - NSError *error) { - if (_isCleanUp) { - return; - } - if (error) { - eventSink([FlutterError - errorWithCode:@"UNAVAILABLE" - message:[error localizedDescription] - details:nil]); - return; - } - // Multiply by gravity, and adjust sign values to - // align with Android. - CMAcceleration acceleration = - accelerometerData.acceleration; - sendTriplet(-acceleration.x * GRAVITY, - -acceleration.y * GRAVITY, - -acceleration.z * GRAVITY, eventSink); - }]; - return nil; -} - -- (FlutterError *)onCancelWithArguments:(id)arguments { - [_motionManager stopAccelerometerUpdates]; - return nil; -} - -- (void)dealloc { - _cleanUp(); -} - -@end - -@implementation FPPUserAccelStreamHandlerPlus - -- (FlutterError *)onListenWithArguments:(id)arguments - eventSink:(FlutterEventSink)eventSink { - _initMotionManager(); - [_motionManager - startDeviceMotionUpdatesToQueue:[[NSOperationQueue alloc] init] - withHandler:^(CMDeviceMotion *data, NSError *error) { - if (_isCleanUp) { - return; - } - if (error) { - eventSink([FlutterError - errorWithCode:@"UNAVAILABLE" - message:[error localizedDescription] - details:nil]); - return; - } - // Multiply by gravity, and adjust sign values to - // align with Android. - CMAcceleration acceleration = data.userAcceleration; - sendTriplet(-acceleration.x * GRAVITY, - -acceleration.y * GRAVITY, - -acceleration.z * GRAVITY, eventSink); - }]; - return nil; -} - -- (FlutterError *)onCancelWithArguments:(id)arguments { - [_motionManager stopDeviceMotionUpdates]; - return nil; -} - -- (void)dealloc { - _cleanUp(); -} - -@end - -@implementation FPPGyroscopeStreamHandlerPlus - -- (FlutterError *)onListenWithArguments:(id)arguments - eventSink:(FlutterEventSink)eventSink { - _initMotionManager(); - [_motionManager - startGyroUpdatesToQueue:[[NSOperationQueue alloc] init] - withHandler:^(CMGyroData *gyroData, NSError *error) { - if (_isCleanUp) { - return; - } - if (error) { - eventSink([FlutterError - errorWithCode:@"UNAVAILABLE" - message:[error localizedDescription] - details:nil]); - return; - } - CMRotationRate rotationRate = gyroData.rotationRate; - sendTriplet(rotationRate.x, rotationRate.y, rotationRate.z, - eventSink); - }]; - return nil; -} - -- (FlutterError *)onCancelWithArguments:(id)arguments { - [_motionManager stopGyroUpdates]; - return nil; -} - -- (void)dealloc { - _cleanUp(); -} - -@end - -@implementation FPPMagnetometerStreamHandlerPlus - -- (FlutterError *)onListenWithArguments:(id)arguments - eventSink:(FlutterEventSink)eventSink { - _initMotionManager(); - // Allow iOS to present calibration interaction. - _motionManager.showsDeviceMovementDisplay = YES; - [_motionManager - startDeviceMotionUpdatesUsingReferenceFrame: - // https://developer.apple.com/documentation/coremotion/cmattitudereferenceframe?language=objc - // "Using this reference frame may require device movement to - // calibrate the magnetometer," which is desired to ensure the - // DeviceMotion actually has updated, calibrated geomagnetic data. - CMAttitudeReferenceFrameXMagneticNorthZVertical - toQueue:[[NSOperationQueue alloc] - init] - withHandler:^(CMDeviceMotion *motionData, - NSError *error) { - if (_isCleanUp) { - return; - } - if (error) { - eventSink([FlutterError - errorWithCode:@"UNAVAILABLE" - message: - [error - localizedDescription] - details:nil]); - return; - } - // The `magneticField` is a - // CMCalibratedMagneticField. - CMMagneticField b = - motionData.magneticField.field; - sendTriplet(b.x, b.y, b.z, eventSink); - }]; - return nil; -} - -- (FlutterError *)onCancelWithArguments:(id)arguments { - [_motionManager stopDeviceMotionUpdates]; - return nil; -} - -- (void)dealloc { - _cleanUp(); -} - -@end diff --git a/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift b/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift new file mode 100644 index 0000000000..a31e1ec9f3 --- /dev/null +++ b/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift @@ -0,0 +1,94 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter + +var _eventChannels: [String: FlutterEventChannel] = [:] +var _streamHandlers: [String: MotionStreamHandler] = [:] +var _isCleanUp = false + +public class FPPSensorsPlusPlugin: NSObject, FlutterPlugin { + + public static func register(with registrar: FlutterPluginRegistrar) { + let accelerometerStreamHandler = FPPAccelerometerStreamHandlerPlus() + let accelerometerStreamHandlerName = "dev.fluttercommunity.plus/sensors/accelerometer" + let accelerometerChannel = FlutterEventChannel( + name: accelerometerStreamHandlerName, + binaryMessenger: registrar.messenger() + ) + accelerometerChannel.setStreamHandler(accelerometerStreamHandler) + _eventChannels[accelerometerStreamHandlerName] = accelerometerChannel + _streamHandlers[accelerometerStreamHandlerName] = accelerometerStreamHandler + + let userAccelerometerStreamHandler = FPPUserAccelStreamHandlerPlus() + let userAccelerometerStreamHandlerName = "dev.fluttercommunity.plus/sensors/user_accel" + let userAccelerometerChannel = FlutterEventChannel( + name: userAccelerometerStreamHandlerName, + binaryMessenger: registrar.messenger() + ) + userAccelerometerChannel.setStreamHandler(userAccelerometerStreamHandler) + _eventChannels[userAccelerometerStreamHandlerName] = userAccelerometerChannel + _streamHandlers[userAccelerometerStreamHandlerName] = userAccelerometerStreamHandler + + let gyroscopeStreamHandler = FPPGyroscopeStreamHandlerPlus() + let gyroscopeStreamHandlerName = "dev.fluttercommunity.plus/sensors/gyroscope" + let gyroscopeChannel = FlutterEventChannel( + name: gyroscopeStreamHandlerName, + binaryMessenger: registrar.messenger() + ) + gyroscopeChannel.setStreamHandler(gyroscopeStreamHandler) + _eventChannels[gyroscopeStreamHandlerName] = gyroscopeChannel + _streamHandlers[gyroscopeStreamHandlerName] = gyroscopeStreamHandler + + let magnetometerStreamHandler = FPPMagnetometerStreamHandlerPlus() + let magnetometerStreamHandlerName = "dev.fluttercommunity.plus/sensors/magnetometer" + let magnetometerChannel = FlutterEventChannel( + name: magnetometerStreamHandlerName, + binaryMessenger: registrar.messenger() + ) + magnetometerChannel.setStreamHandler(magnetometerStreamHandler) + _eventChannels[magnetometerStreamHandlerName] = magnetometerChannel + _streamHandlers[magnetometerStreamHandlerName] = magnetometerStreamHandler + + let methodChannel = FlutterMethodChannel( + name: "dev.fluttercommunity.plus/sensors/method", + binaryMessenger: registrar.messenger() + ) + methodChannel.setMethodCallHandler { call, result in + let streamHandler: MotionStreamHandler!; + switch (call.method) { + case "setAccelerationSamplingPeriod": + streamHandler = _streamHandlers[accelerometerStreamHandlerName] + case "setUserAccelerometerSamplingPeriod": + streamHandler = _streamHandlers[userAccelerometerStreamHandlerName] + case "setGyroscopeSamplingPeriod": + streamHandler = _streamHandlers[gyroscopeStreamHandlerName] + case "setMagnetometerSamplingPeriod": + streamHandler = _streamHandlers[magnetometerStreamHandlerName] + default: + return result(FlutterMethodNotImplemented) + } + streamHandler.samplingPeriod = call.arguments as! Int + result(nil) + } + + _isCleanUp = false + } + + func detachFromEngineForRegistrar(registrar: NSObject!) { + FPPSensorsPlusPlugin._cleanUp() + } + + static func _cleanUp() { + _isCleanUp = true + for channel in _eventChannels.values { + channel.setStreamHandler(nil) + } + _eventChannels.removeAll() + for handler in _streamHandlers.values { + handler.onCancel(withArguments: nil) + } + _streamHandlers.removeAll() + } +} diff --git a/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift b/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift new file mode 100644 index 0000000000..6bf127ac80 --- /dev/null +++ b/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift @@ -0,0 +1,232 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Foundation +import Flutter +import UIKit +import CoreMotion + +let GRAVITY = 9.81 +var _motionManager: CMMotionManager! + +public protocol MotionStreamHandler: FlutterStreamHandler { + var samplingPeriod: Int { get set } +} + +func _initMotionManager() { + if (_motionManager == nil) { + _motionManager = CMMotionManager() + _motionManager.accelerometerUpdateInterval = 0.2 + _motionManager.deviceMotionUpdateInterval = 0.2 + _motionManager.gyroUpdateInterval = 0.2 + _motionManager.magnetometerUpdateInterval = 0.2 + } +} + +func sendTriplet(x: Float64, y: Float64, z: Float64, 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] + triplet.withUnsafeBufferPointer { buffer in + sink(FlutterStandardTypedData.init(float64: Data(buffer: buffer))) + } + } +} + +class FPPAccelerometerStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.accelerometerUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } + + func onListen( + withArguments arguments: Any?, + eventSink sink: @escaping FlutterEventSink + ) -> FlutterError? { + _initMotionManager() + _motionManager.startAccelerometerUpdates(to: OperationQueue()) { data, error in + if _isCleanUp { + return + } + if (error != nil) { + sink(FlutterError.init( + code: "UNAVAILABLE", + message: error!.localizedDescription, + details: nil + )) + return + } + // Multiply by gravity, and adjust sign values to + // align with Android. + let acceleration = data!.acceleration + sendTriplet( + x: -acceleration.x * GRAVITY, + y: -acceleration.y * GRAVITY, + z: -acceleration.z * GRAVITY, + sink: sink + ) + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + _motionManager.stopAccelerometerUpdates() + return nil + } + + func dealloc() { + FPPSensorsPlusPlugin._cleanUp() + } +} + +class FPPUserAccelStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.deviceMotionUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } + + func onListen( + withArguments arguments: Any?, + eventSink sink: @escaping FlutterEventSink + ) -> FlutterError? { + _initMotionManager() + _motionManager.startDeviceMotionUpdates(to: OperationQueue()) { data, error in + if _isCleanUp { + return + } + if (error != nil) { + sink(FlutterError.init( + code: "UNAVAILABLE", + message: error!.localizedDescription, + details: nil + )) + return + } + // Multiply by gravity, and adjust sign values to + // align with Android. + let acceleration = data!.userAcceleration + sendTriplet( + x: -acceleration.x * GRAVITY, + y: -acceleration.y * GRAVITY, + z: -acceleration.z * GRAVITY, + sink: sink + ) + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + _motionManager.stopDeviceMotionUpdates() + return nil + } + + func dealloc() { + FPPSensorsPlusPlugin._cleanUp() + } +} + +class FPPGyroscopeStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.gyroUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } + + func onListen( + withArguments arguments: Any?, + eventSink sink: @escaping FlutterEventSink + ) -> FlutterError? { + _initMotionManager() + _motionManager.startGyroUpdates(to: OperationQueue()) { data, error in + if _isCleanUp { + return + } + if (error != nil) { + sink(FlutterError( + code: "UNAVAILABLE", + message: error!.localizedDescription, + details: nil + )) + return + } + let rotationRate = data!.rotationRate + sendTriplet(x: rotationRate.x, y: rotationRate.y, z: rotationRate.z, sink: sink) + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + _motionManager.stopGyroUpdates() + return nil + } + + func dealloc() { + FPPSensorsPlusPlugin._cleanUp() + } +} + +class FPPMagnetometerStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.deviceMotionUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } + + func onListen( + withArguments arguments: Any?, + eventSink sink: @escaping FlutterEventSink + ) -> FlutterError? { + _initMotionManager() + // Allow iOS to present calibration interaction. + _motionManager.showsDeviceMovementDisplay = true + _motionManager.startDeviceMotionUpdates( + // https://developer.apple.com/documentation/coremotion/cmattitudereferenceframe?language=objc + // "Using this reference frame may require device movement to + // calibrate the magnetometer," which is desired to ensure the + // DeviceMotion actually has updated, calibrated geomagnetic data. + using: CMAttitudeReferenceFrame.xMagneticNorthZVertical, + to: OperationQueue() + ) { data, error in + if _isCleanUp { + return + } + if (error != nil) { + sink(FlutterError( + code: "UNAVAILABLE", + message: error!.localizedDescription, + details: nil + )) + return + } + // The `magneticField` is a + // CMCalibratedMagneticField. + let magneticField = data!.magneticField.field + sendTriplet(x: magneticField.x, y: magneticField.y, z: magneticField.z, sink: sink) + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + _motionManager.stopDeviceMotionUpdates() + return nil + } + + func dealloc() { + FPPSensorsPlusPlugin._cleanUp() + } +} diff --git a/packages/sensors_plus/sensors_plus/ios/sensors_plus.podspec b/packages/sensors_plus/sensors_plus/ios/sensors_plus.podspec index 6b589cfdab..60e999c9f2 100644 --- a/packages/sensors_plus/sensors_plus/ios/sensors_plus.podspec +++ b/packages/sensors_plus/sensors_plus/ios/sensors_plus.podspec @@ -1,5 +1,6 @@ # -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint sensors_plus.podspec` to validate before publishing. # Pod::Spec.new do |s| s.name = 'sensors_plus' @@ -14,9 +15,10 @@ Flutter plugin to access the accelerometer, gyroscope, and magnetometer sensors. s.source = { :http => 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/sensors_plus' } s.documentation_url = 'https://pub.dev/packages/sensors_plus' s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' - s.platform = :ios, '11.0' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' end diff --git a/packages/sensors_plus/sensors_plus/lib/sensors_plus.dart b/packages/sensors_plus/sensors_plus/lib/sensors_plus.dart index 61e492fc4d..e6a29301a4 100644 --- a/packages/sensors_plus/sensors_plus/lib/sensors_plus.dart +++ b/packages/sensors_plus/sensors_plus/lib/sensors_plus.dart @@ -9,21 +9,61 @@ export 'src/sensors.dart' if (dart.library.html) 'src/sensors_plus_web.dart'; final _sensors = Sensors(); /// A broadcast stream of events from the device accelerometer. +@Deprecated('Use accelerometerEventStream() instead.') Stream get accelerometerEvents { return _sensors.accelerometerEvents; } /// A broadcast stream of events from the device gyroscope. +@Deprecated('Use gyroscopeEventStream() instead.') Stream get gyroscopeEvents { return _sensors.gyroscopeEvents; } /// Events from the device accelerometer with gravity removed. +@Deprecated('Use userAccelerometerEventStream() instead.') Stream get userAccelerometerEvents { return _sensors.userAccelerometerEvents; } /// A broadcast stream of events from the device magnetometer. +@Deprecated('Use magnetometerEventStream() instead.') Stream get magnetometerEvents { return _sensors.magnetometerEvents; } + +/// Returns a broadcast stream of events from the device accelerometer at the +/// given sampling frequency. +@override +Stream accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.accelerometerEventStream(samplingPeriod: samplingPeriod); +} + +/// Returns a broadcast stream of events from the device gyroscope at the +/// given sampling frequency. +@override +Stream gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.gyroscopeEventStream(samplingPeriod: samplingPeriod); +} + +/// Returns a broadcast stream of events from the device accelerometer with +/// gravity removed at the given sampling frequency. +@override +Stream userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.userAccelerometerEventStream(samplingPeriod: samplingPeriod); +} + +/// Returns a broadcast stream of events from the device magnetometer at the +/// given sampling frequency. +@override +Stream magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.magnetometerEventStream(samplingPeriod: samplingPeriod); +} diff --git a/packages/sensors_plus/sensors_plus/lib/src/sensors.dart b/packages/sensors_plus/sensors_plus/lib/src/sensors.dart index 59ac78cb8f..520d0b4f4f 100644 --- a/packages/sensors_plus/sensors_plus/lib/src/sensors.dart +++ b/packages/sensors_plus/sensors_plus/lib/src/sensors.dart @@ -13,27 +13,56 @@ class Sensors extends SensorsPlatform { static SensorsPlatform get _platform => SensorsPlatform.instance; - /// A broadcast stream of events from the device accelerometer. + /// Returns a broadcast stream of events from the device accelerometer at the + /// given sampling frequency. + /// + /// This method always returning the same stream. If this method is called + /// again, the sampling period of the stream will be update. All previous + /// listener will also be affected. @override - Stream get accelerometerEvents { - return _platform.accelerometerEvents; + Stream accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + return _platform.accelerometerEventStream(samplingPeriod: samplingPeriod); } - /// A broadcast stream of events from the device gyroscope. + /// Returns a broadcast stream of events from the device gyroscope at the + /// given sampling frequency. + /// + /// This method always returning the same stream. If this method is called + /// again, the sampling period of the stream will be update. All previous + /// listener will also be affected. @override - Stream get gyroscopeEvents { - return _platform.gyroscopeEvents; + Stream gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + return _platform.gyroscopeEventStream(samplingPeriod: samplingPeriod); } - /// Events from the device accelerometer with gravity removed. + /// Returns a broadcast stream of events from the device accelerometer with + /// gravity removed at the given sampling frequency. + /// + /// This method always returning the same stream. If this method is called + /// again, the sampling period of the stream will be update. All previous + /// listener will also be affected. @override - Stream get userAccelerometerEvents { - return _platform.userAccelerometerEvents; + Stream userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + return _platform.userAccelerometerEventStream( + samplingPeriod: samplingPeriod); } - /// A broadcast stream of events from the device magnetometer. + /// Returns a broadcast stream of events from the device magnetometer at the + /// given sampling frequency. + /// + /// This method always returning the same stream. If this method is called + /// again, the sampling period of the stream will be update. All previous + /// listener will also be affected. @override - Stream get magnetometerEvents { - return _platform.magnetometerEvents; + Stream magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + return _platform.magnetometerEventStream(samplingPeriod: samplingPeriod); } } diff --git a/packages/sensors_plus/sensors_plus/lib/src/sensors_plus_web.dart b/packages/sensors_plus/sensors_plus/lib/src/sensors_plus_web.dart index 0a5eb0553d..6f0b72503b 100644 --- a/packages/sensors_plus/sensors_plus/lib/src/sensors_plus_web.dart +++ b/packages/sensors_plus/sensors_plus/lib/src/sensors_plus_web.dart @@ -9,21 +9,61 @@ export 'web_sensors.dart'; final _sensors = WebSensorsPlugin(); /// A broadcast stream of events from the device accelerometer. +@Deprecated('Use accelerometerEventStream() instead.') Stream get accelerometerEvents { return _sensors.accelerometerEvents; } /// A broadcast stream of events from the device gyroscope. +@Deprecated('Use gyroscopeEventStream() instead.') Stream get gyroscopeEvents { return _sensors.gyroscopeEvents; } /// Events from the device accelerometer with gravity removed. +@Deprecated('Use userAccelerometerEventStream() instead.') Stream get userAccelerometerEvents { return _sensors.userAccelerometerEvents; } /// A broadcast stream of events from the device magnetometer. +@Deprecated('Use magnetometerEventStream() instead.') Stream get magnetometerEvents { return _sensors.magnetometerEvents; } + +/// Returns a broadcast stream of events from the device accelerometer at the +/// given sampling frequency. +@override +Stream accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.accelerometerEventStream(samplingPeriod: samplingPeriod); +} + +/// Returns a broadcast stream of events from the device gyroscope at the +/// given sampling frequency. +@override +Stream gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.gyroscopeEventStream(samplingPeriod: samplingPeriod); +} + +/// Returns a broadcast stream of events from the device accelerometer with +/// gravity removed at the given sampling frequency. +@override +Stream userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.userAccelerometerEventStream(samplingPeriod: samplingPeriod); +} + +/// Returns a broadcast stream of events from the device magnetometer at the +/// given sampling frequency. +@override +Stream magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return _sensors.magnetometerEventStream(samplingPeriod: samplingPeriod); +} diff --git a/packages/sensors_plus/sensors_plus/lib/src/web_sensors.dart b/packages/sensors_plus/sensors_plus/lib/src/web_sensors.dart index 36d8dc6dc8..bd536d954b 100644 --- a/packages/sensors_plus/sensors_plus/lib/src/web_sensors.dart +++ b/packages/sensors_plus/sensors_plus/lib/src/web_sensors.dart @@ -55,8 +55,11 @@ class WebSensorsPlugin extends SensorsPlatform { StreamController? _accelerometerStreamController; late Stream _accelerometerResultStream; + // todo: make web also support setting samplingPeriod @override - Stream get accelerometerEvents { + Stream accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_accelerometerStreamController == null) { _accelerometerStreamController = StreamController(); _featureDetected( @@ -107,8 +110,11 @@ class WebSensorsPlugin extends SensorsPlatform { StreamController? _gyroscopeEventStreamController; late Stream _gyroscopeEventResultStream; + // todo: make web also support setting samplingPeriod @override - Stream get gyroscopeEvents { + Stream gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_gyroscopeEventStreamController == null) { _gyroscopeEventStreamController = StreamController(); _featureDetected( @@ -159,8 +165,11 @@ class WebSensorsPlugin extends SensorsPlatform { StreamController? _userAccelerometerStreamController; late Stream _userAccelerometerResultStream; + // todo: make web also support setting samplingPeriod @override - Stream get userAccelerometerEvents { + Stream userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_userAccelerometerStreamController == null) { _userAccelerometerStreamController = StreamController(); @@ -213,8 +222,11 @@ class WebSensorsPlugin extends SensorsPlatform { StreamController? _magnetometerStreamController; late Stream _magnetometerResultStream; + // todo: make web also support setting samplingPeriod @override - Stream get magnetometerEvents { + Stream magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_magnetometerStreamController == null) { _magnetometerStreamController = StreamController(); _featureDetected( diff --git a/packages/sensors_plus/sensors_plus/test/sensors_test.dart b/packages/sensors_plus/sensors_plus/test/sensors_test.dart index 4c8c6853fd..5700a17aa8 100644 --- a/packages/sensors_plus/sensors_plus/test/sensors_test.dart +++ b/packages/sensors_plus/sensors_plus/test/sensors_test.dart @@ -11,48 +11,52 @@ import 'package:test/test.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - test('$accelerometerEvents are streamed', () async { + test('accelerometerEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/accelerometer'; const sensorData = [1.0, 2.0, 3.0]; + _initializeFakeMethodChannel('setAccelerationSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await accelerometerEvents.first; + final event = await accelerometerEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); expect(event.z, sensorData[2]); }); - test('$gyroscopeEvents are streamed', () async { + test('gyroscopeEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/gyroscope'; const sensorData = [3.0, 4.0, 5.0]; + _initializeFakeMethodChannel('setGyroscopeSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await gyroscopeEvents.first; + final event = await gyroscopeEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); expect(event.z, sensorData[2]); }); - test('$userAccelerometerEvents are streamed', () async { + test('userAccelerometerEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/user_accel'; const sensorData = [6.0, 7.0, 8.0]; + _initializeFakeMethodChannel('setUserAccelerometerSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await userAccelerometerEvents.first; + final event = await userAccelerometerEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); expect(event.z, sensorData[2]); }); - test('$magnetometerEvents are streamed', () async { + test('magnetometerEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/magnetometer'; const sensorData = [8.0, 9.0, 10.0]; + _initializeFakeMethodChannel('setMagnetometerSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await magnetometerEvents.first; + final event = await magnetometerEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); @@ -60,6 +64,21 @@ void main() { }); } +void _initializeFakeMethodChannel(String methodName) { + const standardMethod = StandardMethodCodec(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMessageHandler('dev.fluttercommunity.plus/sensors/method', + (ByteData? message) async { + final methodCall = standardMethod.decodeMethodCall(message); + if (methodCall.method == methodName) { + return standardMethod.encodeSuccessEnvelope(null); + } else { + fail('Expected $methodName'); + } + }); +} + void _initializeFakeSensorChannel(String channelName, List sensorData) { const standardMethod = StandardMethodCodec(); diff --git a/packages/sensors_plus/sensors_plus_platform_interface/lib/sensors_plus_platform_interface.dart b/packages/sensors_plus/sensors_plus_platform_interface/lib/sensors_plus_platform_interface.dart index 0c1d041100..ebfd62ef4e 100644 --- a/packages/sensors_plus/sensors_plus_platform_interface/lib/sensors_plus_platform_interface.dart +++ b/packages/sensors_plus/sensors_plus_platform_interface/lib/sensors_plus_platform_interface.dart @@ -4,8 +4,10 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:sensors_plus_platform_interface/src/method_channel_sensors.dart'; +import 'package:sensors_plus_platform_interface/src/sensor_interval.dart'; import 'src/accelerometer_event.dart'; import 'src/gyroscope_event.dart'; @@ -16,6 +18,7 @@ export 'src/accelerometer_event.dart'; export 'src/gyroscope_event.dart'; export 'src/magnetometer_event.dart'; export 'src/user_accelerometer_event.dart'; +export 'src/sensor_interval.dart'; /// The common platform interface for sensors. abstract class SensorsPlatform extends PlatformInterface { @@ -39,23 +42,64 @@ abstract class SensorsPlatform extends PlatformInterface { } /// A broadcast stream of events from the device accelerometer. + @nonVirtual + @Deprecated('Use accelerometerEventStream() instead.') Stream get accelerometerEvents { - throw UnimplementedError('accelerometerEvents has not been implemented.'); + return accelerometerEventStream(); } /// A broadcast stream of events from the device gyroscope. + @nonVirtual + @Deprecated('Use gyroscopeEventStream() instead.') Stream get gyroscopeEvents { - throw UnimplementedError('gyroscopeEvents has not been implemented.'); + return gyroscopeEventStream(); } /// Events from the device accelerometer with gravity removed. + @nonVirtual + @Deprecated('Use userAccelerometerEventStream() instead.') Stream get userAccelerometerEvents { - throw UnimplementedError( - 'userAccelerometerEvents has not been implemented.'); + return userAccelerometerEventStream(); } /// A broadcast stream of events from the device magnetometer. + @nonVirtual + @Deprecated('Use magnetometerEventStream() instead.') Stream get magnetometerEvents { + return magnetometerEventStream(); + } + + /// Returns a broadcast stream of events from the device accelerometer at the + /// given sampling frequency. + Stream accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + throw UnimplementedError( + 'listenToAccelerometerEvents has not been implemented.'); + } + + /// Returns a broadcast stream of events from the device gyroscope at the + /// given sampling frequency. + Stream gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + throw UnimplementedError('gyroscopeEvents has not been implemented.'); + } + + /// Returns a broadcast stream of events from the device accelerometer with + /// gravity removed at the given sampling frequency. + Stream userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + throw UnimplementedError( + 'userAccelerometerEvents has not been implemented.'); + } + + /// Returns a broadcast stream of events from the device magnetometer at the + /// given sampling frequency. + Stream magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { throw UnimplementedError('magnetometerEvents has not been implemented.'); } } diff --git a/packages/sensors_plus/sensors_plus_platform_interface/lib/src/method_channel_sensors.dart b/packages/sensors_plus/sensors_plus_platform_interface/lib/src/method_channel_sensors.dart index 6fbeacac5d..244c647647 100644 --- a/packages/sensors_plus/sensors_plus_platform_interface/lib/src/method_channel_sensors.dart +++ b/packages/sensors_plus/sensors_plus_platform_interface/lib/src/method_channel_sensors.dart @@ -9,6 +9,9 @@ import 'package:sensors_plus_platform_interface/sensors_plus_platform_interface. /// A method channel -based implementation of the SensorsPlatform interface. class MethodChannelSensors extends SensorsPlatform { + static const MethodChannel _methodChannel = + MethodChannel('dev.fluttercommunity.plus/sensors/method'); + static const EventChannel _accelerometerEventChannel = EventChannel('dev.fluttercommunity.plus/sensors/accelerometer'); @@ -26,9 +29,14 @@ class MethodChannelSensors extends SensorsPlatform { Stream? _userAccelerometerEvents; Stream? _magnetometerEvents; - /// A broadcast stream of events from the device accelerometer. + /// Returns a broadcast stream of events from the device accelerometer at the + /// given sampling frequency. @override - Stream get accelerometerEvents { + Stream accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + _methodChannel.invokeMethod( + 'setAccelerationSamplingPeriod', samplingPeriod.inMicroseconds); _accelerometerEvents ??= _accelerometerEventChannel .receiveBroadcastStream() .map((dynamic event) { @@ -38,9 +46,14 @@ class MethodChannelSensors extends SensorsPlatform { return _accelerometerEvents!; } - /// A broadcast stream of events from the device gyroscope. + /// Returns a broadcast stream of events from the device gyroscope at the + /// given sampling frequency. @override - Stream get gyroscopeEvents { + Stream gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + _methodChannel.invokeMethod( + 'setGyroscopeSamplingPeriod', samplingPeriod.inMicroseconds); _gyroscopeEvents ??= _gyroscopeEventChannel.receiveBroadcastStream().map((dynamic event) { final list = event.cast(); @@ -49,9 +62,14 @@ class MethodChannelSensors extends SensorsPlatform { return _gyroscopeEvents!; } - /// Events from the device accelerometer with gravity removed. + /// Returns a broadcast stream of events from the device accelerometer with + /// gravity removed at the given sampling frequency. @override - Stream get userAccelerometerEvents { + Stream userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + _methodChannel.invokeMethod( + 'setUserAccelerometerSamplingPeriod', samplingPeriod.inMicroseconds); _userAccelerometerEvents ??= _userAccelerometerEventChannel .receiveBroadcastStream() .map((dynamic event) { @@ -61,9 +79,14 @@ class MethodChannelSensors extends SensorsPlatform { return _userAccelerometerEvents!; } - /// A broadcast stream of events from the device magnetometer. + /// Returns a broadcast stream of events from the device magnetometer at the + /// given sampling frequency. @override - Stream get magnetometerEvents { + Stream magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + _methodChannel.invokeMethod( + 'setMagnetometerSamplingPeriod', samplingPeriod.inMicroseconds); _magnetometerEvents ??= _magnetometerEventChannel.receiveBroadcastStream().map((dynamic event) { final list = event.cast(); diff --git a/packages/sensors_plus/sensors_plus_platform_interface/lib/src/sensor_interval.dart b/packages/sensors_plus/sensors_plus_platform_interface/lib/src/sensor_interval.dart new file mode 100644 index 0000000000..df124aea69 --- /dev/null +++ b/packages/sensors_plus/sensors_plus_platform_interface/lib/src/sensor_interval.dart @@ -0,0 +1,9 @@ +import 'package:meta/meta.dart'; + +@sealed +class SensorInterval { + static const normalInterval = Duration(milliseconds: 200); + static const uiInterval = Duration(milliseconds: 66, microseconds: 667); + static const gameInterval = Duration(milliseconds: 20); + static const fastestInterval = Duration.zero; +} diff --git a/packages/sensors_plus/sensors_plus_platform_interface/test/sensors_plus_platform_interface_test.dart b/packages/sensors_plus/sensors_plus_platform_interface/test/sensors_plus_platform_interface_test.dart index d50ec63aba..f25c7186ef 100644 --- a/packages/sensors_plus/sensors_plus_platform_interface/test/sensors_plus_platform_interface_test.dart +++ b/packages/sensors_plus/sensors_plus_platform_interface/test/sensors_plus_platform_interface_test.dart @@ -11,71 +11,92 @@ import 'package:test/test.dart'; final MethodChannelSensors methodChannel = MethodChannelSensors(); -/// A broadcast stream of events from the device accelerometer. -Stream get accelerometerEvents { - return methodChannel.accelerometerEvents; +/// Returns a broadcast stream of events from the device accelerometer at the +/// given sampling frequency. +@override +Stream accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return methodChannel.accelerometerEventStream(samplingPeriod: samplingPeriod); } -/// A broadcast stream of events from the device gyroscope. -Stream get gyroscopeEvents { - return methodChannel.gyroscopeEvents; +/// Returns a broadcast stream of events from the device gyroscope at the +/// given sampling frequency. +@override +Stream gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return methodChannel.gyroscopeEventStream(samplingPeriod: samplingPeriod); } -/// Events from the device accelerometer with gravity removed. -Stream get userAccelerometerEvents { - return methodChannel.userAccelerometerEvents; +/// Returns a broadcast stream of events from the device accelerometer with +/// gravity removed at the given sampling frequency. +@override +Stream userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return methodChannel.userAccelerometerEventStream( + samplingPeriod: samplingPeriod); } -/// A broadcast stream of events from the device magnetometer. -Stream get magnetometerEvents { - return methodChannel.magnetometerEvents; +/// Returns a broadcast stream of events from the device magnetometer at the +/// given sampling frequency. +@override +Stream magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return methodChannel.magnetometerEventStream(samplingPeriod: samplingPeriod); } void main() { TestWidgetsFlutterBinding.ensureInitialized(); - test('$accelerometerEvents are streamed', () async { + test('accelerometerEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/accelerometer'; const sensorData = [1.0, 2.0, 3.0]; + _initializeFakeMethodChannel('setAccelerationSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await accelerometerEvents.first; + final event = await accelerometerEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); expect(event.z, sensorData[2]); }); - test('$gyroscopeEvents are streamed', () async { + test('gyroscopeEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/gyroscope'; const sensorData = [3.0, 4.0, 5.0]; + _initializeFakeMethodChannel('setGyroscopeSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await gyroscopeEvents.first; + final event = await gyroscopeEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); expect(event.z, sensorData[2]); }); - test('$userAccelerometerEvents are streamed', () async { + test('userAccelerometerEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/user_accel'; const sensorData = [6.0, 7.0, 8.0]; + _initializeFakeMethodChannel('setUserAccelerometerSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await userAccelerometerEvents.first; + final event = await userAccelerometerEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); expect(event.z, sensorData[2]); }); - test('$magnetometerEvents are streamed', () async { + test('magnetometerEvents are streamed', () async { const channelName = 'dev.fluttercommunity.plus/sensors/magnetometer'; const sensorData = [8.0, 9.0, 10.0]; + _initializeFakeMethodChannel('setMagnetometerSamplingPeriod'); _initializeFakeSensorChannel(channelName, sensorData); - final event = await magnetometerEvents.first; + final event = await magnetometerEventStream().first; expect(event.x, sensorData[0]); expect(event.y, sensorData[1]); @@ -83,6 +104,21 @@ void main() { }); } +void _initializeFakeMethodChannel(String methodName) { + const standardMethod = StandardMethodCodec(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMessageHandler('dev.fluttercommunity.plus/sensors/method', + (ByteData? message) async { + final methodCall = standardMethod.decodeMethodCall(message); + if (methodCall.method == methodName) { + return standardMethod.encodeSuccessEnvelope(null); + } else { + fail('Expected $methodName'); + } + }); +} + void _initializeFakeSensorChannel(String channelName, List sensorData) { const standardMethod = StandardMethodCodec();