Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import android.os.Build
/** Helper class for checking Android version-related information. */
internal object AndroidVersion {

/**
* This is the version code for Android 15 (SDK Level 35). Internally at Meta this code is also
* compiled against SDK 34, so we need to retain this constant instead of using
* [Build.VERSION_CODES.VANILLA_ICE_CREAM] directly.
*/
internal const val VERSION_CODE_VANILLA_ICE_CREAM: Int = 35

/**
* This is the version code for Android 16 (SDK Level 36). Delete it once we bump up the default
* compile SDK version to 36.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.PixelUtil.dpToPx
import com.facebook.react.uimanager.PixelUtil.pxToDp
import com.facebook.react.uimanager.ReactAccessibilityDelegate
import com.facebook.react.util.AndroidVersion.VERSION_CODE_VANILLA_ICE_CREAM
import com.facebook.react.views.text.internal.span.CustomLetterSpacingSpan
import com.facebook.react.views.text.internal.span.CustomLineHeightSpan
import com.facebook.react.views.text.internal.span.CustomStyleSpan
Expand Down Expand Up @@ -105,6 +106,18 @@ internal object TextLayoutManager {

private val tagToSpannableCache = ConcurrentHashMap<Int, Spannable>()

// Lazily cached Method for StaticLayout.Builder.setUseBoundsForWidth (API 35+).
// Reflection is needed because some internal targets compile against an SDK older than 35.
private val setUseBoundsForWidthMethod: java.lang.reflect.Method? by lazy {
try {
StaticLayout.Builder::class
.java
.getMethod("setUseBoundsForWidth", Boolean::class.javaPrimitiveType)
} catch (_: ReflectiveOperationException) {
null
}
}

fun setCachedSpannableForTag(reactTag: Int, sp: Spannable): Unit {
tagToSpannableCache[reactTag] = sp
}
Expand Down Expand Up @@ -623,7 +636,7 @@ internal object TextLayoutManager {

// Pre-Android 15: Use existing advance-based logic
if (
Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM ||
Build.VERSION.SDK_INT < VERSION_CODE_VANILLA_ICE_CREAM ||
!ReactNativeFeatureFlags.fixTextClippingAndroid15useBoundsForWidth()
) {
val desiredWidth = ceil(Layout.getDesiredWidth(text, paint)).toInt()
Expand Down Expand Up @@ -724,11 +737,14 @@ internal object TextLayoutManager {
builder.setUseLineSpacingFromFallbacks(true)
}

// setUseBoundsForWidth added in API 35 — use reflection to support internal targets that
// compile against an SDK older than 35.
// https://developer.android.com/reference/android/text/StaticLayout.Builder#setUseBoundsForWidth(boolean)
if (
Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM &&
Build.VERSION.SDK_INT >= VERSION_CODE_VANILLA_ICE_CREAM &&
ReactNativeFeatureFlags.fixTextClippingAndroid15useBoundsForWidth()
) {
builder.setUseBoundsForWidth(true)
setUseBoundsForWidthMethod?.invoke(builder, true)
}

return builder.build()
Expand Down
Loading