@truewatchtech/react-native-mobile 0.3.15 → 0.4.0-alpha.4

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 (78) hide show
  1. package/FTMobileReactNativeSDK.podspec +2 -1
  2. package/android/build.gradle +21 -3
  3. package/android/src/main/java/com/ft/sdk/reactnative/FTSessionReplayImpl.java +60 -0
  4. package/android/src/main/java/com/ft/sdk/reactnative/FTTraceImpl.java +1 -1
  5. package/android/src/main/java/com/ft/sdk/reactnative/extensions/ReactDrawablesExt.java +155 -0
  6. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/NoopTextPropertiesResolver.java +23 -0
  7. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.java +57 -0
  8. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/ShadowNodeWrapper.java +84 -0
  9. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/TextPropertiesResolver.java +20 -0
  10. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/mappers/DefaultMapper.java +78 -0
  11. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/mappers/Pair.java +11 -0
  12. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/mappers/ReactEditTextMapper.java +136 -0
  13. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/mappers/ReactNativeImageViewMapper.java +117 -0
  14. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/mappers/ReactTextMapper.java +57 -0
  15. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/mappers/ReactViewGroupMapper.java +22 -0
  16. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/mappers/ReactViewModalMapper.java +21 -0
  17. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/resources/ReactDrawableCopier.java +35 -0
  18. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/utils/DrawableUtils.java +34 -0
  19. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/utils/ReflectionUtils.java +43 -0
  20. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/utils/text/FabricTextViewUtils.java +69 -0
  21. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/utils/text/LegacyTextViewUtils.java +97 -0
  22. package/android/src/main/java/com/ft/sdk/reactnative/sessionreplay/utils/text/TextViewUtils.java +184 -0
  23. package/android/src/main/java/com/ft/sdk/reactnative/utils/ColorUtils.java +24 -0
  24. package/android/src/newarch/java/com/ft/sdk/reactnative/FTSessionReplayModule.java +30 -0
  25. package/android/src/oldarch/java/com/ft/sdk/reactnative/FTSessionReplayModule.java +25 -0
  26. package/android/src/rn69/java/com/ft/sdk/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.java +100 -0
  27. package/android/src/rn75/java/com/ft/sdk/reactnative/sessionreplay/extensions/LengthPercentageExt.java +27 -0
  28. package/android/src/rn75/java/com/ft/sdk/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.java +116 -0
  29. package/android/src/rn76/java/com/ft/sdk/reactnative/sessionreplay/extensions/LengthPercentageExt.java +38 -0
  30. package/android/src/rn76/java/com/ft/sdk/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.java +117 -0
  31. package/android/src/rn79/java/com/ft/sdk/reactnative/sessionreplay/extensions/LengthPercentageExt.java +38 -0
  32. package/android/src/rn79/java/com/ft/sdk/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.java +132 -0
  33. package/android/src/rn80/java/com/ft/sdk/reactnative/sessionreplay/extensions/ComputedBorderRadiusExt.java +58 -0
  34. package/android/src/rn80/java/com/ft/sdk/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.java +190 -0
  35. package/android/src/rnlegacy/java/com/ft/sdk/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.java +120 -0
  36. package/android/src/rnpost74/java/com/ft/sdk/reactnative/FTMobilePackage.java +3 -4
  37. package/android/src/rnpre74/java/com/ft/sdk/reactnative/FTMobilePackage.java +1 -0
  38. package/ios/FTMobileReactNative.m +3 -2
  39. package/ios/FTRCTTextViewRecorder.h +33 -0
  40. package/ios/FTRCTTextViewRecorder.m +120 -0
  41. package/ios/FTReactNativeLog.m +1 -1
  42. package/ios/FTReactNativeRUM.h +0 -1
  43. package/ios/FTReactNativeSessionReplay.h +6 -0
  44. package/ios/FTReactNativeSessionReplay.mm +44 -0
  45. package/ios/FTReactNativeTrace.h +0 -2
  46. package/ios/FTReactNativeTrace.m +0 -2
  47. package/ios/FtMobileAgent.xcodeproj/project.pbxproj +6 -0
  48. package/lib/commonjs/ft_logger.js.map +1 -1
  49. package/lib/commonjs/ft_mobile_agent.js.map +1 -1
  50. package/lib/commonjs/ft_rum.js.map +1 -1
  51. package/lib/commonjs/ft_session_replay.js +34 -0
  52. package/lib/commonjs/ft_session_replay.js.map +1 -0
  53. package/lib/commonjs/ft_tracing.js.map +1 -1
  54. package/lib/commonjs/index.js +19 -0
  55. package/lib/commonjs/index.js.map +1 -1
  56. package/lib/commonjs/version.js +1 -1
  57. package/lib/commonjs/version.js.map +1 -1
  58. package/lib/module/ft_logger.js.map +1 -1
  59. package/lib/module/ft_mobile_agent.js.map +1 -1
  60. package/lib/module/ft_rum.js.map +1 -1
  61. package/lib/module/ft_session_replay.js +29 -0
  62. package/lib/module/ft_session_replay.js.map +1 -0
  63. package/lib/module/ft_tracing.js.map +1 -1
  64. package/lib/module/index.js +2 -1
  65. package/lib/module/index.js.map +1 -1
  66. package/lib/module/version.js +1 -1
  67. package/lib/module/version.js.map +1 -1
  68. package/lib/typescript/ft_session_replay.d.ts +27 -0
  69. package/lib/typescript/index.d.ts +2 -1
  70. package/lib/typescript/version.d.ts +1 -1
  71. package/package.json +1 -1
  72. package/src/ft_logger.tsx +0 -1
  73. package/src/ft_mobile_agent.tsx +0 -1
  74. package/src/ft_rum.tsx +1 -3
  75. package/src/ft_session_replay.tsx +34 -0
  76. package/src/ft_tracing.tsx +0 -1
  77. package/src/index.tsx +3 -1
  78. package/src/version.ts +1 -1
@@ -0,0 +1,136 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.mappers;
8
+
9
+ import android.graphics.drawable.Drawable;
10
+ import android.view.View;
11
+
12
+ import com.ft.sdk.reactnative.sessionreplay.utils.ReactViewBackgroundDrawableUtils;
13
+ import com.ft.sdk.reactnative.sessionreplay.utils.text.TextViewUtils;
14
+ import com.facebook.react.views.textinput.ReactEditText;
15
+ import com.ft.sdk.sessionreplay.model.ImageWireframe;
16
+ import com.ft.sdk.sessionreplay.model.PlaceholderWireframe;
17
+ import com.ft.sdk.sessionreplay.model.ShapeBorder;
18
+ import com.ft.sdk.sessionreplay.model.ShapeStyle;
19
+ import com.ft.sdk.sessionreplay.model.ShapeWireframe;
20
+ import com.ft.sdk.sessionreplay.model.Wireframe;
21
+ import com.ft.sdk.sessionreplay.recorder.MappingContext;
22
+ import com.ft.sdk.sessionreplay.recorder.mapper.BaseAsyncBackgroundWireframeMapper;
23
+ import com.ft.sdk.sessionreplay.recorder.mapper.EditTextMapper;
24
+ import com.ft.sdk.sessionreplay.utils.AsyncJobStatusCallback;
25
+ import com.ft.sdk.sessionreplay.utils.DefaultColorStringFormatter;
26
+ import com.ft.sdk.sessionreplay.utils.DefaultViewBoundsResolver;
27
+ import com.ft.sdk.sessionreplay.utils.DefaultViewIdentifierResolver;
28
+ import com.ft.sdk.sessionreplay.utils.DrawableToColorMapperFactory;
29
+ import com.ft.sdk.sessionreplay.utils.GlobalBounds;
30
+ import com.ft.sdk.sessionreplay.utils.InternalLogger;
31
+
32
+ import java.util.ArrayList;
33
+ import java.util.List;
34
+
35
+ public class ReactEditTextMapper extends BaseAsyncBackgroundWireframeMapper<ReactEditText> {
36
+ private final TextViewUtils textViewUtils;
37
+ private final ReactViewBackgroundDrawableUtils drawableUtils = new ReactViewBackgroundDrawableUtils();
38
+ private final EditTextMapper editTextMapper;
39
+
40
+ public ReactEditTextMapper(TextViewUtils textViewUtils) {
41
+ super(
42
+ DefaultViewIdentifierResolver.get(),
43
+ DefaultColorStringFormatter.get(),
44
+ DefaultViewBoundsResolver.get(),
45
+ DrawableToColorMapperFactory.getDefault()
46
+ );
47
+ this.textViewUtils = textViewUtils;
48
+ this.editTextMapper = new EditTextMapper(
49
+ viewIdentifierResolver,
50
+ colorStringFormatter,
51
+ viewBoundsResolver,
52
+ drawableToColorMapper
53
+ );
54
+ }
55
+
56
+ @Override
57
+ public List<Wireframe> map(
58
+ ReactEditText view,
59
+ MappingContext mappingContext,
60
+ AsyncJobStatusCallback asyncJobStatusCallback,
61
+ InternalLogger internalLogger
62
+ ) {
63
+ List<Wireframe> backgroundWireframes = new ArrayList<>(super.map(view, mappingContext, asyncJobStatusCallback, internalLogger));
64
+ List<Wireframe> editTextWireframes = editTextMapper.map(
65
+ view,
66
+ mappingContext,
67
+ asyncJobStatusCallback,
68
+ internalLogger
69
+ );
70
+
71
+ List<Wireframe> filteredEditTextWireframes = new ArrayList<>();
72
+ for (Wireframe wf : editTextWireframes) {
73
+ if (!(wf instanceof ImageWireframe) && !(wf instanceof PlaceholderWireframe)) {
74
+ filteredEditTextWireframes.add(wf);
75
+ }
76
+ }
77
+ backgroundWireframes.addAll(filteredEditTextWireframes);
78
+ return textViewUtils.mapTextViewToWireframes(
79
+ backgroundWireframes,
80
+ view,
81
+ mappingContext
82
+ );
83
+ }
84
+
85
+ @Override
86
+ public Wireframe resolveBackgroundAsImageWireframe(
87
+ View view,
88
+ GlobalBounds bounds,
89
+ int width,
90
+ int height,
91
+ MappingContext mappingContext,
92
+ AsyncJobStatusCallback asyncJobStatusCallback
93
+ ) {
94
+ if (!(view instanceof ReactEditText)) {
95
+ return super.resolveBackgroundAsImageWireframe(
96
+ view,
97
+ bounds,
98
+ width,
99
+ height,
100
+ mappingContext,
101
+ asyncJobStatusCallback
102
+ );
103
+ }
104
+ Drawable backgroundDrawable = drawableUtils.getReactBackgroundFromDrawable(((ReactEditText) view).getBackground());
105
+ if (backgroundDrawable == null) {
106
+ return null;
107
+ }
108
+ float density = mappingContext.getSystemInformation().getScreenDensity();
109
+ Long identifier = viewIdentifierResolver.resolveChildUniqueIdentifier(
110
+ view,
111
+ "drawable0"
112
+ );
113
+ if (identifier == null) {
114
+ return null;
115
+ }
116
+ GlobalBounds globalBounds = viewBoundsResolver.resolveViewGlobalBounds(
117
+ view,
118
+ density
119
+ );
120
+ Pair<ShapeStyle, ShapeBorder> shapeAndBorder = drawableUtils.resolveShapeAndBorder(
121
+ backgroundDrawable,
122
+ ((ReactEditText) view).getAlpha(),
123
+ mappingContext.getSystemInformation().getScreenDensity()
124
+ );
125
+ return new ShapeWireframe(
126
+ identifier,
127
+ globalBounds.getX(),
128
+ globalBounds.getY(),
129
+ globalBounds.getWidth(),
130
+ globalBounds.getHeight(),
131
+ null,
132
+ shapeAndBorder.first,
133
+ shapeAndBorder.second
134
+ );
135
+ }
136
+ }
@@ -0,0 +1,117 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.mappers;
8
+
9
+ import android.graphics.Rect;
10
+ import android.graphics.drawable.Drawable;
11
+ import android.widget.ImageView;
12
+
13
+ import com.ft.sdk.reactnative.extensions.ReactDrawablesExt;
14
+ import com.ft.sdk.reactnative.sessionreplay.resources.ReactDrawableCopier;
15
+ import com.facebook.drawee.drawable.FadeDrawable;
16
+ import com.facebook.react.views.image.ReactImageView;
17
+ import com.ft.sdk.sessionreplay.internal.utils.ImageViewUtils;
18
+ import com.ft.sdk.sessionreplay.internal.utils.RectExt;
19
+ import com.ft.sdk.sessionreplay.model.Wireframe;
20
+ import com.ft.sdk.sessionreplay.model.WireframeClip;
21
+ import com.ft.sdk.sessionreplay.recorder.MappingContext;
22
+ import com.ft.sdk.sessionreplay.recorder.mapper.BaseAsyncBackgroundWireframeMapper;
23
+ import com.ft.sdk.sessionreplay.utils.AsyncJobStatusCallback;
24
+ import com.ft.sdk.sessionreplay.utils.DefaultColorStringFormatter;
25
+ import com.ft.sdk.sessionreplay.utils.DefaultViewBoundsResolver;
26
+ import com.ft.sdk.sessionreplay.utils.DefaultViewIdentifierResolver;
27
+ import com.ft.sdk.sessionreplay.utils.DrawableToColorMapperFactory;
28
+ import com.ft.sdk.sessionreplay.utils.InternalLogger;
29
+
30
+ import java.util.ArrayList;
31
+ import java.util.List;
32
+
33
+ public class ReactNativeImageViewMapper extends BaseAsyncBackgroundWireframeMapper<ReactImageView> {
34
+ private final ReactDrawableCopier drawableCopier = new ReactDrawableCopier();
35
+ private final ImageViewUtils imageViewUtils = ImageViewUtils.get();
36
+
37
+ public ReactNativeImageViewMapper() {
38
+ super(
39
+ DefaultViewIdentifierResolver.get(),
40
+ DefaultColorStringFormatter.get(),
41
+ DefaultViewBoundsResolver.get(),
42
+ DrawableToColorMapperFactory.getDefault()
43
+ );
44
+ }
45
+
46
+ @Override
47
+ public List<Wireframe> map(
48
+ ReactImageView view,
49
+ MappingContext mappingContext,
50
+ AsyncJobStatusCallback asyncJobStatusCallback,
51
+ InternalLogger internalLogger
52
+ ) {
53
+ List<Wireframe> wireframes = new ArrayList<>(super.map(view, mappingContext, asyncJobStatusCallback, internalLogger));
54
+
55
+ Drawable drawable = view.getDrawable() != null ? view.getDrawable().getCurrent() : null;
56
+ if (drawable == null) {
57
+ return wireframes;
58
+ }
59
+ Rect parentRect = imageViewUtils.resolveParentRectAbsPosition(view);
60
+ ImageView.ScaleType scaleType = (drawable instanceof FadeDrawable)
61
+ ? ReactDrawablesExt.imageViewScaleType(ReactDrawablesExt.getScaleTypeDrawable((FadeDrawable) drawable))
62
+ : view.getScaleType();
63
+ Rect contentRect = imageViewUtils.resolveContentRectWithScaling(view, drawable, scaleType);
64
+
65
+ android.content.res.Resources resources = view.getResources();
66
+ float density = resources.getDisplayMetrics().density;
67
+
68
+ WireframeClip clipping = view.getCropToPadding()
69
+ ? RectExt.toWireframeClip(imageViewUtils.calculateClipping(parentRect, contentRect, density))
70
+ : null;
71
+
72
+ long contentXPosInDp = (long) (contentRect.left / density);
73
+ long contentYPosInDp = (long) (contentRect.top / density);
74
+ int contentWidthPx = contentRect.width();
75
+ int contentHeightPx = contentRect.height();
76
+
77
+ // resolve foreground
78
+ Wireframe imageWireframe = mappingContext.getImageWireframeHelper().createImageWireframeByDrawable(
79
+ view,
80
+ mappingContext.getImagePrivacy(),
81
+ wireframes.size(),
82
+ contentXPosInDp,
83
+ contentYPosInDp,
84
+ contentWidthPx,
85
+ contentHeightPx,
86
+ true,
87
+ drawable,
88
+ drawableCopier,
89
+ asyncJobStatusCallback,
90
+ clipping,
91
+ null,
92
+ null,
93
+ "drawable",
94
+ generateUUID(view)
95
+ );
96
+ if (imageWireframe != null) {
97
+ wireframes.add(imageWireframe);
98
+ }
99
+
100
+ return wireframes;
101
+ }
102
+
103
+ private String generateUUID(ReactImageView reactImageView) {
104
+ int hashCode = System.identityHashCode(reactImageView);
105
+ String drawableType = reactImageView.getDrawable() != null ? reactImageView.getDrawable().getCurrent().getClass().getName() : "null";
106
+ return drawableType + "-" + hashCode;
107
+ }
108
+
109
+ private WireframeClip toWireframeClip(Rect rect) {
110
+ return new WireframeClip(
111
+ (long) rect.top,
112
+ (long) rect.bottom,
113
+ (long) rect.left,
114
+ (long) rect.right
115
+ );
116
+ }
117
+ }
@@ -0,0 +1,57 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.mappers;
8
+
9
+ import com.ft.sdk.reactnative.sessionreplay.utils.text.TextViewUtils;
10
+ import com.facebook.react.views.text.ReactTextView;
11
+ import com.ft.sdk.sessionreplay.model.ImageWireframe;
12
+ import com.ft.sdk.sessionreplay.model.PlaceholderWireframe;
13
+ import com.ft.sdk.sessionreplay.model.Wireframe;
14
+ import com.ft.sdk.sessionreplay.recorder.MappingContext;
15
+ import com.ft.sdk.sessionreplay.recorder.mapper.TextViewMapper;
16
+ import com.ft.sdk.sessionreplay.utils.AsyncJobStatusCallback;
17
+ import com.ft.sdk.sessionreplay.utils.DefaultColorStringFormatter;
18
+ import com.ft.sdk.sessionreplay.utils.DefaultViewBoundsResolver;
19
+ import com.ft.sdk.sessionreplay.utils.DefaultViewIdentifierResolver;
20
+ import com.ft.sdk.sessionreplay.utils.DrawableToColorMapperFactory;
21
+ import com.ft.sdk.sessionreplay.utils.InternalLogger;
22
+
23
+ import java.util.ArrayList;
24
+ import java.util.List;
25
+
26
+ public class ReactTextMapper extends TextViewMapper<ReactTextView> {
27
+ private final TextViewUtils textViewUtils;
28
+
29
+ public ReactTextMapper(TextViewUtils textViewUtils) {
30
+ super(
31
+ DefaultViewIdentifierResolver.get(),
32
+ DefaultColorStringFormatter.get(),
33
+ DefaultViewBoundsResolver.get(),
34
+ DrawableToColorMapperFactory.getDefault()
35
+ );
36
+ this.textViewUtils = textViewUtils;
37
+ }
38
+
39
+
40
+ @Override
41
+ public List<Wireframe> map(ReactTextView view, MappingContext mappingContext, AsyncJobStatusCallback asyncJobStatusCallback, InternalLogger internalLogger) {
42
+ List<Wireframe> wireframes = super.map(view, mappingContext, asyncJobStatusCallback, internalLogger);
43
+ List<Wireframe> mappedWireframes = textViewUtils.mapTextViewToWireframes(
44
+ wireframes,
45
+ view,
46
+ mappingContext
47
+ );
48
+ List<Wireframe> result = new ArrayList<>();
49
+ for (Wireframe wf : mappedWireframes) {
50
+ if (!(wf instanceof ImageWireframe) &&
51
+ !(wf instanceof PlaceholderWireframe)) {
52
+ result.add(wf);
53
+ }
54
+ }
55
+ return result;
56
+ }
57
+ }
@@ -0,0 +1,22 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.mappers;
8
+
9
+ import com.ft.sdk.reactnative.sessionreplay.utils.DrawableUtils;
10
+ import com.ft.sdk.reactnative.sessionreplay.utils.ReactViewBackgroundDrawableUtils;
11
+ import com.facebook.react.views.view.ReactViewGroup;
12
+ import com.ft.sdk.sessionreplay.recorder.mapper.TraverseAllChildrenMapper;
13
+
14
+ public class ReactViewGroupMapper extends DefaultMapper<ReactViewGroup> implements TraverseAllChildrenMapper<ReactViewGroup> {
15
+ public ReactViewGroupMapper() {
16
+ this(new ReactViewBackgroundDrawableUtils());
17
+ }
18
+
19
+ public ReactViewGroupMapper(DrawableUtils drawableUtils) {
20
+ super(drawableUtils);
21
+ }
22
+ }
@@ -0,0 +1,21 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.mappers;
8
+
9
+ import com.ft.sdk.reactnative.sessionreplay.utils.ReactViewBackgroundDrawableUtils;
10
+ import com.ft.sdk.reactnative.sessionreplay.utils.DrawableUtils;
11
+ import com.facebook.react.views.modal.ReactModalHostView;
12
+
13
+ public class ReactViewModalMapper extends DefaultMapper<ReactModalHostView> {
14
+ public ReactViewModalMapper() {
15
+ this(new ReactViewBackgroundDrawableUtils());
16
+ }
17
+
18
+ public ReactViewModalMapper(DrawableUtils drawableUtils) {
19
+ super(drawableUtils);
20
+ }
21
+ }
@@ -0,0 +1,35 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.resources;
8
+
9
+ import android.content.res.Resources;
10
+ import android.graphics.drawable.BitmapDrawable;
11
+ import android.graphics.drawable.Drawable;
12
+
13
+ import com.ft.sdk.reactnative.extensions.ReactDrawablesExt;
14
+ import com.ft.sdk.sessionreplay.resources.DefaultDrawableCopier;
15
+ import com.ft.sdk.sessionreplay.resources.DrawableCopier;
16
+
17
+ public class ReactDrawableCopier implements DrawableCopier {
18
+ private final DefaultDrawableCopier defaultCopier = new DefaultDrawableCopier();
19
+
20
+ @Override
21
+ public Drawable copy(Drawable originalDrawable, Resources resources) {
22
+ if (originalDrawable.getConstantState() != null) {
23
+ return defaultCopier.copy(originalDrawable, resources);
24
+ } else {
25
+ android.graphics.Bitmap bitmap = ReactDrawablesExt.tryToExtractBitmap(originalDrawable, resources);
26
+ if (bitmap != null) {
27
+ BitmapDrawable bitmapDrawable = new BitmapDrawable(resources, bitmap);
28
+ bitmapDrawable.setBounds(originalDrawable.getBounds());
29
+ bitmapDrawable.setAlpha(originalDrawable.getAlpha());
30
+ return bitmapDrawable;
31
+ }
32
+ return null;
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,34 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.utils;
8
+
9
+ import android.graphics.drawable.Drawable;
10
+
11
+ import com.ft.sdk.reactnative.sessionreplay.mappers.Pair;
12
+ import com.ft.sdk.sessionreplay.model.ShapeBorder;
13
+ import com.ft.sdk.sessionreplay.model.ShapeStyle;
14
+
15
+ public abstract class DrawableUtils {
16
+ protected final ReflectionUtils reflectionUtils;
17
+
18
+ public DrawableUtils() {
19
+ this(new ReflectionUtils());
20
+ }
21
+
22
+ public DrawableUtils(ReflectionUtils reflectionUtils) {
23
+ this.reflectionUtils = reflectionUtils;
24
+ }
25
+
26
+ public abstract Pair<ShapeStyle, ShapeBorder> resolveShapeAndBorder(
27
+ Drawable drawable,
28
+ float opacity,
29
+ float pixelDensity
30
+ );
31
+
32
+ public abstract Drawable getReactBackgroundFromDrawable(Drawable drawable);
33
+
34
+ }
@@ -0,0 +1,43 @@
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
+
7
+ package com.ft.sdk.reactnative.sessionreplay.utils;
8
+
9
+ import java.lang.reflect.Field;
10
+
11
+ public class ReflectionUtils {
12
+ public Object getDeclaredField(Object instance, String fieldName) {
13
+ if (instance == null) {
14
+ return null;
15
+ }
16
+ Class<?> classInstance = instance.getClass();
17
+ Field declaredField = searchForField(classInstance, fieldName);
18
+
19
+ if (declaredField != null) {
20
+ declaredField.setAccessible(true);
21
+ try {
22
+ return declaredField.get(instance);
23
+ } catch (IllegalAccessException e) {
24
+ return null;
25
+ }
26
+ }
27
+ return null;
28
+ }
29
+
30
+ private Field searchForField(Class<?> className, String fieldName) {
31
+ for (Field field : className.getDeclaredFields()) {
32
+ if (field.getName().equals(fieldName)) {
33
+ return field;
34
+ }
35
+ }
36
+
37
+ if (className.getSuperclass() != null) {
38
+ return searchForField(className.getSuperclass(), fieldName);
39
+ } else {
40
+ return null;
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,69 @@
1
+ package com.ft.sdk.reactnative.sessionreplay.utils.text;
2
+
3
+ import android.text.Spannable;
4
+ import android.text.style.ForegroundColorSpan;
5
+ import android.view.View;
6
+ import android.widget.TextView;
7
+
8
+ import com.ft.sdk.reactnative.sessionreplay.utils.DrawableUtils;
9
+ import com.ft.sdk.reactnative.utils.ColorUtils;
10
+ import com.facebook.react.bridge.ReactContext;
11
+ import com.ft.sdk.garble.utils.LogUtils;
12
+ import com.ft.sdk.sessionreplay.model.TextStyle;
13
+ import com.ft.sdk.sessionreplay.model.TextWireframe;
14
+ import com.ft.sdk.sessionreplay.utils.InternalLogger;
15
+
16
+ import java.util.Locale;
17
+
18
+ public class FabricTextViewUtils extends TextViewUtils {
19
+ private static final String TAG = "FabricTextViewUtils";
20
+ private final ReactContext reactContext;
21
+ private final InternalLogger logger;
22
+
23
+ public FabricTextViewUtils(ReactContext reactContext, InternalLogger logger, DrawableUtils drawableUtils) {
24
+ super(reactContext, drawableUtils);
25
+ this.reactContext = reactContext;
26
+ this.logger = logger;
27
+ }
28
+
29
+ @Override
30
+ protected TextStyle resolveTextStyle(TextWireframe textWireframe, float pixelsDensity, TextView view) {
31
+ String fontColor = getTextColor(view, textWireframe);
32
+ Long fontSize = getFontSize(view, pixelsDensity);
33
+ String fontFamily = getFontFamily(textWireframe);
34
+ return new TextStyle(fontFamily, fontSize, fontColor);
35
+ }
36
+
37
+ private String getTextColor(TextView view, TextWireframe textWireframe) {
38
+ Spannable spanned = (Spannable) getFieldFromView(view, TextViewUtils.SPANNED_FIELD_NAME);
39
+ ForegroundColorSpan[] spans = spanned != null ? spanned.getSpans(0, spanned.length(), ForegroundColorSpan.class) : null;
40
+ String fontColor = (spans != null && spans.length > 0)
41
+ ? ColorUtils.formatAsRgba(spans[0].getForegroundColor())
42
+ : textWireframe.getTextStyle().getColor();
43
+ return fontColor;
44
+ }
45
+
46
+ private Long getFontSize(TextView view, float pixelsDensity) {
47
+ return (long) (view.getTextSize() / pixelsDensity);
48
+ }
49
+
50
+ private String getFontFamily(TextWireframe textWireframe) {
51
+ String fontFamily = textWireframe.getTextStyle().getFamily();
52
+ return resolveFontFamily(fontFamily.toLowerCase(Locale.US));
53
+ }
54
+
55
+ public Object getFieldFromView(View view, String value) {
56
+ try {
57
+ java.lang.reflect.Field field = view.getClass().getDeclaredField(value);
58
+ field.setAccessible(true);
59
+ return field.get(view);
60
+ } catch (Exception e) {
61
+ handleError(e, TextViewUtils.RESOLVE_FABRICFIELD_ERROR);
62
+ return null;
63
+ }
64
+ }
65
+
66
+ private void handleError(Exception e, String message) {
67
+ logger.e(TAG, "message:" + message + "," + LogUtils.getStackTraceString(e));
68
+ }
69
+ }
@@ -0,0 +1,97 @@
1
+ package com.ft.sdk.reactnative.sessionreplay.utils.text;
2
+
3
+ import android.widget.TextView;
4
+
5
+ import com.ft.sdk.reactnative.sessionreplay.ShadowNodeWrapper;
6
+ import com.ft.sdk.reactnative.sessionreplay.utils.DrawableUtils;
7
+ import com.ft.sdk.reactnative.sessionreplay.utils.ReflectionUtils;
8
+ import com.ft.sdk.reactnative.utils.ColorUtils;
9
+ import com.facebook.react.bridge.ReactContext;
10
+ import com.facebook.react.uimanager.UIManagerModule;
11
+ import com.facebook.react.views.text.TextAttributes;
12
+ import com.ft.sdk.garble.utils.LogUtils;
13
+ import com.ft.sdk.sessionreplay.model.TextStyle;
14
+ import com.ft.sdk.sessionreplay.model.TextWireframe;
15
+ import com.ft.sdk.sessionreplay.utils.InternalLogger;
16
+
17
+ import java.util.Locale;
18
+
19
+ public class LegacyTextViewUtils extends TextViewUtils {
20
+ private static final String TAG = "LegacyTextViewUtils";
21
+ private final ReactContext reactContext;
22
+ private final InternalLogger logger;
23
+ private final ReflectionUtils reflectionUtils;
24
+ private UIManagerModule uiManager;
25
+
26
+ public LegacyTextViewUtils(ReactContext reactContext, InternalLogger logger, ReflectionUtils reflectionUtils, DrawableUtils drawableUtils) {
27
+ super(reactContext, drawableUtils);
28
+ this.reactContext = reactContext;
29
+ this.logger = logger;
30
+ this.reflectionUtils = reflectionUtils;
31
+ this.uiManager = getUiManagerModule();
32
+ }
33
+
34
+ @Override
35
+ protected TextStyle resolveTextStyle(TextWireframe textWireframe, float pixelsDensity, TextView view) {
36
+ ShadowNodeWrapper shadowNodeWrapper = ShadowNodeWrapper.getShadowNodeWrapper(
37
+ reactContext,
38
+ uiManager,
39
+ reflectionUtils,
40
+ view.getId()
41
+ );
42
+ if (shadowNodeWrapper == null) return null;
43
+ String fontFamily = getFontFamily(shadowNodeWrapper);
44
+ if (fontFamily == null) fontFamily = textWireframe.getTextStyle().getFamily();
45
+ Long fontSize = getFontSize(shadowNodeWrapper);
46
+ if (fontSize != null) {
47
+ fontSize = (long) (fontSize / pixelsDensity);
48
+ } else {
49
+ fontSize = textWireframe.getTextStyle().getSize();
50
+ }
51
+ String fontColor = getTextColor(shadowNodeWrapper);
52
+ if (fontColor == null) fontColor = textWireframe.getTextStyle().getColor();
53
+ return new TextStyle(fontFamily, fontSize, fontColor);
54
+ }
55
+
56
+ private String getTextColor(ShadowNodeWrapper shadowNodeWrapper) {
57
+ if (shadowNodeWrapper == null) return null;
58
+ Boolean isColorSet = (Boolean) shadowNodeWrapper.getDeclaredShadowNodeField(TextViewUtils.IS_COLOR_SET_FIELD_NAME);
59
+ if (isColorSet == null || !isColorSet) {
60
+ return "#000000FF";
61
+ }
62
+ Integer resolvedColor = (Integer) shadowNodeWrapper.getDeclaredShadowNodeField(TextViewUtils.COLOR_FIELD_NAME);
63
+ if (resolvedColor != null) {
64
+ return ColorUtils.formatAsRgba(resolvedColor);
65
+ }
66
+ return null;
67
+ }
68
+
69
+ private Long getFontSize(ShadowNodeWrapper shadowNodeWrapper) {
70
+ if (shadowNodeWrapper == null) return null;
71
+ TextAttributes textAttributes = (TextAttributes) shadowNodeWrapper.getDeclaredShadowNodeField(TextViewUtils.TEXT_ATTRIBUTES_FIELD_NAME);
72
+ if (textAttributes != null) {
73
+ return (long) textAttributes.getEffectiveFontSize();
74
+ }
75
+ return null;
76
+ }
77
+
78
+ private String getFontFamily(ShadowNodeWrapper shadowNodeWrapper) {
79
+ if (shadowNodeWrapper == null) return null;
80
+ String fontFamily = (String) shadowNodeWrapper.getDeclaredShadowNodeField(TextViewUtils.FONT_FAMILY_FIELD_NAME);
81
+ if (fontFamily != null) {
82
+ return resolveFontFamily(fontFamily.toLowerCase(Locale.US));
83
+ }
84
+ return null;
85
+ }
86
+
87
+ private UIManagerModule getUiManagerModule() {
88
+ try {
89
+ return reactContext.getNativeModule(UIManagerModule.class);
90
+ } catch (IllegalStateException e) {
91
+ logger.w(
92
+ TAG, TextViewUtils.RESOLVE_UIMANAGERMODULE_ERROR + ":" + LogUtils.getStackTraceString(e)
93
+ );
94
+ return null;
95
+ }
96
+ }
97
+ }