From 79a3119ba57fdf762fd754183e7e22a99b0cb179 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Sun, 12 May 2024 00:05:40 -0700 Subject: [PATCH] Kotlinify DeviceInfoModule (#44536) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44536 # Changelog: [Internal] - As in the title. Differential Revision: D57248069 --- .../ReactAndroid/api/ReactAndroid.api | 4 +- .../modules/deviceinfo/DeviceInfoModule.java | 109 ------------------ .../modules/deviceinfo/DeviceInfoModule.kt | 85 ++++++++++++++ 3 files changed, 87 insertions(+), 111 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 31b73c401ba098..778ea036153e63 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3241,10 +3241,10 @@ public abstract interface class com/facebook/react/modules/debug/interfaces/Deve public abstract fun setRemoteJSDebugEnabled (Z)V } -public class com/facebook/react/modules/deviceinfo/DeviceInfoModule : com/facebook/fbreact/specs/NativeDeviceInfoSpec, com/facebook/react/bridge/LifecycleEventListener { +public final class com/facebook/react/modules/deviceinfo/DeviceInfoModule : com/facebook/fbreact/specs/NativeDeviceInfoSpec, com/facebook/react/bridge/LifecycleEventListener { public fun (Landroid/content/Context;)V public fun (Lcom/facebook/react/bridge/ReactApplicationContext;)V - public fun emitUpdateDimensionsEvent ()V + public final fun emitUpdateDimensionsEvent ()V public fun getTypedExportedConstants ()Ljava/util/Map; public fun invalidate ()V public fun onHostDestroy ()V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java deleted file mode 100644 index e8ff3bb7720288..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java +++ /dev/null @@ -1,109 +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.deviceinfo; - -import android.content.Context; -import androidx.annotation.Nullable; -import com.facebook.fbreact.specs.NativeDeviceInfoSpec; -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactNoCrashSoftException; -import com.facebook.react.bridge.ReactSoftExceptionLogger; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.module.annotations.ReactModule; -import com.facebook.react.uimanager.DisplayMetricsHolder; -import java.util.HashMap; -import java.util.Map; - -/** Module that exposes Android Constants to JS. */ -@ReactModule(name = NativeDeviceInfoSpec.NAME) -public class DeviceInfoModule extends NativeDeviceInfoSpec implements LifecycleEventListener { - - private final @Nullable ReactApplicationContext mReactApplicationContext; - - private float mFontScale; - private @Nullable ReadableMap mPreviousDisplayMetrics; - - public DeviceInfoModule(ReactApplicationContext reactContext) { - super(reactContext); - DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext); - mFontScale = reactContext.getResources().getConfiguration().fontScale; - mReactApplicationContext = reactContext; - mReactApplicationContext.addLifecycleEventListener(this); - } - - public DeviceInfoModule(Context context) { - super(null); - mReactApplicationContext = null; - DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context); - mFontScale = context.getResources().getConfiguration().fontScale; - } - - @Override - public @Nullable Map getTypedExportedConstants() { - WritableMap displayMetrics = DisplayMetricsHolder.getDisplayMetricsWritableMap(mFontScale); - - // Cache the initial dimensions for later comparison in emitUpdateDimensionsEvent - mPreviousDisplayMetrics = displayMetrics.copy(); - - HashMap constants = new HashMap<>(); - constants.put("Dimensions", displayMetrics.toHashMap()); - return constants; - } - - @Override - public void onHostResume() { - if (mReactApplicationContext == null) { - return; - } - - float fontScale = mReactApplicationContext.getResources().getConfiguration().fontScale; - if (mFontScale != fontScale) { - mFontScale = fontScale; - emitUpdateDimensionsEvent(); - } - } - - @Override - public void onHostPause() {} - - @Override - public void onHostDestroy() {} - - public void emitUpdateDimensionsEvent() { - if (mReactApplicationContext == null) { - return; - } - - if (mReactApplicationContext.hasActiveReactInstance()) { - // Don't emit an event to JS if the dimensions haven't changed - WritableMap displayMetrics = DisplayMetricsHolder.getDisplayMetricsWritableMap(mFontScale); - if (mPreviousDisplayMetrics == null) { - mPreviousDisplayMetrics = displayMetrics.copy(); - } else if (!displayMetrics.equals(mPreviousDisplayMetrics)) { - mPreviousDisplayMetrics = displayMetrics.copy(); - mReactApplicationContext.emitDeviceEvent("didUpdateDimensions", displayMetrics); - } - } else { - ReactSoftExceptionLogger.logSoftException( - NAME, - new ReactNoCrashSoftException( - "No active CatalystInstance, cannot emitUpdateDimensionsEvent")); - } - } - - @Override - public void invalidate() { - super.invalidate(); - - if (mReactApplicationContext != null) { - mReactApplicationContext.removeLifecycleEventListener(this); - } - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.kt new file mode 100644 index 00000000000000..c32afac1149201 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.kt @@ -0,0 +1,85 @@ +/* + * 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.deviceinfo + +import android.content.Context +import com.facebook.fbreact.specs.NativeDeviceInfoSpec +import com.facebook.react.bridge.LifecycleEventListener +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactNoCrashSoftException +import com.facebook.react.bridge.ReactSoftExceptionLogger +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.DisplayMetricsHolder.getDisplayMetricsWritableMap +import com.facebook.react.uimanager.DisplayMetricsHolder.initDisplayMetricsIfNotInitialized + +/** Module that exposes Android Constants to JS. */ +@ReactModule(name = NativeDeviceInfoSpec.NAME) +public class DeviceInfoModule : NativeDeviceInfoSpec, LifecycleEventListener { + private var reactApplicationContext: ReactApplicationContext? = null + private var fontScale: Float + private var previousDisplayMetrics: ReadableMap? = null + + public constructor(reactContext: ReactApplicationContext) : super(reactContext) { + initDisplayMetricsIfNotInitialized(reactContext) + fontScale = reactContext.resources.configuration.fontScale + reactContext.addLifecycleEventListener(this) + reactApplicationContext = reactContext + } + + public constructor(context: Context) : super(null) { + reactApplicationContext = null + initDisplayMetricsIfNotInitialized(context) + fontScale = context.resources.configuration.fontScale + } + + override public fun getTypedExportedConstants(): Map { + val displayMetrics = getDisplayMetricsWritableMap(fontScale.toDouble()) + + // Cache the initial dimensions for later comparison in emitUpdateDimensionsEvent + previousDisplayMetrics = displayMetrics.copy() + return mapOf("Dimensions" to displayMetrics.toHashMap()) + } + + override fun onHostResume() { + val newFontScale = reactApplicationContext?.resources?.configuration?.fontScale + if (newFontScale != null && newFontScale != fontScale) { + fontScale = newFontScale + emitUpdateDimensionsEvent() + } + } + + override fun onHostPause(): Unit = Unit + + override fun onHostDestroy(): Unit = Unit + + public fun emitUpdateDimensionsEvent() { + reactApplicationContext?.let { context -> + if (context.hasActiveReactInstance()) { + // Don't emit an event to JS if the dimensions haven't changed + val displayMetrics = getDisplayMetricsWritableMap(fontScale.toDouble()) + if (previousDisplayMetrics == null) { + previousDisplayMetrics = displayMetrics.copy() + } else if (displayMetrics != previousDisplayMetrics) { + previousDisplayMetrics = displayMetrics.copy() + context.emitDeviceEvent("didUpdateDimensions", displayMetrics) + } + } else { + ReactSoftExceptionLogger.logSoftException( + NativeDeviceInfoSpec.NAME, + ReactNoCrashSoftException( + "No active CatalystInstance, cannot emitUpdateDimensionsEvent")) + } + } + } + + override fun invalidate() { + super.invalidate() + reactApplicationContext?.removeLifecycleEventListener(this) + } +}