diff --git a/example/react-native/ios/Podfile.lock b/example/react-native/ios/Podfile.lock index fc24e13..d7f4097 100644 --- a/example/react-native/ios/Podfile.lock +++ b/example/react-native/ios/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - BackgroundThread (1.1.11): + - BackgroundThread (1.1.15): - boost - DoubleConversion - fast_float @@ -28,7 +28,7 @@ PODS: - SocketRocket - Yoga - boost (1.84.0) - - CloudKitModule (1.1.11): + - CloudKitModule (1.1.15): - boost - DoubleConversion - fast_float @@ -66,7 +66,7 @@ PODS: - hermes-engine (0.14.0): - hermes-engine/Pre-built (= 0.14.0) - hermes-engine/Pre-built (0.14.0) - - KeychainModule (1.1.11): + - KeychainModule (1.1.15): - boost - DoubleConversion - fast_float @@ -96,7 +96,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - NitroModules (0.31.10): + - NitroModules (0.33.2): - boost - DoubleConversion - fast_float @@ -2653,7 +2653,7 @@ PODS: - React-perflogger (= 0.83.0) - React-utils (= 0.83.0) - SocketRocket - - ReactNativeCheckBiometricAuthChanged (1.1.11): + - ReactNativeCheckBiometricAuthChanged (1.1.15): - boost - DoubleConversion - fast_float @@ -2683,7 +2683,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ReactNativeDeviceUtils (1.1.11): + - ReactNativeDeviceUtils (1.1.15): - boost - DoubleConversion - fast_float @@ -2713,7 +2713,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ReactNativeGetRandomValues (1.1.11): + - ReactNativeGetRandomValues (1.1.15): - boost - DoubleConversion - fast_float @@ -2743,7 +2743,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ReactNativeLiteCard (1.1.11): + - ReactNativeLiteCard (1.1.15): - boost - DoubleConversion - fast_float @@ -2771,7 +2771,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - Skeleton (1.1.11): + - Skeleton (1.1.15): - boost - DoubleConversion - fast_float @@ -3077,17 +3077,17 @@ EXTERNAL SOURCES: :path: "../../../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - BackgroundThread: d6bedf61338886caa616744dc1e4aa77656dc285 + BackgroundThread: 8bfdbb6081771366de5e5e2b588aad1beafea9be boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 - CloudKitModule: febc66c8e919ad7f2f6e789af621dfaa0655e103 + CloudKitModule: a7596fae8e1e2d05bd0ba2fa4d4ad90b5e93ea5a DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 FBLazyVector: a293a88992c4c33f0aee184acab0b64a08ff9458 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: 70fdc9d0bb0d8532e0411dcb21e53ce5a160960a - KeychainModule: 014ea2c49f4faa006a6e08b0ec6671875e830654 - NitroModules: 5bc319d441f4983894ea66b1d392c519536e6d23 + KeychainModule: 7a82d9b61fbd70183fdb991384e6a99eff8ac502 + NitroModules: 11bba9d065af151eae51e38a6425e04c3b223ff3 RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 RCTDeprecation: 2b70c6e3abe00396cefd8913efbf6a2db01a2b36 RCTRequired: f3540eee8094231581d40c5c6d41b0f170237a81 @@ -3158,11 +3158,11 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: ebcf3a78dc1bcdf054c9e8d309244bade6b31568 ReactCodegen: 554b421c45b7df35ac791da1b734335470b55fcc ReactCommon: 424cc34cf5055d69a3dcf02f3436481afb8b0f6f - ReactNativeCheckBiometricAuthChanged: 39255aa18891d558cb015483cc76bd7a4dc85df8 - ReactNativeDeviceUtils: adf7b3b1acc437360f7e2e13bcf5b6b74d8da0f8 - ReactNativeGetRandomValues: 1f4deca887951794a2cd3e85276c18bb944ec315 - ReactNativeLiteCard: 9b360619d69533b5e9aec940d3cdfb0d0c157f3a - Skeleton: b63a360c1f9f0c60e7938399d99bf25e151d6a46 + ReactNativeCheckBiometricAuthChanged: 5757aec913dee03c7d488eebb6b05a91ff774e61 + ReactNativeDeviceUtils: 2372c7f86169033f39b524b0bfc28323a2cf6bdc + ReactNativeGetRandomValues: 60a36d2a7e0ced4e37bbbc9faa98e11f27655518 + ReactNativeLiteCard: d59be2b082bc3e7ef452095042c1e6b5483ab210 + Skeleton: af32eaa6d321cf4f3266cf408dadec752dfb8e1d SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: 6ca93c8c13f56baeec55eb608577619b17a4d64e diff --git a/example/react-native/package.json b/example/react-native/package.json index 47a8049..861b125 100644 --- a/example/react-native/package.json +++ b/example/react-native/package.json @@ -42,7 +42,7 @@ "eslint": "^8.19.0", "jest": "^29.6.3", "prettier": "2.8.8", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "react-test-renderer": "19.2.0", "typescript": "^5.8.3" }, diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index ab9f217..1105833 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.14", + "version": "1.1.16", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 86aa6dd..89cd2e7 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.14", + "version": "1.1.16", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "^0.31.10" + "react-native-nitro-modules": "0.33.2" }, "react-native-builder-bob": { "source": "src", diff --git a/native-modules/react-native-cloud-kit-module/android/src/main/java/com/margelo/nitro/cloudkitmodule/CloudKitModule.kt b/native-modules/react-native-cloud-kit-module/android/src/main/java/com/margelo/nitro/cloudkitmodule/CloudKitModule.kt index a32de2b..35dcc35 100644 --- a/native-modules/react-native-cloud-kit-module/android/src/main/java/com/margelo/nitro/cloudkitmodule/CloudKitModule.kt +++ b/native-modules/react-native-cloud-kit-module/android/src/main/java/com/margelo/nitro/cloudkitmodule/CloudKitModule.kt @@ -31,7 +31,7 @@ class CloudKitModule : HybridCloudKitModuleSpec() { } override fun fetchRecord(params: FetchRecordParams): Promise { - return Promise.resolved(Variant_NullType_RecordResult.First(NullType.NULL)) + return Promise.resolved(Variant_NullType_RecordResult.create(NullType.NULL)) } override fun deleteRecord(params: DeleteRecordParams): Promise { diff --git a/native-modules/react-native-cloud-kit-module/ios/CloudKitModule.swift b/native-modules/react-native-cloud-kit-module/ios/CloudKitModule.swift index 2ba3063..7c34943 100644 --- a/native-modules/react-native-cloud-kit-module/ios/CloudKitModule.swift +++ b/native-modules/react-native-cloud-kit-module/ios/CloudKitModule.swift @@ -76,7 +76,7 @@ class CloudKitModule: HybridCloudKitModuleSpec { // MARK: - Fetch Record - public func fetchRecord(params: FetchRecordParams) throws -> NitroModules.Promise { + public func fetchRecord(params: FetchRecordParams) throws -> Promise { return Promise.async { let ckRecordID = CKRecord.ID(recordName: params.recordID) @@ -88,18 +88,16 @@ class CloudKitModule: HybridCloudKitModuleSpec { let createdAt = Int64((record.creationDate?.timeIntervalSince1970 ?? 0) * 1000) let modifiedAt = Int64((record.modificationDate?.timeIntervalSince1970 ?? 0) * 1000) - let result = Variant_NullType_RecordResult.second( - RecordResult( - recordID: record.recordID.recordName, - recordType: record.recordType, - data: data, - meta: meta, - createdAt: Double(createdAt), - modifiedAt: Double(modifiedAt)) - ) - return result + return Variant_NullType_RecordResult.second(RecordResult( + recordID: record.recordID.recordName, + recordType: record.recordType, + data: data, + meta: meta, + createdAt: Double(createdAt), + modifiedAt: Double(modifiedAt) + )) } catch let error as CKError where error.code == .unknownItem { - return Variant_NullType_RecordResult.first(NullType.null) + return Variant_NullType_RecordResult.first(NullType.null) } } } diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 0f92054..a1a842b 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.14", + "version": "1.1.16", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "^0.31.10" + "react-native-nitro-modules": "0.33.2" }, "react-native-builder-bob": { "source": "src", diff --git a/native-modules/react-native-device-utils/android/src/main/java/com/margelo/nitro/reactnativedeviceutils/ReactNativeDeviceUtils.kt b/native-modules/react-native-device-utils/android/src/main/java/com/margelo/nitro/reactnativedeviceutils/ReactNativeDeviceUtils.kt index 8d0db39..434e0c9 100644 --- a/native-modules/react-native-device-utils/android/src/main/java/com/margelo/nitro/reactnativedeviceutils/ReactNativeDeviceUtils.kt +++ b/native-modules/react-native-device-utils/android/src/main/java/com/margelo/nitro/reactnativedeviceutils/ReactNativeDeviceUtils.kt @@ -1,9 +1,12 @@ package com.margelo.nitro.reactnativedeviceutils import android.app.Activity +import android.content.Context +import android.content.pm.PackageManager import android.graphics.Color import android.graphics.Rect import android.os.Build +import android.preference.PreferenceManager import androidx.core.content.ContextCompat import androidx.core.util.Consumer import androidx.window.layout.FoldingFeature @@ -25,7 +28,191 @@ data class Listener( @DoNotStrip class ReactNativeDeviceUtils : HybridReactNativeDeviceUtilsSpec(), LifecycleEventListener { - + + /** + * Foldable device model constants for various manufacturers. + * Reference: https://storage.googleapis.com/play_public/supported_devices.html + */ + companion object { + private const val PREF_KEY_FOLDABLE = "1k_fold" + + // Xiaomi foldable models + private val XIAOMI_FOLDABLE_MODELS = setOf( + "M2011J18C", // Mi MIX FOLD + "22061218C", // MIX FOLD 2 + "2308CPXD0C", // MIX FOLD 3 + "24072PX77C", // MIX FOLD 4 + "2405CPX3DC", // MIX FLIP + "2405CPX3DG" // MIX FLIP + ) + + // Huawei foldable models + private val HUAWEI_FOLDABLE_MODELS = setOf( + "TAH-AN00", "TAH-AN00m", "TAH-N29m", // Mate X + "GRL-AL10", // Mate X3 + "TET-AN50", // Mate Xs + "PAL-AL00", "PAL-LX9", // Mate Xs 2 + "ICL-AL20", "ICL-AL10", // Pocket S + "BAL-AL00", "BAL-L49", "BAL-AL60", // Pocket 2 + "PSD-AL00", // Mate X5 + "LEM-AL00", // Mate X6 + "ALT-AL10", "ALT-AL00", "ALT-L29", // Pocket + "TGW-AL00", "TGW-L29", // Mate X5 + "TWH-AL10", // Mate X3 + "DHF-AL00", "DHF-LX9", // Mate Xs 3 + "RHA-AN00m" // Magic V series + ) + + // Huawei foldable device codes + private val HUAWEI_FOLDABLE_DEVICES = setOf( + "HWTAH", "HWMRX", "HWTET", "HWPAL", "MateX" + ) + + // Vivo foldable models + private val VIVO_FOLDABLE_MODELS = setOf( + "V2337A", // X Fold3 Pro + "V2330", // X Fold3 Pro + "V2178A", // X Fold + "V2229A", // X Fold+ + "V2266A", // vivo X Fold2 + "V2303A", // vivo X Fold3 + "V2256A", // X Flip + "V2436A", // X Fold5 + "V2429" // X Fold5 + ) + + // OPPO foldable models + private val OPPO_FOLDABLE_MODELS = setOf( + // Find N5 + "PKH110", "CPH2671", + // Find N5 卫星通信版 + "PKH120", + // Find N3 + "PHN110", "CPH2499", + // Find N3 Flip + "PHT110", "CPH2519", + // Find N2 Flip + "CPH2437", "PGT110", + // Find N + "PEUM00" + ) + + // Samsung foldable models + private val SAMSUNG_FOLDABLE_MODELS = setOf( + // Galaxy Fold + "SCV44", "SM-F9000", "SM-F900F", "SM-F900U", "SM-F900U1", "SM-F900W", + // Galaxy Fold 5G + "SM-F907B", "SM-F907N", + // Galaxy Z Fold2 5G + "SM-F9160", "SM-F916B", "SM-F916N", "SM-F916Q", "SM-F916U", "SM-F916U1", "SM-F916W", + // Galaxy Z Fold3 5G + "SC-55B", "SCG11", "SM-F9260", "SM-F926B", "SM-F926N", "SM-F926U", "SM-F926U1", "SM-F926W", + // Galaxy Z Fold4 + "SC-55C", "SCG16", "SM-F9360", "SM-F936B", "SM-F936N", "SM-F936U", "SM-F936U1", "SM-F936W", + // Galaxy Z Fold5 + "SC-55D", "SCG22", "SM-F9460", "SM-F946B", "SM-F946N", "SM-F946Q", "SM-F946U", "SM-F946U1", "SM-F946W", + // Galaxy Z Fold6 + "SC-55E", "SCG28", "SM-F9560", "SM-F956B", "SM-F956N", "SM-F956Q", "SM-F956U", "SM-F956U1", "SM-F956W", + // Galaxy Z Fold7 + "SC-56F", "SCG34", "SM-F9660", "SM-F966B", "SM-F966N", "SM-F966Q", "SM-F966U", "SM-F966U1", "SM-F966W", "SM-F966Z", + // Galaxy Z Fold Special Edition + "SM-F958N", + // Galaxy Z TriFold + "SM-F9680", "SM-F968B", "SM-F968N", "SM-F968U1", + // Galaxy Z Flip + "SCV47", "SM-F7000", "SM-F700F", "SM-F700N", "SM-F700U", "SM-F700U1", "SM-F700W", + // Galaxy Z Flip 5G + "SCG04", "SM-F7070", "SM-F707B", "SM-F707N", "SM-F707U", "SM-F707U1", "SM-F707W", + // Galaxy Z Flip3 5G + "SC-54B", "SCG12", "SM-F7110", "SM-F711B", "SM-F711N", "SM-F711U", "SM-F711U1", "SM-F711W", + // Galaxy Z Flip4 + "SC-54C", "SCG17", "SM-F7210", "SM-F721B", "SM-F721C", "SM-F721N", "SM-F721U", "SM-F721U1", "SM-F721W", + // Galaxy Z Flip5 + "SC-54D", "SCG23", "SM-F7310", "SM-F731B", "SM-F731N", "SM-F731Q", "SM-F731U", "SM-F731U1", "SM-F731W", + // Galaxy Z Flip6 + "SC-54E", "SCG29", "SM-F7410", "SM-F741B", "SM-F741N", "SM-F741Q", "SM-F741U", "SM-F741U1", "SM-F741W", + // Galaxy Z Flip7 + "SC-55F", "SCG35", "SM-F7660", "SM-F766B", "SM-F766N", "SM-F766Q", "SM-F766U", "SM-F766U1", "SM-F766W", "SM-F766Z", + // Galaxy Z Flip7 FE + "SM-F7610", "SM-F761B", "SM-F761N", "SM-F761U", "SM-F761U1", + // 心系天下 W23/W25 Flip + "SM-W7023", "SM-W7025" + ) + + // Samsung foldable model prefixes + private val SAMSUNG_FOLDABLE_PREFIXES = listOf( + "SM-F9", // Galaxy Z Fold series + "SM-F7", // Galaxy Z Flip series + "SM-W70" // 心系天下 W series Flip + ) + + // Google foldable models + private val GOOGLE_FOLDABLE_MODELS = setOf( + "Pixel Fold", + "Pixel 9 Pro Fold", + "Pixel 10 Pro Fold" + ) + + // Motorola foldable models + private val MOTOROLA_FOLDABLE_MODELS = setOf( + // razr 40 series + "XT2323-3", // moto razr 40 + "XT2321-2", // moto razr 40 Ultra + // razr 50 series + "XT2451-4", // moto razr 50 + "XT2453-2", // motorola razr 50 + // razr 60 series + "XT2551-3", // motorola razr 60 ultra + // razr 2022 + "XT2251-1", + // razr Japan models + "M-51E", // motorola razr 50d + "M-51F" // motorola razr 60d + ) + + // ZTE/Nubia foldable models + private val ZTE_FOLDABLE_MODELS = setOf( + "NX732J", // nubia Flip 2 5G + "NX724J", // nubia Flip 5G + "Z9900S", // nubia Fold + "A502ZT", // nubia Fold (carrier) + "A304ZT", // Libero Flip + "Z8900CA" // nubia Flip 2 5G + ) + + // Tecno foldable models + private val TECNO_FOLDABLE_MODELS = setOf( + "TECNO-AD10", "TECNO AD10", // PHANTOM V Fold + "TECNO-AE10", "TECNO AE10", // PHANTOM V Fold2 5G + "TECNO-AD11", "TECNO AD11", // PHANTOM V Flip 5G + "TECNO-AE11", "TECNO AE11" // PHANTOM V Flip2 5G + ) + + // Infinix foldable models + private val INFINIX_FOLDABLE_MODELS = setOf( + "Infinix-X6962", "Infinix X6962" // ZERO Flip + ) + + // Royole foldable models + private val ROYOLE_FOLDABLE_MODELS = setOf( + "RY1205" // VERTU Ayxta Fold 3 + ) + + // Honor foldable models + private val HONOR_FOLDABLE_MODELS = setOf( + "VER-N49", // HONOR Magic V2 + "VER-N49DP", // PORSCHE DESIGN HONOR Magic V2 RSR + "FCP-N49", // HONOR Magic V3 + "MBH-N49", // HONOR Magic V5 + "FRI-NX9" // HONOR Magic Vs + ) + + // Vertu foldable models + private val VERTU_FOLDABLE_MODELS = setOf( + "VTL-202302" // METAFLIP + ) + } + private var windowLayoutInfo: WindowLayoutInfo? = null private var isSpanning = false private var layoutInfoConsumer: Consumer? = null @@ -53,37 +240,293 @@ class ReactNativeDeviceUtils : HybridReactNativeDeviceUtilsSpec(), LifecycleEven // MARK: - Dual Screen Detection override fun isDualScreenDevice(): Boolean { + // Check cached value from PreferenceManager first + val cached = getCachedFoldableStatus() + if (cached == true) { + isDualScreenDeviceDetected = true + return true + } + if (isDualScreenDeviceDetected != null) { return isDualScreenDeviceDetected!! } + val activity = getCurrentActivity() ?: return false if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - isDualScreenDeviceDetected = hasFoldingFeature(activity) + val hasFolding = hasFoldingFeature(activity) + if (hasFolding) { + saveFoldableStatus(true) + } + isDualScreenDeviceDetected = hasFolding return isDualScreenDeviceDetected!! } isDualScreenDeviceDetected = false return isDualScreenDeviceDetected!! } - private fun isFoldableDeviceByName(): Boolean { - val deviceModel = Build.MODEL.lowercase() - val deviceManufacturer = Build.MANUFACTURER.lowercase() - - // Common foldable device patterns - val foldablePatterns = listOf( - "fold", "flip", "duo", "surface duo", "galaxy z", - "mate x", "mix fold", "find n", "magic v", - "pixel fold", "honor magic v", "vivo x fold", - "xiaomi mix fold", "oppo find n" - ) - - for (pattern in foldablePatterns) { - if (deviceModel.contains(pattern) || - (deviceManufacturer + " " + deviceModel).contains(pattern)) { - return true + // MARK: - Manufacturer-specific Foldable Detection + + /** + * Check if the device is a Xiaomi foldable + * Detection: Model list matching + system property check + */ + private fun isXiaomiFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "XIAOMI") return false + + val model = Build.MODEL.uppercase() + if (XIAOMI_FOLDABLE_MODELS.contains(model)) return true + + // Fallback: Check system property for foldable type + try { + val clazz = Class.forName("android.os.SystemProperties") + val method = clazz.getMethod("get", String::class.java) + val value = method.invoke(null, "persist.sys.muiltdisplay_type") as? String + if (value == "2") return true + } catch (e: Exception) { + // Ignore reflection errors + } + return false + } + + /** + * Check if the device is a Huawei foldable + * Detection: Model list + device code + system feature check + */ + private fun isHuaweiFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "HUAWEI") return false + + val model = Build.MODEL.uppercase() + val device = Build.DEVICE.uppercase() + + // Check model list + if (HUAWEI_FOLDABLE_MODELS.any { model.contains(it.uppercase()) }) return true + + // Check device codes + if (HUAWEI_FOLDABLE_DEVICES.any { device.contains(it.uppercase()) }) return true + + // Fallback: Check system feature for posture sensor + try { + val context = NitroModules.applicationContext + if (context != null) { + val pm = context.packageManager + if (pm.hasSystemFeature("com.huawei.hardware.sensor.posture")) { + return true + } } + } catch (e: Exception) { + // Ignore } return false } + + /** + * Check if the device is a Vivo foldable + * Detection: Model list + private API check + */ + private fun isVivoFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "VIVO") return false + + val model = Build.MODEL.uppercase() + if (VIVO_FOLDABLE_MODELS.contains(model)) return true + + // Fallback: Check using FtDeviceInfo API + try { + val clazz = Class.forName("android.util.FtDeviceInfo") + val method = clazz.getMethod("getDeviceType") + val deviceType = method.invoke(null) as? String + if (deviceType?.lowercase() == "foldable") return true + } catch (e: Exception) { + // Ignore reflection errors + } + return false + } + + /** + * Check if the device is an OPPO foldable + * Detection: Model list + feature config check + */ + private fun isOppoFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "OPPO") return false + + val model = Build.MODEL.uppercase() + if (OPPO_FOLDABLE_MODELS.contains(model)) return true + + // Fallback: Check using OplusFeatureConfigManager + try { + val clazz = Class.forName("com.oplus.content.OplusFeatureConfigManager") + val getInstanceMethod = clazz.getMethod("getInstance") + val instance = getInstanceMethod.invoke(null) + val hasFeatureMethod = clazz.getMethod("hasFeature", String::class.java) + val hasFeature = hasFeatureMethod.invoke(instance, "oplus.hardware.type.fold") as? Boolean + if (hasFeature == true) return true + } catch (e: Exception) { + // Ignore reflection errors + } + return false + } + + /** + * Check if the device is a Samsung foldable + * Detection: Model prefix matching + model list + */ + private fun isSamsungFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "SAMSUNG") return false + + val model = Build.MODEL.uppercase() + + // Check model prefixes (SM-F9xxx for Fold, SM-F7xxx for Flip) + for (prefix in SAMSUNG_FOLDABLE_PREFIXES) { + if (model.startsWith(prefix.uppercase())) return true + } + + // Check Japan carrier model list + if (SAMSUNG_FOLDABLE_MODELS.contains(model)) return true + + return false + } + + /** + * Check if the device is a Google foldable + */ + private fun isGoogleFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "GOOGLE") return false + + val model = Build.MODEL.uppercase() + return GOOGLE_FOLDABLE_MODELS.any { model.contains(it.uppercase()) } + } + + /** + * Check if the device is a Motorola foldable + */ + private fun isMotorolaFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "MOTOROLA") return false + + val model = Build.MODEL.uppercase() + return MOTOROLA_FOLDABLE_MODELS.contains(model) + } + + /** + * Check if the device is a ZTE/Nubia foldable + */ + private fun isZteFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "ZTE" && manufacturer != "NUBIA") return false + + val model = Build.MODEL.uppercase() + return ZTE_FOLDABLE_MODELS.contains(model) + } + + /** + * Check if the device is a Tecno foldable + */ + private fun isTecnoFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "TECNO") return false + + val model = Build.MODEL.uppercase() + return TECNO_FOLDABLE_MODELS.any { model.contains(it.uppercase()) } + } + + /** + * Check if the device is an Infinix foldable + */ + private fun isInfinixFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "INFINIX") return false + + val model = Build.MODEL.uppercase() + return INFINIX_FOLDABLE_MODELS.any { model.contains(it.uppercase()) } + } + + /** + * Check if the device is a Royole foldable + */ + private fun isRoyoleFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "ROYOLE") return false + + val model = Build.MODEL.uppercase() + return ROYOLE_FOLDABLE_MODELS.contains(model) + } + + /** + * Check if the device is an Honor foldable + */ + private fun isHonorFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "HONOR") return false + + val model = Build.MODEL.uppercase() + return HONOR_FOLDABLE_MODELS.contains(model) + } + + /** + * Check if the device is a Vertu foldable + */ + private fun isVertuFoldable(): Boolean { + val manufacturer = Build.MANUFACTURER.uppercase() + if (manufacturer != "VERTU") return false + + val model = Build.MODEL.uppercase() + return VERTU_FOLDABLE_MODELS.contains(model) + } + + /** + * Get cached foldable status from PreferenceManager + */ + private fun getCachedFoldableStatus(): Boolean? { + try { + val context = NitroModules.applicationContext ?: return null + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + if (!prefs.contains(PREF_KEY_FOLDABLE)) return null + return prefs.getBoolean(PREF_KEY_FOLDABLE, false) + } catch (e: Exception) { + return null + } + } + + /** + * Save foldable status to PreferenceManager + */ + private fun saveFoldableStatus(isFoldable: Boolean) { + try { + val context = NitroModules.applicationContext ?: return + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + prefs.edit().putBoolean(PREF_KEY_FOLDABLE, isFoldable).apply() + } catch (e: Exception) { + // Ignore save errors + } + } + + /** + * Detect if device is foldable by checking manufacturer-specific methods + * Results are cached in PreferenceManager with key "1k_fold" + */ + private fun isFoldableDeviceByName(): Boolean { + // Check each manufacturer + val isFoldable = isXiaomiFoldable() || + isHuaweiFoldable() || + isVivoFoldable() || + isOppoFoldable() || + isSamsungFoldable() || + isGoogleFoldable() || + isMotorolaFoldable() || + isZteFoldable() || + isTecnoFoldable() || + isInfinixFoldable() || + isRoyoleFoldable() || + isHonorFoldable() || + isVertuFoldable() + + // Cache the result + return isFoldable + } private fun hasFoldingFeature(activity: Activity): Boolean { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { @@ -229,7 +672,8 @@ class ReactNativeDeviceUtils : HybridReactNativeDeviceUtilsSpec(), LifecycleEven } fun callSpanningChangedListeners(isSpanning: Boolean) { - for (listener in spanningChangedListeners) { + // Create a snapshot to avoid ConcurrentModificationException when listeners modify the list during callbacks + for (listener in spanningChangedListeners.toList()) { listener.callback(isSpanning) } } diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index b0f3b39..3d42c2d 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.14", + "version": "1.1.16", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "^0.31.10" + "react-native-nitro-modules": "0.33.2" }, "react-native-builder-bob": { "source": "src", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index a961170..64ca192 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.14", + "version": "1.1.16", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "^0.31.10" + "react-native-nitro-modules": "0.33.2" }, "react-native-builder-bob": { "source": "src", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 12634d1..cac8464 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.14", + "version": "1.1.16", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "^0.31.10" + "react-native-nitro-modules": "0.33.2" }, "react-native-builder-bob": { "source": "src", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index dcc6c57..6c19f8f 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.14", + "version": "1.1.16", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index d8c2bc0..a65d37f 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.14", + "version": "1.1.16", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "0.31.10" + "react-native-nitro-modules": "0.33.2" }, "packageManager": "yarn@4.11.0", "react-native-builder-bob": { diff --git a/package.json b/package.json index 54247f5..7c23745 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -50,6 +50,6 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "^0.31.10" + "react-native-nitro-modules": "0.33.2" } } diff --git a/scripts/nitro-view/template/package.json b/scripts/nitro-view/template/package.json index cc29367..e27462a 100644 --- a/scripts/nitro-view/template/package.json +++ b/scripts/nitro-view/template/package.json @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "0.31.10" + "react-native-nitro-modules": "0.33.2" }, "packageManager": "yarn@4.11.0", "react-native-builder-bob": { diff --git a/scripts/nitro/template/package.json b/scripts/nitro/template/package.json index a4b3622..2ce716b 100644 --- a/scripts/nitro/template/package.json +++ b/scripts/nitro/template/package.json @@ -82,7 +82,7 @@ "react": "19.2.0", "react-native": "0.83.0", "react-native-builder-bob": "^0.40.13", - "react-native-nitro-modules": "0.31.10", + "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", "turbo": "^2.5.6", "typescript": "^5.9.2" @@ -90,7 +90,7 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-nitro-modules": "^0.31.10" + "react-native-nitro-modules": "0.33.2" }, "react-native-builder-bob": { "source": "src", diff --git a/yarn.lock b/yarn.lock index ebbb3e8..8f83aa6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2769,7 +2769,7 @@ __metadata: prettier: "npm:2.8.8" react: "npm:19.2.0" react-native: "npm:0.83.0" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" react-native-safe-area-context: "npm:^5.5.2" react-test-renderer: "npm:19.2.0" typescript: "npm:^5.8.3" @@ -2802,14 +2802,14 @@ __metadata: react: "npm:19.2.0" react-native: "npm:0.83.0" react-native-builder-bob: "npm:^0.40.13" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" typescript: "npm:^5.9.2" peerDependencies: react: "*" react-native: "*" - react-native-nitro-modules: ^0.31.10 + react-native-nitro-modules: 0.33.2 languageName: unknown linkType: soft @@ -2871,14 +2871,14 @@ __metadata: react: "npm:19.2.0" react-native: "npm:0.83.0" react-native-builder-bob: "npm:^0.40.13" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" typescript: "npm:^5.9.2" peerDependencies: react: "*" react-native: "*" - react-native-nitro-modules: ^0.31.10 + react-native-nitro-modules: 0.33.2 languageName: unknown linkType: soft @@ -2907,14 +2907,14 @@ __metadata: react: "npm:19.2.0" react-native: "npm:0.83.0" react-native-builder-bob: "npm:^0.40.13" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" typescript: "npm:^5.9.2" peerDependencies: react: "*" react-native: "*" - react-native-nitro-modules: ^0.31.10 + react-native-nitro-modules: 0.33.2 languageName: unknown linkType: soft @@ -2943,14 +2943,14 @@ __metadata: react: "npm:19.2.0" react-native: "npm:0.83.0" react-native-builder-bob: "npm:^0.40.13" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" typescript: "npm:^5.9.2" peerDependencies: react: "*" react-native: "*" - react-native-nitro-modules: ^0.31.10 + react-native-nitro-modules: 0.33.2 languageName: unknown linkType: soft @@ -2979,14 +2979,14 @@ __metadata: react: "npm:19.2.0" react-native: "npm:0.83.0" react-native-builder-bob: "npm:^0.40.13" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" typescript: "npm:^5.9.2" peerDependencies: react: "*" react-native: "*" - react-native-nitro-modules: ^0.31.10 + react-native-nitro-modules: 0.33.2 languageName: unknown linkType: soft @@ -3015,14 +3015,14 @@ __metadata: react: "npm:19.2.0" react-native: "npm:0.83.0" react-native-builder-bob: "npm:^0.40.13" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" typescript: "npm:^5.9.2" peerDependencies: react: "*" react-native: "*" - react-native-nitro-modules: ^0.31.10 + react-native-nitro-modules: 0.33.2 languageName: unknown linkType: soft @@ -3084,14 +3084,14 @@ __metadata: react: "npm:19.2.0" react-native: "npm:0.83.0" react-native-builder-bob: "npm:^0.40.13" - react-native-nitro-modules: "npm:0.31.10" + react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" typescript: "npm:^5.9.2" peerDependencies: react: "*" react-native: "*" - react-native-nitro-modules: 0.31.10 + react-native-nitro-modules: 0.33.2 languageName: unknown linkType: soft @@ -10661,7 +10661,17 @@ __metadata: languageName: node linkType: hard -"react-native-nitro-modules@npm:0.31.10, react-native-nitro-modules@npm:^0.31.10": +"react-native-nitro-modules@npm:0.33.2": + version: 0.33.2 + resolution: "react-native-nitro-modules@npm:0.33.2" + peerDependencies: + react: "*" + react-native: "*" + checksum: 10/fece339c9f69b256d4e18e6fbf29bc52a16e2e8ea7e70551d8265dbaf455402a67fd8ca9f4e8abe5b6e6d3e33bf6c598d4e980dbbed00a3b791f6fa49c98be17 + languageName: node + linkType: hard + +"react-native-nitro-modules@npm:^0.31.10": version: 0.31.10 resolution: "react-native-nitro-modules@npm:0.31.10" peerDependencies: