react-native-tvos 0.83.10-0 → 0.83.10-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/Libraries/Core/ReactNativeVersion.js +1 -1
  2. package/React/Base/RCTVersion.m +1 -1
  3. package/ReactAndroid/gradle.properties +1 -1
  4. package/ReactAndroid/src/main/AndroidManifest.xml +1 -1
  5. package/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.kt +1 -1
  6. package/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +5 -1
  7. package/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.kt +11 -2
  8. package/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.kt +5 -1
  9. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.kt +2 -1
  10. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugOverlayController.kt +8 -2
  11. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/MultipartStreamReader.kt +2 -1
  12. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +6 -0
  13. package/ReactAndroid/src/main/java/com/facebook/react/modules/i18nmanager/I18nManagerModule.kt +8 -1
  14. package/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.kt +17 -3
  15. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  16. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +6 -1
  17. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.kt +2 -1
  18. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BackgroundDrawable.kt +0 -1
  19. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BackgroundImageDrawable.kt +0 -1
  20. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BorderDrawable.kt +0 -1
  21. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt +4 -1
  22. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/Drawable.kt +30 -0
  23. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/LayerDrawable.kt +32 -0
  24. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt +0 -1
  25. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt +0 -4
  26. package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.kt +12 -2
  27. package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.kt +5 -0
  28. package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.kt +38 -28
  29. package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +22 -7
  30. package/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt +7 -0
  31. package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +7 -2
  32. package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputLocalData.kt +13 -2
  33. package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.kt +13 -2
  34. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.kt +11 -2
  35. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +8 -0
  36. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  37. package/gradle/libs.versions.toml +1 -1
  38. package/package.json +2 -2
@@ -29,7 +29,7 @@ export default class ReactNativeVersion {
29
29
  static major: number = 0;
30
30
  static minor: number = 83;
31
31
  static patch: number = 10;
32
- static prerelease: string | null = '0';
32
+ static prerelease: string | null = '1';
33
33
 
34
34
  static getVersionString(): string {
35
35
  return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(83),
26
26
  RCTVersionPatch: @(10),
27
- RCTVersionPrerelease: @"0",
27
+ RCTVersionPrerelease: @"1",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.83.10-0
1
+ VERSION_NAME=0.83.10-1
2
2
  react.internal.publishingGroup=io.github.react-native-tvos
3
3
  react.internal.hermesPublishingGroup=com.facebook.hermes
4
4
 
@@ -8,7 +8,7 @@
8
8
  up from the file to lint until it find an AndroidManifest with a minSdkVersion. This is then used
9
9
  as the min SDK to lint the file.-->
10
10
  <uses-sdk
11
- android:minSdkVersion="24"
11
+ android:minSdkVersion="22"
12
12
  android:targetSdkVersion="36"
13
13
  />
14
14
 
@@ -49,5 +49,5 @@ public class DebugCorePackage public constructor() :
49
49
  reactContext: ReactApplicationContext,
50
50
  viewManagerName: String,
51
51
  ): ViewManager<*, *>? =
52
- viewManagersMap.getOrDefault(viewManagerName, null)?.provider?.get() as? ViewManager<*, *>
52
+ viewManagersMap[viewManagerName]?.provider?.get() as? ViewManager<*, *>
53
53
  }
@@ -252,7 +252,11 @@ public class ReactActivityDelegate {
252
252
  public void requestPermissions(
253
253
  String[] permissions, int requestCode, @Nullable PermissionListener listener) {
254
254
  mPermissionListener = listener;
255
- getPlainActivity().requestPermissions(permissions, requestCode);
255
+ // Runtime permissions were introduced in API 23 (M). On older platforms permissions are
256
+ // granted at install time, so there is nothing to request.
257
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
258
+ getPlainActivity().requestPermissions(permissions, requestCode);
259
+ }
256
260
  }
257
261
 
258
262
  public void onRequestPermissionsResult(
@@ -9,7 +9,9 @@ package com.facebook.react
9
9
 
10
10
  import android.app.Activity
11
11
  import android.content.Intent
12
+ import android.os.Build
12
13
  import android.os.Bundle
14
+ import android.os.Process
13
15
  import android.view.KeyEvent
14
16
  import android.view.LayoutInflater
15
17
  import android.view.View
@@ -160,7 +162,11 @@ public open class ReactFragment : Fragment(), PermissionAwareActivity {
160
162
  activity?.checkPermission(permission, pid, uid) ?: 0
161
163
 
162
164
  override fun checkSelfPermission(permission: String): Int =
163
- activity?.checkSelfPermission(permission) ?: 0
165
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
166
+ activity?.checkSelfPermission(permission) ?: 0
167
+ } else {
168
+ activity?.checkPermission(permission, Process.myPid(), Process.myUid()) ?: 0
169
+ }
164
170
 
165
171
  @Suppress("DEPRECATION")
166
172
  override fun requestPermissions(
@@ -169,7 +175,10 @@ public open class ReactFragment : Fragment(), PermissionAwareActivity {
169
175
  listener: PermissionListener?,
170
176
  ) {
171
177
  permissionListener = listener
172
- requestPermissions(permissions, requestCode)
178
+ // Runtime permissions were introduced in API 23 (M); on older platforms they are install-time.
179
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
180
+ requestPermissions(permissions, requestCode)
181
+ }
173
182
  }
174
183
 
175
184
  /** Builder class to help instantiate a ReactFragment. */
@@ -7,6 +7,7 @@
7
7
 
8
8
  package com.facebook.react.bridge.queue
9
9
 
10
+ import android.os.Build
10
11
  import android.os.Looper
11
12
  import android.os.Process
12
13
  import com.facebook.common.logging.FLog
@@ -104,7 +105,10 @@ private constructor(
104
105
  }
105
106
  }
106
107
 
107
- public override fun isIdle(): Boolean = looper.queue.isIdle
108
+ public override fun isIdle(): Boolean =
109
+ // Looper.getQueue()/MessageQueue.isIdle() require API 23 (M); there is no pre-M way to
110
+ // introspect another thread's queue, so report idle to avoid blocking instrumentation.
111
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) looper.queue.isIdle else true
108
112
 
109
113
  public companion object {
110
114
  @JvmStatic
@@ -200,7 +200,8 @@ public class BundleDownloader public constructor(private val client: OkHttpClien
200
200
  // The http status code for each separate chunk is in the X-Http-Status header.
201
201
  var status = response.code()
202
202
  if (headers.containsKey("X-Http-Status")) {
203
- status = headers.getOrDefault("X-Http-Status", "0").toInt()
203
+ // Map.getOrDefault requires API 24; use Kotlin get-with-default (API 1).
204
+ status = (headers["X-Http-Status"] ?: "0").toInt()
204
205
  }
205
206
  processBundleResult(
206
207
  url,
@@ -11,6 +11,7 @@ import android.content.Context
11
11
  import android.content.Intent
12
12
  import android.graphics.PixelFormat
13
13
  import android.net.Uri
14
+ import android.os.Build
14
15
  import android.provider.Settings
15
16
  import android.view.WindowManager
16
17
  import android.widget.FrameLayout
@@ -60,6 +61,11 @@ internal class DebugOverlayController(private val reactContext: ReactContext) {
60
61
  @JvmStatic
61
62
  fun requestPermission(context: Context) {
62
63
  // Get permission to show debug overlay in dev builds.
64
+ // Settings.canDrawOverlays / ACTION_MANAGE_OVERLAY_PERMISSION were introduced in API 23 (M);
65
+ // on older platforms the overlay permission is granted at install time.
66
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
67
+ return
68
+ }
63
69
  if (!Settings.canDrawOverlays(context)) {
64
70
  val intent =
65
71
  Intent(
@@ -79,8 +85,8 @@ internal class DebugOverlayController(private val reactContext: ReactContext) {
79
85
 
80
86
  private fun permissionCheck(context: Context): Boolean {
81
87
  // Get permission to show debug overlay in dev builds.
82
- // overlay permission not yet granted
83
- return Settings.canDrawOverlays(context)
88
+ // overlay permission not yet granted (always granted at install time before API 23 (M))
89
+ return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(context)
84
90
  }
85
91
 
86
92
  private fun canHandleIntent(context: Context, intent: Intent): Boolean {
@@ -155,7 +155,8 @@ internal class MultipartStreamReader(
155
155
  val currentTime = System.currentTimeMillis()
156
156
  if (currentTime - lastProgressEvent > 16 || isFinal) {
157
157
  lastProgressEvent = currentTime
158
- val headersContentLength = headers.getOrDefault("Content-Length", "0").toLong()
158
+ // Map.getOrDefault requires API 24; use Kotlin's get-with-default (API 1) instead.
159
+ val headersContentLength = (headers["Content-Length"] ?: "0").toLong()
159
160
  listener.onChunkProgress(headers, contentLength, headersContentLength)
160
161
  }
161
162
  }
@@ -103,6 +103,12 @@ internal class FrameTimingsObserver(
103
103
  if (!isTracing) {
104
104
  return@OnFrameMetricsAvailableListener
105
105
  }
106
+ // FrameMetrics#getMetric requires API 24 (N). This listener is only ever registered on
107
+ // API 24+ (see isSupported / the guarded construction in ReactHostImpl), so this is a
108
+ // defensive no-op that also makes the API level explicit to the linter.
109
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
110
+ return@OnFrameMetricsAvailableListener
111
+ }
106
112
  val beginTimestamp = frameMetrics.getMetric(FrameMetrics.VSYNC_TIMESTAMP)
107
113
  val endTimestamp = beginTimestamp + frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)
108
114
  emitFrameTiming(beginTimestamp, endTimestamp)
@@ -7,6 +7,7 @@
7
7
 
8
8
  package com.facebook.react.modules.i18nmanager
9
9
 
10
+ import android.os.Build
10
11
  import com.facebook.fbreact.specs.NativeI18nManagerSpec
11
12
  import com.facebook.react.bridge.ReactApplicationContext
12
13
  import com.facebook.react.module.annotations.ReactModule
@@ -17,7 +18,13 @@ internal class I18nManagerModule(context: ReactApplicationContext?) :
17
18
  NativeI18nManagerSpec(context) {
18
19
  override fun getTypedExportedConstants(): Map<String, Any> {
19
20
  val context = reactApplicationContext
20
- val locale = context.resources.configuration.locales[0]
21
+ val configuration = context.resources.configuration
22
+ val locale =
23
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
24
+ configuration.locales[0]
25
+ } else {
26
+ @Suppress("DEPRECATION") configuration.locale
27
+ }
21
28
 
22
29
  return mapOf(
23
30
  "isRTL" to I18nUtil.instance.isRTL(context),
@@ -8,7 +8,10 @@
8
8
  package com.facebook.react.modules.permissions
9
9
 
10
10
  import android.app.Activity
11
+ import android.content.Context
11
12
  import android.content.pm.PackageManager
13
+ import android.os.Build
14
+ import android.os.Process
12
15
  import android.util.SparseArray
13
16
  import com.facebook.common.logging.FLog
14
17
  import com.facebook.fbreact.specs.NativePermissionsAndroidSpec
@@ -39,9 +42,20 @@ public class PermissionsModule(reactContext: ReactApplicationContext?) :
39
42
  */
40
43
  public override fun checkPermission(permission: String, promise: Promise) {
41
44
  val context = reactApplicationContext.baseContext
42
- promise.resolve(context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED)
45
+ promise.resolve(checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED)
43
46
  }
44
47
 
48
+ /**
49
+ * [Context.checkSelfPermission] was introduced in API 23 (M). On older platforms permissions are
50
+ * granted at install time, so fall back to [Context.checkPermission] for the current process.
51
+ */
52
+ private fun checkSelfPermission(context: Context, permission: String): Int =
53
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
54
+ context.checkSelfPermission(permission)
55
+ } else {
56
+ context.checkPermission(permission, Process.myPid(), Process.myUid())
57
+ }
58
+
45
59
  /**
46
60
  * Check whether the app should display a message explaining why a certain permission is needed.
47
61
  * successCallback is called with true if the app should display a message, false otherwise. This
@@ -66,7 +80,7 @@ public class PermissionsModule(reactContext: ReactApplicationContext?) :
66
80
  */
67
81
  public override fun requestPermission(permission: String, promise: Promise) {
68
82
  val context = reactApplicationContext.baseContext
69
- if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) {
83
+ if (checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
70
84
  promise.resolve(GRANTED)
71
85
  return
72
86
  }
@@ -104,7 +118,7 @@ public class PermissionsModule(reactContext: ReactApplicationContext?) :
104
118
  val context = reactApplicationContext.baseContext
105
119
  for (i in 0 until permissions.size()) {
106
120
  val perm = permissions.getString(i) ?: continue
107
- if (context.checkSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
121
+ if (checkSelfPermission(context, perm) == PackageManager.PERMISSION_GRANTED) {
108
122
  grantedPermissions.putString(perm, GRANTED)
109
123
  checkedPermissionsCount++
110
124
  } else {
@@ -15,6 +15,6 @@ public object ReactNativeVersion {
15
15
  "major" to 0,
16
16
  "minor" to 83,
17
17
  "patch" to 10,
18
- "prerelease" to "0"
18
+ "prerelease" to "1"
19
19
  )
20
20
  }
@@ -11,6 +11,7 @@ import android.app.Activity
11
11
  import android.content.Context
12
12
  import android.content.Intent
13
13
  import android.nfc.NfcAdapter
14
+ import android.os.Build
14
15
  import android.os.Bundle
15
16
  import androidx.core.graphics.createBitmap
16
17
  import com.facebook.common.logging.FLog
@@ -1611,7 +1612,11 @@ public class ReactHostImpl(
1611
1612
  when (state) {
1612
1613
  TracingState.ENABLED_IN_BACKGROUND_MODE,
1613
1614
  TracingState.ENABLED_IN_CDP_MODE -> {
1614
- if (InspectorFlags.getFrameRecordingEnabled()) {
1615
+ // FrameMetrics-based frame recording requires API 24 (N). FrameTimingsObserver's
1616
+ // listener implements Window.OnFrameMetricsAvailableListener (an API-24 interface),
1617
+ // which would crash at construction on older platforms.
1618
+ if (InspectorFlags.getFrameRecordingEnabled() &&
1619
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
1615
1620
  val observer =
1616
1621
  FrameTimingsObserver(
1617
1622
  _screenshotsEnabled,
@@ -237,7 +237,8 @@ internal object UIManagerModuleConstantsHelper {
237
237
  // Since event maps are client based Map interface, it could be immutable
238
238
  if (destValue !is HashMap<*, *>) {
239
239
  destValue = HashMap(destValue)
240
- dest.replace(key, destValue as MutableMap<*, *>)
240
+ // Map.replace requires API 24; the key is already present, so put (API 1) is equivalent.
241
+ dest[key] = destValue as MutableMap<*, *>
241
242
  }
242
243
  @Suppress("UNCHECKED_CAST")
243
244
  recursiveMerge(destValue as MutableMap<String, Any>, sourceValue as MutableMap<String, Any>)
@@ -16,7 +16,6 @@ import android.graphics.Path
16
16
  import android.graphics.PixelFormat
17
17
  import android.graphics.Rect
18
18
  import android.graphics.RectF
19
- import android.graphics.drawable.Drawable
20
19
  import com.facebook.react.uimanager.PixelUtil.dpToPx
21
20
  import com.facebook.react.uimanager.PixelUtil.pxToDp
22
21
  import com.facebook.react.uimanager.style.BorderInsets
@@ -15,7 +15,6 @@ import android.graphics.Path
15
15
  import android.graphics.PixelFormat
16
16
  import android.graphics.Rect
17
17
  import android.graphics.RectF
18
- import android.graphics.drawable.Drawable
19
18
  import com.facebook.react.uimanager.FloatUtil
20
19
  import com.facebook.react.uimanager.LengthPercentage
21
20
  import com.facebook.react.uimanager.LengthPercentageType
@@ -20,7 +20,6 @@ import android.graphics.PointF
20
20
  import android.graphics.Rect
21
21
  import android.graphics.RectF
22
22
  import android.graphics.Region
23
- import android.graphics.drawable.Drawable
24
23
  import android.os.Build
25
24
  import com.facebook.react.uimanager.FloatUtil.floatsEqual
26
25
  import com.facebook.react.uimanager.LengthPercentage
@@ -12,6 +12,9 @@ import android.graphics.Outline
12
12
  import android.graphics.Path
13
13
  import android.graphics.RectF
14
14
  import android.graphics.drawable.Drawable
15
+ // Framework LayerDrawable, kept for LayerDrawable.PADDING_MODE_STACK and the Array<Drawable?> type.
16
+ // The superclass below is the package-local proxy (fully qualified) so getLayoutDirection() is
17
+ // runtime-safe on API 22 — see LayerDrawable.kt.
15
18
  import android.graphics.drawable.LayerDrawable
16
19
  import android.os.Build
17
20
  import com.facebook.react.common.annotations.UnstableReactNativeAPI
@@ -59,7 +62,7 @@ internal class CompositeBackgroundDrawable(
59
62
  // Holder value for currently set border radius
60
63
  var borderRadius: BorderRadiusStyle? = null,
61
64
  ) :
62
- LayerDrawable(
65
+ com.facebook.react.uimanager.drawable.LayerDrawable(
63
66
  createLayersArray(
64
67
  originalBackground,
65
68
  outerShadows,
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.uimanager.drawable
9
+
10
+ import android.annotation.TargetApi
11
+ import android.os.Build
12
+ import android.view.View
13
+
14
+ /**
15
+ * Package-local base [android.graphics.drawable.Drawable] for React Native's drawable subsystem.
16
+ *
17
+ * [android.graphics.drawable.Drawable.getLayoutDirection] was only introduced in API 23 (M). The
18
+ * drawables in this package read `layoutDirection` internally, which would throw a
19
+ * [NoSuchMethodError] on API 22. By declaring the override here (and guarding the `super` call),
20
+ * subclasses that extend this proxy instead of the framework class stay runtime-safe on API 22.
21
+ */
22
+ internal abstract class Drawable : android.graphics.drawable.Drawable() {
23
+ @TargetApi(Build.VERSION_CODES.M)
24
+ override fun getLayoutDirection(): Int =
25
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
26
+ super.getLayoutDirection()
27
+ } else {
28
+ View.LAYOUT_DIRECTION_LTR
29
+ }
30
+ }
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.uimanager.drawable
9
+
10
+ import android.annotation.TargetApi
11
+ import android.os.Build
12
+ import android.view.View
13
+
14
+ /**
15
+ * Package-local base [android.graphics.drawable.LayerDrawable] for React Native's drawable
16
+ * subsystem.
17
+ *
18
+ * [android.graphics.drawable.Drawable.getLayoutDirection] was only introduced in API 23 (M).
19
+ * [CompositeBackgroundDrawable] reads `layoutDirection` internally, which would throw a
20
+ * [NoSuchMethodError] on API 22. By declaring the override here (and guarding the `super` call),
21
+ * it stays runtime-safe on API 22 while remaining a real framework [LayerDrawable].
22
+ */
23
+ internal abstract class LayerDrawable(layers: Array<android.graphics.drawable.Drawable?>) :
24
+ android.graphics.drawable.LayerDrawable(layers) {
25
+ @TargetApi(Build.VERSION_CODES.M)
26
+ override fun getLayoutDirection(): Int =
27
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
28
+ super.getLayoutDirection()
29
+ } else {
30
+ View.LAYOUT_DIRECTION_LTR
31
+ }
32
+ }
@@ -17,7 +17,6 @@ import android.graphics.Path
17
17
  import android.graphics.PathEffect
18
18
  import android.graphics.PixelFormat
19
19
  import android.graphics.RectF
20
- import android.graphics.drawable.Drawable
21
20
  import com.facebook.react.uimanager.PixelUtil.pxToDp
22
21
  import com.facebook.react.uimanager.style.BorderRadiusStyle
23
22
  import com.facebook.react.uimanager.style.ComputedBorderRadius
@@ -12,11 +12,9 @@ import android.animation.ValueAnimator
12
12
  import android.content.Context
13
13
  import android.graphics.Point
14
14
  import android.graphics.Rect
15
- import android.os.Build
16
15
  import android.view.View
17
16
  import android.view.ViewGroup
18
17
  import android.widget.OverScroller
19
- import androidx.annotation.RequiresApi
20
18
  import androidx.core.view.ViewCompat.FocusDirection
21
19
  import androidx.core.view.ViewCompat.FocusRealDirection
22
20
  import com.facebook.common.logging.FLog
@@ -248,7 +246,6 @@ public object ReactScrollViewHelper {
248
246
  scrollListeners.add(WeakReference(listener))
249
247
  }
250
248
 
251
- @RequiresApi(Build.VERSION_CODES.N)
252
249
  @JvmStatic
253
250
  public fun removeScrollListener(listener: ScrollListener) {
254
251
  // Avoid using removeIf, only available in API 26+
@@ -267,7 +264,6 @@ public object ReactScrollViewHelper {
267
264
  layoutChangeListeners.add(WeakReference(listener))
268
265
  }
269
266
 
270
- @RequiresApi(Build.VERSION_CODES.N)
271
267
  @JvmStatic
272
268
  public fun removeLayoutChangeListener(listener: LayoutChangeListener) {
273
269
  // Avoid using removeIf, only available in API 26+
@@ -9,6 +9,7 @@
9
9
 
10
10
  package com.facebook.react.views.text
11
11
 
12
+ import android.annotation.TargetApi
12
13
  import android.graphics.Color
13
14
  import android.os.Build
14
15
  import android.text.Layout
@@ -65,6 +66,9 @@ import com.facebook.yoga.YogaUnit
65
66
  @Deprecated(
66
67
  message = "This class is part of Legacy Architecture and will be removed in a future release"
67
68
  )
69
+ // The break-strategy / hyphenation-frequency Layout constants used below were added in API 23 (M).
70
+ // They are compile-time int constants (runtime-safe), and the pre-M fallbacks are inlined literals.
71
+ @TargetApi(Build.VERSION_CODES.M)
68
72
  public abstract class ReactBaseTextShadowNode
69
73
  @JvmOverloads
70
74
  public constructor(
@@ -81,8 +85,10 @@ public constructor(
81
85
  protected var numberOfLines: Int = ReactConstants.UNSET
82
86
  private set
83
87
 
84
- protected var textBreakStrategy: Int = Layout.BREAK_STRATEGY_HIGH_QUALITY
85
- protected var hyphenationFrequency: Int = Layout.HYPHENATION_FREQUENCY_NONE
88
+ protected var textBreakStrategy: Int =
89
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) Layout.BREAK_STRATEGY_HIGH_QUALITY else 0
90
+ protected var hyphenationFrequency: Int =
91
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) Layout.HYPHENATION_FREQUENCY_NONE else 0
86
92
  protected var justificationMode: Int =
87
93
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
88
94
  0
@@ -408,6 +414,10 @@ public constructor(
408
414
 
409
415
  @ReactProp(name = ViewProps.TEXT_BREAK_STRATEGY)
410
416
  public open fun setTextBreakStrategy(textBreakStrategy: String?) {
417
+ // Layout break strategies were introduced in API 23 (M); they are unused before then.
418
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
419
+ return
420
+ }
411
421
  this.textBreakStrategy =
412
422
  when (textBreakStrategy) {
413
423
  null,
@@ -7,6 +7,7 @@
7
7
 
8
8
  package com.facebook.react.views.text
9
9
 
10
+ import android.os.Build
10
11
  import android.text.Layout
11
12
  import android.text.TextUtils
12
13
  import android.text.util.Linkify
@@ -110,6 +111,10 @@ public abstract class ReactTextAnchorViewManager<
110
111
 
111
112
  @ReactProp(name = "android_hyphenationFrequency")
112
113
  internal fun setAndroidHyphenationFrequency(view: ReactTextView, frequency: String?) {
114
+ // Hyphenation frequency was introduced in API 23 (M).
115
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
116
+ return
117
+ }
113
118
  when (frequency) {
114
119
  null,
115
120
  "none" -> view.hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE
@@ -212,21 +212,26 @@ public constructor(reactTextViewManagerCallback: ReactTextViewManagerCallback? =
212
212
  // Is used when the width is not known and the text is not boring, ie. if it contains
213
213
  // unicode characters.
214
214
  val hintWidth = ceil(desiredWidth.toDouble()).toInt()
215
- val builder =
216
- StaticLayout.Builder.obtain(text, 0, text.length, textPaint, hintWidth)
217
- .setAlignment(alignment)
218
- .setLineSpacing(0f, 1f)
219
- .setIncludePad(includeFontPadding)
220
- .setBreakStrategy(textBreakStrategy)
221
- .setHyphenationFrequency(hyphenationFrequency)
222
-
223
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
224
- builder.setJustificationMode(justificationMode)
225
- }
226
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
227
- builder.setUseLineSpacingFromFallbacks(true)
215
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
216
+ val builder =
217
+ StaticLayout.Builder.obtain(text, 0, text.length, textPaint, hintWidth)
218
+ .setAlignment(alignment)
219
+ .setLineSpacing(0f, 1f)
220
+ .setIncludePad(includeFontPadding)
221
+ .setBreakStrategy(textBreakStrategy)
222
+ .setHyphenationFrequency(hyphenationFrequency)
223
+
224
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
225
+ builder.setJustificationMode(justificationMode)
226
+ }
227
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
228
+ builder.setUseLineSpacingFromFallbacks(true)
229
+ }
230
+ layout = builder.build()
231
+ } else {
232
+ // StaticLayout.Builder was introduced in API 23 (M); use the legacy constructor below.
233
+ layout = StaticLayout(text, textPaint, hintWidth, alignment, 1f, 0f, includeFontPadding)
228
234
  }
229
- layout = builder.build()
230
235
  } else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
231
236
  // Is used for single-line, boring text when the width is either unknown or bigger
232
237
  // than the width of the text.
@@ -250,22 +255,27 @@ public constructor(reactTextViewManagerCallback: ReactTextViewManagerCallback? =
250
255
  width = ceil(width.toDouble()).toFloat()
251
256
  }
252
257
 
253
- val builder =
254
- StaticLayout.Builder.obtain(text, 0, text.length, textPaint, width.toInt())
255
- .setAlignment(alignment)
256
- .setLineSpacing(0f, 1f)
257
- .setIncludePad(includeFontPadding)
258
- .setBreakStrategy(textBreakStrategy)
259
- .setHyphenationFrequency(hyphenationFrequency)
260
-
261
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
262
- builder.setJustificationMode(justificationMode)
263
- }
258
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
259
+ val builder =
260
+ StaticLayout.Builder.obtain(text, 0, text.length, textPaint, width.toInt())
261
+ .setAlignment(alignment)
262
+ .setLineSpacing(0f, 1f)
263
+ .setIncludePad(includeFontPadding)
264
+ .setBreakStrategy(textBreakStrategy)
265
+ .setHyphenationFrequency(hyphenationFrequency)
266
+
267
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
268
+ builder.setJustificationMode(justificationMode)
269
+ }
264
270
 
265
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
266
- builder.setUseLineSpacingFromFallbacks(true)
271
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
272
+ builder.setUseLineSpacingFromFallbacks(true)
273
+ }
274
+ layout = builder.build()
275
+ } else {
276
+ // StaticLayout.Builder was introduced in API 23 (M); use the legacy constructor below.
277
+ layout = StaticLayout(text, textPaint, width.toInt(), alignment, 1f, 0f, includeFontPadding)
267
278
  }
268
- layout = builder.build()
269
279
  }
270
280
  return layout
271
281
  }
@@ -119,7 +119,10 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
119
119
 
120
120
  // Defaults for these fields:
121
121
  // https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/widget/TextView.java#L1061
122
- setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
122
+ // Break strategies were introduced in API 23 (M).
123
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
124
+ setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
125
+ }
123
126
  setMovementMethod(getDefaultMovementMethod());
124
127
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
125
128
  setJustificationMode(Layout.JUSTIFICATION_MODE_NONE);
@@ -156,7 +159,10 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
156
159
  // focus engine from landing on text views when no other views are available
157
160
  setFocusable(View.NOT_FOCUSABLE);
158
161
 
159
- setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
162
+ // Hyphenation frequency was introduced in API 23 (M).
163
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
164
+ setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
165
+ }
160
166
  updateView(); // call after changing ellipsizeLocation in particular
161
167
  }
162
168
 
@@ -375,8 +381,10 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
375
381
  mMinimumFontSize,
376
382
  mNumberOfLines,
377
383
  getIncludeFontPadding(),
378
- getBreakStrategy(),
379
- getHyphenationFrequency(),
384
+ // Break strategy / hyphenation getters were introduced in API 23 (M); pass a -1
385
+ // sentinel before then (the value is unused by the legacy StaticLayout path).
386
+ (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? -1 : getBreakStrategy(),
387
+ (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? -1 : getHyphenationFrequency(),
380
388
  // always passing ALIGN_NORMAL here should be fine, since this method doesn't depend on
381
389
  // how exactly lines are aligned, just their width
382
390
  Layout.Alignment.ALIGN_NORMAL,
@@ -439,7 +447,8 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
439
447
  if (nextTextAlign != getGravityHorizontal()) {
440
448
  setGravityHorizontal(nextTextAlign);
441
449
  }
442
- if (getBreakStrategy() != update.getTextBreakStrategy()) {
450
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
451
+ && getBreakStrategy() != update.getTextBreakStrategy()) {
443
452
  setBreakStrategy(update.getTextBreakStrategy());
444
453
  }
445
454
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -660,13 +669,19 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
660
669
 
661
670
  @Override
662
671
  public void setBreakStrategy(int breakStrategy) {
663
- super.setBreakStrategy(breakStrategy);
672
+ // TextView.setBreakStrategy was introduced in API 23 (M).
673
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
674
+ super.setBreakStrategy(breakStrategy);
675
+ }
664
676
  mShouldAdjustSpannableFontSize = true;
665
677
  }
666
678
 
667
679
  @Override
668
680
  public void setHyphenationFrequency(int hyphenationFrequency) {
669
- super.setHyphenationFrequency(hyphenationFrequency);
681
+ // TextView.setHyphenationFrequency was introduced in API 23 (M).
682
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
683
+ super.setHyphenationFrequency(hyphenationFrequency);
684
+ }
670
685
  mShouldAdjustSpannableFontSize = true;
671
686
  }
672
687
 
@@ -629,6 +629,13 @@ internal object TextLayoutManager {
629
629
  else -> desiredWidth
630
630
  }
631
631
 
632
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
633
+ // StaticLayout.Builder (with break-strategy / hyphenation / ellipsize / maxLines support) was
634
+ // introduced in API 23 (M); fall back to the legacy constructor on older platforms.
635
+ @Suppress("DEPRECATION")
636
+ return StaticLayout(text, paint, layoutWidth, alignment, 1f, 0f, includeFontPadding)
637
+ }
638
+
632
639
  val builder =
633
640
  StaticLayout.Builder.obtain(text, 0, text.length, paint, layoutWidth)
634
641
  .setAlignment(alignment)
@@ -270,7 +270,10 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
270
270
  override fun onDestroyActionMode(mode: ActionMode) = Unit
271
271
  }
272
272
  customSelectionActionModeCallback = customActionModeCallback
273
- customInsertionActionModeCallback = customActionModeCallback
273
+ // setCustomInsertionActionModeCallback was introduced in API 23 (M).
274
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
275
+ customInsertionActionModeCallback = customActionModeCallback
276
+ }
274
277
  }
275
278
 
276
279
  @SuppressLint("ClassImplementsFinalize")
@@ -734,7 +737,9 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
734
737
  }
735
738
  disableTextDiffing = false
736
739
 
737
- if (breakStrategy != reactTextUpdate.textBreakStrategy) {
740
+ // TextView break strategies were introduced in API 23 (M).
741
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
742
+ breakStrategy != reactTextUpdate.textBreakStrategy) {
738
743
  breakStrategy = reactTextUpdate.textBreakStrategy
739
744
  }
740
745
 
@@ -7,18 +7,26 @@
7
7
 
8
8
  package com.facebook.react.views.textinput
9
9
 
10
+ import android.annotation.TargetApi
11
+ import android.os.Build
12
+ import android.text.Layout
10
13
  import android.text.SpannableStringBuilder
11
14
  import android.util.TypedValue
12
15
  import android.widget.EditText
13
16
 
14
17
  /** Local state bearer for EditText instance. */
18
+ // EditText break-strategy accessors / Layout constants below were added in API 23 (M).
19
+ @TargetApi(Build.VERSION_CODES.M)
15
20
  public class ReactTextInputLocalData(editText: EditText) {
16
21
  private val text = SpannableStringBuilder(editText.text)
17
22
  private val textSize = editText.textSize
18
23
  private val minLines = editText.minLines
19
24
  private val maxLines = editText.maxLines
20
25
  private val inputType = editText.inputType
21
- private val breakStrategy = editText.breakStrategy
26
+ // EditText.getBreakStrategy was introduced in API 23 (M).
27
+ private val breakStrategy =
28
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) editText.breakStrategy
29
+ else Layout.BREAK_STRATEGY_SIMPLE
22
30
  private val placeholder: CharSequence? = editText.hint
23
31
 
24
32
  public fun apply(editText: EditText) {
@@ -28,6 +36,9 @@ public class ReactTextInputLocalData(editText: EditText) {
28
36
  editText.maxLines = maxLines
29
37
  editText.inputType = inputType
30
38
  editText.hint = placeholder
31
- editText.breakStrategy = breakStrategy
39
+ // EditText.setBreakStrategy was introduced in API 23 (M).
40
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
41
+ editText.breakStrategy = breakStrategy
42
+ }
32
43
  }
33
44
  }
@@ -10,6 +10,8 @@
10
10
  package com.facebook.react.views.textinput
11
11
 
12
12
  import android.annotation.SuppressLint
13
+ import android.annotation.TargetApi
14
+ import android.os.Build
13
15
  import android.text.Layout
14
16
  import android.util.TypedValue
15
17
  import android.view.ViewGroup
@@ -43,6 +45,8 @@ import com.facebook.yoga.YogaNode
43
45
  message = "This class is part of Legacy Architecture and will be removed in a future release",
44
46
  level = DeprecationLevel.WARNING,
45
47
  )
48
+ // Break-strategy Layout constants / EditText break-strategy accessors were added in API 23 (M).
49
+ @TargetApi(Build.VERSION_CODES.M)
46
50
  internal class ReactTextInputShadowNode
47
51
  @JvmOverloads
48
52
  constructor(reactTextViewManagerCallback: ReactTextViewManagerCallback? = null) :
@@ -67,7 +71,8 @@ constructor(reactTextViewManagerCallback: ReactTextViewManagerCallback? = null)
67
71
  }
68
72
 
69
73
  init {
70
- textBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY
74
+ textBreakStrategy =
75
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) Layout.BREAK_STRATEGY_HIGH_QUALITY else 0
71
76
  setMeasureFunction(this)
72
77
  }
73
78
 
@@ -122,8 +127,10 @@ constructor(reactTextViewManagerCallback: ReactTextViewManagerCallback? = null)
122
127
  editText.setLines(numberOfLines)
123
128
  }
124
129
 
130
+ // EditText break-strategy accessors were introduced in API 23 (M).
125
131
  @SuppressLint("WrongConstant")
126
- if (editText.breakStrategy != textBreakStrategy) {
132
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
133
+ editText.breakStrategy != textBreakStrategy) {
127
134
  editText.breakStrategy = textBreakStrategy
128
135
  }
129
136
  }
@@ -156,6 +163,10 @@ constructor(reactTextViewManagerCallback: ReactTextViewManagerCallback? = null)
156
163
  }
157
164
 
158
165
  override fun setTextBreakStrategy(textBreakStrategy: String?) {
166
+ // Layout break strategies were introduced in API 23 (M); they are unused before then.
167
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
168
+ return
169
+ }
159
170
  when (textBreakStrategy) {
160
171
  null,
161
172
  "simple" -> this.textBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE
@@ -14,6 +14,7 @@ import android.graphics.Color
14
14
  import android.graphics.drawable.ColorDrawable
15
15
  import android.graphics.drawable.Drawable
16
16
  import android.graphics.drawable.RippleDrawable
17
+ import android.os.Build
17
18
  import android.util.TypedValue
18
19
  import com.facebook.react.bridge.JSApplicationIllegalArgumentException
19
20
  import com.facebook.react.bridge.ReadableMap
@@ -83,7 +84,10 @@ public object ReactDrawableHelper {
83
84
  private fun setRadius(drawableDescriptionDict: ReadableMap, drawable: Drawable?): Drawable? {
84
85
  if (drawableDescriptionDict.hasKey("rippleRadius") && drawable is RippleDrawable) {
85
86
  val rippleRadius = drawableDescriptionDict.getDouble("rippleRadius")
86
- drawable.radius = PixelUtil.toPixelFromDIP(rippleRadius).toInt()
87
+ // RippleDrawable.setRadius was introduced in API 23 (M).
88
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
89
+ drawable.radius = PixelUtil.toPixelFromDIP(rippleRadius).toInt()
90
+ }
87
91
  }
88
92
  return drawable
89
93
  }
@@ -102,7 +106,12 @@ public object ReactDrawableHelper {
102
106
  true,
103
107
  )
104
108
  ) {
105
- context.resources.getColor(resolveOutValue.resourceId, context.theme)
109
+ // Resources.getColor(int, Theme) was introduced in API 23 (M).
110
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
111
+ context.resources.getColor(resolveOutValue.resourceId, context.theme)
112
+ } else {
113
+ @Suppress("DEPRECATION") context.resources.getColor(resolveOutValue.resourceId)
114
+ }
106
115
  } else {
107
116
  throw JSApplicationIllegalArgumentException(
108
117
  "Attribute colorControlHighlight couldn't be resolved into a drawable"
@@ -8,9 +8,11 @@
8
8
  package com.facebook.react.views.view
9
9
 
10
10
  import android.accessibilityservice.AccessibilityServiceInfo
11
+ import android.annotation.TargetApi
11
12
  import android.content.Context
12
13
  import android.content.pm.PackageManager
13
14
  import android.graphics.Rect
15
+ import android.os.Build
14
16
  import android.view.View
15
17
  import android.view.View.OnFocusChangeListener
16
18
  import android.view.ViewGroup
@@ -395,7 +397,13 @@ public open class ReactViewManager : ReactClippingViewManager<ReactViewGroup>()
395
397
  }
396
398
 
397
399
  @ReactProp(name = "nativeForegroundAndroid")
400
+ @TargetApi(Build.VERSION_CODES.M)
398
401
  public open fun setNativeForeground(view: ReactViewGroup, foreground: ReadableMap?) {
402
+ // ReactViewGroup extends ViewGroup (not FrameLayout), so View.setForeground crashes before
403
+ // API 23 (M). Treat it as a no-op on older platforms.
404
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
405
+ return
406
+ }
399
407
  view.foreground =
400
408
  foreground?.let { ReactDrawableHelper.createDrawableFromJSDescription(view.context, it) }
401
409
  }
@@ -22,7 +22,7 @@ constexpr struct {
22
22
  int32_t Major = 0;
23
23
  int32_t Minor = 83;
24
24
  int32_t Patch = 10;
25
- std::string_view Prerelease = "0";
25
+ std::string_view Prerelease = "1";
26
26
  } ReactNativeVersion;
27
27
 
28
28
  } // namespace facebook::react
@@ -1,6 +1,6 @@
1
1
  [versions]
2
2
  # Android versions
3
- minSdk = "24"
3
+ minSdk = "22"
4
4
  targetSdk = "36"
5
5
  compileSdk = "36"
6
6
  buildTools = "36.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-tvos",
3
- "version": "0.83.10-0",
3
+ "version": "0.83.10-1",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -198,7 +198,7 @@
198
198
  "whatwg-fetch": "^3.0.0",
199
199
  "ws": "^7.5.10",
200
200
  "yargs": "^17.6.2",
201
- "@react-native-tvos/virtualized-lists": "0.83.10-0"
201
+ "@react-native-tvos/virtualized-lists": "0.83.10-1"
202
202
  },
203
203
  "codegenConfig": {
204
204
  "libraries": [