diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt index f62a17cda..8a0c152a6 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt @@ -4,70 +4,144 @@ * Copyright 2016-Present Datadog, Inc. */ -package com.datadog.reactnative.sessionreplay.mappers + package com.datadog.reactnative.sessionreplay.mappers -import com.datadog.android.api.InternalLogger -import com.datadog.android.sessionreplay.model.MobileSegment -import com.datadog.android.sessionreplay.recorder.MappingContext -import com.datadog.android.sessionreplay.recorder.mapper.EditTextMapper -import com.datadog.android.sessionreplay.recorder.mapper.WireframeMapper -import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback -import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter -import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver -import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver -import com.datadog.android.sessionreplay.utils.DrawableToColorMapper -import com.datadog.reactnative.sessionreplay.NoopTextPropertiesResolver -import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver -import com.datadog.reactnative.sessionreplay.TextPropertiesResolver -import com.datadog.reactnative.sessionreplay.utils.TextViewUtils -import com.facebook.react.bridge.ReactContext -import com.facebook.react.uimanager.UIManagerModule -import com.facebook.react.views.textinput.ReactEditText + import android.view.View + import com.datadog.android.api.InternalLogger + import com.datadog.android.sessionreplay.model.MobileSegment + import com.datadog.android.sessionreplay.recorder.MappingContext + import com.datadog.android.sessionreplay.recorder.mapper.BaseAsyncBackgroundWireframeMapper + import com.datadog.android.sessionreplay.recorder.mapper.EditTextMapper + import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback + import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter + import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver + import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver + import com.datadog.android.sessionreplay.utils.DrawableToColorMapper + import com.datadog.android.sessionreplay.utils.GlobalBounds + import com.datadog.reactnative.sessionreplay.NoopTextPropertiesResolver + import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver + import com.datadog.reactnative.sessionreplay.TextPropertiesResolver + import com.datadog.reactnative.sessionreplay.utils.DrawableUtils + import com.datadog.reactnative.sessionreplay.utils.ReactViewBackgroundDrawableUtils + import com.datadog.reactnative.sessionreplay.utils.TextViewUtils + import com.facebook.react.bridge.ReactContext + import com.facebook.react.uimanager.UIManagerModule + import com.facebook.react.views.image.ReactImageView + import com.facebook.react.views.textinput.ReactEditText internal class ReactEditTextMapper( - private val reactTextPropertiesResolver: TextPropertiesResolver = - NoopTextPropertiesResolver(), - private val textViewUtils: TextViewUtils = TextViewUtils(), -): WireframeMapper { + private val reactTextPropertiesResolver: TextPropertiesResolver = + NoopTextPropertiesResolver(), + private val textViewUtils: TextViewUtils = TextViewUtils(), + ): BaseAsyncBackgroundWireframeMapper( + viewIdentifierResolver = DefaultViewIdentifierResolver, + colorStringFormatter = DefaultColorStringFormatter, + viewBoundsResolver = DefaultViewBoundsResolver, + drawableToColorMapper = DrawableToColorMapper.getDefault(), + ) { + private val drawableUtils = DrawableUtils() + private val backgroundDrawableUtils = ReactViewBackgroundDrawableUtils() - private val editTextMapper = EditTextMapper( - viewIdentifierResolver = DefaultViewIdentifierResolver, - colorStringFormatter = DefaultColorStringFormatter, - viewBoundsResolver = DefaultViewBoundsResolver, - drawableToColorMapper = DrawableToColorMapper.getDefault(), - ) + private val editTextMapper = EditTextMapper( + viewIdentifierResolver = viewIdentifierResolver, + colorStringFormatter = colorStringFormatter, + viewBoundsResolver = viewBoundsResolver, + drawableToColorMapper = drawableToColorMapper, + ) + + internal constructor( + reactContext: ReactContext, + uiManagerModule: UIManagerModule? + ): this( + reactTextPropertiesResolver = if (uiManagerModule == null) { + NoopTextPropertiesResolver() + } else { + ReactTextPropertiesResolver( + reactContext = reactContext, + uiManagerModule = uiManagerModule + ) + } + ) + + override fun map( + view: ReactEditText, + mappingContext: MappingContext, + asyncJobStatusCallback: AsyncJobStatusCallback, + internalLogger: InternalLogger + ): List { + val bgWireframes = mutableListOf().apply { + addAll(super.map( + view, + mappingContext, + asyncJobStatusCallback, + internalLogger + )) + } + + bgWireframes += editTextMapper.map( + view = view, + mappingContext = mappingContext, + asyncJobStatusCallback = asyncJobStatusCallback, + internalLogger = internalLogger + ).filterNot { it is MobileSegment.Wireframe.ImageWireframe } + + return textViewUtils.mapTextViewToWireframes( + wireframes = bgWireframes, + view = view, + mappingContext = mappingContext, + reactTextPropertiesResolver = reactTextPropertiesResolver + ) + } - internal constructor( - reactContext: ReactContext, - uiManagerModule: UIManagerModule? - ): this( - reactTextPropertiesResolver = if (uiManagerModule == null) { - NoopTextPropertiesResolver() - } else { - ReactTextPropertiesResolver( - reactContext = reactContext, - uiManagerModule = uiManagerModule - ) - } - ) - override fun map( - view: ReactEditText, - mappingContext: MappingContext, - asyncJobStatusCallback: AsyncJobStatusCallback, - internalLogger: InternalLogger - ): List { - val wireframes = editTextMapper.map( - view = view, - mappingContext = mappingContext, - asyncJobStatusCallback = asyncJobStatusCallback, - internalLogger = internalLogger - ) + override fun resolveBackgroundAsImageWireframe( + view: View, + bounds: GlobalBounds, + width: Int, + height: Int, + mappingContext: MappingContext, + asyncJobStatusCallback: AsyncJobStatusCallback + ): MobileSegment.Wireframe? { + if (view !is ReactImageView) { + return super.resolveBackgroundAsImageWireframe( + view, + bounds, + width, + height, + mappingContext, + asyncJobStatusCallback + ) + } - return textViewUtils.mapTextViewToWireframes( - wireframes = wireframes, - view = view, - mappingContext = mappingContext, - reactTextPropertiesResolver = reactTextPropertiesResolver - ) - } -} + val bgDrawable = drawableUtils.getReactBackgroundFromDrawable(view.background) + ?: return null + + val density = mappingContext.systemInformation.screenDensity + + val identifier = viewIdentifierResolver.resolveChildUniqueIdentifier( + view, + "drawable0" + ) ?: return null + + val globalBounds = viewBoundsResolver.resolveViewGlobalBounds( + view, + density + ) + + val (shape, border) = backgroundDrawableUtils.resolveShapeAndBorder( + bgDrawable, + view.alpha, + mappingContext.systemInformation.screenDensity + ) + + return MobileSegment.Wireframe.ShapeWireframe( + identifier, + globalBounds.x, + globalBounds.y, + globalBounds.width, + globalBounds.height, + border = border, + shapeStyle = shape + ) + } + } + \ No newline at end of file diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtils.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtils.kt index bf6ac4983..1afc3e287 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtils.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtils.kt @@ -9,6 +9,7 @@ package com.datadog.reactnative.sessionreplay.utils import android.graphics.drawable.Drawable import android.graphics.drawable.InsetDrawable import android.graphics.drawable.LayerDrawable +import com.facebook.drawee.drawable.ForwardingDrawable import com.facebook.react.views.view.ReactViewBackgroundDrawable internal class DrawableUtils { @@ -21,12 +22,18 @@ internal class DrawableUtils { return getReactBackgroundFromDrawable(drawable.drawable) } + if (drawable is ForwardingDrawable) { + return getReactBackgroundFromDrawable(drawable.drawable) + } + if (drawable is LayerDrawable) { for (layerNumber in 0 until drawable.numberOfLayers) { - val layer = drawable.getDrawable(layerNumber) - if (layer is ReactViewBackgroundDrawable) { - return layer - } + try { + val layer = drawable.getDrawable(layerNumber) + if (layer is ReactViewBackgroundDrawable) { + return layer + } + } catch (_: IllegalArgumentException) {} } }