chore: update map
This commit is contained in:
+292
-75
@@ -1,102 +1,319 @@
|
||||
project(Reanimated)
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set (CMAKE_VERBOSE_MAKEFILE ON)
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 73)
|
||||
set (CMAKE_CXX_STANDARD 20)
|
||||
else()
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
# default CMAKE_CXX_FLAGS: "-g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fstack-protector-all"
|
||||
|
||||
# default CMAKE_CXX_FLAGS: "-g -DANDROID -fdata-sections -ffunction-sections
|
||||
# -funwind-tables -fstack-protector-strong -no-canonical-prefixes
|
||||
# -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fstack-protector-all"
|
||||
include("${REACT_NATIVE_DIR}/ReactAndroid/cmake-utils/folly-flags.cmake")
|
||||
add_compile_options(${folly_FLAGS})
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71)
|
||||
include("${REACT_NATIVE_DIR}/ReactAndroid/cmake-utils/folly-flags.cmake")
|
||||
add_compile_options(${folly_FLAGS})
|
||||
else()
|
||||
set(folly_FLAGS "-DFOLLY_NO_CONFIG=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_HAVE_MEMRCHR=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_MOBILE=1 -DFOLLY_HAVE_RECVMMSG=1 -DFOLLY_HAVE_PTHREAD=1")
|
||||
string(APPEND CMAKE_CXX_FLAGS " ${folly_FLAGS}")
|
||||
endif()
|
||||
|
||||
string(
|
||||
APPEND
|
||||
CMAKE_CXX_FLAGS
|
||||
" -DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}\
|
||||
-DREANIMATED_VERSION=${REANIMATED_VERSION}\
|
||||
-DREANIMATED_FEATURE_FLAGS=\"${REANIMATED_FEATURE_FLAGS}\"")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fno-omit-frame-pointer -fstack-protector-all")
|
||||
# flags to optimize the binary size
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fvisibility=hidden -ffunction-sections -fdata-sections")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION} -DREANIMATED_VERSION=${REANIMATED_VERSION} -DHERMES_ENABLE_DEBUGGER=${HERMES_ENABLE_DEBUGGER}")
|
||||
|
||||
if(${REANIMATED_PROFILING})
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DREANIMATED_PROFILING")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fexceptions -fno-omit-frame-pointer -frtti -fstack-protector-all -std=c++${CMAKE_CXX_STANDARD} -Wall -Werror")
|
||||
|
||||
if(${IS_NEW_ARCHITECTURE_ENABLED})
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DRCT_NEW_ARCH_ENABLED")
|
||||
endif()
|
||||
|
||||
if(${IS_REANIMATED_EXAMPLE_APP})
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DIS_REANIMATED_EXAMPLE_APP -Wpedantic")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DIS_REANIMATED_EXAMPLE_APP")
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DNDEBUG")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DNDEBUG")
|
||||
endif()
|
||||
|
||||
set(BUILD_DIR "${CMAKE_SOURCE_DIR}/build")
|
||||
set(ANDROID_CPP_DIR "${CMAKE_SOURCE_DIR}/src/main/cpp")
|
||||
set(COMMON_CPP_DIR "${CMAKE_SOURCE_DIR}/../Common/cpp")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
|
||||
|
||||
file(GLOB_RECURSE REANIMATED_COMMON_CPP_SOURCES CONFIGURE_DEPENDS
|
||||
"${COMMON_CPP_DIR}/reanimated/*.cpp")
|
||||
file(GLOB_RECURSE REANIMATED_ANDROID_CPP_SOURCES CONFIGURE_DEPENDS
|
||||
"${ANDROID_CPP_DIR}/reanimated/*.cpp")
|
||||
set (PACKAGE_NAME "reanimated")
|
||||
set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
|
||||
set (SRC_DIR ${CMAKE_SOURCE_DIR}/src)
|
||||
set (COMMON_SRC_DIR "${CMAKE_SOURCE_DIR}/../Common")
|
||||
|
||||
find_package(fbjni REQUIRED CONFIG)
|
||||
find_package(ReactAndroid REQUIRED CONFIG)
|
||||
file(GLOB_RECURSE SOURCES_COMMON CONFIGURE_DEPENDS "${COMMON_SRC_DIR}/cpp/**.cpp")
|
||||
file(GLOB_RECURSE SOURCES_ANDROID CONFIGURE_DEPENDS "${SRC_DIR}/main/cpp/**.cpp")
|
||||
|
||||
add_library(reanimated SHARED ${REANIMATED_COMMON_CPP_SOURCES}
|
||||
${REANIMATED_ANDROID_CPP_SOURCES})
|
||||
|
||||
if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
|
||||
include(
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/cmake-utils/react-native-flags.cmake")
|
||||
target_compile_reactnative_options(reanimated PUBLIC)
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71)
|
||||
# Consume shared libraries and headers from prefabs
|
||||
find_package(fbjni REQUIRED CONFIG)
|
||||
find_package(ReactAndroid REQUIRED CONFIG)
|
||||
if(${JS_RUNTIME} STREQUAL "hermes")
|
||||
find_package(hermes-engine REQUIRED CONFIG)
|
||||
endif()
|
||||
else()
|
||||
string(APPEND CMAKE_CXX_FLAGS
|
||||
" -fexceptions -frtti -std=c++${CMAKE_CXX_STANDARD} -Wall -Werror")
|
||||
# Consume shared libraries from found .so files
|
||||
if(${IS_NEW_ARCHITECTURE_ENABLED})
|
||||
message(FATAL_ERROR "not supported")
|
||||
else()
|
||||
set (RN_SO_DIR "${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni/first-party/react/jni")
|
||||
set (FBJNI_HEADERS_DIR "${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni/first-party/fbjni/headers")
|
||||
endif()
|
||||
file (GLOB LIBRN_DIR "${RN_SO_DIR}/${ANDROID_ABI}")
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
reanimated
|
||||
PRIVATE "${COMMON_CPP_DIR}"
|
||||
"${ANDROID_CPP_DIR}"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/yoga"
|
||||
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni/react/turbomodule"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/callinvoker"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/runtimeexecutor"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/jsiexecutor"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/react/renderer/graphics/platform/cxx"
|
||||
"${REACT_NATIVE_WORKLETS_DIR}/Common/cpp"
|
||||
"${REACT_NATIVE_WORKLETS_DIR}/android/src/main/cpp")
|
||||
|
||||
set_target_properties(reanimated PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
set(BUILD_TYPE "debug")
|
||||
else()
|
||||
set(BUILD_TYPE "release")
|
||||
endif()
|
||||
|
||||
add_library(worklets SHARED IMPORTED)
|
||||
|
||||
set_target_properties(
|
||||
worklets
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION
|
||||
"${REACT_NATIVE_WORKLETS_DIR}/android/build/intermediates/cmake/${BUILD_TYPE}/obj/${ANDROID_ABI}/libworklets.so"
|
||||
add_library(
|
||||
${PACKAGE_NAME}
|
||||
SHARED
|
||||
${SOURCES_COMMON}
|
||||
${SOURCES_ANDROID}
|
||||
${INCLUDE_JSI_CPP}
|
||||
${INCLUDE_JSIDYNAMIC_CPP}
|
||||
)
|
||||
|
||||
set_target_properties(reanimated PROPERTIES LINKER_LANGUAGE CXX)
|
||||
# remove dead code sections
|
||||
set_target_properties(reanimated PROPERTIES LINK_FLAGS "-Wl,--gc-sections")
|
||||
# includes
|
||||
|
||||
target_link_libraries(reanimated log ReactAndroid::jsi fbjni::fbjni android
|
||||
worklets)
|
||||
target_include_directories(
|
||||
${PACKAGE_NAME}
|
||||
PRIVATE
|
||||
"${COMMON_SRC_DIR}/cpp/AnimatedSensor"
|
||||
"${COMMON_SRC_DIR}/cpp/Fabric"
|
||||
"${COMMON_SRC_DIR}/cpp/hidden_headers"
|
||||
"${COMMON_SRC_DIR}/cpp/LayoutAnimations"
|
||||
"${COMMON_SRC_DIR}/cpp/NativeModules"
|
||||
"${COMMON_SRC_DIR}/cpp/ReanimatedRuntime"
|
||||
"${COMMON_SRC_DIR}/cpp/Registries"
|
||||
"${COMMON_SRC_DIR}/cpp/SharedItems"
|
||||
"${COMMON_SRC_DIR}/cpp/Tools"
|
||||
"${SRC_DIR}/main/cpp"
|
||||
)
|
||||
|
||||
if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
|
||||
target_link_libraries(reanimated ReactAndroid::reactnative)
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71)
|
||||
target_include_directories(
|
||||
${PACKAGE_NAME}
|
||||
PRIVATE
|
||||
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni/react/turbomodule"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/callinvoker"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/react/renderer/graphics/platform/cxx"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/runtimeexecutor"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/yoga"
|
||||
)
|
||||
else()
|
||||
target_link_libraries(reanimated ReactAndroid::react_nativemodule_core)
|
||||
file(GLOB LIBFBJNI_INCLUDE_DIR ${FBJNI_HEADERS_DIR})
|
||||
target_include_directories(
|
||||
${PACKAGE_NAME}
|
||||
PRIVATE
|
||||
"${LIBFBJNI_INCLUDE_DIR}"
|
||||
"${BUILD_DIR}/third-party-ndk/boost/boost_${BOOST_VERSION}"
|
||||
"${BUILD_DIR}/third-party-ndk/double-conversion"
|
||||
"${BUILD_DIR}/third-party-ndk/folly"
|
||||
"${BUILD_DIR}/third-party-ndk/glog/exported"
|
||||
"${REACT_NATIVE_DIR}/React"
|
||||
"${REACT_NATIVE_DIR}/React/Base"
|
||||
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni"
|
||||
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni"
|
||||
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/java/com/facebook/react/fabric/jni"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/callinvoker"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/jsi"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/hermes"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/react/renderer/graphics/platform/cxx"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/runtimeexecutor"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/turbomodule/core"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/turbomodule"
|
||||
"${REACT_NATIVE_DIR}/ReactCommon/yoga"
|
||||
)
|
||||
endif()
|
||||
|
||||
# build shared lib
|
||||
|
||||
set_target_properties(${PACKAGE_NAME} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
log
|
||||
android
|
||||
)
|
||||
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71)
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
ReactAndroid::folly_runtime
|
||||
ReactAndroid::glog
|
||||
ReactAndroid::jsi
|
||||
ReactAndroid::reactnativejni
|
||||
fbjni::fbjni
|
||||
)
|
||||
else()
|
||||
find_library(
|
||||
JSI_LIB
|
||||
jsi
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
find_library(
|
||||
GLOG_LIB
|
||||
glog
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
|
||||
find_library(
|
||||
FBJNI_LIB
|
||||
fbjni
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
|
||||
if(${REACT_NATIVE_MINOR_VERSION} LESS 69)
|
||||
find_library(
|
||||
FOLLY_LIB
|
||||
folly_json
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
else()
|
||||
find_library(
|
||||
FOLLY_LIB
|
||||
folly_runtime
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
endif()
|
||||
|
||||
find_library(
|
||||
REACTNATIVEJNI_LIB
|
||||
reactnativejni
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
${JSI_LIB}
|
||||
${GLOG_LIB}
|
||||
${FBJNI_LIB}
|
||||
${FOLLY_LIB}
|
||||
${REACTNATIVEJNI_LIB}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${JS_RUNTIME} STREQUAL "hermes")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DJS_RUNTIME_HERMES=1")
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71)
|
||||
# From prefab from module `com.facebook.react:hermes-android`
|
||||
set(HERMES_LIB hermes-engine::libhermes)
|
||||
elseif(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 69)
|
||||
# Bundled Hermes from module `com.facebook.react:hermes-engine` or project `:ReactAndroid:hermes-engine`
|
||||
target_include_directories(
|
||||
${PACKAGE_NAME}
|
||||
PRIVATE
|
||||
"${JS_RUNTIME_DIR}/API"
|
||||
"${JS_RUNTIME_DIR}/public"
|
||||
)
|
||||
set(HERMES_LIB "${BUILD_DIR}/third-party-ndk/hermes/jni/${ANDROID_ABI}/libhermes.so")
|
||||
else()
|
||||
# From `hermes-engine` npm package
|
||||
target_include_directories(
|
||||
${PACKAGE_NAME}
|
||||
PRIVATE
|
||||
"${JS_RUNTIME_DIR}/android/include"
|
||||
)
|
||||
set(HERMES_LIB "${BUILD_DIR}/third-party-ndk/hermes/jni/${ANDROID_ABI}/libhermes.so")
|
||||
endif()
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
${HERMES_LIB}
|
||||
)
|
||||
if (${HERMES_ENABLE_DEBUGGER})
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71)
|
||||
set(HERMES_EXECUTOR_LIB ReactAndroid::hermes_executor)
|
||||
else()
|
||||
find_library(
|
||||
HERMES_EXECUTOR_LIB
|
||||
hermes-executor-debug
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
endif()
|
||||
if(${REACT_NATIVE_MINOR_VERSION} LESS_EQUAL 67)
|
||||
find_library(
|
||||
HERMES_INSPECTOR_LIB
|
||||
hermes-inspector
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
${HERMES_INSPECTOR_LIB}
|
||||
)
|
||||
endif()
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
${HERMES_EXECUTOR_LIB}
|
||||
)
|
||||
endif()
|
||||
elseif(${JS_RUNTIME} STREQUAL "v8")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DJS_RUNTIME_V8=1")
|
||||
target_include_directories(
|
||||
${PACKAGE_NAME}
|
||||
PRIVATE
|
||||
"${JS_RUNTIME_DIR}/src"
|
||||
)
|
||||
file (GLOB V8_SO_DIR "${JS_RUNTIME_DIR}/android/build/intermediates/library_jni/*/jni/${ANDROID_ABI}")
|
||||
find_library(
|
||||
V8EXECUTOR_LIB
|
||||
v8executor
|
||||
PATHS ${V8_SO_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
${V8EXECUTOR_LIB}
|
||||
)
|
||||
elseif(${JS_RUNTIME} STREQUAL "jsc")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -DJS_RUNTIME_JSC=1")
|
||||
if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71)
|
||||
set(JSEXECUTOR_LIB ReactAndroid::jscexecutor)
|
||||
else()
|
||||
find_library(
|
||||
JSEXECUTOR_LIB
|
||||
jscexecutor
|
||||
PATHS ${LIBRN_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
endif()
|
||||
target_link_libraries(${PACKAGE_NAME} ${JSEXECUTOR_LIB})
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown JS runtime ${JS_RUNTIME}.")
|
||||
endif()
|
||||
|
||||
if(${IS_NEW_ARCHITECTURE_ENABLED})
|
||||
target_link_libraries(
|
||||
${PACKAGE_NAME}
|
||||
ReactAndroid::fabricjni
|
||||
ReactAndroid::react_debug
|
||||
ReactAndroid::react_render_core
|
||||
ReactAndroid::react_render_mounting
|
||||
ReactAndroid::react_render_scheduler
|
||||
ReactAndroid::react_render_uimanager
|
||||
ReactAndroid::rrc_view
|
||||
)
|
||||
endif()
|
||||
|
||||
# Resolves "CMake Warning: Manually-specified variables were not used by the project"
|
||||
# when any of the following variables is not used in some build configuration.
|
||||
set (ignoreMe "${JS_RUNTIME_DIR}")
|
||||
set (ignoreMe "${BOOST_VERSION}")
|
||||
|
||||
+725
-182
File diff suppressed because it is too large
Load Diff
Generated
Vendored
BIN
Binary file not shown.
frontend-admin/node_modules/react-native-reanimated/android/gradle/wrapper/gradle-wrapper.properties
Generated
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
-1
@@ -1,3 +1,2 @@
|
||||
-keep class com.swmansion.reanimated.** { *; }
|
||||
-keep class com.facebook.react.turbomodule.** { *; }
|
||||
-keep class com.facebook.react.fabric.** { *; }
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ apply plugin: 'com.diffplug.spotless'
|
||||
|
||||
spotless {
|
||||
java {
|
||||
target 'src/**/*.java'
|
||||
target 'src/main/java/**/*.java'
|
||||
googleJavaFormat()
|
||||
}
|
||||
}
|
||||
|
||||
Generated
Vendored
+4
-1
@@ -1,2 +1,5 @@
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"/>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.swmansion.reanimated">
|
||||
|
||||
</manifest>
|
||||
|
||||
Generated
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace reanimated {
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::jni;
|
||||
|
||||
class AnimationFrameCallback : public HybridClass<AnimationFrameCallback> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/swmansion/reanimated/nativeProxy/AnimationFrameCallback;";
|
||||
|
||||
void onAnimationFrame(double timestampMs) {
|
||||
callback_(timestampMs);
|
||||
}
|
||||
|
||||
static void registerNatives() {
|
||||
javaClassStatic()->registerNatives({
|
||||
makeNativeMethod(
|
||||
"onAnimationFrame", AnimationFrameCallback::onAnimationFrame),
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
friend HybridBase;
|
||||
|
||||
explicit AnimationFrameCallback(std::function<void(double)> callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
|
||||
std::function<void(double)> callback_;
|
||||
};
|
||||
|
||||
} // namespace reanimated
|
||||
Generated
Vendored
-48
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <reanimated/Tools/ReanimatedSystraceSection.h>
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <react/jni/WritableNativeMap.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace reanimated {
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::jni;
|
||||
|
||||
class EventHandler : public HybridClass<EventHandler> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/swmansion/reanimated/nativeProxy/EventHandler;";
|
||||
|
||||
void receiveEvent(
|
||||
jni::alias_ref<JString> eventKey,
|
||||
jint emitterReactTag,
|
||||
jni::alias_ref<react::WritableMap> event) {
|
||||
ReanimatedSystraceSection s("EventHandler::receiveEvent");
|
||||
handler_(eventKey, emitterReactTag, event);
|
||||
}
|
||||
|
||||
static void registerNatives() {
|
||||
javaClassStatic()->registerNatives({
|
||||
makeNativeMethod("receiveEvent", EventHandler::receiveEvent),
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
friend HybridBase;
|
||||
|
||||
explicit EventHandler(std::function<void(
|
||||
jni::alias_ref<JString>,
|
||||
jint emitterReactTag,
|
||||
jni::alias_ref<react::WritableMap>)> handler)
|
||||
: handler_(std::move(handler)) {}
|
||||
|
||||
std::function<
|
||||
void(jni::alias_ref<JString>, jint, jni::alias_ref<react::WritableMap>)>
|
||||
handler_;
|
||||
};
|
||||
|
||||
} // namespace reanimated
|
||||
Generated
Vendored
-36
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace reanimated {
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::jni;
|
||||
|
||||
class KeyboardWorkletWrapper : public HybridClass<KeyboardWorkletWrapper> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/swmansion/reanimated/keyboard/KeyboardWorkletWrapper;";
|
||||
|
||||
void invoke(int keyboardState, int height) {
|
||||
callback_(keyboardState, height);
|
||||
}
|
||||
|
||||
static void registerNatives() {
|
||||
javaClassStatic()->registerNatives({
|
||||
makeNativeMethod("invoke", KeyboardWorkletWrapper::invoke),
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
friend HybridBase;
|
||||
|
||||
explicit KeyboardWorkletWrapper(std::function<void(int, int)> callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
|
||||
std::function<void(int, int)> callback_;
|
||||
};
|
||||
|
||||
} // namespace reanimated
|
||||
Generated
Vendored
-324
@@ -1,324 +0,0 @@
|
||||
#include <reanimated/RuntimeDecorators/RNRuntimeDecorator.h>
|
||||
#include <reanimated/Tools/PlatformDepMethodsHolder.h>
|
||||
#include <reanimated/Tools/ReanimatedVersion.h>
|
||||
#include <reanimated/android/AnimationFrameCallback.h>
|
||||
#include <reanimated/android/EventHandler.h>
|
||||
#include <reanimated/android/KeyboardWorkletWrapper.h>
|
||||
#include <reanimated/android/NativeProxy.h>
|
||||
#include <reanimated/android/SensorSetter.h>
|
||||
|
||||
#include <react/fabric/Binding.h>
|
||||
|
||||
namespace reanimated {
|
||||
|
||||
using namespace facebook;
|
||||
using namespace react;
|
||||
|
||||
NativeProxy::NativeProxy(
|
||||
jni::alias_ref<NativeProxy::javaobject> jThis,
|
||||
const std::shared_ptr<WorkletsModuleProxy> &workletsModuleProxy,
|
||||
jsi::Runtime *rnRuntime,
|
||||
const std::shared_ptr<facebook::react::CallInvoker> &jsCallInvoker,
|
||||
jni::alias_ref<facebook::react::JFabricUIManager::javaobject>
|
||||
fabricUIManager)
|
||||
: javaPart_(jni::make_global(jThis)),
|
||||
rnRuntime_(rnRuntime),
|
||||
workletsModuleProxy_(workletsModuleProxy),
|
||||
reanimatedModuleProxy_(std::make_shared<ReanimatedModuleProxy>(
|
||||
workletsModuleProxy,
|
||||
*rnRuntime,
|
||||
jsCallInvoker,
|
||||
getPlatformDependentMethods(),
|
||||
getIsReducedMotion())) {
|
||||
#ifndef NDEBUG
|
||||
checkJavaVersion();
|
||||
injectCppVersion();
|
||||
#endif // NDEBUG
|
||||
reanimatedModuleProxy_->init(getPlatformDependentMethods());
|
||||
const auto &uiManager =
|
||||
fabricUIManager->getBinding()->getScheduler()->getUIManager();
|
||||
reanimatedModuleProxy_->initializeFabric(uiManager);
|
||||
registerEventHandler();
|
||||
// removed temporarily, event listener mechanism needs to be fixed on RN side
|
||||
// eventListener_ = std::make_shared<EventListener>(
|
||||
// [reanimatedModuleProxy,
|
||||
// getAnimationTimestamp](const RawEvent &rawEvent) {
|
||||
// return reanimatedModuleProxy->handleRawEvent(
|
||||
// rawEvent, getAnimationTimestamp());
|
||||
// });
|
||||
// reactScheduler_ = binding->getScheduler();
|
||||
// reactScheduler_->addEventListener(eventListener_);
|
||||
}
|
||||
|
||||
NativeProxy::~NativeProxy() {
|
||||
// removed temporary, new event listener mechanism need fix on the RN side
|
||||
// reactScheduler_->removeEventListener(eventListener_);
|
||||
}
|
||||
|
||||
jni::local_ref<NativeProxy::jhybriddata> NativeProxy::initHybrid(
|
||||
jni::alias_ref<jhybridobject> jThis,
|
||||
jni::alias_ref<WorkletsModule::javaobject> jWorkletsModule,
|
||||
jlong jsContext,
|
||||
jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>
|
||||
jsCallInvokerHolder,
|
||||
jni::alias_ref<facebook::react::JFabricUIManager::javaobject>
|
||||
fabricUIManager) {
|
||||
auto jsCallInvoker = jsCallInvokerHolder->cthis()->getCallInvoker();
|
||||
auto workletsModuleProxy = jWorkletsModule->cthis()->getWorkletsModuleProxy();
|
||||
return makeCxxInstance(
|
||||
jThis,
|
||||
workletsModuleProxy,
|
||||
(jsi::Runtime *)jsContext,
|
||||
jsCallInvoker,
|
||||
fabricUIManager);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void NativeProxy::checkJavaVersion() {
|
||||
std::string javaVersion;
|
||||
try {
|
||||
javaVersion =
|
||||
getJniMethod<jstring()>("getReanimatedJavaVersion")(javaPart_.get())
|
||||
->toStdString();
|
||||
} catch (std::exception &) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"[Reanimated] C++ side failed to resolve Java code version.\n") +
|
||||
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#c-side-failed-to-resolve-java-code-version` for more details.");
|
||||
}
|
||||
|
||||
auto cppVersion = getReanimatedCppVersion();
|
||||
if (cppVersion != javaVersion) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"[Reanimated] Mismatch between C++ code version and Java code version (") +
|
||||
cppVersion + " vs. " + javaVersion + " respectively).\n" +
|
||||
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#mismatch-between-c-code-version-and-java-code-version` for more details.");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeProxy::injectCppVersion() {
|
||||
auto cppVersion = getReanimatedCppVersion();
|
||||
try {
|
||||
static const auto method =
|
||||
getJniMethod<void(jni::local_ref<JString>)>("setCppVersion");
|
||||
method(javaPart_.get(), make_jstring(cppVersion));
|
||||
} catch (std::exception &) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"[Reanimated] C++ side failed to resolve Java code version (injection).\n") +
|
||||
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#c-side-failed-to-resolve-java-code-version` for more details.");
|
||||
}
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
void NativeProxy::installJSIBindings() {
|
||||
jsi::Runtime &rnRuntime = *rnRuntime_;
|
||||
RNRuntimeDecorator::decorate(
|
||||
rnRuntime,
|
||||
workletsModuleProxy_->getUIWorkletRuntime()->getJSIRuntime(),
|
||||
reanimatedModuleProxy_);
|
||||
}
|
||||
|
||||
bool NativeProxy::isAnyHandlerWaitingForEvent(
|
||||
const std::string &eventName,
|
||||
const int emitterReactTag) {
|
||||
return reanimatedModuleProxy_->isAnyHandlerWaitingForEvent(
|
||||
eventName, emitterReactTag);
|
||||
}
|
||||
|
||||
void NativeProxy::performOperations() {
|
||||
reanimatedModuleProxy_->performOperations();
|
||||
}
|
||||
|
||||
bool NativeProxy::getIsReducedMotion() {
|
||||
static const auto method = getJniMethod<jboolean()>("getIsReducedMotion");
|
||||
return method(javaPart_.get());
|
||||
}
|
||||
|
||||
void NativeProxy::registerNatives() {
|
||||
registerHybrid(
|
||||
{makeNativeMethod("initHybrid", NativeProxy::initHybrid),
|
||||
makeNativeMethod("installJSIBindings", NativeProxy::installJSIBindings),
|
||||
makeNativeMethod(
|
||||
"isAnyHandlerWaitingForEvent",
|
||||
NativeProxy::isAnyHandlerWaitingForEvent),
|
||||
makeNativeMethod("performOperations", NativeProxy::performOperations),
|
||||
makeNativeMethod("invalidateCpp", NativeProxy::invalidateCpp)});
|
||||
}
|
||||
|
||||
void NativeProxy::requestRender(std::function<void(double)> onRender) {
|
||||
static const auto method =
|
||||
getJniMethod<void(AnimationFrameCallback::javaobject)>("requestRender");
|
||||
method(
|
||||
javaPart_.get(),
|
||||
AnimationFrameCallback::newObjectCxxArgs(std::move(onRender)).get());
|
||||
}
|
||||
|
||||
void NativeProxy::registerEventHandler() {
|
||||
auto eventHandler = bindThis(&NativeProxy::handleEvent);
|
||||
static const auto method =
|
||||
getJniMethod<void(EventHandler::javaobject)>("registerEventHandler");
|
||||
method(
|
||||
javaPart_.get(),
|
||||
EventHandler::newObjectCxxArgs(std::move(eventHandler)).get());
|
||||
}
|
||||
|
||||
void NativeProxy::maybeFlushUIUpdatesQueue() {
|
||||
// Module might be already destroyed.
|
||||
if (!javaPart_) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const auto method = getJniMethod<void()>("maybeFlushUIUpdatesQueue");
|
||||
method(javaPart_.get());
|
||||
}
|
||||
|
||||
void NativeProxy::synchronouslyUpdateUIProps(
|
||||
const std::vector<int> &intBuffer,
|
||||
const std::vector<double> &doubleBuffer) {
|
||||
static const auto method = getJniMethod<void(
|
||||
jni::alias_ref<jni::JArrayInt>, jni::alias_ref<jni::JArrayDouble>)>(
|
||||
"synchronouslyUpdateUIProps");
|
||||
auto jArrayInt = jni::JArrayInt::newArray(intBuffer.size());
|
||||
auto jArrayDouble = jni::JArrayDouble::newArray(doubleBuffer.size());
|
||||
jArrayInt->setRegion(0, intBuffer.size(), intBuffer.data());
|
||||
jArrayDouble->setRegion(0, doubleBuffer.size(), doubleBuffer.data());
|
||||
method(javaPart_.get(), jArrayInt, jArrayDouble);
|
||||
}
|
||||
|
||||
int NativeProxy::registerSensor(
|
||||
int sensorType,
|
||||
int interval,
|
||||
int,
|
||||
std::function<void(double[], int)> setter) {
|
||||
static const auto method =
|
||||
getJniMethod<int(int, int, SensorSetter::javaobject)>("registerSensor");
|
||||
return method(
|
||||
javaPart_.get(),
|
||||
sensorType,
|
||||
interval,
|
||||
SensorSetter::newObjectCxxArgs(std::move(setter)).get());
|
||||
}
|
||||
void NativeProxy::unregisterSensor(int sensorId) {
|
||||
static const auto method = getJniMethod<void(int)>("unregisterSensor");
|
||||
method(javaPart_.get(), sensorId);
|
||||
}
|
||||
|
||||
void NativeProxy::setGestureState(int handlerTag, int newState) {
|
||||
static const auto method = getJniMethod<void(int, int)>("setGestureState");
|
||||
method(javaPart_.get(), handlerTag, newState);
|
||||
}
|
||||
|
||||
int NativeProxy::subscribeForKeyboardEvents(
|
||||
std::function<void(int, int)> callback,
|
||||
bool isStatusBarTranslucent,
|
||||
bool isNavigationBarTranslucent) {
|
||||
static const auto method =
|
||||
getJniMethod<int(KeyboardWorkletWrapper::javaobject, bool, bool)>(
|
||||
"subscribeForKeyboardEvents");
|
||||
return method(
|
||||
javaPart_.get(),
|
||||
KeyboardWorkletWrapper::newObjectCxxArgs(std::move(callback)).get(),
|
||||
isStatusBarTranslucent,
|
||||
isNavigationBarTranslucent);
|
||||
}
|
||||
|
||||
void NativeProxy::unsubscribeFromKeyboardEvents(int listenerId) {
|
||||
static const auto method =
|
||||
getJniMethod<void(int)>("unsubscribeFromKeyboardEvents");
|
||||
method(javaPart_.get(), listenerId);
|
||||
}
|
||||
|
||||
double NativeProxy::getAnimationTimestamp() {
|
||||
static const auto method = getJniMethod<jlong()>("getAnimationTimestamp");
|
||||
jlong output = method(javaPart_.get());
|
||||
return static_cast<double>(output);
|
||||
}
|
||||
|
||||
void NativeProxy::handleEvent(
|
||||
jni::alias_ref<JString> eventName,
|
||||
jint emitterReactTag,
|
||||
jni::alias_ref<react::WritableMap> event) {
|
||||
// handles RCTEvents from RNGestureHandler
|
||||
if (event.get() == nullptr) {
|
||||
// Ignore events with null payload.
|
||||
return;
|
||||
}
|
||||
// TODO: convert event directly to jsi::Value without JSON serialization
|
||||
std::string eventAsString;
|
||||
try {
|
||||
eventAsString = event->toString();
|
||||
} catch (std::exception &) {
|
||||
// Events from other libraries may contain NaN or INF values which
|
||||
// cannot be represented in JSON. See
|
||||
// https://github.com/software-mansion/react-native-reanimated/issues/1776
|
||||
// for details.
|
||||
return;
|
||||
}
|
||||
std::string eventJSON = eventAsString;
|
||||
if (eventJSON == "null") {
|
||||
return;
|
||||
}
|
||||
|
||||
jsi::Runtime &rt =
|
||||
workletsModuleProxy_->getUIWorkletRuntime()->getJSIRuntime();
|
||||
jsi::Value payload;
|
||||
try {
|
||||
payload = jsi::Value::createFromJsonUtf8(
|
||||
rt, reinterpret_cast<uint8_t *>(&eventJSON[0]), eventJSON.size());
|
||||
} catch (std::exception &) {
|
||||
// Ignore events with malformed JSON payload.
|
||||
return;
|
||||
}
|
||||
|
||||
reanimatedModuleProxy_->handleEvent(
|
||||
eventName->toString(), emitterReactTag, payload, getAnimationTimestamp());
|
||||
}
|
||||
|
||||
PlatformDepMethodsHolder NativeProxy::getPlatformDependentMethods() {
|
||||
auto getAnimationTimestamp = bindThis(&NativeProxy::getAnimationTimestamp);
|
||||
|
||||
auto requestRender = bindThis(&NativeProxy::requestRender);
|
||||
|
||||
auto synchronouslyUpdateUIPropsFunction =
|
||||
bindThis(&NativeProxy::synchronouslyUpdateUIProps);
|
||||
|
||||
auto registerSensorFunction = bindThis(&NativeProxy::registerSensor);
|
||||
|
||||
auto unregisterSensorFunction = bindThis(&NativeProxy::unregisterSensor);
|
||||
|
||||
auto setGestureStateFunction = bindThis(&NativeProxy::setGestureState);
|
||||
|
||||
auto subscribeForKeyboardEventsFunction =
|
||||
bindThis(&NativeProxy::subscribeForKeyboardEvents);
|
||||
|
||||
auto unsubscribeFromKeyboardEventsFunction =
|
||||
bindThis(&NativeProxy::unsubscribeFromKeyboardEvents);
|
||||
|
||||
auto maybeFlushUiUpdatesQueueFunction =
|
||||
bindThis(&NativeProxy::maybeFlushUIUpdatesQueue);
|
||||
|
||||
return {
|
||||
requestRender,
|
||||
synchronouslyUpdateUIPropsFunction,
|
||||
getAnimationTimestamp,
|
||||
registerSensorFunction,
|
||||
unregisterSensorFunction,
|
||||
setGestureStateFunction,
|
||||
subscribeForKeyboardEventsFunction,
|
||||
unsubscribeFromKeyboardEventsFunction,
|
||||
maybeFlushUiUpdatesQueueFunction,
|
||||
};
|
||||
}
|
||||
|
||||
void NativeProxy::invalidateCpp() {
|
||||
workletsModuleProxy_.reset();
|
||||
// cleanup all animated sensors here, since the next line resets
|
||||
// the pointer and it will be too late after it
|
||||
reanimatedModuleProxy_->cleanupSensors();
|
||||
reanimatedModuleProxy_.reset();
|
||||
javaPart_ = nullptr;
|
||||
}
|
||||
|
||||
} // namespace reanimated
|
||||
Generated
Vendored
-120
@@ -1,120 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <reanimated/NativeModules/ReanimatedModuleProxy.h>
|
||||
|
||||
#include <worklets/android/WorkletsModule.h>
|
||||
|
||||
#include <ReactCommon/CallInvokerHolder.h>
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <jsi/jsi.h>
|
||||
#include <react/fabric/JFabricUIManager.h>
|
||||
#include <react/jni/WritableNativeMap.h>
|
||||
#include <react/renderer/scheduler/Scheduler.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace reanimated {
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::jni;
|
||||
|
||||
class NativeProxy : public jni::HybridClass<NativeProxy>,
|
||||
std::enable_shared_from_this<NativeProxy> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/swmansion/reanimated/NativeProxy;";
|
||||
static jni::local_ref<jhybriddata> initHybrid(
|
||||
jni::alias_ref<jhybridobject> jThis,
|
||||
jni::alias_ref<WorkletsModule::javaobject> jWorkletsModule,
|
||||
jlong jsContext,
|
||||
jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>
|
||||
jsCallInvokerHolder,
|
||||
jni::alias_ref<facebook::react::JFabricUIManager::javaobject>
|
||||
fabricUIManager);
|
||||
|
||||
static void registerNatives();
|
||||
|
||||
~NativeProxy();
|
||||
|
||||
private:
|
||||
friend HybridBase;
|
||||
jni::global_ref<NativeProxy::javaobject> javaPart_;
|
||||
jsi::Runtime *rnRuntime_;
|
||||
std::shared_ptr<WorkletsModuleProxy> workletsModuleProxy_;
|
||||
std::shared_ptr<ReanimatedModuleProxy> reanimatedModuleProxy_;
|
||||
#ifndef NDEBUG
|
||||
void checkJavaVersion();
|
||||
void injectCppVersion();
|
||||
#endif // NDEBUG
|
||||
// removed temporarily, event listener mechanism needs to be fixed on RN side
|
||||
// std::shared_ptr<facebook::react::Scheduler> reactScheduler_;
|
||||
// std::shared_ptr<EventListener> eventListener_;
|
||||
void installJSIBindings();
|
||||
void synchronouslyUpdateUIProps(
|
||||
const std::vector<int> &intBuffer,
|
||||
const std::vector<double> &doubleBuffer);
|
||||
PlatformDepMethodsHolder getPlatformDependentMethods();
|
||||
|
||||
double getAnimationTimestamp();
|
||||
bool isAnyHandlerWaitingForEvent(
|
||||
const std::string &eventName,
|
||||
const int emitterReactTag);
|
||||
void performOperations();
|
||||
bool getIsReducedMotion();
|
||||
void requestRender(std::function<void(double)> onRender);
|
||||
void registerEventHandler();
|
||||
void maybeFlushUIUpdatesQueue();
|
||||
void setGestureState(int handlerTag, int newState);
|
||||
int registerSensor(
|
||||
int sensorType,
|
||||
int interval,
|
||||
int iosReferenceFrame,
|
||||
std::function<void(double[], int)> setter);
|
||||
void unregisterSensor(int sensorId);
|
||||
int subscribeForKeyboardEvents(
|
||||
std::function<void(int, int)> callback,
|
||||
bool isStatusBarTranslucent,
|
||||
bool isNavigationBarTranslucent);
|
||||
void unsubscribeFromKeyboardEvents(int listenerId);
|
||||
void handleEvent(
|
||||
jni::alias_ref<JString> eventName,
|
||||
jint emitterReactTag,
|
||||
jni::alias_ref<react::WritableMap> event);
|
||||
|
||||
/***
|
||||
* Wraps a method of `NativeProxy` in a function object capturing `this`
|
||||
* @tparam TReturn return type of passed method
|
||||
* @tparam TParams parameter types of passed method
|
||||
* @param methodPtr pointer to method to be wrapped
|
||||
* @return a function object with the same signature as the method, calling
|
||||
* that method on `this`
|
||||
*/
|
||||
template <class TReturn, class... TParams>
|
||||
std::function<TReturn(TParams...)> bindThis(
|
||||
TReturn (NativeProxy::*methodPtr)(TParams...)) {
|
||||
// It's probably safe to pass `this` as reference here...
|
||||
return [this, methodPtr](TParams &&...args) {
|
||||
return (this->*methodPtr)(std::forward<TParams>(args)...);
|
||||
};
|
||||
}
|
||||
|
||||
template <class Signature>
|
||||
JMethod<Signature> getJniMethod(std::string const &methodName) {
|
||||
return javaPart_->getClass()->getMethod<Signature>(methodName.c_str());
|
||||
}
|
||||
|
||||
explicit NativeProxy(
|
||||
jni::alias_ref<NativeProxy::jhybridobject> jThis,
|
||||
const std::shared_ptr<WorkletsModuleProxy> &workletsModuleProxy,
|
||||
jsi::Runtime *rnRuntime,
|
||||
const std::shared_ptr<facebook::react::CallInvoker> &jsCallInvoker,
|
||||
jni::alias_ref<facebook::react::JFabricUIManager::javaobject>
|
||||
fabricUIManager);
|
||||
|
||||
void invalidateCpp();
|
||||
};
|
||||
|
||||
} // namespace reanimated
|
||||
Generated
Vendored
-17
@@ -1,17 +0,0 @@
|
||||
#include <fbjni/fbjni.h>
|
||||
|
||||
#include <reanimated/android/AnimationFrameCallback.h>
|
||||
#include <reanimated/android/EventHandler.h>
|
||||
#include <reanimated/android/KeyboardWorkletWrapper.h>
|
||||
#include <reanimated/android/NativeProxy.h>
|
||||
#include <reanimated/android/SensorSetter.h>
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
|
||||
return facebook::jni::initialize(vm, [] {
|
||||
reanimated::NativeProxy::registerNatives();
|
||||
reanimated::AnimationFrameCallback::registerNatives();
|
||||
reanimated::EventHandler::registerNatives();
|
||||
reanimated::SensorSetter::registerNatives();
|
||||
reanimated::KeyboardWorkletWrapper::registerNatives();
|
||||
});
|
||||
}
|
||||
Generated
Vendored
-42
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace reanimated {
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::jni;
|
||||
|
||||
class SensorSetter : public HybridClass<SensorSetter> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/swmansion/reanimated/nativeProxy/SensorSetter;";
|
||||
|
||||
void sensorSetter(jni::alias_ref<JArrayFloat> value, int orientationDegrees) {
|
||||
size_t size = value->size();
|
||||
auto elements = value->getRegion(0, size);
|
||||
double array[7];
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
array[i] = elements[i];
|
||||
}
|
||||
callback_(array, orientationDegrees);
|
||||
}
|
||||
|
||||
static void registerNatives() {
|
||||
javaClassStatic()->registerNatives({
|
||||
makeNativeMethod("sensorSetter", SensorSetter::sensorSetter),
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
friend HybridBase;
|
||||
|
||||
explicit SensorSetter(std::function<void(double[], int)> callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
|
||||
std::function<void(double[], int)> callback_;
|
||||
};
|
||||
|
||||
} // namespace reanimated
|
||||
Generated
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
package com.swmansion.reanimated;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.devsupport.interfaces.DevOptionHandler;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
|
||||
public class DevMenuUtils {
|
||||
|
||||
public static void addDevMenuOption(ReactApplicationContext context, DevOptionHandler handler) {
|
||||
// In Expo, `ApplicationContext` is not an instance of `ReactApplication`
|
||||
if (context.getApplicationContext() instanceof ReactApplication) {
|
||||
DevSupportManager devSupportManager =
|
||||
((ReactApplication) context.getApplicationContext())
|
||||
.getReactHost()
|
||||
.getDevSupportManager();
|
||||
|
||||
if (devSupportManager != null) {
|
||||
devSupportManager.addCustomDevOption("Toggle slow animations (Reanimated)", handler);
|
||||
} else {
|
||||
throw new RuntimeException("[Reanimated] DevSupportManager is not available");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
Vendored
-494
@@ -1,494 +0,0 @@
|
||||
package com.swmansion.reanimated;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.Settings;
|
||||
import androidx.annotation.OptIn;
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.bridge.JavaOnlyArray;
|
||||
import com.facebook.react.bridge.JavaOnlyMap;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.annotations.FrameworkAPI;
|
||||
import com.facebook.react.fabric.FabricUIManager;
|
||||
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
|
||||
import com.facebook.react.uimanager.UIManagerHelper;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import com.swmansion.common.GestureHandlerStateManager;
|
||||
import com.swmansion.reanimated.keyboard.KeyboardAnimationManager;
|
||||
import com.swmansion.reanimated.keyboard.KeyboardWorkletWrapper;
|
||||
import com.swmansion.reanimated.nativeProxy.AnimationFrameCallback;
|
||||
import com.swmansion.reanimated.nativeProxy.EventHandler;
|
||||
import com.swmansion.reanimated.nativeProxy.SensorSetter;
|
||||
import com.swmansion.reanimated.sensor.ReanimatedSensorContainer;
|
||||
import com.swmansion.reanimated.sensor.ReanimatedSensorType;
|
||||
import com.swmansion.worklets.JSCallInvokerResolver;
|
||||
import com.swmansion.worklets.WorkletsModule;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.PrimitiveIterator;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @noinspection JavaJniMissingFunction
|
||||
*/
|
||||
public class NativeProxy {
|
||||
static {
|
||||
SoLoader.loadLibrary("reanimated");
|
||||
}
|
||||
|
||||
protected final WorkletsModule mWorkletsModule;
|
||||
protected NodesManager mNodesManager;
|
||||
protected final FabricUIManager mFabricUIManager;
|
||||
protected final WeakReference<ReactApplicationContext> mContext;
|
||||
private final ReanimatedSensorContainer reanimatedSensorContainer;
|
||||
private final GestureHandlerStateManager gestureHandlerStateManager;
|
||||
private final KeyboardAnimationManager keyboardAnimationManager;
|
||||
private Long firstUptime = SystemClock.uptimeMillis();
|
||||
private boolean slowAnimationsEnabled = false;
|
||||
private final int ANIMATIONS_DRAG_FACTOR = 10;
|
||||
protected String cppVersion = null;
|
||||
|
||||
/**
|
||||
* Invalidating concurrently could be fatal. It shouldn't happen in a normal flow, but it doesn't
|
||||
* cost us much to add synchronization for extra safety.
|
||||
*/
|
||||
private final AtomicBoolean mInvalidated = new AtomicBoolean(false);
|
||||
|
||||
@DoNotStrip
|
||||
@SuppressWarnings("unused")
|
||||
private final HybridData mHybridData;
|
||||
|
||||
public @OptIn(markerClass = FrameworkAPI.class) NativeProxy(
|
||||
ReactApplicationContext context, WorkletsModule workletsModule, NodesManager nodesManager) {
|
||||
context.assertOnJSQueueThread();
|
||||
|
||||
mWorkletsModule = workletsModule;
|
||||
mContext = new WeakReference<>(context);
|
||||
reanimatedSensorContainer = new ReanimatedSensorContainer(mContext);
|
||||
keyboardAnimationManager = new KeyboardAnimationManager(mContext);
|
||||
addDevMenuOption();
|
||||
|
||||
GestureHandlerStateManager tempHandlerStateManager;
|
||||
try {
|
||||
Class<NativeModule> gestureHandlerModuleClass =
|
||||
(Class<NativeModule>)
|
||||
Class.forName("com.swmansion.gesturehandler.react.RNGestureHandlerModule");
|
||||
tempHandlerStateManager =
|
||||
(GestureHandlerStateManager) context.getNativeModule(gestureHandlerModuleClass);
|
||||
} catch (ClassCastException | ClassNotFoundException e) {
|
||||
tempHandlerStateManager = null;
|
||||
}
|
||||
gestureHandlerStateManager = tempHandlerStateManager;
|
||||
mNodesManager = nodesManager;
|
||||
|
||||
mFabricUIManager =
|
||||
(FabricUIManager) UIManagerHelper.getUIManager(context, UIManagerType.FABRIC);
|
||||
|
||||
CallInvokerHolderImpl callInvokerHolder = JSCallInvokerResolver.getJSCallInvokerHolder(context);
|
||||
mHybridData =
|
||||
initHybrid(
|
||||
workletsModule,
|
||||
Objects.requireNonNull(context.getJavaScriptContextHolder()).get(),
|
||||
callInvokerHolder,
|
||||
mFabricUIManager);
|
||||
if (BuildConfig.DEBUG) {
|
||||
checkCppVersion(); // injectCppVersion should be called during initHybrid above
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(markerClass = FrameworkAPI.class)
|
||||
private native HybridData initHybrid(
|
||||
WorkletsModule workletsModule,
|
||||
long jsContext,
|
||||
CallInvokerHolderImpl jsCallInvokerHolder,
|
||||
FabricUIManager fabricUIManager);
|
||||
|
||||
public native boolean isAnyHandlerWaitingForEvent(String eventName, int emitterReactTag);
|
||||
|
||||
public native void performOperations();
|
||||
|
||||
protected native void installJSIBindings();
|
||||
|
||||
private native void invalidateCpp();
|
||||
|
||||
protected HybridData getHybridData() {
|
||||
return mHybridData;
|
||||
}
|
||||
|
||||
protected void invalidate() {
|
||||
if (mInvalidated.getAndSet(true)) {
|
||||
return;
|
||||
}
|
||||
if (mHybridData != null && mHybridData.isValid()) {
|
||||
invalidateCpp();
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleSlowAnimations() {
|
||||
slowAnimationsEnabled = !slowAnimationsEnabled;
|
||||
if (slowAnimationsEnabled) {
|
||||
firstUptime = SystemClock.uptimeMillis();
|
||||
}
|
||||
mNodesManager.enableSlowAnimations(slowAnimationsEnabled, ANIMATIONS_DRAG_FACTOR);
|
||||
mWorkletsModule.toggleSlowAnimations();
|
||||
}
|
||||
|
||||
private void addDevMenuOption() {
|
||||
// In Expo, `ApplicationContext` is not an instance of `ReactApplication`
|
||||
DevMenuUtils.addDevMenuOption(mContext.get(), this::toggleSlowAnimations);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public void requestRender(AnimationFrameCallback callback) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
mNodesManager.postOnAnimation(callback);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public String getReanimatedJavaVersion() {
|
||||
return BuildConfig.REANIMATED_VERSION_JAVA;
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
@SuppressWarnings("unused")
|
||||
// It turns out it's pretty difficult to set a member of a class
|
||||
// instance through JNI so we decided to use a setter instead.
|
||||
protected void setCppVersion(String version) {
|
||||
cppVersion = version;
|
||||
}
|
||||
|
||||
protected void checkCppVersion() {
|
||||
if (cppVersion == null) {
|
||||
throw new RuntimeException(
|
||||
"[Reanimated] Java side failed to resolve C++ code version. "
|
||||
+ "See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#java-side-failed-to-resolve-c-code-version for more information.");
|
||||
}
|
||||
String javaVersion = getReanimatedJavaVersion();
|
||||
if (!cppVersion.equals(javaVersion)) {
|
||||
throw new RuntimeException(
|
||||
"[Reanimated] Mismatch between Java code version and C++ code version ("
|
||||
+ javaVersion
|
||||
+ " vs. "
|
||||
+ cppVersion
|
||||
+ " respectively). See "
|
||||
+ "https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#mismatch-between-java-code-version-and-c-code-version for more information.");
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Keep in sync with ReanimatedModuleProxy::performOperations
|
||||
private static final int CMD_START_OF_VIEW = 1;
|
||||
private static final int CMD_START_OF_TRANSFORM = 2;
|
||||
private static final int CMD_END_OF_TRANSFORM = 3;
|
||||
private static final int CMD_END_OF_VIEW = 4;
|
||||
|
||||
private static final int CMD_OPACITY = 10;
|
||||
private static final int CMD_ELEVATION = 11;
|
||||
private static final int CMD_Z_INDEX = 12;
|
||||
private static final int CMD_SHADOW_OPACITY = 13;
|
||||
private static final int CMD_SHADOW_RADIUS = 14;
|
||||
private static final int CMD_BACKGROUND_COLOR = 15;
|
||||
private static final int CMD_COLOR = 16;
|
||||
private static final int CMD_TINT_COLOR = 17;
|
||||
|
||||
private static final int CMD_BORDER_RADIUS = 20;
|
||||
private static final int CMD_BORDER_TOP_LEFT_RADIUS = 21;
|
||||
private static final int CMD_BORDER_TOP_RIGHT_RADIUS = 22;
|
||||
private static final int CMD_BORDER_TOP_START_RADIUS = 23;
|
||||
private static final int CMD_BORDER_TOP_END_RADIUS = 24;
|
||||
private static final int CMD_BORDER_BOTTOM_LEFT_RADIUS = 25;
|
||||
private static final int CMD_BORDER_BOTTOM_RIGHT_RADIUS = 26;
|
||||
private static final int CMD_BORDER_BOTTOM_START_RADIUS = 27;
|
||||
private static final int CMD_BORDER_BOTTOM_END_RADIUS = 28;
|
||||
private static final int CMD_BORDER_START_START_RADIUS = 29;
|
||||
private static final int CMD_BORDER_START_END_RADIUS = 30;
|
||||
private static final int CMD_BORDER_END_START_RADIUS = 31;
|
||||
private static final int CMD_BORDER_END_END_RADIUS = 32;
|
||||
|
||||
private static final int CMD_BORDER_COLOR = 40;
|
||||
private static final int CMD_BORDER_TOP_COLOR = 41;
|
||||
private static final int CMD_BORDER_BOTTOM_COLOR = 42;
|
||||
private static final int CMD_BORDER_LEFT_COLOR = 43;
|
||||
private static final int CMD_BORDER_RIGHT_COLOR = 44;
|
||||
private static final int CMD_BORDER_START_COLOR = 45;
|
||||
private static final int CMD_BORDER_END_COLOR = 46;
|
||||
|
||||
private static final int CMD_TRANSFORM_TRANSLATE_X = 100;
|
||||
private static final int CMD_TRANSFORM_TRANSLATE_Y = 101;
|
||||
private static final int CMD_TRANSFORM_SCALE = 102;
|
||||
private static final int CMD_TRANSFORM_SCALE_X = 103;
|
||||
private static final int CMD_TRANSFORM_SCALE_Y = 104;
|
||||
private static final int CMD_TRANSFORM_ROTATE = 105;
|
||||
private static final int CMD_TRANSFORM_ROTATE_X = 106;
|
||||
private static final int CMD_TRANSFORM_ROTATE_Y = 107;
|
||||
private static final int CMD_TRANSFORM_ROTATE_Z = 108;
|
||||
private static final int CMD_TRANSFORM_SKEW_X = 109;
|
||||
private static final int CMD_TRANSFORM_SKEW_Y = 110;
|
||||
private static final int CMD_TRANSFORM_MATRIX = 111;
|
||||
private static final int CMD_TRANSFORM_PERSPECTIVE = 112;
|
||||
|
||||
private static final int CMD_UNIT_DEG = 200;
|
||||
private static final int CMD_UNIT_RAD = 201;
|
||||
private static final int CMD_UNIT_PX = 202;
|
||||
private static final int CMD_UNIT_PERCENT = 203;
|
||||
|
||||
private static String commandToString(int command) {
|
||||
return switch (command) {
|
||||
case CMD_OPACITY -> "opacity";
|
||||
case CMD_ELEVATION -> "elevation";
|
||||
case CMD_Z_INDEX -> "zIndex";
|
||||
case CMD_SHADOW_OPACITY -> "shadowOpacity";
|
||||
case CMD_SHADOW_RADIUS -> "shadowRadius";
|
||||
case CMD_BACKGROUND_COLOR -> "backgroundColor";
|
||||
case CMD_COLOR -> "color";
|
||||
case CMD_TINT_COLOR -> "tintColor";
|
||||
case CMD_BORDER_RADIUS -> "borderRadius";
|
||||
case CMD_BORDER_TOP_LEFT_RADIUS -> "borderTopLeftRadius";
|
||||
case CMD_BORDER_TOP_RIGHT_RADIUS -> "borderTopRightRadius";
|
||||
case CMD_BORDER_TOP_START_RADIUS -> "borderTopStartRadius";
|
||||
case CMD_BORDER_TOP_END_RADIUS -> "borderTopEndRadius";
|
||||
case CMD_BORDER_BOTTOM_LEFT_RADIUS -> "borderBottomLeftRadius";
|
||||
case CMD_BORDER_BOTTOM_RIGHT_RADIUS -> "borderBottomRightRadius";
|
||||
case CMD_BORDER_BOTTOM_START_RADIUS -> "borderBottomStartRadius";
|
||||
case CMD_BORDER_BOTTOM_END_RADIUS -> "borderBottomEndRadius";
|
||||
case CMD_BORDER_START_START_RADIUS -> "borderStartStartRadius";
|
||||
case CMD_BORDER_START_END_RADIUS -> "borderStartEndRadius";
|
||||
case CMD_BORDER_END_START_RADIUS -> "borderEndStartRadius";
|
||||
case CMD_BORDER_END_END_RADIUS -> "borderEndEndRadius";
|
||||
case CMD_BORDER_COLOR -> "borderColor";
|
||||
case CMD_BORDER_TOP_COLOR -> "borderTopColor";
|
||||
case CMD_BORDER_BOTTOM_COLOR -> "borderBottomColor";
|
||||
case CMD_BORDER_LEFT_COLOR -> "borderLeftColor";
|
||||
case CMD_BORDER_RIGHT_COLOR -> "borderRightColor";
|
||||
case CMD_BORDER_START_COLOR -> "borderStartColor";
|
||||
case CMD_BORDER_END_COLOR -> "borderEndColor";
|
||||
default -> throw new RuntimeException("Unknown command: " + command);
|
||||
};
|
||||
}
|
||||
|
||||
private static String transformCommandToString(int transformCommand) {
|
||||
return switch (transformCommand) {
|
||||
case CMD_TRANSFORM_TRANSLATE_X -> "translateX";
|
||||
case CMD_TRANSFORM_TRANSLATE_Y -> "translateY";
|
||||
case CMD_TRANSFORM_SCALE -> "scale";
|
||||
case CMD_TRANSFORM_SCALE_X -> "scaleX";
|
||||
case CMD_TRANSFORM_SCALE_Y -> "scaleY";
|
||||
case CMD_TRANSFORM_ROTATE -> "rotate";
|
||||
case CMD_TRANSFORM_ROTATE_X -> "rotateX";
|
||||
case CMD_TRANSFORM_ROTATE_Y -> "rotateY";
|
||||
case CMD_TRANSFORM_ROTATE_Z -> "rotateZ";
|
||||
case CMD_TRANSFORM_SKEW_X -> "skewX";
|
||||
case CMD_TRANSFORM_SKEW_Y -> "skewY";
|
||||
case CMD_TRANSFORM_MATRIX -> "matrix";
|
||||
case CMD_TRANSFORM_PERSPECTIVE -> "perspective";
|
||||
default -> throw new RuntimeException("Unknown transform command: " + transformCommand);
|
||||
};
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public void synchronouslyUpdateUIProps(int[] intBuffer, double[] doubleBuffer) {
|
||||
PrimitiveIterator.OfInt intIterator = Arrays.stream(intBuffer).iterator();
|
||||
PrimitiveIterator.OfDouble doubleIterator = Arrays.stream(doubleBuffer).iterator();
|
||||
int viewTag = -1;
|
||||
JavaOnlyMap props = new JavaOnlyMap();
|
||||
while (intIterator.hasNext()) {
|
||||
int command = intIterator.nextInt();
|
||||
switch (command) {
|
||||
case CMD_START_OF_VIEW:
|
||||
viewTag = intIterator.nextInt();
|
||||
props = new JavaOnlyMap();
|
||||
break;
|
||||
|
||||
case CMD_OPACITY:
|
||||
case CMD_ELEVATION:
|
||||
case CMD_Z_INDEX:
|
||||
case CMD_SHADOW_OPACITY:
|
||||
case CMD_SHADOW_RADIUS:
|
||||
{
|
||||
String name = commandToString(command);
|
||||
props.putDouble(name, doubleIterator.nextDouble());
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_BACKGROUND_COLOR:
|
||||
case CMD_COLOR:
|
||||
case CMD_TINT_COLOR:
|
||||
case CMD_BORDER_COLOR:
|
||||
case CMD_BORDER_TOP_COLOR:
|
||||
case CMD_BORDER_BOTTOM_COLOR:
|
||||
case CMD_BORDER_LEFT_COLOR:
|
||||
case CMD_BORDER_RIGHT_COLOR:
|
||||
case CMD_BORDER_START_COLOR:
|
||||
case CMD_BORDER_END_COLOR:
|
||||
{
|
||||
String name = commandToString(command);
|
||||
props.putInt(name, intIterator.nextInt());
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_BORDER_RADIUS:
|
||||
case CMD_BORDER_TOP_LEFT_RADIUS:
|
||||
case CMD_BORDER_TOP_RIGHT_RADIUS:
|
||||
case CMD_BORDER_TOP_START_RADIUS:
|
||||
case CMD_BORDER_TOP_END_RADIUS:
|
||||
case CMD_BORDER_BOTTOM_LEFT_RADIUS:
|
||||
case CMD_BORDER_BOTTOM_RIGHT_RADIUS:
|
||||
case CMD_BORDER_BOTTOM_START_RADIUS:
|
||||
case CMD_BORDER_BOTTOM_END_RADIUS:
|
||||
case CMD_BORDER_START_START_RADIUS:
|
||||
case CMD_BORDER_START_END_RADIUS:
|
||||
case CMD_BORDER_END_START_RADIUS:
|
||||
case CMD_BORDER_END_END_RADIUS:
|
||||
{
|
||||
String name = commandToString(command);
|
||||
double value = doubleIterator.nextDouble();
|
||||
switch (intIterator.nextInt()) {
|
||||
case CMD_UNIT_PX -> props.putDouble(name, value);
|
||||
case CMD_UNIT_PERCENT -> props.putString(name, value + "%");
|
||||
default -> throw new RuntimeException("Unknown unit command");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_START_OF_TRANSFORM:
|
||||
JavaOnlyArray transform = new JavaOnlyArray();
|
||||
while (true) {
|
||||
int transformCommand = intIterator.nextInt();
|
||||
if (transformCommand == CMD_END_OF_TRANSFORM) {
|
||||
props.putArray("transform", transform);
|
||||
break;
|
||||
}
|
||||
String name = transformCommandToString(transformCommand);
|
||||
switch (transformCommand) {
|
||||
case CMD_TRANSFORM_TRANSLATE_X:
|
||||
case CMD_TRANSFORM_TRANSLATE_Y:
|
||||
{
|
||||
double value = doubleIterator.nextDouble();
|
||||
switch (intIterator.nextInt()) {
|
||||
case CMD_UNIT_PX -> transform.pushMap(JavaOnlyMap.of(name, value));
|
||||
case CMD_UNIT_PERCENT -> transform.pushMap(JavaOnlyMap.of(name, value + "%"));
|
||||
default -> throw new RuntimeException("Unknown unit command");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_TRANSFORM_SCALE:
|
||||
case CMD_TRANSFORM_SCALE_X:
|
||||
case CMD_TRANSFORM_SCALE_Y:
|
||||
case CMD_TRANSFORM_PERSPECTIVE:
|
||||
{
|
||||
double value = doubleIterator.nextDouble();
|
||||
transform.pushMap(JavaOnlyMap.of(name, value));
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_TRANSFORM_ROTATE:
|
||||
case CMD_TRANSFORM_ROTATE_X:
|
||||
case CMD_TRANSFORM_ROTATE_Y:
|
||||
case CMD_TRANSFORM_ROTATE_Z:
|
||||
case CMD_TRANSFORM_SKEW_X:
|
||||
case CMD_TRANSFORM_SKEW_Y:
|
||||
double angle = doubleIterator.nextDouble();
|
||||
String unit =
|
||||
switch (intIterator.nextInt()) {
|
||||
case CMD_UNIT_DEG -> "deg";
|
||||
case CMD_UNIT_RAD -> "rad";
|
||||
default -> throw new RuntimeException("Unknown unit command");
|
||||
};
|
||||
transform.pushMap(JavaOnlyMap.of(name, angle + unit));
|
||||
break;
|
||||
|
||||
case CMD_TRANSFORM_MATRIX:
|
||||
int length = intIterator.nextInt();
|
||||
JavaOnlyArray matrix = new JavaOnlyArray();
|
||||
for (int i = 0; i < length; i++) {
|
||||
matrix.pushDouble(doubleIterator.nextDouble());
|
||||
}
|
||||
transform.pushMap(JavaOnlyMap.of(name, matrix));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unknown transform type: " + transformCommand);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_END_OF_VIEW:
|
||||
mFabricUIManager.synchronouslyUpdateViewOnUIThread(viewTag, props);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unexcepted command: " + command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public void setGestureState(int handlerTag, int newState) {
|
||||
if (gestureHandlerStateManager != null) {
|
||||
gestureHandlerStateManager.setGestureHandlerState(handlerTag, newState);
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public long getAnimationTimestamp() {
|
||||
if (slowAnimationsEnabled) {
|
||||
return this.firstUptime
|
||||
+ (SystemClock.uptimeMillis() - this.firstUptime) / ANIMATIONS_DRAG_FACTOR;
|
||||
} else {
|
||||
return SystemClock.uptimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public void registerEventHandler(EventHandler handler) {
|
||||
handler.mCustomEventNamesResolver = mNodesManager.getEventNameResolver();
|
||||
mNodesManager.registerEventHandler(handler);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public int registerSensor(int sensorType, int interval, SensorSetter setter) {
|
||||
return reanimatedSensorContainer.registerSensor(
|
||||
ReanimatedSensorType.getInstanceById(sensorType), interval, setter);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public void unregisterSensor(int sensorId) {
|
||||
reanimatedSensorContainer.unregisterSensor(sensorId);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public int subscribeForKeyboardEvents(
|
||||
KeyboardWorkletWrapper keyboardWorkletWrapper,
|
||||
boolean isStatusBarTranslucent,
|
||||
boolean isNavigationBarTranslucent) {
|
||||
return keyboardAnimationManager.subscribeForKeyboardUpdates(
|
||||
keyboardWorkletWrapper, isStatusBarTranslucent, isNavigationBarTranslucent);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public void unsubscribeFromKeyboardEvents(int listenerId) {
|
||||
keyboardAnimationManager.unsubscribeFromKeyboardUpdates(listenerId);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public boolean getIsReducedMotion() {
|
||||
ContentResolver mContentResolver = mContext.get().getContentResolver();
|
||||
String rawValue =
|
||||
Settings.Global.getString(mContentResolver, Settings.Global.TRANSITION_ANIMATION_SCALE);
|
||||
float parsedValue = rawValue != null ? Float.parseFloat(rawValue) : 1f;
|
||||
return parsedValue == 0f;
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
void maybeFlushUIUpdatesQueue() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
if (!mNodesManager.isAnimationRunning()) {
|
||||
mNodesManager.performOperations();
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+330
-96
@@ -1,49 +1,103 @@
|
||||
package com.swmansion.reanimated;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import androidx.tracing.Trace;
|
||||
import static java.lang.Float.NaN;
|
||||
|
||||
import android.view.View;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.GuardedRunnable;
|
||||
import com.facebook.react.bridge.JavaOnlyMap;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.UIManager;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.fabric.FabricUIManager;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.modules.core.ReactChoreographer;
|
||||
import com.facebook.react.uimanager.GuardedFrameCallback;
|
||||
import com.facebook.react.uimanager.UIManagerHelper;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap;
|
||||
import com.facebook.react.uimanager.UIImplementation;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import com.facebook.react.uimanager.UIManagerReanimatedHelper;
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.EventDispatcherListener;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import com.swmansion.reanimated.layoutReanimation.AnimationsManager;
|
||||
import com.swmansion.reanimated.nativeProxy.NoopEventHandler;
|
||||
import com.swmansion.worklets.WorkletsModule;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class NodesManager implements EventDispatcherListener {
|
||||
|
||||
private Long mFirstUptime = SystemClock.uptimeMillis();
|
||||
private boolean mSlowAnimationsEnabled = false;
|
||||
private int mAnimationsDragFactor;
|
||||
public void scrollTo(int viewTag, double x, double y, boolean animated) {
|
||||
View view;
|
||||
try {
|
||||
view = mUIManager.resolveView(viewTag);
|
||||
} catch (IllegalViewOperationException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
NativeMethodsHelper.scrollTo(view, x, y, animated);
|
||||
}
|
||||
|
||||
public void dispatchCommand(int viewTag, String commandId, ReadableArray commandArgs) {
|
||||
// mUIManager.dispatchCommand must be called from native modules queue thread
|
||||
// because of an assert in ShadowNodeRegistry.getNode
|
||||
mContext.runOnNativeModulesQueueThread(
|
||||
new GuardedRunnable(mContext.getExceptionHandler()) {
|
||||
@Override
|
||||
public void runGuarded() {
|
||||
mUIManager.dispatchCommand(viewTag, commandId, commandArgs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public float[] measure(int viewTag) {
|
||||
View view;
|
||||
try {
|
||||
view = mUIManager.resolveView(viewTag);
|
||||
} catch (IllegalViewOperationException e) {
|
||||
e.printStackTrace();
|
||||
return (new float[] {NaN, NaN, NaN, NaN, NaN, NaN});
|
||||
}
|
||||
return NativeMethodsHelper.measure(view);
|
||||
}
|
||||
|
||||
public interface OnAnimationFrame {
|
||||
void onAnimationFrame(double timestampMs);
|
||||
}
|
||||
|
||||
private AnimationsManager mAnimationManager;
|
||||
private final UIImplementation mUIImplementation;
|
||||
private final DeviceEventManagerModule.RCTDeviceEventEmitter mEventEmitter;
|
||||
private final ReactChoreographer mReactChoreographer;
|
||||
private final GuardedFrameCallback mChoreographerCallback;
|
||||
protected final UIManagerModule.CustomEventNamesResolver mCustomEventNamesResolver;
|
||||
private final AtomicBoolean mCallbackPosted = new AtomicBoolean();
|
||||
private final ReactContext mContext;
|
||||
private final UIManagerModule mUIManager;
|
||||
private ReactApplicationContext mReactApplicationContext;
|
||||
private RCTEventEmitter mCustomEventHandler = new NoopEventHandler();
|
||||
private List<OnAnimationFrame> mFrameCallbacks = new ArrayList<>();
|
||||
private ConcurrentLinkedQueue<CopiedEvent> mEventQueue = new ConcurrentLinkedQueue<>();
|
||||
private double lastFrameTimeMs;
|
||||
private FabricUIManager mFabricUIManager;
|
||||
public Set<String> uiProps = Collections.emptySet();
|
||||
public Set<String> nativeProps = Collections.emptySet();
|
||||
private ReaCompatibility compatibility;
|
||||
|
||||
public NativeProxy getNativeProxy() {
|
||||
return mNativeProxy;
|
||||
@@ -51,23 +105,47 @@ public class NodesManager implements EventDispatcherListener {
|
||||
|
||||
private NativeProxy mNativeProxy;
|
||||
|
||||
public void invalidate() {
|
||||
if (mNativeProxy != null) {
|
||||
mNativeProxy.invalidate();
|
||||
mNativeProxy = null;
|
||||
public AnimationsManager getAnimationsManager() {
|
||||
return mAnimationManager;
|
||||
}
|
||||
|
||||
public void onCatalystInstanceDestroy() {
|
||||
if (mAnimationManager != null) {
|
||||
mAnimationManager.onCatalystInstanceDestroy();
|
||||
}
|
||||
|
||||
if (mFabricUIManager != null) {
|
||||
mFabricUIManager.getEventDispatcher().removeListener(this);
|
||||
if (mNativeProxy != null) {
|
||||
mNativeProxy.onCatalystInstanceDestroy();
|
||||
mNativeProxy = null;
|
||||
}
|
||||
}
|
||||
|
||||
public NodesManager(ReactApplicationContext context, WorkletsModule workletsModule) {
|
||||
context.assertOnJSQueueThread();
|
||||
public void initWithContext(ReactApplicationContext reactApplicationContext) {
|
||||
mReactApplicationContext = reactApplicationContext;
|
||||
mNativeProxy = new NativeProxy(reactApplicationContext);
|
||||
mAnimationManager.setAndroidUIScheduler(getNativeProxy().getAndroidUIScheduler());
|
||||
compatibility = new ReaCompatibility(reactApplicationContext);
|
||||
compatibility.registerFabricEventListener(this);
|
||||
}
|
||||
|
||||
UIManager uiManager = UIManagerHelper.getUIManager(context, UIManagerType.FABRIC);
|
||||
assert uiManager != null;
|
||||
mCustomEventNamesResolver = uiManager::resolveCustomDirectEventName;
|
||||
private final class NativeUpdateOperation {
|
||||
public int mViewTag;
|
||||
public WritableMap mNativeProps;
|
||||
|
||||
public NativeUpdateOperation(int viewTag, WritableMap nativeProps) {
|
||||
mViewTag = viewTag;
|
||||
mNativeProps = nativeProps;
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<NativeUpdateOperation> mOperationsInBatch = new LinkedList<>();
|
||||
private boolean mTryRunBatchUpdatesSynchronously = false;
|
||||
|
||||
public NodesManager(ReactContext context) {
|
||||
mContext = context;
|
||||
mUIManager = context.getNativeModule(UIManagerModule.class);
|
||||
mUIImplementation = mUIManager.getUIImplementation();
|
||||
mCustomEventNamesResolver = mUIManager.getDirectEventNamesResolver();
|
||||
mEventEmitter = context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
|
||||
|
||||
mReactChoreographer = ReactChoreographer.getInstance();
|
||||
@@ -79,9 +157,17 @@ public class NodesManager implements EventDispatcherListener {
|
||||
}
|
||||
};
|
||||
|
||||
mNativeProxy = new NativeProxy(context, workletsModule, this);
|
||||
mFabricUIManager = (FabricUIManager) uiManager;
|
||||
mFabricUIManager.getEventDispatcher().addListener(this);
|
||||
// We register as event listener at the end, because we pass `this` and we haven't finished
|
||||
// contructing an object yet.
|
||||
// This lead to a crash described in
|
||||
// https://github.com/software-mansion/react-native-reanimated/issues/604 which was caused by
|
||||
// Nodes Manager being constructed on UI thread and registering for events.
|
||||
// Events are handled in the native modules thread in the `onEventDispatch()` method.
|
||||
// This method indirectly uses `mChoreographerCallback` which was created after event
|
||||
// registration, creating race condition
|
||||
mUIManager.getEventDispatcher().addListener(this);
|
||||
|
||||
mAnimationManager = new AnimationsManager(mContext, mUIManager);
|
||||
}
|
||||
|
||||
public void onHostPause() {
|
||||
@@ -116,58 +202,99 @@ public class NodesManager implements EventDispatcherListener {
|
||||
}
|
||||
|
||||
public void performOperations() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
if (mNativeProxy != null) {
|
||||
mNativeProxy.performOperations();
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
if (mNativeProxy != null) {
|
||||
mNativeProxy.performOperations();
|
||||
}
|
||||
} else if (!mOperationsInBatch.isEmpty()) {
|
||||
final Queue<NativeUpdateOperation> copiedOperationsQueue = mOperationsInBatch;
|
||||
mOperationsInBatch = new LinkedList<>();
|
||||
final boolean trySynchronously = mTryRunBatchUpdatesSynchronously;
|
||||
mTryRunBatchUpdatesSynchronously = false;
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
mContext.runOnNativeModulesQueueThread(
|
||||
new GuardedRunnable(mContext.getExceptionHandler()) {
|
||||
@Override
|
||||
public void runGuarded() {
|
||||
boolean queueWasEmpty =
|
||||
UIManagerReanimatedHelper.isOperationQueueEmpty(mUIImplementation);
|
||||
boolean shouldDispatchUpdates = trySynchronously && queueWasEmpty;
|
||||
if (!shouldDispatchUpdates) {
|
||||
semaphore.release();
|
||||
}
|
||||
while (!copiedOperationsQueue.isEmpty()) {
|
||||
NativeUpdateOperation op = copiedOperationsQueue.remove();
|
||||
ReactShadowNode shadowNode = mUIImplementation.resolveShadowNode(op.mViewTag);
|
||||
if (shadowNode != null) {
|
||||
mUIManager.updateView(op.mViewTag, shadowNode.getViewClass(), op.mNativeProps);
|
||||
}
|
||||
}
|
||||
if (queueWasEmpty) {
|
||||
mUIImplementation.dispatchViewUpdates(-1); // no associated batchId
|
||||
}
|
||||
if (shouldDispatchUpdates) {
|
||||
semaphore.release();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (trySynchronously) {
|
||||
try {
|
||||
semaphore.tryAcquire(16, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// if the thread is interruped we just continue and let the layout update happen
|
||||
// asynchronously
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onAnimationFrame(long frameTimeNanos) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
// Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onAnimationFrame");
|
||||
|
||||
try {
|
||||
if (BuildConfig.REANIMATED_PROFILING) {
|
||||
Trace.beginSection("onAnimationFrame");
|
||||
double currentFrameTimeMs = frameTimeNanos / 1000000.;
|
||||
|
||||
if (currentFrameTimeMs > lastFrameTimeMs) {
|
||||
// It is possible for ChoreographerCallback to be executed twice within the same frame
|
||||
// due to frame drops. If this occurs, the additional callback execution should be ignored.
|
||||
lastFrameTimeMs = currentFrameTimeMs;
|
||||
|
||||
while (!mEventQueue.isEmpty()) {
|
||||
CopiedEvent copiedEvent = mEventQueue.poll();
|
||||
handleEvent(
|
||||
copiedEvent.getTargetTag(), copiedEvent.getEventName(), copiedEvent.getPayload());
|
||||
}
|
||||
|
||||
double currentFrameTimeMs = frameTimeNanos / 1000000.;
|
||||
if (mSlowAnimationsEnabled) {
|
||||
currentFrameTimeMs =
|
||||
mFirstUptime + (currentFrameTimeMs - mFirstUptime) / mAnimationsDragFactor;
|
||||
}
|
||||
|
||||
if (currentFrameTimeMs > lastFrameTimeMs) {
|
||||
// It is possible for ChoreographerCallback to be executed twice within the same frame
|
||||
// due to frame drops. If this occurs, the additional callback execution should be ignored.
|
||||
lastFrameTimeMs = currentFrameTimeMs;
|
||||
|
||||
while (!mEventQueue.isEmpty()) {
|
||||
CopiedEvent copiedEvent = mEventQueue.poll();
|
||||
handleEvent(
|
||||
copiedEvent.getTargetTag(), copiedEvent.getEventName(), copiedEvent.getPayload());
|
||||
if (!mFrameCallbacks.isEmpty()) {
|
||||
List<OnAnimationFrame> frameCallbacks = mFrameCallbacks;
|
||||
mFrameCallbacks = new ArrayList<>(frameCallbacks.size());
|
||||
for (int i = 0, size = frameCallbacks.size(); i < size; i++) {
|
||||
frameCallbacks.get(i).onAnimationFrame(currentFrameTimeMs);
|
||||
}
|
||||
|
||||
if (!mFrameCallbacks.isEmpty()) {
|
||||
List<OnAnimationFrame> frameCallbacks = mFrameCallbacks;
|
||||
mFrameCallbacks = new ArrayList<>(frameCallbacks.size());
|
||||
for (int i = 0, size = frameCallbacks.size(); i < size; i++) {
|
||||
frameCallbacks.get(i).onAnimationFrame(currentFrameTimeMs);
|
||||
}
|
||||
}
|
||||
|
||||
performOperations();
|
||||
}
|
||||
|
||||
mCallbackPosted.set(false);
|
||||
if (!mFrameCallbacks.isEmpty() || !mEventQueue.isEmpty()) {
|
||||
// enqueue next frame
|
||||
startUpdatingOnAnimationFrame();
|
||||
}
|
||||
} finally {
|
||||
if (BuildConfig.REANIMATED_PROFILING) {
|
||||
Trace.endSection();
|
||||
}
|
||||
performOperations();
|
||||
}
|
||||
|
||||
mCallbackPosted.set(false);
|
||||
if (!mFrameCallbacks.isEmpty() || !mEventQueue.isEmpty()) {
|
||||
// enqueue next frame
|
||||
startUpdatingOnAnimationFrame();
|
||||
}
|
||||
|
||||
// Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
|
||||
public void enqueueUpdateViewOnNativeThread(
|
||||
int viewTag, WritableMap nativeProps, boolean trySynchronously) {
|
||||
if (trySynchronously) {
|
||||
mTryRunBatchUpdatesSynchronously = true;
|
||||
}
|
||||
mOperationsInBatch.add(new NativeUpdateOperation(viewTag, nativeProps));
|
||||
}
|
||||
|
||||
public void configureProps(Set<String> uiPropsSet, Set<String> nativePropsSet) {
|
||||
uiProps = uiPropsSet;
|
||||
nativeProps = nativePropsSet;
|
||||
}
|
||||
|
||||
public void postOnAnimation(OnAnimationFrame onAnimationFrame) {
|
||||
@@ -177,32 +304,22 @@ public class NodesManager implements EventDispatcherListener {
|
||||
|
||||
@Override
|
||||
public void onEventDispatch(Event event) {
|
||||
try {
|
||||
if (BuildConfig.REANIMATED_PROFILING) {
|
||||
Trace.beginSection("onEventDispatch");
|
||||
}
|
||||
|
||||
if (mNativeProxy == null) {
|
||||
return;
|
||||
}
|
||||
// Events can be dispatched from any thread so we have to make sure handleEvent is run from
|
||||
// the UI thread.
|
||||
if (UiThreadUtil.isOnUiThread()) {
|
||||
handleEvent(event);
|
||||
performOperations();
|
||||
} else {
|
||||
String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName());
|
||||
int viewTag = event.getViewTag();
|
||||
boolean shouldSaveEvent = mNativeProxy.isAnyHandlerWaitingForEvent(eventName, viewTag);
|
||||
if (shouldSaveEvent) {
|
||||
mEventQueue.offer(new CopiedEvent(event));
|
||||
}
|
||||
startUpdatingOnAnimationFrame();
|
||||
}
|
||||
} finally {
|
||||
if (BuildConfig.REANIMATED_PROFILING) {
|
||||
Trace.endSection();
|
||||
if (mNativeProxy == null) {
|
||||
return;
|
||||
}
|
||||
// Events can be dispatched from any thread so we have to make sure handleEvent is run from the
|
||||
// UI thread.
|
||||
if (UiThreadUtil.isOnUiThread()) {
|
||||
handleEvent(event);
|
||||
performOperations();
|
||||
} else {
|
||||
String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName());
|
||||
int viewTag = event.getViewTag();
|
||||
boolean shouldSaveEvent = mNativeProxy.isAnyHandlerWaitingForEvent(eventName, viewTag);
|
||||
if (shouldSaveEvent) {
|
||||
mEventQueue.offer(new CopiedEvent(event));
|
||||
}
|
||||
startUpdatingOnAnimationFrame();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,11 +343,128 @@ public class NodesManager implements EventDispatcherListener {
|
||||
mEventEmitter.emit(name, body);
|
||||
}
|
||||
|
||||
public void enableSlowAnimations(boolean slowAnimationsEnabled, int animationsDragFactor) {
|
||||
mSlowAnimationsEnabled = slowAnimationsEnabled;
|
||||
mAnimationsDragFactor = animationsDragFactor;
|
||||
if (slowAnimationsEnabled) {
|
||||
mFirstUptime = SystemClock.uptimeMillis();
|
||||
public void updateProps(int viewTag, Map<String, Object> props) {
|
||||
// TODO: update PropsNode to use this method instead of its own way of updating props
|
||||
boolean hasUIProps = false;
|
||||
boolean hasNativeProps = false;
|
||||
boolean hasJSProps = false;
|
||||
JavaOnlyMap newUIProps = new JavaOnlyMap();
|
||||
WritableMap newJSProps = Arguments.createMap();
|
||||
WritableMap newNativeProps = Arguments.createMap();
|
||||
|
||||
for (Map.Entry<String, Object> entry : props.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (uiProps.contains(key)) {
|
||||
hasUIProps = true;
|
||||
addProp(newUIProps, key, value);
|
||||
} else if (nativeProps.contains(key)) {
|
||||
hasNativeProps = true;
|
||||
addProp(newNativeProps, key, value);
|
||||
} else {
|
||||
hasJSProps = true;
|
||||
addProp(newJSProps, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (viewTag != View.NO_ID) {
|
||||
if (hasUIProps) {
|
||||
mUIImplementation.synchronouslyUpdateViewOnUIThread(
|
||||
viewTag, new ReactStylesDiffMap(newUIProps));
|
||||
}
|
||||
if (hasNativeProps) {
|
||||
enqueueUpdateViewOnNativeThread(viewTag, newNativeProps, true);
|
||||
}
|
||||
if (hasJSProps) {
|
||||
WritableMap evt = Arguments.createMap();
|
||||
evt.putInt("viewTag", viewTag);
|
||||
evt.putMap("props", newJSProps);
|
||||
sendEvent("onReanimatedPropsChange", evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void synchronouslyUpdateUIProps(int viewTag, ReadableMap uiProps) {
|
||||
compatibility.synchronouslyUpdateUIProps(viewTag, uiProps);
|
||||
}
|
||||
|
||||
public String obtainProp(int viewTag, String propName) {
|
||||
View view = mUIManager.resolveView(viewTag);
|
||||
String result =
|
||||
"error: unknown propName " + propName + ", currently supported: opacity, zIndex";
|
||||
if (propName.equals("opacity")) {
|
||||
Float opacity = view.getAlpha();
|
||||
result = Float.toString(opacity);
|
||||
} else if (propName.equals("zIndex")) {
|
||||
Float zIndex = view.getElevation();
|
||||
result = Float.toString(zIndex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static WritableMap copyReadableMap(ReadableMap map) {
|
||||
WritableMap copy = Arguments.createMap();
|
||||
copy.merge(map);
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static WritableArray copyReadableArray(ReadableArray array) {
|
||||
WritableArray copy = Arguments.createArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
ReadableType type = array.getType(i);
|
||||
switch (type) {
|
||||
case Boolean:
|
||||
copy.pushBoolean(array.getBoolean(i));
|
||||
break;
|
||||
case String:
|
||||
copy.pushString(array.getString(i));
|
||||
break;
|
||||
case Null:
|
||||
copy.pushNull();
|
||||
break;
|
||||
case Number:
|
||||
copy.pushDouble(array.getDouble(i));
|
||||
break;
|
||||
case Map:
|
||||
copy.pushMap(copyReadableMap(array.getMap(i)));
|
||||
break;
|
||||
case Array:
|
||||
copy.pushArray(copyReadableArray(array.getArray(i)));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("[Reanimated] Unknown type of ReadableArray.");
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static void addProp(WritableMap propMap, String key, Object value) {
|
||||
if (value == null) {
|
||||
propMap.putNull(key);
|
||||
} else if (value instanceof Double) {
|
||||
propMap.putDouble(key, (Double) value);
|
||||
} else if (value instanceof Integer) {
|
||||
propMap.putInt(key, (Integer) value);
|
||||
} else if (value instanceof Number) {
|
||||
propMap.putDouble(key, ((Number) value).doubleValue());
|
||||
} else if (value instanceof Boolean) {
|
||||
propMap.putBoolean(key, (Boolean) value);
|
||||
} else if (value instanceof String) {
|
||||
propMap.putString(key, (String) value);
|
||||
} else if (value instanceof ReadableArray) {
|
||||
if (!(value instanceof WritableArray)) {
|
||||
propMap.putArray(key, copyReadableArray((ReadableArray) value));
|
||||
} else {
|
||||
propMap.putArray(key, (ReadableArray) value);
|
||||
}
|
||||
} else if (value instanceof ReadableMap) {
|
||||
if (!(value instanceof WritableMap)) {
|
||||
propMap.putMap(key, copyReadableMap((ReadableMap) value));
|
||||
} else {
|
||||
propMap.putMap(key, (ReadableMap) value);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("[Reanimated] Unknown type of animated value.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
Vendored
+78
-24
@@ -1,38 +1,55 @@
|
||||
package com.swmansion.reanimated;
|
||||
|
||||
import android.util.Log;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.swmansion.worklets.WorkletsModule;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.UIBlock;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.UIManagerModuleListener;
|
||||
import java.util.ArrayList;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ReactModule(name = ReanimatedModule.NAME)
|
||||
public class ReanimatedModule extends NativeReanimatedModuleSpec implements LifecycleEventListener {
|
||||
private final NodesManager mNodesManager;
|
||||
private final WorkletsModule mWorkletsModule;
|
||||
public class ReanimatedModule extends ReactContextBaseJavaModule
|
||||
implements LifecycleEventListener, UIManagerModuleListener {
|
||||
|
||||
public static final String NAME = "ReanimatedModule";
|
||||
|
||||
private interface UIThreadOperation {
|
||||
void execute(NodesManager nodesManager);
|
||||
}
|
||||
|
||||
private ArrayList<UIThreadOperation> mOperations = new ArrayList<>();
|
||||
private @Nullable NodesManager mNodesManager;
|
||||
|
||||
public ReanimatedModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
reactContext.assertOnJSQueueThread();
|
||||
mWorkletsModule = reactContext.getNativeModule(WorkletsModule.class);
|
||||
mNodesManager = new NodesManager(reactContext, mWorkletsModule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
ReactApplicationContext reactContext = getReactApplicationContext();
|
||||
reactContext.assertOnJSQueueThread();
|
||||
reactContext.addLifecycleEventListener(this);
|
||||
ReactApplicationContext reactCtx = getReactApplicationContext();
|
||||
UIManagerModule uiManager = reactCtx.getNativeModule(UIManagerModule.class);
|
||||
reactCtx.addLifecycleEventListener(this);
|
||||
uiManager.addUIManagerListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
mNodesManager.onHostPause();
|
||||
if (mNodesManager != null) {
|
||||
mNodesManager.onHostPause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
mNodesManager.onHostResume();
|
||||
if (mNodesManager != null) {
|
||||
mNodesManager.onHostResume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,33 +57,70 @@ public class ReanimatedModule extends NativeReanimatedModuleSpec implements Life
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void willDispatchViewUpdates(final UIManagerModule uiManager) {
|
||||
if (mOperations.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final ArrayList<UIThreadOperation> operations = mOperations;
|
||||
mOperations = new ArrayList<>();
|
||||
uiManager.addUIBlock(
|
||||
new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
NodesManager nodesManager = getNodesManager();
|
||||
for (UIThreadOperation operation : operations) {
|
||||
operation.execute(nodesManager);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
/*package*/
|
||||
public NodesManager getNodesManager() {
|
||||
// This method is called from react-native-gesture-handler.
|
||||
if (mNodesManager == null) {
|
||||
mNodesManager = new NodesManager(getReactApplicationContext());
|
||||
}
|
||||
|
||||
return mNodesManager;
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public boolean installTurboModule() {
|
||||
getReactApplicationContext().assertOnJSQueueThread();
|
||||
mNodesManager.getNativeProxy().installJSIBindings();
|
||||
return true;
|
||||
public void installTurboModule() {
|
||||
// When debugging in chrome the JS context is not available.
|
||||
// https://github.com/facebook/react-native/blob/v0.67.0-rc.6/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java#L25
|
||||
Utils.isChromeDebugger = getReactApplicationContext().getJavaScriptContextHolder().get() == 0;
|
||||
|
||||
if (!Utils.isChromeDebugger) {
|
||||
this.getNodesManager().initWithContext(getReactApplicationContext());
|
||||
} else {
|
||||
Log.w(
|
||||
"[REANIMATED]",
|
||||
"Unable to create Reanimated Native Module. You can ignore this message if you are using Chrome Debugger now.");
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void addListener(String ignoredEventName) {
|
||||
public void addListener(String eventName) {
|
||||
// Keep: Required for RN built in Event Emitter Calls.
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void removeListeners(Integer ignoredCount) {
|
||||
public void removeListeners(Integer count) {
|
||||
// Keep: Required for RN built in Event Emitter Calls.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
super.invalidate();
|
||||
mNodesManager.invalidate();
|
||||
ReactApplicationContext reactContext = getReactApplicationContext();
|
||||
reactContext.removeLifecycleEventListener(this);
|
||||
public void onCatalystInstanceDestroy() {
|
||||
super.onCatalystInstanceDestroy();
|
||||
|
||||
if (mNodesManager != null) {
|
||||
mNodesManager.onCatalystInstanceDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
Vendored
+47
-21
@@ -1,58 +1,84 @@
|
||||
package com.swmansion.reanimated;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.facebook.react.BaseReactPackage;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_END;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_START;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.TurboReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactMarker;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.module.annotations.ReactModuleList;
|
||||
import com.facebook.react.module.model.ReactModuleInfo;
|
||||
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
||||
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
|
||||
import com.facebook.react.uimanager.ReanimatedUIManager;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@ReactModuleList(
|
||||
nativeModules = {
|
||||
ReanimatedModule.class,
|
||||
})
|
||||
public class ReanimatedPackage extends BaseReactPackage implements ReactPackage {
|
||||
public class ReanimatedPackage extends TurboReactPackage implements ReactPackage {
|
||||
|
||||
@Override
|
||||
public NativeModule getModule(
|
||||
@NonNull String name, @NonNull ReactApplicationContext reactContext) {
|
||||
return switch (name) {
|
||||
case ReanimatedModule.NAME -> new ReanimatedModule(reactContext);
|
||||
default -> null;
|
||||
};
|
||||
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
|
||||
if (name.equals(ReanimatedModule.NAME)) {
|
||||
return new ReanimatedModule(reactContext);
|
||||
}
|
||||
if (name.equals(ReanimatedUIManager.NAME)) {
|
||||
return createUIManager(reactContext);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactModuleInfoProvider getReactModuleInfoProvider() {
|
||||
Class<? extends NativeModule>[] moduleList =
|
||||
new Class[] {
|
||||
ReanimatedModule.class,
|
||||
ReanimatedModule.class, ReanimatedUIManager.class,
|
||||
};
|
||||
|
||||
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
|
||||
for (Class<? extends NativeModule> moduleClass : moduleList) {
|
||||
ReactModule reactModule =
|
||||
Objects.requireNonNull(moduleClass.getAnnotation(ReactModule.class));
|
||||
ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
|
||||
|
||||
reactModuleInfoMap.put(
|
||||
reactModule.name(),
|
||||
new ReactModuleInfo(
|
||||
reactModule.name(),
|
||||
moduleClass.getName(),
|
||||
reactModule.canOverrideExistingModule(),
|
||||
true,
|
||||
reactModule.needsEagerInit(),
|
||||
reactModule.hasConstants(),
|
||||
reactModule.isCxxModule(),
|
||||
true));
|
||||
TurboModule.class.isAssignableFrom(moduleClass)));
|
||||
}
|
||||
|
||||
return () -> reactModuleInfoMap;
|
||||
return new ReactModuleInfoProvider() {
|
||||
@Override
|
||||
public Map<String, ReactModuleInfo> getReactModuleInfos() {
|
||||
return reactModuleInfoMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private UIManagerModule createUIManager(final ReactApplicationContext reactContext) {
|
||||
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_START);
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createUIManagerModule");
|
||||
final ReactInstanceManager reactInstanceManager = getReactInstanceManager(reactContext);
|
||||
List<ViewManager> viewManagers = reactInstanceManager.getOrCreateViewManagers(reactContext);
|
||||
int minTimeLeftInFrameForNonBatchedOperationMs = -1;
|
||||
try {
|
||||
return ReanimatedUIManagerFactory.create(
|
||||
reactContext, viewManagers, minTimeLeftInFrameForNonBatchedOperationMs);
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_END);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Generated
Vendored
+2
-10
@@ -8,6 +8,8 @@ import java.util.Map;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static boolean isChromeDebugger = false;
|
||||
|
||||
public static Map<String, Integer> processMapping(ReadableMap style) {
|
||||
ReadableMapKeySetIterator iter = style.keySetIterator();
|
||||
HashMap<String, Integer> mapping = new HashMap<>();
|
||||
@@ -44,14 +46,4 @@ public class Utils {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static Runnable combineRunnables(final Runnable... runnables) {
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
for (Runnable r : runnables) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Generated
Vendored
-53
@@ -1,53 +0,0 @@
|
||||
package com.swmansion.reanimated.keyboard;
|
||||
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
|
||||
public class Keyboard {
|
||||
private KeyboardState mState = KeyboardState.UNKNOWN;
|
||||
private int mHeight = 0;
|
||||
private int mActiveTransitionCounter = 0;
|
||||
private static final int CONTENT_TYPE_MASK = WindowInsetsCompat.Type.ime();
|
||||
private static final int SYSTEM_BAR_TYPE_MASK = WindowInsetsCompat.Type.systemBars();
|
||||
|
||||
public KeyboardState getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public void updateHeight(WindowInsetsCompat insets, boolean isNavigationBarTranslucent) {
|
||||
int contentBottomInset = insets.getInsets(CONTENT_TYPE_MASK).bottom;
|
||||
int systemBarBottomInset =
|
||||
isNavigationBarTranslucent ? 0 : insets.getInsets(SYSTEM_BAR_TYPE_MASK).bottom;
|
||||
int keyboardHeightDip = contentBottomInset - systemBarBottomInset;
|
||||
int keyboardHeight = (int) PixelUtil.toDIPFromPixel(Math.max(0, keyboardHeightDip));
|
||||
if (keyboardHeight <= 0 && mState == KeyboardState.OPEN) {
|
||||
/*
|
||||
When the keyboard is being canceling, for one frame the insets show a keyboard height of 0,
|
||||
causing a jump of the keyboard. We can avoid it by ignoring that frame and calling
|
||||
the listeners on the following frame.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
mHeight = keyboardHeight;
|
||||
}
|
||||
|
||||
public void onAnimationStart() {
|
||||
if (mActiveTransitionCounter > 0) {
|
||||
mState = mState == KeyboardState.OPENING ? KeyboardState.CLOSING : KeyboardState.OPENING;
|
||||
} else {
|
||||
mState = mHeight <= 0 ? KeyboardState.OPENING : KeyboardState.CLOSING;
|
||||
}
|
||||
mActiveTransitionCounter++;
|
||||
}
|
||||
|
||||
public void onAnimationEnd() {
|
||||
mActiveTransitionCounter--;
|
||||
if (mActiveTransitionCounter == 0) {
|
||||
mState = mHeight <= 0 ? KeyboardState.CLOSED : KeyboardState.OPEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
Vendored
-67
@@ -1,67 +0,0 @@
|
||||
package com.swmansion.reanimated.keyboard;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.WindowInsetsAnimationCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import java.util.List;
|
||||
|
||||
public class KeyboardAnimationCallback extends WindowInsetsAnimationCompat.Callback {
|
||||
private final Keyboard mKeyboard;
|
||||
private final NotifyAboutKeyboardChangeFunction mNotifyAboutKeyboardChange;
|
||||
private static final int CONTENT_TYPE_MASK = WindowInsetsCompat.Type.ime();
|
||||
private final boolean mIsNavigationBarTranslucent;
|
||||
|
||||
public KeyboardAnimationCallback(
|
||||
Keyboard keyboard,
|
||||
NotifyAboutKeyboardChangeFunction notifyAboutKeyboardChange,
|
||||
boolean isNavigationBarTranslucent) {
|
||||
super(WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE);
|
||||
mNotifyAboutKeyboardChange = notifyAboutKeyboardChange;
|
||||
mIsNavigationBarTranslucent = isNavigationBarTranslucent;
|
||||
mKeyboard = keyboard;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public WindowInsetsAnimationCompat.BoundsCompat onStart(
|
||||
@NonNull WindowInsetsAnimationCompat animation,
|
||||
@NonNull WindowInsetsAnimationCompat.BoundsCompat bounds) {
|
||||
if (!isKeyboardAnimation(animation)) {
|
||||
return bounds;
|
||||
}
|
||||
mKeyboard.onAnimationStart();
|
||||
mNotifyAboutKeyboardChange.call();
|
||||
return super.onStart(animation, bounds);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public WindowInsetsCompat onProgress(
|
||||
@NonNull WindowInsetsCompat insets,
|
||||
@NonNull List<WindowInsetsAnimationCompat> runningAnimations) {
|
||||
boolean isAnyKeyboardAnimationRunning = false;
|
||||
for (WindowInsetsAnimationCompat animation : runningAnimations) {
|
||||
if (isKeyboardAnimation(animation)) {
|
||||
isAnyKeyboardAnimationRunning = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isAnyKeyboardAnimationRunning) {
|
||||
mKeyboard.updateHeight(insets, mIsNavigationBarTranslucent);
|
||||
mNotifyAboutKeyboardChange.call();
|
||||
}
|
||||
return insets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd(@NonNull WindowInsetsAnimationCompat animation) {
|
||||
if (isKeyboardAnimation(animation)) {
|
||||
mKeyboard.onAnimationEnd();
|
||||
mNotifyAboutKeyboardChange.call();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isKeyboardAnimation(@NonNull WindowInsetsAnimationCompat animation) {
|
||||
return (animation.getTypeMask() & CONTENT_TYPE_MASK) != 0;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
-52
@@ -1,52 +0,0 @@
|
||||
package com.swmansion.reanimated.keyboard;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@FunctionalInterface
|
||||
interface NotifyAboutKeyboardChangeFunction {
|
||||
void call();
|
||||
}
|
||||
|
||||
public class KeyboardAnimationManager {
|
||||
private int mNextListenerId = 0;
|
||||
private final ConcurrentHashMap<Integer, KeyboardWorkletWrapper> mListeners =
|
||||
new ConcurrentHashMap<>();
|
||||
private final Keyboard mKeyboard = new Keyboard();
|
||||
private final WindowsInsetsManager mWindowsInsetsManager;
|
||||
|
||||
public KeyboardAnimationManager(WeakReference<ReactApplicationContext> reactContext) {
|
||||
mWindowsInsetsManager =
|
||||
new WindowsInsetsManager(reactContext, mKeyboard, this::notifyAboutKeyboardChange);
|
||||
}
|
||||
|
||||
public int subscribeForKeyboardUpdates(
|
||||
KeyboardWorkletWrapper callback,
|
||||
boolean isStatusBarTranslucent,
|
||||
boolean isNavigationBarTranslucent) {
|
||||
int listenerId = mNextListenerId++;
|
||||
if (mListeners.isEmpty()) {
|
||||
KeyboardAnimationCallback keyboardAnimationCallback =
|
||||
new KeyboardAnimationCallback(
|
||||
mKeyboard, this::notifyAboutKeyboardChange, isNavigationBarTranslucent);
|
||||
mWindowsInsetsManager.startObservingChanges(
|
||||
keyboardAnimationCallback, isStatusBarTranslucent, isNavigationBarTranslucent);
|
||||
}
|
||||
mListeners.put(listenerId, callback);
|
||||
return listenerId;
|
||||
}
|
||||
|
||||
public void unsubscribeFromKeyboardUpdates(int listenerId) {
|
||||
mListeners.remove(listenerId);
|
||||
if (mListeners.isEmpty()) {
|
||||
mWindowsInsetsManager.stopObservingChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyAboutKeyboardChange() {
|
||||
for (KeyboardWorkletWrapper listener : mListeners.values()) {
|
||||
listener.invoke(mKeyboard.getState().asInt(), mKeyboard.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
package com.swmansion.reanimated.keyboard;
|
||||
|
||||
public enum KeyboardState {
|
||||
UNKNOWN(0),
|
||||
OPENING(1),
|
||||
OPEN(2),
|
||||
CLOSING(3),
|
||||
CLOSED(4);
|
||||
|
||||
private final int mValue;
|
||||
|
||||
KeyboardState(int value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public int asInt() {
|
||||
return mValue;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
-16
@@ -1,16 +0,0 @@
|
||||
package com.swmansion.reanimated.keyboard;
|
||||
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
@DoNotStrip
|
||||
public class KeyboardWorkletWrapper {
|
||||
@DoNotStrip private final HybridData mHybridData;
|
||||
|
||||
@DoNotStrip
|
||||
private KeyboardWorkletWrapper(HybridData hybridData) {
|
||||
mHybridData = hybridData;
|
||||
}
|
||||
|
||||
public native void invoke(int keyboardState, int height);
|
||||
}
|
||||
Generated
Vendored
-135
@@ -1,135 +0,0 @@
|
||||
package com.swmansion.reanimated.keyboard;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class WindowsInsetsManager {
|
||||
|
||||
private boolean mIsStatusBarTranslucent = false;
|
||||
private boolean mIsNavigationBarTranslucent = false;
|
||||
private final WeakReference<ReactApplicationContext> mReactContext;
|
||||
private final Keyboard mKeyboard;
|
||||
private final NotifyAboutKeyboardChangeFunction mNotifyAboutKeyboardChange;
|
||||
|
||||
private final String MissingContextErrorMsg = "Unable to get reference to react activity";
|
||||
|
||||
public WindowsInsetsManager(
|
||||
WeakReference<ReactApplicationContext> reactContext,
|
||||
Keyboard keyboard,
|
||||
NotifyAboutKeyboardChangeFunction notifyAboutKeyboardChange) {
|
||||
mReactContext = reactContext;
|
||||
mKeyboard = keyboard;
|
||||
mNotifyAboutKeyboardChange = notifyAboutKeyboardChange;
|
||||
}
|
||||
|
||||
private Activity getCurrentActivity() {
|
||||
return mReactContext.get().getCurrentActivity();
|
||||
}
|
||||
|
||||
public void startObservingChanges(
|
||||
KeyboardAnimationCallback keyboardAnimationCallback,
|
||||
boolean isStatusBarTranslucent,
|
||||
boolean isNavigationBarTranslucent) {
|
||||
mIsStatusBarTranslucent = isStatusBarTranslucent;
|
||||
mIsNavigationBarTranslucent = isNavigationBarTranslucent;
|
||||
updateWindowDecor(false);
|
||||
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity == null) {
|
||||
Log.e("Reanimated", MissingContextErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
View rootView = currentActivity.getWindow().getDecorView();
|
||||
ViewCompat.setOnApplyWindowInsetsListener(rootView, this::onApplyWindowInsetsListener);
|
||||
ViewCompat.setWindowInsetsAnimationCallback(rootView, keyboardAnimationCallback);
|
||||
}
|
||||
|
||||
public void stopObservingChanges() {
|
||||
updateWindowDecor(!mIsStatusBarTranslucent && !mIsNavigationBarTranslucent);
|
||||
updateInsets(0, 0);
|
||||
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity == null) {
|
||||
Log.e("Reanimated", MissingContextErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
View rootView = currentActivity.getWindow().getDecorView();
|
||||
ViewCompat.setWindowInsetsAnimationCallback(rootView, null);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(rootView, null);
|
||||
}
|
||||
|
||||
private void updateWindowDecor(boolean decorFitsSystemWindow) {
|
||||
new Handler(Looper.getMainLooper())
|
||||
.post(
|
||||
() -> {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity == null) {
|
||||
Log.e("Reanimated", MissingContextErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(
|
||||
currentActivity.getWindow(), decorFitsSystemWindow);
|
||||
});
|
||||
}
|
||||
|
||||
private WindowInsetsCompat onApplyWindowInsetsListener(View view, WindowInsetsCompat insets) {
|
||||
WindowInsetsCompat defaultInsets = ViewCompat.onApplyWindowInsets(view, insets);
|
||||
if (mKeyboard.getState() == KeyboardState.OPEN) {
|
||||
mKeyboard.updateHeight(insets, mIsNavigationBarTranslucent);
|
||||
mNotifyAboutKeyboardChange.call();
|
||||
}
|
||||
setWindowInsets(defaultInsets);
|
||||
return defaultInsets;
|
||||
}
|
||||
|
||||
private void setWindowInsets(WindowInsetsCompat insets) {
|
||||
int systemBarsTypeMask = WindowInsetsCompat.Type.systemBars();
|
||||
int paddingTop = insets.getInsets(systemBarsTypeMask).top;
|
||||
int paddingBottom = insets.getInsets(systemBarsTypeMask).bottom;
|
||||
updateInsets(paddingTop, paddingBottom);
|
||||
}
|
||||
|
||||
private void updateInsets(int paddingTop, int paddingBottom) {
|
||||
new Handler(Looper.getMainLooper())
|
||||
.post(
|
||||
() -> {
|
||||
FrameLayout.LayoutParams params = getLayoutParams(paddingTop, paddingBottom);
|
||||
int actionBarId = androidx.appcompat.R.id.action_bar_root;
|
||||
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity == null) {
|
||||
Log.e("Reanimated", MissingContextErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
View actionBarRootView =
|
||||
currentActivity.getWindow().getDecorView().findViewById(actionBarId);
|
||||
actionBarRootView.setLayoutParams(params);
|
||||
});
|
||||
}
|
||||
|
||||
private FrameLayout.LayoutParams getLayoutParams(int paddingTop, int paddingBottom) {
|
||||
int matchParentFlag = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||
FrameLayout.LayoutParams params =
|
||||
new FrameLayout.LayoutParams(matchParentFlag, matchParentFlag);
|
||||
|
||||
params.setMargins(
|
||||
0,
|
||||
mIsStatusBarTranslucent ? 0 : paddingTop,
|
||||
0,
|
||||
mIsNavigationBarTranslucent ? 0 : paddingBottom);
|
||||
return params;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+1
-2
@@ -12,8 +12,7 @@ import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
public class EventHandler implements RCTEventEmitter {
|
||||
|
||||
@DoNotStrip private final HybridData mHybridData;
|
||||
|
||||
public UIManagerModule.CustomEventNamesResolver mCustomEventNamesResolver;
|
||||
UIManagerModule.CustomEventNamesResolver mCustomEventNamesResolver;
|
||||
|
||||
@DoNotStrip
|
||||
private EventHandler(HybridData hybridData) {
|
||||
|
||||
Generated
Vendored
+1
-2
@@ -17,7 +17,6 @@ public class ReanimatedSensor {
|
||||
Sensor sensor;
|
||||
ReanimatedSensorType sensorType;
|
||||
int interval;
|
||||
private static final int DEFAULT_INTERVAL = 8;
|
||||
|
||||
ReanimatedSensor(
|
||||
WeakReference<ReactApplicationContext> reactContext,
|
||||
@@ -31,7 +30,7 @@ public class ReanimatedSensor {
|
||||
(SensorManager) reactContext.get().getSystemService(reactContext.get().SENSOR_SERVICE);
|
||||
this.sensorType = sensorType;
|
||||
if (interval == -1) {
|
||||
this.interval = DEFAULT_INTERVAL;
|
||||
this.interval = SensorManager.SENSOR_DELAY_UI;
|
||||
} else {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user