1// Copyright 2015-present 650 Industries. All rights reserved. 2 3#import "EXKernel.h" 4#import "EXFrame.h" 5#import "EXFrameReactAppManager.h" 6#import "EXKernelReactAppManager.h" 7#import "EXSensorManager.h" 8#import <CoreMotion/CoreMotion.h> 9 10@interface EXSensorManager () 11 12@property (nonatomic, strong) CMMotionManager *manager; 13@property (nonatomic, strong) NSMutableDictionary *accelerometerHandlers; 14@property (nonatomic, strong) NSMutableDictionary *deviceMotionHandlers; 15@property (nonatomic, strong) NSMutableDictionary *gyroscopeHandlers; 16@property (nonatomic, strong) NSMutableDictionary *magnetometerHandlers; 17@property (nonatomic, strong) NSMutableDictionary *magnetometerUncalibratedHandlers; 18 19@end 20 21@implementation EXSensorManager 22 23- (instancetype)init 24{ 25 if (self = [super init]) { 26 _accelerometerHandlers = [[NSMutableDictionary alloc] init]; 27 _deviceMotionHandlers = [[NSMutableDictionary alloc] init]; 28 _gyroscopeHandlers = [[NSMutableDictionary alloc] init]; 29 _magnetometerHandlers = [[NSMutableDictionary alloc] init]; 30 _magnetometerUncalibratedHandlers = [[NSMutableDictionary alloc] init]; 31 } 32 return self; 33} 34 35- (CMMotionManager *)manager 36{ 37 if (!_manager) { 38 _manager = [[CMMotionManager alloc] init]; 39 } 40 return _manager; 41} 42 43- (void)dealloc 44{ 45 [self.manager stopAccelerometerUpdates]; 46 [self.manager stopDeviceMotionUpdates]; 47 [self.manager stopGyroUpdates]; 48 [self.manager stopMagnetometerUpdates]; 49} 50 51- (void)sensorModuleDidSubscribeForAccelerometerUpdates:(id)scopedSensorModule 52 withHandler:(void (^)(NSDictionary *event))handlerBlock 53{ 54 if ([self.manager isAccelerometerAvailable]) { 55 self.accelerometerHandlers[((EXScopedEventEmitter *)scopedSensorModule).experienceId] = handlerBlock; 56 } 57 if (![self.manager isAccelerometerActive]) { 58 [self.manager setAccelerometerUpdateInterval:0.1f]; 59 [self.manager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *data, NSError *error) { 60 for (void (^handler)(NSDictionary *) in self.accelerometerHandlers.allValues) { 61 handler(@{ 62 @"x": [NSNumber numberWithDouble:data.acceleration.x], 63 @"y": [NSNumber numberWithDouble:data.acceleration.y], 64 @"z": [NSNumber numberWithDouble:data.acceleration.z] 65 }); 66 } 67 }]; 68 } 69} 70 71- (void)sensorModuleDidUnsubscribeForAccelerometerUpdates:(id)scopedSensorModule 72{ 73 [self.accelerometerHandlers removeObjectForKey:((EXScopedEventEmitter *)scopedSensorModule).experienceId]; 74 if (self.accelerometerHandlers.count == 0) { 75 [self.manager stopAccelerometerUpdates]; 76 } 77} 78 79- (void)setAccelerometerUpdateInterval:(NSTimeInterval)intervalMs 80{ 81 [self.manager setAccelerometerUpdateInterval:intervalMs]; 82} 83 84- (void)sensorModuleDidSubscribeForDeviceMotionUpdates:(id)scopedSensorModule 85 withHandler:(void (^)(NSDictionary *event))handlerBlock 86{ 87 if ([self.manager isDeviceMotionAvailable]) { 88 self.deviceMotionHandlers[((EXScopedEventEmitter *)scopedSensorModule).experienceId] = handlerBlock; 89 } 90 if (![self.manager isDeviceMotionActive]) { 91 [self activateDeviceMotionUpdates]; 92 } 93} 94 95- (void)sensorModuleDidUnsubscribeForDeviceMotionUpdates:(id)scopedSensorModule 96{ 97 [self.deviceMotionHandlers removeObjectForKey:((EXScopedEventEmitter *)scopedSensorModule).experienceId]; 98 if (self.deviceMotionHandlers.count == 0 && self.magnetometerHandlers.count == 0) { 99 [self.manager stopDeviceMotionUpdates]; 100 } 101} 102 103- (void)setDeviceMotionUpdateInterval:(NSTimeInterval)intervalMs 104{ 105 [self.manager setDeviceMotionUpdateInterval:intervalMs]; 106} 107 108- (void)sensorModuleDidSubscribeForGyroscopeUpdates:(id)scopedSensorModule 109 withHandler:(void (^)(NSDictionary *event))handlerBlock 110{ 111 if ([self.manager isGyroAvailable]) { 112 self.gyroscopeHandlers[((EXScopedEventEmitter *)scopedSensorModule).experienceId] = handlerBlock; 113 } 114 if (![self.manager isGyroActive]) { 115 [self.manager setGyroUpdateInterval:0.1f]; 116 [self.manager startGyroUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMGyroData *data, NSError *error) { 117 for (void (^handler)(NSDictionary *) in self.gyroscopeHandlers.allValues) { 118 handler(@{ 119 @"x": [NSNumber numberWithDouble:data.rotationRate.x], 120 @"y": [NSNumber numberWithDouble:data.rotationRate.y], 121 @"z": [NSNumber numberWithDouble:data.rotationRate.z] 122 }); 123 } 124 }]; 125 } 126} 127 128- (void)sensorModuleDidUnsubscribeForGyroscopeUpdates:(id)scopedSensorModule 129{ 130 [self.gyroscopeHandlers removeObjectForKey:((EXScopedEventEmitter *)scopedSensorModule).experienceId]; 131 if (self.gyroscopeHandlers.count == 0) { 132 [self.manager stopGyroUpdates]; 133 } 134} 135 136- (void)setGyroscopeUpdateInterval:(NSTimeInterval)intervalMs 137{ 138 [self.manager setGyroUpdateInterval:intervalMs]; 139} 140 141- (void)sensorModuleDidSubscribeForMagnetometerUpdates:(id)scopedSensorModule 142 withHandler:(void (^)(NSDictionary *event))handlerBlock 143{ 144 if ([self.manager isDeviceMotionAvailable]) { 145 self.magnetometerHandlers[((EXScopedEventEmitter *)scopedSensorModule).experienceId] = handlerBlock; 146 } 147 if (![self.manager isDeviceMotionActive]) { 148 [self activateDeviceMotionUpdates]; 149 } 150} 151 152- (void)sensorModuleDidUnsubscribeForMagnetometerUpdates:(id)scopedSensorModule 153{ 154 [self.magnetometerHandlers removeObjectForKey:((EXScopedEventEmitter *)scopedSensorModule).experienceId]; 155 if (self.deviceMotionHandlers.count == 0 && self.magnetometerHandlers.count == 0) { 156 [self.manager stopDeviceMotionUpdates]; 157 } 158} 159 160- (void)setMagnetometerUpdateInterval:(NSTimeInterval)intervalMs 161{ 162 [self.manager setMagnetometerUpdateInterval:intervalMs]; 163} 164 165- (void)sensorModuleDidSubscribeForMagnetometerUncalibratedUpdates:(id)scopedSensorModule 166 withHandler:(void (^)(NSDictionary *event))handlerBlock 167{ 168 if ([self.manager isMagnetometerAvailable]) { 169 self.magnetometerUncalibratedHandlers[((EXScopedEventEmitter *)scopedSensorModule).experienceId] = handlerBlock; 170 } 171 if (![self.manager isMagnetometerActive]) { 172 [self.manager setMagnetometerUpdateInterval:0.1f]; 173 [self.manager startMagnetometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMagnetometerData *data, NSError *error) { 174 for (void (^handler)(NSDictionary *) in self.magnetometerUncalibratedHandlers.allValues) { 175 handler(@{ 176 @"x": [NSNumber numberWithDouble:data.magneticField.x], 177 @"y": [NSNumber numberWithDouble:data.magneticField.y], 178 @"z": [NSNumber numberWithDouble:data.magneticField.z] 179 }); 180 } 181 }]; 182 } 183} 184 185- (void)sensorModuleDidUnsubscribeForMagnetometerUncalibratedUpdates:(id)scopedSensorModule 186{ 187 [self.magnetometerUncalibratedHandlers removeObjectForKey:((EXScopedEventEmitter *)scopedSensorModule).experienceId]; 188 if (self.magnetometerUncalibratedHandlers.count == 0) { 189 [self.manager stopMagnetometerUpdates]; 190 } 191} 192 193- (void)setMagnetometerUncalibratedUpdateInterval:(NSTimeInterval)intervalMs 194{ 195 [self.manager setMagnetometerUpdateInterval:intervalMs]; 196} 197 198- (void)activateDeviceMotionUpdates 199{ 200 [self.manager setDeviceMotionUpdateInterval:0.1f]; 201 [self.manager 202 startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical 203 toQueue:[NSOperationQueue mainQueue] 204 withHandler:^(CMDeviceMotion *data, NSError *error) { 205 UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; 206 int orientationDegrees; 207 switch (orientation) { 208 case UIDeviceOrientationPortrait: 209 orientationDegrees = 0; 210 break; 211 case UIDeviceOrientationLandscapeLeft: 212 orientationDegrees = -90; 213 break; 214 case UIDeviceOrientationLandscapeRight: 215 orientationDegrees = 90; 216 break; 217 case UIDeviceOrientationPortraitUpsideDown: 218 orientationDegrees = 180; 219 break; 220 default: 221 orientationDegrees = 0; 222 break; 223 } 224 225 NSDictionary *result = @{ 226 @"acceleration": @{ 227 @"x": @(data.userAcceleration.x * EXGravity), 228 @"y": @(data.userAcceleration.y * EXGravity), 229 @"z": @(data.userAcceleration.z * EXGravity) 230 }, 231 @"accelerationIncludingGravity": @{ 232 @"x": @((data.userAcceleration.x + data.gravity.x) * EXGravity), 233 @"y": @((data.userAcceleration.y + data.gravity.y) * EXGravity), 234 @"z": @((data.userAcceleration.z + data.gravity.z) * EXGravity) 235 }, 236 @"rotation": @{ 237 @"alpha": @(data.attitude.yaw), 238 @"beta": @(data.attitude.pitch), 239 @"gamma": @(data.attitude.roll), 240 }, 241 @"rotationRate" :@{ 242 @"alpha": @(data.rotationRate.z), 243 @"beta": @(data.rotationRate.y), 244 @"gamma": @(data.rotationRate.x) 245 }, 246 @"orientation": @(orientationDegrees) 247 }; 248 249 // DeviceMotionUpdates handle DeviceMotion data as well as magnetic field 250 for (void (^handler)(NSDictionary *) in self.deviceMotionHandlers.allValues) { 251 handler(result); 252 } 253 254 for (void (^handler)(NSDictionary *) in self.magnetometerHandlers.allValues) { 255 handler(@{ 256 @"x": [NSNumber numberWithDouble:data.magneticField.field.x], 257 @"y": [NSNumber numberWithDouble:data.magneticField.field.y], 258 @"z": [NSNumber numberWithDouble:data.magneticField.field.z] 259 }); 260 } 261 }]; 262} 263 264@end 265