#import #if !TARGET_OS_TV && !TARGET_OS_OSX && !TARGET_OS_VISION @implementation ReanimatedSensor - (instancetype)init:(ReanimatedSensorType)sensorType interval:(int)interval iosReferenceFrame:(int)iosReferenceFrame setter:(void (^)(double[], int))setter { self = [super init]; _sensorType = sensorType; if (interval == -1) { _interval = 1.0 / UIScreen.mainScreen.maximumFramesPerSecond; } else { _interval = interval / 1000.0; // in seconds } _referenceFrame = iosReferenceFrame; _setter = setter; _motionManager = [[CMMotionManager alloc] init]; return self; } - (bool)initialize { if (_sensorType == ACCELEROMETER) { return [self initializeAccelerometer]; } else if (_sensorType == GYROSCOPE) { return [self initializeGyroscope]; } else if (_sensorType == GRAVITY) { return [self initializeGravity]; } else if (_sensorType == MAGNETIC_FIELD) { return [self initializeMagnetometer]; } else if (_sensorType == ROTATION_VECTOR) { return [self initializeOrientation]; } return false; } - (bool)initializeGyroscope { if (![_motionManager isGyroAvailable]) { return false; } [_motionManager setGyroUpdateInterval:_interval]; [_motionManager startGyroUpdates]; [_motionManager startGyroUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMGyroData *sensorData, NSError *error) { double currentTime = [[NSProcessInfo processInfo] systemUptime]; if (currentTime - self->_lastTimestamp < self->_interval) { return; } double data[] = {sensorData.rotationRate.x, sensorData.rotationRate.y, sensorData.rotationRate.z}; self->_setter(data, [self getInterfaceOrientation]); self->_lastTimestamp = currentTime; }]; return true; } - (bool)initializeAccelerometer { if (![_motionManager isAccelerometerAvailable]) { return false; } [_motionManager setAccelerometerUpdateInterval:_interval]; [_motionManager startAccelerometerUpdates]; [_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *sensorData, NSError *error) { double currentTime = [[NSProcessInfo processInfo] systemUptime]; if (currentTime - self->_lastTimestamp < self->_interval) { return; } double G = 9.81; // convert G to m/s^2 double data[] = { sensorData.acceleration.x * G, sensorData.acceleration.y * G, sensorData.acceleration.z * G}; self->_setter(data, [self getInterfaceOrientation]); self->_lastTimestamp = currentTime; }]; return true; } - (bool)initializeGravity { if (![_motionManager isDeviceMotionAvailable]) { return false; } [_motionManager setDeviceMotionUpdateInterval:_interval]; [_motionManager setShowsDeviceMovementDisplay:YES]; [_motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *sensorData, NSError *error) { double currentTime = [[NSProcessInfo processInfo] systemUptime]; if (currentTime - self->_lastTimestamp < self->_interval) { return; } double G = 9.81; // convert G to m/s^2 double data[] = { sensorData.gravity.x * G, sensorData.gravity.y * G, sensorData.gravity.z * G}; self->_setter(data, [self getInterfaceOrientation]); self->_lastTimestamp = currentTime; }]; return true; } - (bool)initializeMagnetometer { if (![_motionManager isMagnetometerAvailable]) { return false; } [_motionManager setMagnetometerUpdateInterval:_interval]; [_motionManager startMagnetometerUpdates]; [_motionManager startMagnetometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMagnetometerData *sensorData, NSError *error) { double currentTime = [[NSProcessInfo processInfo] systemUptime]; if (currentTime - self->_lastTimestamp < self->_interval) { return; } double data[] = { sensorData.magneticField.x, sensorData.magneticField.y, sensorData.magneticField.z}; self->_setter(data, [self getInterfaceOrientation]); self->_lastTimestamp = currentTime; }]; return true; } - (bool)initializeOrientation { if (![_motionManager isDeviceMotionAvailable]) { return false; } [_motionManager setDeviceMotionUpdateInterval:_interval]; [_motionManager setShowsDeviceMovementDisplay:YES]; // _referenceFrame = Auto, on devices without magnetometer fall back to `XArbitraryZVertical`, // `XArbitraryCorrectedZVertical` otherwise if (_referenceFrame == 4) { if (![_motionManager isMagnetometerAvailable]) { _referenceFrame = 0; } else { _referenceFrame = 1; } } // the binary shift works here because of the definition of CMAttitudeReferenceFrame [_motionManager startDeviceMotionUpdatesUsingReferenceFrame:(1 << _referenceFrame) toQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *sensorData, NSError *error) { double currentTime = [[NSProcessInfo processInfo] systemUptime]; if (currentTime - self->_lastTimestamp < self->_interval) { return; } CMAttitude *attitude = sensorData.attitude; double data[] = { attitude.quaternion.x, attitude.quaternion.y, attitude.quaternion.z, attitude.quaternion.w, attitude.yaw, attitude.pitch, attitude.roll}; self->_setter(data, [self getInterfaceOrientation]); self->_lastTimestamp = currentTime; }]; return true; } - (void)cancel { if (_sensorType == ACCELEROMETER) { [_motionManager stopAccelerometerUpdates]; } else if (_sensorType == GYROSCOPE) { [_motionManager stopGyroUpdates]; } else if (_sensorType == GRAVITY) { [_motionManager stopDeviceMotionUpdates]; } else if (_sensorType == MAGNETIC_FIELD) { [_motionManager stopMagnetometerUpdates]; } else if (_sensorType == ROTATION_VECTOR) { [_motionManager stopDeviceMotionUpdates]; } } - (int)getInterfaceOrientation { UIInterfaceOrientation orientation = UIInterfaceOrientationPortrait; if (@available(iOS 13.0, *)) { orientation = UIApplication.sharedApplication.windows.firstObject.windowScene.interfaceOrientation; } else { orientation = UIApplication.sharedApplication.statusBarOrientation; } switch (orientation) { case UIInterfaceOrientationLandscapeLeft: return 270; case UIInterfaceOrientationLandscapeRight: return 90; case UIInterfaceOrientationPortraitUpsideDown: return 180; default: return 0; } } @end #else @implementation ReanimatedSensor - (instancetype)init:(ReanimatedSensorType)sensorType interval:(int)interval iosReferenceFrame:(int)iosReferenceFrame setter:(void (^)(double[], int))setter { self = [super init]; return self; } - (bool)initialize { return false; } - (bool)initializeGyroscope { return false; } - (bool)initializeAccelerometer { return false; } - (bool)initializeGravity { return false; } - (bool)initializeMagnetometer { return false; } - (bool)initializeOrientation { return false; } - (void)cancel { } @end #endif