From 0ee58e0beafee7cbc9355c8f5075705f6ccb4434 Mon Sep 17 00:00:00 2001 From: 6y <tlserver6y@gmail.com> Date: Tue, 19 Sep 2023 10:28:04 +0800 Subject: [PATCH 1/7] refactor(sensors_plus): Rename linearAccelerationStreamHandler to userAccelStreamHandler --- .../dev/fluttercommunity/plus/sensors/SensorsPlugin.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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..155a79a5fa 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 @@ -16,7 +16,7 @@ class SensorsPlugin : FlutterPlugin { private lateinit var magnetometerChannel: EventChannel private lateinit var accelerationStreamHandler: StreamHandlerImpl - private lateinit var linearAccelerationStreamHandler: StreamHandlerImpl + private lateinit var userAccelStreamHandler: StreamHandlerImpl private lateinit var gyroScopeStreamHandler: StreamHandlerImpl private lateinit var magnetometerStreamHandler: StreamHandlerImpl @@ -39,11 +39,11 @@ class SensorsPlugin : FlutterPlugin { accelerometerChannel.setStreamHandler(accelerationStreamHandler) 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( @@ -67,7 +67,7 @@ class SensorsPlugin : FlutterPlugin { magnetometerChannel.setStreamHandler(null) accelerationStreamHandler.onCancel(null) - linearAccelerationStreamHandler.onCancel(null) + userAccelStreamHandler.onCancel(null) gyroScopeStreamHandler.onCancel(null) magnetometerStreamHandler.onCancel(null) } From 48911b825869c3a68dcbdb04db34b22ae4c7d242 Mon Sep 17 00:00:00 2001 From: 6y <tlserver6y@gmail.com> Date: Tue, 19 Sep 2023 12:23:28 +0800 Subject: [PATCH 2/7] refactor(sensors_plus): Rename accelerationStreamHandler to accelerometerStreamHandler and gyroScopeStreamHandler to gyroscopeStreamHandler --- .../plus/sensors/SensorsPlugin.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 155a79a5fa..6d97cf477f 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 @@ -15,9 +15,9 @@ class SensorsPlugin : FlutterPlugin { private lateinit var gyroscopeChannel: EventChannel private lateinit var magnetometerChannel: EventChannel - private lateinit var accelerationStreamHandler: StreamHandlerImpl + private lateinit var accelerometerStreamHandler: StreamHandlerImpl private lateinit var userAccelStreamHandler: StreamHandlerImpl - private lateinit var gyroScopeStreamHandler: StreamHandlerImpl + private lateinit var gyroscopeStreamHandler: StreamHandlerImpl private lateinit var magnetometerStreamHandler: StreamHandlerImpl override fun onAttachedToEngine(binding: FlutterPluginBinding) { @@ -32,11 +32,11 @@ class SensorsPlugin : FlutterPlugin { 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) userAccelStreamHandler = StreamHandlerImpl( @@ -46,11 +46,11 @@ class SensorsPlugin : FlutterPlugin { 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,9 +66,9 @@ class SensorsPlugin : FlutterPlugin { gyroscopeChannel.setStreamHandler(null) magnetometerChannel.setStreamHandler(null) - accelerationStreamHandler.onCancel(null) + accelerometerStreamHandler.onCancel(null) userAccelStreamHandler.onCancel(null) - gyroScopeStreamHandler.onCancel(null) + gyroscopeStreamHandler.onCancel(null) magnetometerStreamHandler.onCancel(null) } From 65593a505e50aaa54ec5a74abf11aa6977fae840 Mon Sep 17 00:00:00 2001 From: 6y <tlserver6y@gmail.com> Date: Tue, 19 Sep 2023 16:39:01 +0800 Subject: [PATCH 3/7] style(sensors_plus): Code format --- .../kotlin/dev/fluttercommunity/plus/sensors/SensorsPlugin.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 6d97cf477f..67849e9423 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 @@ -75,7 +75,8 @@ class SensorsPlugin : FlutterPlugin { companion object { 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 = From 848328bc75eb8c238bf4b3b5a9760c68fe4b1ca0 Mon Sep 17 00:00:00 2001 From: 6y <tlserver6y@gmail.com> Date: Fri, 22 Sep 2023 17:42:31 +0800 Subject: [PATCH 4/7] refactor(sensors_plus): Update ios platform language to swift --- .../ios/Runner.xcodeproj/project.pbxproj | 23 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../ios/Classes/FPPSensorsPlusPlugin.h | 20 -- .../ios/Classes/FPPSensorsPlusPlugin.m | 285 ------------------ .../ios/Classes/FPPSensorsPlusPlugin.swift | 72 +++++ .../ios/Classes/FPPStreamHandlerPlus.swift | 194 ++++++++++++ .../sensors_plus/ios/sensors_plus.podspec | 10 +- 7 files changed, 294 insertions(+), 312 deletions(-) delete mode 100644 packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.h delete mode 100644 packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.m create mode 100644 packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift create mode 100644 packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift 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..24c6975178 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 = "<group>"; + }; 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -105,7 +112,6 @@ 178BE122EE4A7CE24B05D8AC /* Pods-RunnerTests.release.xcconfig */, 101AB93329D02192F269FF15 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = "<group>"; }; @@ -129,6 +135,7 @@ 331C8082294A63A400263BE5 /* RunnerTests */, 9643F7DAEAB1D555F9F2E496 /* Pods */, E9DC5051924EC6D7963378C9 /* Frameworks */, + 18B7D72A2ABD9B4F006A0D55 /* Recovered References */, ); sourceTree = "<group>"; }; @@ -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; @@ -468,8 +476,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = DDS7MYD673; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -490,6 +500,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 +519,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 +536,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 +592,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 +642,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; @@ -646,8 +661,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = DDS7MYD673; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -668,8 +685,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = DDS7MYD673; 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 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "1300" + LastUpgradeVersion = "1430" version = "1.3"> <BuildAction parallelizeBuildables = "YES" 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 <Flutter/Flutter.h> - -@interface FPPSensorsPlusPlugin : NSObject <FlutterPlugin> -@end - -@interface FPPUserAccelStreamHandlerPlus : NSObject <FlutterStreamHandler> -@end - -@interface FPPAccelerometerStreamHandlerPlus : NSObject <FlutterStreamHandler> -@end - -@interface FPPGyroscopeStreamHandlerPlus : NSObject <FlutterStreamHandler> -@end - -@interface FPPMagnetometerStreamHandlerPlus : NSObject <FlutterStreamHandler> -@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 <CoreMotion/CoreMotion.h> - -@implementation FPPSensorsPlusPlugin - -NSMutableDictionary<NSString *, FlutterEventChannel *> *_eventChannels; -NSMutableDictionary<NSString *, NSObject<FlutterStreamHandler> *> - *_streamHandlers; -BOOL _isCleanUp = NO; - -+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)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<FlutterPluginRegistrar> *)registrar { - _cleanUp(); -} - -static void _cleanUp(void) { - _isCleanUp = YES; - for (FlutterEventChannel *channel in _eventChannels.allValues) { - [channel setStreamHandler:nil]; - } - [_eventChannels removeAllObjects]; - for (NSObject<FlutterStreamHandler> *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..bf1180505e --- /dev/null +++ b/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift @@ -0,0 +1,72 @@ +// 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: FlutterStreamHandler] = [:] +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 + + _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..3b600fb615 --- /dev/null +++ b/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift @@ -0,0 +1,194 @@ +// 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! + +func _initMotionManager() { + if (_motionManager == nil) { + _motionManager = CMMotionManager() + } +} + +func sendTriplet(x: Float64, y: Float64, z: Float64, sink: FlutterEventSink) { + if _isCleanUp { + return + } + // Even after [detachFromEngineForRegistrar] some events may still be received + // and fired until fully detached. + let triplet = [x, y, z]; + triplet.withUnsafeBufferPointer { buffer in + sink(FlutterStandardTypedData.init(float64: Data(buffer: buffer))) + } +} + +class FPPAccelerometerStreamHandlerPlus: NSObject, FlutterStreamHandler { + + 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, FlutterStreamHandler { + + 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, FlutterStreamHandler { + + 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, FlutterStreamHandler { + + 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 From 35dbf84b28afa8dfc3b3fc2252108937208e0171 Mon Sep 17 00:00:00 2001 From: 6y <tlserver6y@gmail.com> Date: Fri, 15 Sep 2023 16:39:23 +0800 Subject: [PATCH 5/7] feat(sensors_plus): Support samplingPeriod --- .../plus/sensors/SensorsPlugin.kt | 30 ++++++++ .../plus/sensors/StreamHandlerImpl.kt | 20 +++-- .../integration_test/sensors_plus_test.dart | 3 +- .../sensors_plus/example/lib/main.dart | 8 +- .../ios/Classes/FPPSensorsPlusPlugin.swift | 24 +++++- .../ios/Classes/FPPStreamHandlerPlus.swift | 54 +++++++++++-- .../sensors_plus/lib/sensors_plus.dart | 40 ++++++++++ .../sensors_plus/lib/src/sensors.dart | 53 ++++++++++--- .../lib/src/sensors_plus_web.dart | 40 ++++++++++ .../sensors_plus/lib/src/web_sensors.dart | 20 ++++- .../sensors_plus/test/sensors_test.dart | 35 +++++++-- .../lib/sensors_plus_platform_interface.dart | 52 ++++++++++++- .../lib/src/method_channel_sensors.dart | 39 ++++++++-- .../lib/src/sensor_interval.dart | 9 +++ .../sensors_plus_platform_interface_test.dart | 76 ++++++++++++++----- 15 files changed, 428 insertions(+), 75 deletions(-) create mode 100644 packages/sensors_plus/sensors_plus_platform_interface/lib/src/sensor_interval.dart 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 67849e9423..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,9 +7,12 @@ 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 @@ -21,13 +24,38 @@ class SensorsPlugin : FlutterPlugin { 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 @@ -73,6 +101,8 @@ class SensorsPlugin : FlutterPlugin { } 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 = 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<AccelerometerEvent>(); late StreamSubscription<AccelerometerEvent> 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/lib/main.dart b/packages/sensors_plus/sensors_plus/example/lib/main.dart index 5453b596a2..064b3f76f2 100644 --- a/packages/sensors_plus/sensors_plus/example/lib/main.dart +++ b/packages/sensors_plus/sensors_plus/example/lib/main.dart @@ -149,7 +149,7 @@ class _MyHomePageState extends State<MyHomePage> { void initState() { super.initState(); _streamSubscriptions.add( - userAccelerometerEvents.listen( + userAccelerometerEventStream().listen( (UserAccelerometerEvent event) { setState(() { _userAccelerometerValues = <double>[event.x, event.y, event.z]; @@ -170,7 +170,7 @@ class _MyHomePageState extends State<MyHomePage> { ), ); _streamSubscriptions.add( - accelerometerEvents.listen( + accelerometerEventStream().listen( (AccelerometerEvent event) { setState(() { _accelerometerValues = <double>[event.x, event.y, event.z]; @@ -191,7 +191,7 @@ class _MyHomePageState extends State<MyHomePage> { ), ); _streamSubscriptions.add( - gyroscopeEvents.listen( + gyroscopeEventStream().listen( (GyroscopeEvent event) { setState(() { _gyroscopeValues = <double>[event.x, event.y, event.z]; @@ -212,7 +212,7 @@ class _MyHomePageState extends State<MyHomePage> { ), ); _streamSubscriptions.add( - magnetometerEvents.listen( + magnetometerEventStream().listen( (MagnetometerEvent event) { setState(() { _magnetometerValues = <double>[event.x, event.y, event.z]; diff --git a/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift b/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift index bf1180505e..a31e1ec9f3 100644 --- a/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift +++ b/packages/sensors_plus/sensors_plus/ios/Classes/FPPSensorsPlusPlugin.swift @@ -5,7 +5,7 @@ import Flutter var _eventChannels: [String: FlutterEventChannel] = [:] -var _streamHandlers: [String: FlutterStreamHandler] = [:] +var _streamHandlers: [String: MotionStreamHandler] = [:] var _isCleanUp = false public class FPPSensorsPlusPlugin: NSObject, FlutterPlugin { @@ -51,6 +51,28 @@ public class FPPSensorsPlusPlugin: NSObject, FlutterPlugin { _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 } diff --git a/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift b/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift index 3b600fb615..6bf127ac80 100644 --- a/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift +++ b/packages/sensors_plus/sensors_plus/ios/Classes/FPPStreamHandlerPlus.swift @@ -10,25 +10,42 @@ 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: FlutterEventSink) { +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. - let triplet = [x, y, z]; - triplet.withUnsafeBufferPointer { buffer in - sink(FlutterStandardTypedData.init(float64: Data(buffer: buffer))) + DispatchQueue.main.async { + let triplet = [x, y, z] + triplet.withUnsafeBufferPointer { buffer in + sink(FlutterStandardTypedData.init(float64: Data(buffer: buffer))) + } } } -class FPPAccelerometerStreamHandlerPlus: NSObject, FlutterStreamHandler { +class FPPAccelerometerStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.accelerometerUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } func onListen( withArguments arguments: Any?, @@ -70,7 +87,14 @@ class FPPAccelerometerStreamHandlerPlus: NSObject, FlutterStreamHandler { } } -class FPPUserAccelStreamHandlerPlus: NSObject, FlutterStreamHandler { +class FPPUserAccelStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.deviceMotionUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } func onListen( withArguments arguments: Any?, @@ -112,7 +136,14 @@ class FPPUserAccelStreamHandlerPlus: NSObject, FlutterStreamHandler { } } -class FPPGyroscopeStreamHandlerPlus: NSObject, FlutterStreamHandler { +class FPPGyroscopeStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.gyroUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } func onListen( withArguments arguments: Any?, @@ -147,7 +178,14 @@ class FPPGyroscopeStreamHandlerPlus: NSObject, FlutterStreamHandler { } } -class FPPMagnetometerStreamHandlerPlus: NSObject, FlutterStreamHandler { +class FPPMagnetometerStreamHandlerPlus: NSObject, MotionStreamHandler { + + var samplingPeriod = 200000 { + didSet { + _initMotionManager() + _motionManager.deviceMotionUpdateInterval = Double(samplingPeriod) * 0.000001 + } + } func onListen( withArguments arguments: Any?, 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<AccelerometerEvent> get accelerometerEvents { return _sensors.accelerometerEvents; } /// A broadcast stream of events from the device gyroscope. +@Deprecated('Use gyroscopeEventStream() instead.') Stream<GyroscopeEvent> get gyroscopeEvents { return _sensors.gyroscopeEvents; } /// Events from the device accelerometer with gravity removed. +@Deprecated('Use userAccelerometerEventStream() instead.') Stream<UserAccelerometerEvent> get userAccelerometerEvents { return _sensors.userAccelerometerEvents; } /// A broadcast stream of events from the device magnetometer. +@Deprecated('Use magnetometerEventStream() instead.') Stream<MagnetometerEvent> get magnetometerEvents { return _sensors.magnetometerEvents; } + +/// Returns a broadcast stream of events from the device accelerometer at the +/// given sampling frequency. +@override +Stream<AccelerometerEvent> 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<GyroscopeEvent> 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<UserAccelerometerEvent> 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<MagnetometerEvent> 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<AccelerometerEvent> get accelerometerEvents { - return _platform.accelerometerEvents; + Stream<AccelerometerEvent> 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<GyroscopeEvent> get gyroscopeEvents { - return _platform.gyroscopeEvents; + Stream<GyroscopeEvent> 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<UserAccelerometerEvent> get userAccelerometerEvents { - return _platform.userAccelerometerEvents; + Stream<UserAccelerometerEvent> 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<MagnetometerEvent> get magnetometerEvents { - return _platform.magnetometerEvents; + Stream<MagnetometerEvent> 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<AccelerometerEvent> get accelerometerEvents { return _sensors.accelerometerEvents; } /// A broadcast stream of events from the device gyroscope. +@Deprecated('Use gyroscopeEventStream() instead.') Stream<GyroscopeEvent> get gyroscopeEvents { return _sensors.gyroscopeEvents; } /// Events from the device accelerometer with gravity removed. +@Deprecated('Use userAccelerometerEventStream() instead.') Stream<UserAccelerometerEvent> get userAccelerometerEvents { return _sensors.userAccelerometerEvents; } /// A broadcast stream of events from the device magnetometer. +@Deprecated('Use magnetometerEventStream() instead.') Stream<MagnetometerEvent> get magnetometerEvents { return _sensors.magnetometerEvents; } + +/// Returns a broadcast stream of events from the device accelerometer at the +/// given sampling frequency. +@override +Stream<AccelerometerEvent> 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<GyroscopeEvent> 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<UserAccelerometerEvent> 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<MagnetometerEvent> 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<AccelerometerEvent>? _accelerometerStreamController; late Stream<AccelerometerEvent> _accelerometerResultStream; + // todo: make web also support setting samplingPeriod @override - Stream<AccelerometerEvent> get accelerometerEvents { + Stream<AccelerometerEvent> accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_accelerometerStreamController == null) { _accelerometerStreamController = StreamController<AccelerometerEvent>(); _featureDetected( @@ -107,8 +110,11 @@ class WebSensorsPlugin extends SensorsPlatform { StreamController<GyroscopeEvent>? _gyroscopeEventStreamController; late Stream<GyroscopeEvent> _gyroscopeEventResultStream; + // todo: make web also support setting samplingPeriod @override - Stream<GyroscopeEvent> get gyroscopeEvents { + Stream<GyroscopeEvent> gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_gyroscopeEventStreamController == null) { _gyroscopeEventStreamController = StreamController<GyroscopeEvent>(); _featureDetected( @@ -159,8 +165,11 @@ class WebSensorsPlugin extends SensorsPlatform { StreamController<UserAccelerometerEvent>? _userAccelerometerStreamController; late Stream<UserAccelerometerEvent> _userAccelerometerResultStream; + // todo: make web also support setting samplingPeriod @override - Stream<UserAccelerometerEvent> get userAccelerometerEvents { + Stream<UserAccelerometerEvent> userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_userAccelerometerStreamController == null) { _userAccelerometerStreamController = StreamController<UserAccelerometerEvent>(); @@ -213,8 +222,11 @@ class WebSensorsPlugin extends SensorsPlatform { StreamController<MagnetometerEvent>? _magnetometerStreamController; late Stream<MagnetometerEvent> _magnetometerResultStream; + // todo: make web also support setting samplingPeriod @override - Stream<MagnetometerEvent> get magnetometerEvents { + Stream<MagnetometerEvent> magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { if (_magnetometerStreamController == null) { _magnetometerStreamController = StreamController<MagnetometerEvent>(); _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 = <double>[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 = <double>[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 = <double>[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 = <double>[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<double> 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<AccelerometerEvent> 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<GyroscopeEvent> 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<UserAccelerometerEvent> 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<MagnetometerEvent> get magnetometerEvents { + return magnetometerEventStream(); + } + + /// Returns a broadcast stream of events from the device accelerometer at the + /// given sampling frequency. + Stream<AccelerometerEvent> 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<GyroscopeEvent> 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<UserAccelerometerEvent> 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<MagnetometerEvent> 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<UserAccelerometerEvent>? _userAccelerometerEvents; Stream<MagnetometerEvent>? _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<AccelerometerEvent> get accelerometerEvents { + Stream<AccelerometerEvent> 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<GyroscopeEvent> get gyroscopeEvents { + Stream<GyroscopeEvent> gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + _methodChannel.invokeMethod( + 'setGyroscopeSamplingPeriod', samplingPeriod.inMicroseconds); _gyroscopeEvents ??= _gyroscopeEventChannel.receiveBroadcastStream().map((dynamic event) { final list = event.cast<double>(); @@ -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<UserAccelerometerEvent> get userAccelerometerEvents { + Stream<UserAccelerometerEvent> 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<MagnetometerEvent> get magnetometerEvents { + Stream<MagnetometerEvent> magnetometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, + }) { + _methodChannel.invokeMethod( + 'setMagnetometerSamplingPeriod', samplingPeriod.inMicroseconds); _magnetometerEvents ??= _magnetometerEventChannel.receiveBroadcastStream().map((dynamic event) { final list = event.cast<double>(); 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<AccelerometerEvent> get accelerometerEvents { - return methodChannel.accelerometerEvents; +/// Returns a broadcast stream of events from the device accelerometer at the +/// given sampling frequency. +@override +Stream<AccelerometerEvent> accelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return methodChannel.accelerometerEventStream(samplingPeriod: samplingPeriod); } -/// A broadcast stream of events from the device gyroscope. -Stream<GyroscopeEvent> get gyroscopeEvents { - return methodChannel.gyroscopeEvents; +/// Returns a broadcast stream of events from the device gyroscope at the +/// given sampling frequency. +@override +Stream<GyroscopeEvent> gyroscopeEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return methodChannel.gyroscopeEventStream(samplingPeriod: samplingPeriod); } -/// Events from the device accelerometer with gravity removed. -Stream<UserAccelerometerEvent> 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<UserAccelerometerEvent> userAccelerometerEventStream({ + Duration samplingPeriod = SensorInterval.normalInterval, +}) { + return methodChannel.userAccelerometerEventStream( + samplingPeriod: samplingPeriod); } -/// A broadcast stream of events from the device magnetometer. -Stream<MagnetometerEvent> get magnetometerEvents { - return methodChannel.magnetometerEvents; +/// Returns a broadcast stream of events from the device magnetometer at the +/// given sampling frequency. +@override +Stream<MagnetometerEvent> 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 = <double>[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 = <double>[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 = <double>[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 = <double>[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<double> sensorData) { const standardMethod = StandardMethodCodec(); From fe74162f0e1ce9d8b14365938f3a413329900ac3 Mon Sep 17 00:00:00 2001 From: 6y <tlserver6y@gmail.com> Date: Tue, 19 Sep 2023 17:42:18 +0800 Subject: [PATCH 6/7] feat(sensors_plus): Update example --- .../sensors_plus/example/lib/main.dart | 226 +++++++++++++----- .../sensors_plus/example/lib/snake.dart | 2 +- 2 files changed, 171 insertions(+), 57 deletions(-) diff --git a/packages/sensors_plus/sensors_plus/example/lib/main.dart b/packages/sensors_plus/sensors_plus/example/lib/main.dart index 064b3f76f2..a8d6634ba9 100644 --- a/packages/sensors_plus/sensors_plus/example/lib/main.dart +++ b/packages/sensors_plus/sensors_plus/example/lib/main.dart @@ -50,28 +50,32 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State<MyHomePage> { + static const Duration _ignoreDuration = Duration(milliseconds: 20); + static const int _snakeRows = 20; static const int _snakeColumns = 20; static const double _snakeCellSize = 10.0; - List<double>? _userAccelerometerValues; - List<double>? _accelerometerValues; - List<double>? _gyroscopeValues; - List<double>? _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 = <StreamSubscription<dynamic>>[]; + 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<MyHomePage> { ), ), Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: <Widget>[ - Text('UserAccelerometer: $userAccelerometer'), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: <Widget>[ - Text('Accelerometer: $accelerometer'), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: <Widget>[ - 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: <Widget>[ - 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<MyHomePage> { void initState() { super.initState(); _streamSubscriptions.add( - userAccelerometerEventStream().listen( + userAccelerometerEventStream(samplingPeriod: sensorInterval).listen( (UserAccelerometerEvent event) { + final now = DateTime.now(); setState(() { - _userAccelerometerValues = <double>[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<MyHomePage> { 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<MyHomePage> { ), ); _streamSubscriptions.add( - accelerometerEventStream().listen( + accelerometerEventStream(samplingPeriod: sensorInterval).listen( (AccelerometerEvent event) { + final now = DateTime.now(); setState(() { - _accelerometerValues = <double>[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<MyHomePage> { 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<MyHomePage> { ), ); _streamSubscriptions.add( - gyroscopeEventStream().listen( + gyroscopeEventStream(samplingPeriod: sensorInterval).listen( (GyroscopeEvent event) { + final now = DateTime.now(); setState(() { - _gyroscopeValues = <double>[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<MyHomePage> { 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<MyHomePage> { ), ); _streamSubscriptions.add( - magnetometerEventStream().listen( + magnetometerEventStream(samplingPeriod: sensorInterval).listen( (MagnetometerEvent event) { + final now = DateTime.now(); setState(() { - _magnetometerValues = <double>[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<Snake> { void initState() { super.initState(); _streamSubscription = - accelerometerEvents.listen((AccelerometerEvent event) { + accelerometerEventStream().listen((AccelerometerEvent event) { setState(() { acceleration = event; }); From 4cd0d6a2fd7a046ba4d46d4110b6f118d8f53366 Mon Sep 17 00:00:00 2001 From: Volodymyr Buberenko <vbuberen@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:52:04 +0200 Subject: [PATCH 7/7] Remove signing information from example app --- .../sensors_plus/example/ios/Runner.xcodeproj/project.pbxproj | 3 --- 1 file changed, 3 deletions(-) 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 24c6975178..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 @@ -476,7 +476,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = DDS7MYD673; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; @@ -661,7 +660,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = DDS7MYD673; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; @@ -685,7 +683,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = DDS7MYD673; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0;