Skip to content

Commit

Permalink
Added useAnimatedSensor() (software-mansion#2868)
Browse files Browse the repository at this point in the history
## Description

Added API to create an animation based on sensor device data in a very simple way.

### Example code

```js
function AnimatedStyleUpdateExample() {

  const animatedSensor = useAnimatedSensor(SensorType.ROTATION, { interval: 10 }); // <- initialization
  const style = useAnimatedStyle(() => {
    const yaw = Math.abs(animatedSensor.sensor.value.yaw);
    const pitch = Math.abs(animatedSensor.sensor.value.pitch);
    return {
      height: withTiming(yaw * 200 + 20, { duration: 100 }), // <- usage
      width: withTiming(pitch * 200 + 20, { duration: 100 }), // <- usage
    };
  });

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Animated.View
        style={[
          { width: 100, height: 80, backgroundColor: 'black', margin: 30 },
          style,
        ]}
      />
    </View>
  );
}
```


https://user-images.githubusercontent.com/36106620/158634922-eaad656e-c837-44d5-8d51-8e7fa27c5a16.mp4
  • Loading branch information
piaskowyk authored Mar 18, 2022
1 parent 63d88ee commit d6d5f96
Show file tree
Hide file tree
Showing 36 changed files with 915 additions and 9 deletions.
72 changes: 72 additions & 0 deletions Common/cpp/AnimatedSensor/AnimatedSensorModule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "AnimatedSensorModule.h"
#include "MutableValue.h"
#include "ValueWrapper.h"

namespace reanimated {

AnimatedSensorModule::AnimatedSensorModule(
const PlatformDepMethodsHolder &platformDepMethodsHolder,
RuntimeManager *runtimeManager)
: platformRegisterSensorFunction_(platformDepMethodsHolder.registerSensor),
platformUnregisterSensorFunction_(
platformDepMethodsHolder.unregisterSensor),
runtimeManager_(runtimeManager) {}

AnimatedSensorModule::~AnimatedSensorModule() {
// It is called during app reload because app reload doesn't call hooks
// unmounting
for (auto sensorId : sensorsIds_) {
platformUnregisterSensorFunction_(sensorId);
}
}

jsi::Value AnimatedSensorModule::registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &sensorDataContainer) {
std::shared_ptr<ShareableValue> sensorsData = ShareableValue::adapt(
rt, sensorDataContainer.getObject(rt), runtimeManager_);
auto &mutableObject =
ValueWrapper::asMutableValue(sensorsData->valueContainer);

std::function<void(double[])> setter;
if (sensorType.asNumber() == SensorType::ROTATION_VECTOR) {
setter = [&, mutableObject](double newValues[]) {
jsi::Runtime &runtime = *runtimeManager_->runtime.get();
jsi::Object value(runtime);
value.setProperty(runtime, "qw", newValues[0]);
value.setProperty(runtime, "qx", newValues[1]);
value.setProperty(runtime, "qy", newValues[2]);
value.setProperty(runtime, "qz", newValues[3]);
value.setProperty(runtime, "yaw", newValues[4]);
value.setProperty(runtime, "pitch", newValues[5]);
value.setProperty(runtime, "roll", newValues[6]);
mutableObject->setValue(runtime, std::move(value));
};
} else {
setter = [&, mutableObject](double newValues[]) {
jsi::Runtime &runtime = *runtimeManager_->runtime.get();
jsi::Object value(runtime);
value.setProperty(runtime, "x", newValues[0]);
value.setProperty(runtime, "y", newValues[1]);
value.setProperty(runtime, "z", newValues[2]);
mutableObject->setValue(runtime, std::move(value));
};
}

int sensorId = platformRegisterSensorFunction_(
sensorType.asNumber(), interval.asNumber(), setter);
if (sensorId != -1) {
sensorsIds_.insert(sensorId);
}
return jsi::Value(sensorId);
}

void AnimatedSensorModule::unregisterSensor(const jsi::Value &sensorId) {
// It is called during sensor hook unmounting
sensorsIds_.erase(sensorId.getNumber());
platformUnregisterSensorFunction_(sensorId.asNumber());
}

} // namespace reanimated
19 changes: 19 additions & 0 deletions Common/cpp/NativeModules/NativeReanimatedModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "JSIStoreValueUser.h"
#include "Mapper.h"
#include "MapperRegistry.h"
#include "MutableValue.h"
#include "ReanimatedHiddenHeaders.h"
#include "RuntimeDecorator.h"
#include "ShareableValue.h"
Expand Down Expand Up @@ -71,6 +72,7 @@ NativeReanimatedModule::NativeReanimatedModule(
eventHandlerRegistry(std::make_shared<EventHandlerRegistry>()),
requestRender(platformDepMethodsHolder.requestRender),
propObtainer(propObtainer),
animatedSensorModule(platformDepMethodsHolder, this),
configurePropsPlatformFunction(
platformDepMethodsHolder.configurePropsFunction) {
auto requestAnimationFrame = [=](FrameCallback callback) {
Expand All @@ -87,6 +89,8 @@ NativeReanimatedModule::NativeReanimatedModule(
platformDepMethodsHolder.scrollToFunction,
platformDepMethodsHolder.measuringFunction,
platformDepMethodsHolder.getCurrentTime,
platformDepMethodsHolder.registerSensor,
platformDepMethodsHolder.unregisterSensor,
platformDepMethodsHolder.setGestureStateFunction,
layoutAnimationsProxy);
onRenderCallback = [this](double timestampMs) {
Expand Down Expand Up @@ -308,4 +312,19 @@ void NativeReanimatedModule::onRender(double timestampMs) {
}
}

jsi::Value NativeReanimatedModule::registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &sensorDataContainer) {
return animatedSensorModule.registerSensor(
rt, sensorType, interval, sensorDataContainer);
}

void NativeReanimatedModule::unregisterSensor(
jsi::Runtime &rt,
const jsi::Value &sensorId) {
animatedSensorModule.unregisterSensor(sensorId);
}

} // namespace reanimated
24 changes: 23 additions & 1 deletion Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,26 @@ static jsi::Value SPEC_PREFIX(enableLayoutAnimations)(
return jsi::Value::undefined();
}

static jsi::Value SPEC_PREFIX(registerSensor)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t count) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->registerSensor(
rt, std::move(args[0]), std::move(args[1]), std::move(args[2]));
}

static jsi::Value SPEC_PREFIX(unregisterSensor)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t count) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->unregisterSensor(rt, std::move(args[0]));
return jsi::Value::undefined();
}

static jsi::Value SPEC_PREFIX(configureProps)(
jsi::Runtime &rt,
TurboModule &turboModule,
Expand Down Expand Up @@ -139,7 +159,9 @@ NativeReanimatedModuleSpec::NativeReanimatedModuleSpec(
methodMap_["getViewProp"] = MethodMetadata{3, SPEC_PREFIX(getViewProp)};
methodMap_["enableLayoutAnimations"] =
MethodMetadata{2, SPEC_PREFIX(enableLayoutAnimations)};
methodMap_["registerSensor"] = MethodMetadata{3, SPEC_PREFIX(registerSensor)};
methodMap_["unregisterSensor"] =
MethodMetadata{1, SPEC_PREFIX(unregisterSensor)};
methodMap_["configureProps"] = MethodMetadata{2, SPEC_PREFIX(configureProps)};
}

} // namespace reanimated
2 changes: 2 additions & 0 deletions Common/cpp/Tools/RuntimeDecorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ void RuntimeDecorator::decorateUIRuntime(
const ScrollToFunction scrollTo,
const MeasuringFunction measure,
const TimeProviderFunction getCurrentTime,
const RegisterSensorFunction registerSensor,
const UnregisterSensorFunction unregisterSensor,
const SetGestureStateFunction setGestureState,
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy) {
RuntimeDecorator::decorateRuntime(rt, "UI");
Expand Down
41 changes: 41 additions & 0 deletions Common/cpp/headers/AnimatedSensor/AnimatedSensorModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <jsi/jsi.h>
#include <unordered_set>

#include "PlatformDepMethodsHolder.h"
#include "RuntimeManager.h"

namespace reanimated {

using namespace facebook;

enum SensorType {
ACCELEROMETER = 1,
GYROSCOPE = 2,
GRAVITY = 3,
MAGNETIC_FIELD = 4,
ROTATION_VECTOR = 5,
};

class AnimatedSensorModule {
std::unordered_set<int> sensorsIds_;
RegisterSensorFunction platformRegisterSensorFunction_;
UnregisterSensorFunction platformUnregisterSensorFunction_;
RuntimeManager *runtimeManager_;

public:
AnimatedSensorModule(
const PlatformDepMethodsHolder &platformDepMethodsHolder,
RuntimeManager *runtimeManager);
~AnimatedSensorModule();

jsi::Value registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &sensorDataContainer);
void unregisterSensor(const jsi::Value &sensorId);
};

} // namespace reanimated
9 changes: 9 additions & 0 deletions Common/cpp/headers/NativeModules/NativeReanimatedModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <vector>

#include "AnimatedSensorModule.h"
#include "ErrorHandler.h"
#include "LayoutAnimationsProxy.h"
#include "NativeReanimatedModuleSpec.h"
Expand Down Expand Up @@ -82,6 +83,13 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec,
void maybeRequestRender();
UpdaterFunction updaterFunction;

jsi::Value registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &sensorDataContainer) override;
void unregisterSensor(jsi::Runtime &rt, const jsi::Value &sensorId) override;

private:
std::shared_ptr<MapperRegistry> mapperRegistry;
std::shared_ptr<EventHandlerRegistry> eventHandlerRegistry;
Expand All @@ -93,6 +101,7 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec,
propObtainer;
std::function<void(double)> onRenderCallback;
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy;
AnimatedSensorModule animatedSensorModule;
ConfigurePropsFunction configurePropsPlatformFunction;
};

Expand Down
10 changes: 10 additions & 0 deletions Common/cpp/headers/NativeModules/NativeReanimatedModuleSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ class JSI_EXPORT NativeReanimatedModuleSpec : public TurboModule {
const jsi::Value &propName,
const jsi::Value &callback) = 0;

// sensors
virtual jsi::Value registerSensor(
jsi::Runtime &rt,
const jsi::Value &sensorType,
const jsi::Value &interval,
const jsi::Value &sensorDataContainer) = 0;
virtual void unregisterSensor(
jsi::Runtime &rt,
const jsi::Value &sensorId) = 0;

// other
virtual jsi::Value enableLayoutAnimations(
jsi::Runtime &rt,
Expand Down
5 changes: 4 additions & 1 deletion Common/cpp/headers/SharedItems/MutableValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ class MutableValue : public jsi::HostObject,
public StoreUser {
private:
friend MutableValueSetterProxy;
RuntimeManager *runtimeManager;
friend LayoutAnimationsProxy;

private:
RuntimeManager *runtimeManager;
std::mutex readWriteMutex;
std::shared_ptr<ShareableValue> value;
std::weak_ptr<jsi::Value> animation;
std::map<unsigned long, std::function<void()>> listeners;

public:
void setValue(jsi::Runtime &rt, const jsi::Value &newValue);
jsi::Value getValue(jsi::Runtime &rt);

Expand Down
3 changes: 3 additions & 0 deletions Common/cpp/headers/SharedItems/ShareableValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string>
#include <unordered_map>
#include <vector>
#include "AnimatedSensorModule.h"
#include "HostFunctionHandler.h"
#include "JSIStoreValueUser.h"
#include "LayoutAnimationsProxy.h"
Expand All @@ -24,6 +25,8 @@ class ShareableValue : public std::enable_shared_from_this<ShareableValue>,
friend WorkletsCache;
friend FrozenObject;
friend LayoutAnimationsProxy;
friend NativeReanimatedModule;
friend AnimatedSensorModule;
friend void extractMutables(
jsi::Runtime &rt,
std::shared_ptr<ShareableValue> sv,
Expand Down
3 changes: 3 additions & 0 deletions Common/cpp/headers/SharedItems/ValueWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
namespace reanimated {

class HostFunctionWrapper;
class AnimatedSensorModule;

class ValueWrapper {
friend AnimatedSensorModule;

public:
ValueWrapper() {}
explicit ValueWrapper(ValueType _type) : type(_type) {}
Expand Down
6 changes: 6 additions & 0 deletions Common/cpp/headers/Tools/PlatformDepMethodsHolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ using ScrollToFunction = std::function<void(int, double, double, bool)>;
using MeasuringFunction =
std::function<std::vector<std::pair<std::string, double>>(int)>;
using TimeProviderFunction = std::function<double(void)>;

using RegisterSensorFunction =
std::function<int(int, int, std::function<void(double[])>)>;
using UnregisterSensorFunction = std::function<void(int)>;
using SetGestureStateFunction = std::function<void(int, int)>;
using ConfigurePropsFunction = std::function<void(
jsi::Runtime &rt,
Expand All @@ -33,6 +37,8 @@ struct PlatformDepMethodsHolder {
ScrollToFunction scrollToFunction;
MeasuringFunction measuringFunction;
TimeProviderFunction getCurrentTime;
RegisterSensorFunction registerSensor;
UnregisterSensorFunction unregisterSensor;
SetGestureStateFunction setGestureStateFunction;
ConfigurePropsFunction configurePropsFunction;
};
Expand Down
2 changes: 2 additions & 0 deletions Common/cpp/headers/Tools/RuntimeDecorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class RuntimeDecorator {
const ScrollToFunction scrollTo,
const MeasuringFunction measure,
const TimeProviderFunction getCurrentTime,
const RegisterSensorFunction registerSensor,
const UnregisterSensorFunction unregisterSensor,
const SetGestureStateFunction setGestureState,
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy);

Expand Down
4 changes: 2 additions & 2 deletions Example/ios/ReanimatedExample/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
Expand Down Expand Up @@ -51,7 +53,5 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
46 changes: 46 additions & 0 deletions Example/src/AnimatedSensorExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import Animated, {
withTiming,
useAnimatedStyle,
useAnimatedSensor,
SensorType,
} from 'react-native-reanimated';
import { View, Button, StyleSheet } from 'react-native';

export default function AnimatedStyleUpdateExample() {
const animatedSensor = useAnimatedSensor(SensorType.ROTATION, {
interval: 10,
});
const style = useAnimatedStyle(() => {
const yaw = Math.abs(animatedSensor.sensor.value.yaw);
const pitch = Math.abs(animatedSensor.sensor.value.pitch);
return {
height: withTiming(yaw * 200 + 20, { duration: 100 }),
width: withTiming(pitch * 200 + 20, { duration: 100 }),
};
});

return (
<View style={componentStyle.container}>
<Button
title={'log data'}
onPress={() => console.log(animatedSensor.sensor.value)}
/>
<Animated.View style={[componentStyle.square, style]} />
</View>
);
}

const componentStyle = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
square: {
width: 50,
height: 50,
backgroundColor: 'black',
margin: 30,
},
});
Loading

0 comments on commit d6d5f96

Please sign in to comment.