diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 8b839b9183ffbb..372a9168b18e3e 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3128,7 +3128,7 @@ public abstract interface class com/facebook/react/modules/common/ModuleDataClea public abstract fun clearSensitiveData ()V } -public class com/facebook/react/modules/core/ChoreographerCompat { +public final class com/facebook/react/modules/core/ChoreographerCompat { public fun ()V } @@ -3140,13 +3140,18 @@ public abstract interface class com/facebook/react/modules/core/DefaultHardwareB public abstract fun invokeDefaultOnBackPressed ()V } -public class com/facebook/react/modules/core/DeviceEventManagerModule : com/facebook/fbreact/specs/NativeDeviceEventManagerSpec { +public final class com/facebook/react/modules/core/DeviceEventManagerModule : com/facebook/fbreact/specs/NativeDeviceEventManagerSpec { + public static final field Companion Lcom/facebook/react/modules/core/DeviceEventManagerModule$Companion; + public static final field NAME Ljava/lang/String; public fun (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/modules/core/DefaultHardwareBackBtnHandler;)V - public fun emitHardwareBackPressed ()V - public fun emitNewIntentReceived (Landroid/net/Uri;)V + public final fun emitHardwareBackPressed ()V + public final fun emitNewIntentReceived (Landroid/net/Uri;)V public fun invokeDefaultBackPressHandler ()V } +public final class com/facebook/react/modules/core/DeviceEventManagerModule$Companion { +} + public abstract interface class com/facebook/react/modules/core/DeviceEventManagerModule$RCTDeviceEventEmitter : com/facebook/react/bridge/JavaScriptModule { public abstract fun emit (Ljava/lang/String;Ljava/lang/Object;)V } @@ -3208,10 +3213,12 @@ public abstract interface class com/facebook/react/modules/core/RCTNativeAppEven } public final class com/facebook/react/modules/core/ReactChoreographer { - public static fun getInstance ()Lcom/facebook/react/modules/core/ReactChoreographer; - public static fun initialize (Lcom/facebook/react/internal/ChoreographerProvider;)V - public fun postFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V - public fun removeFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V + public static final field Companion Lcom/facebook/react/modules/core/ReactChoreographer$Companion; + public synthetic fun (Lcom/facebook/react/internal/ChoreographerProvider;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public static final fun getInstance ()Lcom/facebook/react/modules/core/ReactChoreographer; + public static final fun initialize (Lcom/facebook/react/internal/ChoreographerProvider;)V + public final fun postFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V + public final fun removeFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V } public final class com/facebook/react/modules/core/ReactChoreographer$CallbackType : java/lang/Enum { @@ -3220,10 +3227,16 @@ public final class com/facebook/react/modules/core/ReactChoreographer$CallbackTy public static final field NATIVE_ANIMATED_MODULE Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType; public static final field PERF_MARKERS Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType; public static final field TIMERS_EVENTS Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType; public static fun values ()[Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType; } +public final class com/facebook/react/modules/core/ReactChoreographer$Companion { + public final fun getInstance ()Lcom/facebook/react/modules/core/ReactChoreographer; + public final fun initialize (Lcom/facebook/react/internal/ChoreographerProvider;)V +} + public final class com/facebook/react/modules/core/TimingModule : com/facebook/fbreact/specs/NativeTimingSpec, com/facebook/react/modules/core/JavaScriptTimerExecutor { public fun (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/devsupport/interfaces/DevSupportManager;)V public fun callIdleCallbacks (D)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java deleted file mode 100644 index 10a8d22abaef87..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.core; - -import android.view.Choreographer; - -public class ChoreographerCompat { - /** - * @deprecated Use Choreographer.FrameCallback instead - */ - @Deprecated - public abstract static class FrameCallback implements Choreographer.FrameCallback {} -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.kt new file mode 100644 index 00000000000000..5f2abe8b5c0189 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.modules.core + +import android.view.Choreographer + +public class ChoreographerCompat { + + @Deprecated("Use Choreographer.FrameCallback instead") + public abstract class FrameCallback : Choreographer.FrameCallback +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DefaultHardwareBackBtnHandler.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DefaultHardwareBackBtnHandler.kt similarity index 74% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DefaultHardwareBackBtnHandler.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DefaultHardwareBackBtnHandler.kt index 241704e6b51602..90c2f2347319bb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DefaultHardwareBackBtnHandler.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DefaultHardwareBackBtnHandler.kt @@ -5,19 +5,17 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.modules.core; - +package com.facebook.react.modules.core /** - * Interface used by {@link DeviceEventManagerModule} to delegate hardware back button events. It's + * Interface used by [DeviceEventManagerModule] to delegate hardware back button events. It's * suppose to provide a default behavior since it would be triggered in the case when JS side * doesn't want to handle back press events. */ -public interface DefaultHardwareBackBtnHandler { - +public fun interface DefaultHardwareBackBtnHandler { /** * By default, all onBackPress() calls should not execute the default backpress handler and should * instead propagate it to the JS instance. If JS doesn't want to handle the back press itself, it * shall call back into native to invoke this function which should execute the default handler */ - void invokeDefaultOnBackPressed(); + public fun invokeDefaultOnBackPressed() } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java deleted file mode 100644 index e8ba782cb568c5..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.core; - -import android.net.Uri; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import com.facebook.fbreact.specs.NativeDeviceEventManagerSpec; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.UiThreadUtil; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.module.annotations.ReactModule; - -/** Native module that handles device hardware events like hardware back presses. */ -@ReactModule(name = NativeDeviceEventManagerSpec.NAME) -public class DeviceEventManagerModule extends NativeDeviceEventManagerSpec { - @DoNotStrip - public interface RCTDeviceEventEmitter extends JavaScriptModule { - void emit(@NonNull String eventName, @Nullable Object data); - } - - private final Runnable mInvokeDefaultBackPressRunnable; - - public DeviceEventManagerModule( - ReactApplicationContext reactContext, final DefaultHardwareBackBtnHandler backBtnHandler) { - super(reactContext); - mInvokeDefaultBackPressRunnable = - new Runnable() { - @Override - public void run() { - UiThreadUtil.assertOnUiThread(); - backBtnHandler.invokeDefaultOnBackPressed(); - } - }; - } - - /** Sends an event to the JS instance that the hardware back has been pressed. */ - public void emitHardwareBackPressed() { - ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn(); - - if (reactApplicationContext != null) { - reactApplicationContext.emitDeviceEvent("hardwareBackPress", null); - } - } - - /** Sends an event to the JS instance that a new intent was received. */ - public void emitNewIntentReceived(Uri uri) { - ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn(); - - if (reactApplicationContext != null) { - WritableMap map = Arguments.createMap(); - map.putString("url", uri.toString()); - reactApplicationContext.emitDeviceEvent("url", map); - } - } - - /** - * Invokes the default back handler for the host of this catalyst instance. This should be invoked - * if JS does not want to handle the back press itself. - */ - @Override - public void invokeDefaultBackPressHandler() { - // There should be no need to check if the catalyst instance is alive. After initialization - // the thread instances cannot be null, and scheduling on a thread after ReactApplicationContext - // teardown is a noop. - getReactApplicationContext().runOnUiQueueThread(mInvokeDefaultBackPressRunnable); - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.kt new file mode 100644 index 00000000000000..4667f0ed537a53 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.modules.core + +import android.net.Uri +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.JavaScriptModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.UiThreadUtil +import com.facebook.react.module.annotations.ReactModule + +/** Native module that handles device hardware events like hardware back presses. */ +@ReactModule(name = com.facebook.fbreact.specs.NativeDeviceEventManagerSpec.NAME) +public class DeviceEventManagerModule( + reactContext: ReactApplicationContext?, + backBtnHandler: DefaultHardwareBackBtnHandler +) : com.facebook.fbreact.specs.NativeDeviceEventManagerSpec(reactContext) { + @DoNotStrip + public fun interface RCTDeviceEventEmitter : JavaScriptModule { + public fun emit(eventName: String, data: Any?) + } + + private val invokeDefaultBackPressRunnable: Runnable = Runnable { + UiThreadUtil.assertOnUiThread() + backBtnHandler.invokeDefaultOnBackPressed() + } + + /** Sends an event to the JS instance that the hardware back has been pressed. */ + public fun emitHardwareBackPressed() { + val reactApplicationContext: ReactApplicationContext? = + getReactApplicationContextIfActiveOrWarn() + reactApplicationContext?.emitDeviceEvent("hardwareBackPress", null) + } + + /** Sends an event to the JS instance that a new intent was received. */ + public fun emitNewIntentReceived(uri: Uri) { + val reactApplicationContext: ReactApplicationContext? = + getReactApplicationContextIfActiveOrWarn() + val map = Arguments.createMap() + map.putString("url", uri.toString()) + reactApplicationContext?.emitDeviceEvent("url", map) + } + + /** + * Invokes the default back handler for the host of this catalyst instance. This should be invoked + * if JS does not want to handle the back press itself. + */ + override fun invokeDefaultBackPressHandler() { + // There should be no need to check if the catalyst instance is alive. After initialization + // the thread instances cannot be null, and scheduling on a thread after ReactApplicationContext + // teardown is a noop. + getReactApplicationContext().runOnUiQueueThread(invokeDefaultBackPressRunnable) + } + + public companion object { + public const val NAME: String = com.facebook.fbreact.specs.NativeDeviceEventManagerSpec.NAME + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimers.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimers.java deleted file mode 100644 index 74455dc16370b8..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimers.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.core; - -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.WritableArray; - -@DoNotStrip -public interface JSTimers extends JavaScriptModule { - void callTimers(WritableArray timerIDs); - - void callIdleCallbacks(double frameTime); - - void emitTimeDriftWarning(String warningMessage); -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimers.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimers.kt new file mode 100644 index 00000000000000..47946ca72bd962 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimers.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.modules.core + +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.bridge.JavaScriptModule +import com.facebook.react.bridge.WritableArray + +@DoNotStrip +public interface JSTimers : JavaScriptModule { + public fun callTimers(timerIDs: WritableArray) + + public fun callIdleCallbacks(frameTime: Double) + + public fun emitTimeDriftWarning(warningMessage: String) +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaScriptTimerExecutor.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaScriptTimerExecutor.kt similarity index 69% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaScriptTimerExecutor.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaScriptTimerExecutor.kt index 768d63a93828cb..413681e657e1da 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaScriptTimerExecutor.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaScriptTimerExecutor.kt @@ -5,33 +5,32 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.modules.core; +package com.facebook.react.modules.core -import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableArray -/** An interface used by {@link JavaTimerManager} to access and call JS timers from Java. */ +/** An interface used by [JavaTimerManager] to access and call JS timers from Java. */ public interface JavaScriptTimerExecutor { - /** * Calls the JS callback(s) associated with the timer ID(s). Also unregisters the callback if the * timer isn't recurring (e.g. unregisters for setTimeout, doesn't for setInterval). * * @param timerIDs An array of timer handles to call. Accepts an array as an optimization, to - * avoid unnecessary JNI calls. + * avoid unnecessary JNI calls. */ - void callTimers(WritableArray timerIDs); + public fun callTimers(timerIDs: WritableArray) /** * Invoke the JS callback registered with `requestIdleCallback`. * * @param frameTime The amount of time left in the frame, in ms. */ - void callIdleCallbacks(double frameTime); + public fun callIdleCallbacks(frameTime: Double) /** * Shows a warning message in development when environment times are out of sync. * * @param warningMessage The message to show */ - void emitTimeDriftWarning(String warningMessage); + public fun emitTimeDriftWarning(warningMessage: String) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionAwareActivity.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionAwareActivity.java deleted file mode 100644 index 21c075c0b8db6b..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionAwareActivity.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.core; - -import android.app.Activity; - -/** - * Interface used to denote activities that can forward permission requests and call {@link - * PermissionListener}s with the permission request results. - */ -public interface PermissionAwareActivity { - - /** See {@link Activity#checkPermission}. */ - int checkPermission(String permission, int pid, int uid); - - /** See {@link Activity#checkSelfPermission}. */ - int checkSelfPermission(String permission); - - /** See {@link Activity#shouldShowRequestPermissionRationale}. */ - boolean shouldShowRequestPermissionRationale(String permission); - - /** See {@link Activity#requestPermissions}. */ - void requestPermissions(String[] permissions, int requestCode, PermissionListener listener); -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionAwareActivity.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionAwareActivity.kt new file mode 100644 index 00000000000000..f4089724d541f1 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionAwareActivity.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.modules.core + +/** + * Interface used to denote activities that can forward permission requests and call + * [PermissionListener] with the permission request results. + */ +public interface PermissionAwareActivity { + /** See [Activity.checkPermission]. */ + public fun checkPermission(permission: String, pid: Int, uid: Int): Int + + /** See [Activity.checkSelfPermission]. */ + public fun checkSelfPermission(permission: String): Int + + /** See [Activity.shouldShowRequestPermissionRationale]. */ + public fun shouldShowRequestPermissionRationale(permission: String): Boolean + + /** See [Activity.requestPermissions]. */ + public fun requestPermissions( + permissions: Array, + requestCode: Int, + listener: PermissionListener? + ) +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionListener.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionListener.kt similarity index 64% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionListener.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionListener.kt index 7c93305b56bb46..881fc979be7fcd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionListener.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionListener.kt @@ -5,21 +5,21 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.modules.core; - -import android.app.Activity; - +package com.facebook.react.modules.core /** * Interface used by activities to delegate permission request results. Classes implementing this * class will be notified whenever there's a result for a permission request. */ -public interface PermissionListener { - +public fun interface PermissionListener { /** - * Method called whenever there's a result to a permission request. It is forwarded from {@link - * Activity#onRequestPermissionsResult}. + * Method called whenever there's a result to a permission request. It is forwarded from + * [Activity.onRequestPermissionsResult]. * * @return boolean Whether the PermissionListener can be removed. */ - boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults); + public fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ): Boolean } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/RCTNativeAppEventEmitter.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/RCTNativeAppEventEmitter.java deleted file mode 100644 index c2cf5d03b1ed78..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/RCTNativeAppEventEmitter.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.core; - -import androidx.annotation.Nullable; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.JavaScriptModule; - -/** Module that handles global application events. */ -@DoNotStrip -public interface RCTNativeAppEventEmitter extends JavaScriptModule { - void emit(String eventName, @Nullable Object data); -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/RCTNativeAppEventEmitter.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/RCTNativeAppEventEmitter.kt new file mode 100644 index 00000000000000..7cfe0289fcfadd --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/RCTNativeAppEventEmitter.kt @@ -0,0 +1,17 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.modules.core + +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.bridge.JavaScriptModule + +/** Module that handles global application events. */ +@DoNotStrip +public fun interface RCTNativeAppEventEmitter : JavaScriptModule { + public fun emit(eventName: String, data: Any?) +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java deleted file mode 100644 index a05be50df4b4f6..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.core; - -import android.view.Choreographer; -import androidx.annotation.Nullable; -import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.UiThreadUtil; -import com.facebook.react.common.ReactConstants; -import com.facebook.react.internal.ChoreographerProvider; -import java.util.ArrayDeque; - -/** - * A simple wrapper around Choreographer that allows us to control the order certain callbacks are - * executed within a given frame. The wrapped Choreographer instance will always be the main thread - * one and the API's are safe to use from any thread. - */ -public final class ReactChoreographer { - - public enum CallbackType { - - /** For use by perf markers that need to happen immediately after draw */ - PERF_MARKERS(0), - - /** For use by {@link com.facebook.react.uimanager.UIManagerModule} */ - DISPATCH_UI(1), - - /** For use by {@link com.facebook.react.animated.NativeAnimatedModule} */ - NATIVE_ANIMATED_MODULE(2), - - /** Events that make JS do things. */ - TIMERS_EVENTS(3), - - /** - * Event used to trigger the idle callback. Called after all UI work has been dispatched to JS. - */ - IDLE_EVENT(4), - ; - - private final int mOrder; - - CallbackType(int order) { - mOrder = order; - } - - /*package*/ int getOrder() { - return mOrder; - } - } - - private static ReactChoreographer sInstance; - - public static void initialize(ChoreographerProvider choreographerProvider) { - if (sInstance == null) { - sInstance = new ReactChoreographer(choreographerProvider); - } - } - - public static ReactChoreographer getInstance() { - Assertions.assertNotNull(sInstance, "ReactChoreographer needs to be initialized."); - return sInstance; - } - - private @Nullable ChoreographerProvider.Choreographer mChoreographer; - - private final ArrayDeque[] mCallbackQueues; - - private final Choreographer.FrameCallback mFrameCallback = - new Choreographer.FrameCallback() { - @Override - public void doFrame(long frameTimeNanos) { - synchronized (mCallbackQueues) { - // Callbacks run once and are then automatically removed, the callback will - // be posted again from postFrameCallback - mHasPostedCallback = false; - - for (int i = 0; i < mCallbackQueues.length; i++) { - ArrayDeque callbackQueue = mCallbackQueues[i]; - int initialLength = callbackQueue.size(); - for (int callback = 0; callback < initialLength; callback++) { - Choreographer.FrameCallback frameCallback = callbackQueue.pollFirst(); - if (frameCallback != null) { - frameCallback.doFrame(frameTimeNanos); - mTotalCallbacks--; - } else { - FLog.e(ReactConstants.TAG, "Tried to execute non-existent frame callback"); - } - } - } - maybeRemoveFrameCallback(); - } - } - }; - - private int mTotalCallbacks = 0; - private boolean mHasPostedCallback = false; - - private ReactChoreographer(ChoreographerProvider choreographerProvider) { - mCallbackQueues = new ArrayDeque[CallbackType.values().length]; - for (int i = 0; i < mCallbackQueues.length; i++) { - mCallbackQueues[i] = new ArrayDeque<>(); - } - - UiThreadUtil.runOnUiThread( - () -> { - mChoreographer = choreographerProvider.getChoreographer(); - }); - } - - public void postFrameCallback(CallbackType type, Choreographer.FrameCallback frameCallback) { - synchronized (mCallbackQueues) { - mCallbackQueues[type.getOrder()].addLast(frameCallback); - mTotalCallbacks++; - Assertions.assertCondition(mTotalCallbacks > 0); - - if (!mHasPostedCallback) { - if (mChoreographer == null) { - // Schedule on the main thread, at which point the constructor's async work will have - // completed - UiThreadUtil.runOnUiThread( - () -> { - synchronized (mCallbackQueues) { - postFrameCallbackOnChoreographer(); - } - }); - } else { - postFrameCallbackOnChoreographer(); - } - } - } - } - - /** - * This method writes on mHasPostedCallback and it should be called from another method that has - * the lock mCallbackQueues - */ - private void postFrameCallbackOnChoreographer() { - mChoreographer.postFrameCallback(mFrameCallback); - mHasPostedCallback = true; - } - - public void removeFrameCallback(CallbackType type, Choreographer.FrameCallback frameCallback) { - synchronized (mCallbackQueues) { - if (mCallbackQueues[type.getOrder()].removeFirstOccurrence(frameCallback)) { - mTotalCallbacks--; - maybeRemoveFrameCallback(); - } else { - FLog.e(ReactConstants.TAG, "Tried to remove non-existent frame callback"); - } - } - } - - /** - * This method reads and writes on mHasPostedCallback and it should be called from another method - * that already has the lock on mCallbackQueues. - */ - private void maybeRemoveFrameCallback() { - Assertions.assertCondition(mTotalCallbacks >= 0); - if (mTotalCallbacks == 0 && mHasPostedCallback) { - if (mChoreographer != null) { - mChoreographer.removeFrameCallback(mFrameCallback); - } - mHasPostedCallback = false; - } - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.kt new file mode 100644 index 00000000000000..db0f269ee47250 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.kt @@ -0,0 +1,138 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.modules.core + +import android.view.Choreographer +import com.facebook.common.logging.FLog +import com.facebook.infer.annotation.Assertions +import com.facebook.react.bridge.UiThreadUtil +import com.facebook.react.common.ReactConstants +import com.facebook.react.internal.ChoreographerProvider +import java.util.ArrayDeque + +/** + * A simple wrapper around Choreographer that allows us to control the order certain callbacks are + * executed within a given frame. The wrapped Choreographer instance will always be the main thread + * one and the API's are safe to use from any thread. + */ +public class ReactChoreographer private constructor(choreographerProvider: ChoreographerProvider) { + public enum class CallbackType(internal val order: Int) { + /** For use by perf markers that need to happen immediately after draw */ + PERF_MARKERS(0), + /** For use by [com.facebook.react.uimanager.UIManagerModule] */ + DISPATCH_UI(1), + /** For use by [com.facebook.react.animated.NativeAnimatedModule] */ + NATIVE_ANIMATED_MODULE(2), + /** Events that make JS do things. */ + TIMERS_EVENTS(3), + /** + * Event used to trigger the idle callback. Called after all UI work has been dispatched to JS. + */ + IDLE_EVENT(4) + } + + private var choreographer: ChoreographerProvider.Choreographer? = null + private val callbackQueues: Array> = + Array(CallbackType.entries.size) { ArrayDeque() } + private var totalCallbacks = 0 + private var hasPostedCallback = false + + private val frameCallback = + Choreographer.FrameCallback { frameTimeNanos -> + synchronized(callbackQueues) { + + // Callbacks run once and are then automatically removed, the callback will + // be posted again from postFrameCallback + hasPostedCallback = false + for (i in callbackQueues.indices) { + val callbackQueue = callbackQueues[i] + val initialLength = callbackQueue.size + for (callback in 0 until initialLength) { + val frameCallback = callbackQueue.pollFirst() + if (frameCallback != null) { + frameCallback.doFrame(frameTimeNanos) + totalCallbacks-- + } else { + FLog.e(ReactConstants.TAG, "Tried to execute non-existent frame callback") + } + } + } + maybeRemoveFrameCallback() + } + } + + init { + UiThreadUtil.runOnUiThread { choreographer = choreographerProvider.getChoreographer() } + } + + public fun postFrameCallback(type: CallbackType, callback: Choreographer.FrameCallback) { + synchronized(callbackQueues) { + callbackQueues[type.order].addLast(callback) + totalCallbacks++ + Assertions.assertCondition(totalCallbacks > 0) + if (!hasPostedCallback) { + if (choreographer == null) { + // Schedule on the main thread, at which point the constructor's async work will have + // completed + UiThreadUtil.runOnUiThread { + synchronized(callbackQueues) { postFrameCallbackOnChoreographer() } + } + } else { + postFrameCallbackOnChoreographer() + } + } + } + } + + /** + * This method writes on mHasPostedCallback and it should be called from another method that has + * the lock on [callbackQueues]. + */ + private fun postFrameCallbackOnChoreographer() { + choreographer?.postFrameCallback(frameCallback) + hasPostedCallback = true + } + + public fun removeFrameCallback(type: CallbackType, frameCallback: Choreographer.FrameCallback?) { + synchronized(callbackQueues) { + if (callbackQueues[type.order].removeFirstOccurrence(frameCallback)) { + totalCallbacks-- + maybeRemoveFrameCallback() + } else { + FLog.e(ReactConstants.TAG, "Tried to remove non-existent frame callback") + } + } + } + + /** + * This method reads and writes on mHasPostedCallback and it should be called from another method + * that already has the lock on [callbackQueues]. + */ + private fun maybeRemoveFrameCallback() { + Assertions.assertCondition(totalCallbacks >= 0) + if (totalCallbacks == 0 && hasPostedCallback) { + choreographer?.removeFrameCallback(frameCallback) + hasPostedCallback = false + } + } + + public companion object { + private var choreographer: ReactChoreographer? = null + + @JvmStatic + public fun initialize(choreographerProvider: ChoreographerProvider) { + if (choreographer == null) { + choreographer = ReactChoreographer(choreographerProvider) + } + } + + @JvmStatic + public val instance: ReactChoreographer + get() = checkNotNull(choreographer) { "ReactChoreographer needs to be initialized." } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.kt index c759b8af7cfd2d..508b5ea21d3fbb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.kt @@ -51,7 +51,7 @@ public class PermissionsModule(reactContext: ReactApplicationContext?) : * [permissionAwareActivity.shouldShowRequestPermissionRationale]. */ override public fun shouldShowRequestPermissionRationale( - permission: String?, + permission: String, promise: Promise ): Unit { try {