Skip to content

Commit ed601a3

Browse files
Merge pull request #910 from DataDog/marcosaia/RUM-10428/rn-80-support
[RUM-10428] Added Session Replay support for RN 0.80
2 parents 5da51fa + 0df7e72 commit ed601a3

File tree

3 files changed

+187
-1
lines changed

3 files changed

+187
-1
lines changed

packages/react-native-session-replay/android/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ android {
135135
java.srcDirs += ['src/oldarch/kotlin']
136136
}
137137

138-
if (reactNativeMinorVersion >= 79) {
138+
if (reactNativeMinorVersion >= 80) {
139+
java.srcDirs += ['src/rn80/kotlin']
140+
} else if (reactNativeMinorVersion >= 79) {
139141
java.srcDirs += ['src/rn79/kotlin']
140142
} else if (reactNativeMinorVersion >= 76) {
141143
java.srcDirs += ['src/rn76/kotlin']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
package com.datadog.reactnative.sessionreplay.extensions
7+
8+
import com.facebook.react.uimanager.style.ComputedBorderRadius
9+
import com.facebook.react.uimanager.style.ComputedBorderRadiusProp
10+
11+
internal fun ComputedBorderRadius?.getAverage(): Float {
12+
val topRightRadius = this
13+
?.getAverageForProp(ComputedBorderRadiusProp.COMPUTED_BORDER_TOP_RIGHT_RADIUS) ?: 0f
14+
val topLeftRadius = this
15+
?.getAverageForProp(ComputedBorderRadiusProp.COMPUTED_BORDER_TOP_LEFT_RADIUS) ?: 0f
16+
val bottomRightRadius = this
17+
?.getAverageForProp(ComputedBorderRadiusProp.COMPUTED_BORDER_BOTTOM_RIGHT_RADIUS) ?: 0f
18+
val bottomLeftRadius = this
19+
?.getAverageForProp(ComputedBorderRadiusProp.COMPUTED_BORDER_BOTTOM_LEFT_RADIUS) ?: 0f
20+
return (topRightRadius + topLeftRadius + bottomRightRadius + bottomLeftRadius) / 4f
21+
}
22+
23+
internal fun ComputedBorderRadius?.getAverageForProp(prop: ComputedBorderRadiusProp): Float {
24+
val vertical = this?.get(prop)?.vertical ?: 0f
25+
val horizontal = this?.get(prop)?.vertical ?: 0f
26+
return (vertical + horizontal) / 2f
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
import android.graphics.Canvas
7+
import android.graphics.Color
8+
import android.graphics.ColorFilter
9+
import android.graphics.PixelFormat
10+
import android.graphics.drawable.Drawable
11+
import android.graphics.drawable.InsetDrawable
12+
import android.graphics.drawable.LayerDrawable
13+
import com.datadog.android.sessionreplay.model.MobileSegment
14+
import com.datadog.reactnative.sessionreplay.extensions.getAverage
15+
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
16+
import com.datadog.reactnative.sessionreplay.utils.formatAsRgba
17+
import com.facebook.react.common.annotations.UnstableReactNativeAPI
18+
import com.facebook.react.uimanager.Spacing
19+
import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable
20+
import com.facebook.react.uimanager.style.ComputedBorderRadius
21+
22+
internal class ReactViewBackgroundDrawableUtils : DrawableUtils() {
23+
/**
24+
* Used to wrap instances of internal class:
25+
* com.facebook.react.uimanager.drawable.BackgroundDrawable
26+
*/
27+
class BackgroundDrawableWrapper(
28+
val backgroundColor: String,
29+
val cornerRadius: Float
30+
) : Drawable() {
31+
override fun draw(p0: Canvas) {}
32+
override fun setAlpha(p0: Int) {}
33+
override fun setColorFilter(p0: ColorFilter?) {}
34+
@Suppress("OVERRIDE_DEPRECATION")
35+
override fun getOpacity(): Int { return PixelFormat.OPAQUE }
36+
}
37+
38+
@OptIn(UnstableReactNativeAPI::class)
39+
override fun resolveShapeAndBorder(
40+
drawable: Drawable,
41+
opacity: Float,
42+
pixelDensity: Float
43+
): Pair<MobileSegment.ShapeStyle?, MobileSegment.ShapeBorder?> {
44+
if (drawable is BackgroundDrawableWrapper) {
45+
return MobileSegment.ShapeStyle(
46+
drawable.backgroundColor,
47+
opacity,
48+
drawable.cornerRadius
49+
) to null
50+
} else if (drawable is CSSBackgroundDrawable) {
51+
val borderProps = resolveBorder(drawable, pixelDensity)
52+
val backgroundColor = getCSSBackgroundColor(drawable)
53+
val colorHexString = if (backgroundColor != null) {
54+
formatAsRgba(backgroundColor)
55+
} else {
56+
return null to borderProps
57+
}
58+
59+
return MobileSegment.ShapeStyle(
60+
colorHexString,
61+
opacity,
62+
getCSSComputedBorderRadius(drawable)?.getAverage() ?: 0f
63+
) to borderProps
64+
}
65+
66+
return null to null
67+
}
68+
69+
@OptIn(UnstableReactNativeAPI::class)
70+
override fun getReactBackgroundFromDrawable(drawable: Drawable?): Drawable? {
71+
return when(drawable) {
72+
is CSSBackgroundDrawable -> drawable
73+
is InsetDrawable -> getReactBackgroundFromDrawable(drawable.drawable)
74+
is LayerDrawable -> getDrawableFromLayerDrawable(drawable)
75+
else -> null
76+
}
77+
}
78+
79+
@OptIn(UnstableReactNativeAPI::class)
80+
private fun getDrawableFromLayerDrawable(layerDrawable: LayerDrawable): Drawable? {
81+
for (layerNumber in 0 until layerDrawable.numberOfLayers) {
82+
val layer = layerDrawable.getDrawable(layerNumber)
83+
if (layer is CSSBackgroundDrawable) {
84+
return layer
85+
} else if (layer != null) {
86+
if (layer.javaClass.name == "com.facebook.react.uimanager.drawable.BackgroundDrawable") {
87+
val backgroundColor = getBackgroundColor(layer) ?: Color.TRANSPARENT
88+
val cornerRadius = getComputedBorderRadius(layer)?.getAverage() ?: 0f
89+
return BackgroundDrawableWrapper(
90+
backgroundColor = formatAsRgba(backgroundColor),
91+
cornerRadius = cornerRadius,
92+
)
93+
}
94+
}
95+
}
96+
return null
97+
}
98+
99+
@OptIn(UnstableReactNativeAPI::class)
100+
private fun getCSSComputedBorderRadius(
101+
drawable: CSSBackgroundDrawable
102+
): ComputedBorderRadius? {
103+
return reflectionUtils.getDeclaredField(
104+
drawable,
105+
CSS_COMPUTED_BORDER_RADIUS_FIELD_NAME
106+
) as? ComputedBorderRadius
107+
}
108+
109+
private fun getComputedBorderRadius(
110+
drawable: Any
111+
): ComputedBorderRadius? {
112+
return reflectionUtils.getDeclaredField(
113+
drawable,
114+
COMPUTED_BORDER_RADIUS_FIELD_NAME
115+
) as? ComputedBorderRadius
116+
}
117+
118+
@OptIn(UnstableReactNativeAPI::class)
119+
private fun getCSSBackgroundColor(
120+
backgroundDrawable: CSSBackgroundDrawable
121+
): Int? {
122+
return reflectionUtils.getDeclaredField(
123+
backgroundDrawable,
124+
CSS_BACKGROUND_COLOR_FIELD_NAME
125+
) as? Int
126+
}
127+
128+
private fun getBackgroundColor(
129+
backgroundDrawable: Any
130+
): Int? {
131+
return reflectionUtils.getDeclaredField(
132+
backgroundDrawable,
133+
BACKGROUND_COLOR_FIELD_NAME
134+
) as? Int
135+
}
136+
137+
@OptIn(UnstableReactNativeAPI::class)
138+
private fun resolveBorder(
139+
backgroundDrawable: CSSBackgroundDrawable,
140+
pixelDensity: Float
141+
): MobileSegment.ShapeBorder {
142+
val borderWidth = (backgroundDrawable.fullBorderWidth / pixelDensity).toLong()
143+
val borderColor = formatAsRgba(backgroundDrawable.getBorderColor(Spacing.ALL))
144+
145+
return MobileSegment.ShapeBorder(
146+
color = borderColor,
147+
width = borderWidth
148+
)
149+
}
150+
151+
private companion object {
152+
private const val CSS_BACKGROUND_COLOR_FIELD_NAME = "mColor"
153+
private const val CSS_COMPUTED_BORDER_RADIUS_FIELD_NAME = "mComputedBorderRadius"
154+
private const val COMPUTED_BORDER_RADIUS_FIELD_NAME = "computedBorderRadius"
155+
private const val BACKGROUND_COLOR_FIELD_NAME = "backgroundColor"
156+
}
157+
}

0 commit comments

Comments
 (0)