@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
@@ -18,5 +18,6 @@ Pod::Spec.new do |s|
18
18
 
19
19
 
20
20
  s.dependency "React-Core"
21
- s.dependency 'FTMobileSDK', '1.5.18'
21
+ s.dependency 'FTMobileSDK', '1.6.2-alpha.3'
22
+ s.dependency 'FTMobileSDK/FTSessionReplay', '1.6.2-alpha.3'
22
23
  end
@@ -54,7 +54,7 @@ android {
54
54
  compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
55
55
  buildToolsVersion getExtOrDefault('buildToolsVersion')
56
56
  defaultConfig {
57
- minSdkVersion 16
57
+ minSdkVersion 21
58
58
  targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
59
59
 
60
60
  buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString())
@@ -92,6 +92,20 @@ android {
92
92
  }
93
93
 
94
94
  if (reactNativeMajorVersion == 0) {
95
+ if (reactNativeMinorVersion >= 80) {
96
+ java.srcDirs += ['src/rn80/java']
97
+ } else if (reactNativeMinorVersion >= 79) {
98
+ java.srcDirs += ['src/rn79/java']
99
+ } else if (reactNativeMinorVersion >= 76) {
100
+ java.srcDirs += ['src/rn76/java']
101
+ } else if (reactNativeMinorVersion >= 75) {
102
+ java.srcDirs += ['src/rn75/java']
103
+ }else if (reactNativeMinorVersion >= 69) {
104
+ java.srcDirs += ['src/rn69/java']
105
+ } else {
106
+ java.srcDirs += ['src/rnlegacy/java']
107
+ }
108
+
95
109
  if (reactNativeMinorVersion >= 74) {
96
110
  java.srcDirs += ['src/rnpost74/java']
97
111
  } else {
@@ -177,7 +191,11 @@ repositories {
177
191
  dependencies {
178
192
  // noinspection GradleDynamicVersion
179
193
  implementation 'com.facebook.react:react-native:+'
180
- implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-sdk:1.6.13'
181
- implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-native:1.1.2'
194
+ implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-sdk:1.7.0-alpha20'
195
+ implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-native:1.1.1'
196
+ implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-session-replay:0.1.2-alpha02'
197
+ // implementation files('../example/android/app/libs/ft-sdk-debug.aar')
198
+ // implementation files('../example/android/app/libs/ft-session-replay-debug.aar')
199
+
182
200
  implementation 'com.google.code.gson:gson:2.8.5'
183
201
  }
@@ -0,0 +1,60 @@
1
+ package com.ft.sdk.reactnative;
2
+
3
+ import com.ft.sdk.reactnative.sessionreplay.ReactNativeSessionReplayExtensionSupport;
4
+ import com.ft.sdk.reactnative.sessionreplay.utils.text.TextViewUtils;
5
+ import com.ft.sdk.reactnative.utils.ReactNativeUtils;
6
+ import com.facebook.react.bridge.Promise;
7
+ import com.facebook.react.bridge.ReactContext;
8
+ import com.facebook.react.bridge.ReactMethod;
9
+ import com.facebook.react.bridge.ReadableMap;
10
+ import com.ft.sdk.FTSdk;
11
+ import com.ft.sdk.SessionReplayManager;
12
+ import com.ft.sdk.sessionreplay.FTSessionReplayConfig;
13
+ import com.ft.sdk.sessionreplay.SessionReplayPrivacy;
14
+
15
+ public class FTSessionReplayImpl {
16
+
17
+ public static final String NAME = "FTReactNativeSessionReplay";
18
+
19
+
20
+ @ReactMethod
21
+ public void sessionReplayConfig(ReadableMap context, Promise promise, ReactContext reactContext) {
22
+ java.util.HashMap<String, Object> map = context.toHashMap();
23
+
24
+ Double sampleRate = map.get("sampleRate") instanceof Double ? (Double) map.get("sampleRate") : null;
25
+ Integer privacy = ReactNativeUtils.convertToNativeInt(map.get("privacy"));
26
+ FTSessionReplayConfig sessionReplayConfig = new FTSessionReplayConfig();
27
+
28
+ if (sampleRate != null) {
29
+ sessionReplayConfig.setSampleRate(sampleRate.floatValue());
30
+ }
31
+
32
+ SessionReplayPrivacy sessionReplayPrivacy;
33
+ if (privacy != null) {
34
+ switch (privacy) {
35
+ case 0:
36
+ sessionReplayPrivacy = SessionReplayPrivacy.MASK;
37
+ break;
38
+ case 1:
39
+ sessionReplayPrivacy = SessionReplayPrivacy.ALLOW;
40
+ break;
41
+ case 2:
42
+ sessionReplayPrivacy = SessionReplayPrivacy.MASK_USER_INPUT;
43
+ break;
44
+ default:
45
+ sessionReplayPrivacy = SessionReplayPrivacy.MASK;
46
+ }
47
+ } else {
48
+ sessionReplayPrivacy = SessionReplayPrivacy.MASK;
49
+ }
50
+ sessionReplayConfig.setPrivacy(sessionReplayPrivacy);
51
+ TextViewUtils textViewUtils = TextViewUtils.create(reactContext,
52
+ SessionReplayManager.get().getInternalLogger());
53
+ sessionReplayConfig.addExtensionSupport(
54
+ new ReactNativeSessionReplayExtensionSupport(textViewUtils
55
+ )
56
+ ).setDelayInit(true);
57
+ FTSdk.initSessionReplayConfig(sessionReplayConfig);
58
+ promise.resolve(null);
59
+ }
60
+ }
@@ -1,5 +1,6 @@
1
1
  package com.ft.sdk.reactnative;
2
2
 
3
+ import com.ft.sdk.reactnative.utils.ReactNativeUtils;
3
4
  import com.facebook.react.bridge.Promise;
4
5
  import com.facebook.react.bridge.ReactMethod;
5
6
  import com.facebook.react.bridge.ReadableMap;
@@ -8,7 +9,6 @@ import com.ft.sdk.FTSdk;
8
9
  import com.ft.sdk.FTTraceConfig;
9
10
  import com.ft.sdk.FTTraceManager;
10
11
  import com.ft.sdk.TraceType;
11
- import com.ft.sdk.reactnative.utils.ReactNativeUtils;
12
12
 
13
13
  import java.util.HashMap;
14
14
  import java.util.Map;
@@ -0,0 +1,155 @@
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.extensions;
8
+
9
+ import android.content.res.Resources;
10
+ import android.graphics.Bitmap;
11
+ import android.graphics.Bitmap.Config;
12
+ import android.graphics.Canvas;
13
+ import android.graphics.drawable.BitmapDrawable;
14
+ import android.graphics.drawable.Drawable;
15
+ import android.graphics.drawable.ShapeDrawable;
16
+ import android.graphics.drawable.VectorDrawable;
17
+ import android.widget.ImageView;
18
+ import androidx.appcompat.graphics.drawable.DrawerArrowDrawable;
19
+ import com.facebook.drawee.drawable.ArrayDrawable;
20
+ import com.facebook.drawee.drawable.ForwardingDrawable;
21
+ import com.facebook.drawee.drawable.RoundedBitmapDrawable;
22
+ import com.facebook.drawee.drawable.ScaleTypeDrawable;
23
+ import com.facebook.drawee.drawable.ScalingUtils;
24
+
25
+ public class ReactDrawablesExt {
26
+ public static ImageView.ScaleType imageViewScaleType(ScaleTypeDrawable scaleTypeDrawable) {
27
+ ScalingUtils.ScaleType scaleType = scaleTypeDrawable.getScaleType();
28
+ if (scaleType == ScalingUtils.ScaleType.CENTER) return ImageView.ScaleType.CENTER;
29
+ if (scaleType == ScalingUtils.ScaleType.CENTER_CROP) return ImageView.ScaleType.CENTER_CROP;
30
+ if (scaleType == ScalingUtils.ScaleType.CENTER_INSIDE) return ImageView.ScaleType.CENTER_INSIDE;
31
+ if (scaleType == ScalingUtils.ScaleType.FIT_CENTER) return ImageView.ScaleType.FIT_CENTER;
32
+ if (scaleType == ScalingUtils.ScaleType.FIT_START) return ImageView.ScaleType.FIT_START;
33
+ if (scaleType == ScalingUtils.ScaleType.FIT_END) return ImageView.ScaleType.FIT_END;
34
+ if (scaleType == ScalingUtils.ScaleType.FIT_XY) return ImageView.ScaleType.FIT_XY;
35
+ return null;
36
+ }
37
+
38
+ public static ScaleTypeDrawable getScaleTypeDrawable(ArrayDrawable arrayDrawable) {
39
+ for (int i = 0; i < arrayDrawable.getNumberOfLayers(); i++) {
40
+ Drawable drawable = getDrawableOrNull(arrayDrawable, i);
41
+ if (drawable instanceof ScaleTypeDrawable) return (ScaleTypeDrawable) drawable;
42
+ }
43
+ return null;
44
+ }
45
+
46
+ public static Drawable getDrawableOrNull(ArrayDrawable arrayDrawable, int index) {
47
+ try {
48
+ return arrayDrawable.getDrawable(index);
49
+ } catch (IllegalArgumentException e) {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ public static Bitmap tryToExtractBitmap(ForwardingDrawable forwardingDrawable, Resources resources) {
55
+ Drawable forwardedDrawable = forwardingDrawable.getDrawable();
56
+ if (forwardedDrawable != null) {
57
+ return tryToExtractBitmap(forwardedDrawable, resources);
58
+ } else {
59
+ return toBitmapOrNull(forwardingDrawable, forwardingDrawable.getIntrinsicWidth(), forwardingDrawable.getIntrinsicHeight(), Config.ARGB_8888);
60
+ }
61
+ }
62
+
63
+ public static Bitmap tryToExtractBitmap(RoundedBitmapDrawable roundedBitmapDrawable) {
64
+ try {
65
+ java.lang.reflect.Field field = RoundedBitmapDrawable.class.getDeclaredField("mBitmap");
66
+ field.setAccessible(true);
67
+ Object value = field.get(roundedBitmapDrawable);
68
+ if (value instanceof Bitmap) {
69
+ return (Bitmap) value;
70
+ }
71
+ } catch (NoSuchFieldException | IllegalAccessException e) {
72
+ // ignore
73
+ } catch (Exception e) {
74
+ // ignore
75
+ }
76
+ return toBitmapOrNull(roundedBitmapDrawable, roundedBitmapDrawable.getIntrinsicWidth(), roundedBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);
77
+ }
78
+
79
+ public static Bitmap tryToExtractBitmap(BitmapDrawable bitmapDrawable, Resources resources) {
80
+ if (bitmapDrawable.getBitmap() != null) {
81
+ return bitmapDrawable.getBitmap();
82
+ }
83
+ if (bitmapDrawable.getConstantState() != null) {
84
+ Drawable copy = bitmapDrawable.getConstantState().newDrawable(resources);
85
+ if (copy instanceof BitmapDrawable) {
86
+ Bitmap b = ((BitmapDrawable) copy).getBitmap();
87
+ if (b != null) return b;
88
+ }
89
+ return toBitmapOrNull(copy, copy.getIntrinsicWidth(), copy.getIntrinsicHeight(), Config.ARGB_8888);
90
+ }
91
+ return null;
92
+ }
93
+
94
+ public static Bitmap tryToExtractBitmap(ArrayDrawable arrayDrawable, Resources resources) {
95
+ int width = 0, height = 0;
96
+ for (int i = 0; i < arrayDrawable.getNumberOfLayers(); i++) {
97
+ Drawable drawable = getDrawableOrNull(arrayDrawable, i);
98
+ if (drawable instanceof ScaleTypeDrawable) {
99
+ return tryToExtractBitmap((ScaleTypeDrawable) drawable, resources);
100
+ }
101
+ if (drawable != null && drawable.getIntrinsicWidth() * drawable.getIntrinsicHeight() > width * height) {
102
+ width = drawable.getIntrinsicWidth();
103
+ height = drawable.getIntrinsicHeight();
104
+ }
105
+ }
106
+ if (width > 0 && height > 0) {
107
+ return toBitmapOrNull(arrayDrawable, width, height, Config.ARGB_8888);
108
+ } else {
109
+ return null;
110
+ }
111
+ }
112
+
113
+ public static Bitmap tryToExtractBitmap(Drawable drawable, Resources resources) {
114
+ if (drawable instanceof ArrayDrawable) {
115
+ return tryToExtractBitmap((ArrayDrawable) drawable, resources);
116
+ } else if (drawable instanceof ForwardingDrawable) {
117
+ return tryToExtractBitmap((ForwardingDrawable) drawable, resources);
118
+ } else if (drawable instanceof RoundedBitmapDrawable) {
119
+ return tryToExtractBitmap((RoundedBitmapDrawable) drawable);
120
+ } else if (drawable instanceof BitmapDrawable) {
121
+ return tryToExtractBitmap((BitmapDrawable) drawable, resources);
122
+ } else if (drawable instanceof VectorDrawable || drawable instanceof ShapeDrawable || drawable instanceof DrawerArrowDrawable) {
123
+ return toBitmapOrNull(drawable, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
124
+ } else {
125
+ return null;
126
+ }
127
+ }
128
+
129
+ public static Bitmap toBitmapOrNull(Drawable drawable, int width, int height, Config config) {
130
+ if (drawable instanceof BitmapDrawable && ((BitmapDrawable) drawable).getBitmap() == null) {
131
+ return null;
132
+ }
133
+ return toBitmap(drawable, width, height, config);
134
+ }
135
+
136
+ public static Bitmap toBitmap(Drawable drawable, int width, int height, Config config) {
137
+ if (drawable instanceof BitmapDrawable) {
138
+ Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
139
+ if (bitmap == null) {
140
+ return Bitmap.createBitmap(width, height, config != null ? config : Config.ARGB_8888);
141
+ }
142
+ if (config == null || bitmap.getConfig() == config) {
143
+ if (width == bitmap.getWidth() && height == bitmap.getHeight()) {
144
+ return bitmap;
145
+ }
146
+ return Bitmap.createScaledBitmap(bitmap, width, height, true);
147
+ }
148
+ }
149
+ Bitmap bitmap = Bitmap.createBitmap(width, height, config != null ? config : Config.ARGB_8888);
150
+ drawable.setBounds(0, 0, width, height);
151
+ drawable.draw(new Canvas(bitmap));
152
+ // restore bounds if needed
153
+ return bitmap;
154
+ }
155
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ *
3
+ * * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
4
+ * * This product includes software developed at Datadog (https://www.datadoghq.com/).
5
+ * * Copyright 2016-Present Datadog, Inc.
6
+ *
7
+ */
8
+
9
+ package com.ft.sdk.reactnative.sessionreplay;
10
+
11
+ import android.widget.TextView;
12
+ import com.ft.sdk.sessionreplay.model.TextWireframe;
13
+
14
+ public class NoopTextPropertiesResolver implements TextPropertiesResolver {
15
+ @Override
16
+ public TextWireframe addReactNativeProperties(
17
+ TextWireframe originalWireframe,
18
+ TextView view,
19
+ float pixelDensity
20
+ ) {
21
+ return originalWireframe;
22
+ }
23
+ }
@@ -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;
8
+
9
+ import com.ft.sdk.reactnative.sessionreplay.mappers.ReactEditTextMapper;
10
+ import com.ft.sdk.reactnative.sessionreplay.mappers.ReactNativeImageViewMapper;
11
+ import com.ft.sdk.reactnative.sessionreplay.mappers.ReactTextMapper;
12
+ import com.ft.sdk.reactnative.sessionreplay.mappers.ReactViewGroupMapper;
13
+ import com.ft.sdk.reactnative.sessionreplay.mappers.ReactViewModalMapper;
14
+ import com.ft.sdk.reactnative.sessionreplay.utils.text.TextViewUtils;
15
+ import com.facebook.react.views.image.ReactImageView;
16
+ import com.facebook.react.views.modal.ReactModalHostView;
17
+ import com.facebook.react.views.text.ReactTextView;
18
+ import com.facebook.react.views.textinput.ReactEditText;
19
+ import com.facebook.react.views.view.ReactViewGroup;
20
+ import com.ft.sdk.sessionreplay.ExtensionSupport;
21
+ import com.ft.sdk.sessionreplay.MapperTypeWrapper;
22
+ import com.ft.sdk.sessionreplay.recorder.OptionSelectorDetector;
23
+ import com.ft.sdk.sessionreplay.utils.DrawableToColorMapper;
24
+
25
+ import java.util.ArrayList;
26
+ import java.util.Arrays;
27
+ import java.util.Collections;
28
+ import java.util.List;
29
+
30
+ public class ReactNativeSessionReplayExtensionSupport implements ExtensionSupport {
31
+ private final TextViewUtils textViewUtils;
32
+
33
+ public ReactNativeSessionReplayExtensionSupport(TextViewUtils textViewUtils) {
34
+ this.textViewUtils = textViewUtils;
35
+ }
36
+
37
+ @Override
38
+ public List<MapperTypeWrapper<?>> getCustomViewMappers() {
39
+ return Arrays.asList(
40
+ new MapperTypeWrapper<>(ReactImageView.class, new ReactNativeImageViewMapper()),
41
+ new MapperTypeWrapper<>(ReactViewGroup.class, new ReactViewGroupMapper()),
42
+ new MapperTypeWrapper<>(ReactTextView.class, new ReactTextMapper(textViewUtils)),
43
+ new MapperTypeWrapper<>(ReactEditText.class, new ReactEditTextMapper(textViewUtils)),
44
+ new MapperTypeWrapper<>(ReactModalHostView.class, new ReactViewModalMapper())
45
+ );
46
+ }
47
+
48
+ @Override
49
+ public List<OptionSelectorDetector> getOptionSelectorDetectors() {
50
+ return new ArrayList<>();
51
+ }
52
+
53
+ @Override
54
+ public List<DrawableToColorMapper> getCustomDrawableMapper() {
55
+ return new ArrayList<>();
56
+ }
57
+ }
@@ -0,0 +1,84 @@
1
+ /*
2
+ *
3
+ * * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
4
+ * * This product includes software developed at Datadog (https://www.datadoghq.com/).
5
+ * * Copyright 2016-Present Datadog, Inc.
6
+ *
7
+ */
8
+
9
+ package com.ft.sdk.reactnative.sessionreplay;
10
+
11
+ import androidx.annotation.VisibleForTesting;
12
+ import com.ft.sdk.reactnative.sessionreplay.utils.ReflectionUtils;
13
+ import com.facebook.react.bridge.ReactContext;
14
+ import com.facebook.react.uimanager.ReactShadowNode;
15
+ import com.facebook.react.uimanager.UIImplementation;
16
+ import com.facebook.react.uimanager.UIManagerModule;
17
+
18
+ import java.util.concurrent.CountDownLatch;
19
+ import java.util.concurrent.TimeUnit;
20
+
21
+ public class ShadowNodeWrapper {
22
+ private final ReactShadowNode<?> shadowNode;
23
+ private final ReflectionUtils reflectionUtils;
24
+
25
+ public static final String UI_IMPLEMENTATION_FIELD_NAME = "mUIImplementation";
26
+
27
+ public ShadowNodeWrapper(ReactShadowNode<?> shadowNode, ReflectionUtils reflectionUtils) {
28
+ this.shadowNode = shadowNode;
29
+ this.reflectionUtils = reflectionUtils;
30
+ }
31
+
32
+ public Object getDeclaredShadowNodeField(String fieldName) {
33
+ if (shadowNode != null) {
34
+ return reflectionUtils.getDeclaredField(shadowNode, fieldName);
35
+ }
36
+ return null;
37
+ }
38
+
39
+ public static ShadowNodeWrapper getShadowNodeWrapper(
40
+ ReactContext reactContext,
41
+ UIManagerModule uiManagerModule,
42
+ ReflectionUtils reflectionUtils,
43
+ int viewId
44
+ ) {
45
+ if (reactContext == null) {
46
+ return null;
47
+ }
48
+
49
+ CountDownLatch countDownLatch = new CountDownLatch(1);
50
+ final ReactShadowNode<?>[] target = new ReactShadowNode[1];
51
+
52
+ Runnable shadowNodeRunnable = new Runnable() {
53
+ @Override
54
+ public void run() {
55
+ ReactShadowNode<?> node = resolveShadowNode(reflectionUtils, uiManagerModule, viewId);
56
+ if (node != null) {
57
+ target[0] = node;
58
+ }
59
+ countDownLatch.countDown();
60
+ }
61
+ };
62
+
63
+ reactContext.runOnNativeModulesQueueThread(shadowNodeRunnable);
64
+ try {
65
+ countDownLatch.await(5, TimeUnit.SECONDS);
66
+ } catch (InterruptedException e) {
67
+ Thread.currentThread().interrupt();
68
+ }
69
+
70
+ if (target[0] == null) {
71
+ return null;
72
+ }
73
+
74
+ return new ShadowNodeWrapper(target[0], reflectionUtils);
75
+ }
76
+
77
+ private static ReactShadowNode<?> resolveShadowNode(ReflectionUtils reflectionUtils, UIManagerModule uiManagerModule, int tag) {
78
+ if (uiManagerModule == null ) {
79
+ return null;
80
+ }
81
+ UIImplementation uiManagerImplementation = (UIImplementation) reflectionUtils.getDeclaredField(uiManagerModule, UI_IMPLEMENTATION_FIELD_NAME);
82
+ return uiManagerImplementation != null ? uiManagerImplementation.resolveShadowNode(tag) : null;
83
+ }
84
+ }
@@ -0,0 +1,20 @@
1
+ /*
2
+ *
3
+ * * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
4
+ * * This product includes software developed at Datadog (https://www.datadoghq.com/).
5
+ * * Copyright 2016-Present Datadog, Inc.
6
+ *
7
+ */
8
+
9
+ package com.ft.sdk.reactnative.sessionreplay;
10
+
11
+ import android.widget.TextView;
12
+ import com.ft.sdk.sessionreplay.model.TextWireframe;
13
+
14
+ public interface TextPropertiesResolver {
15
+ TextWireframe addReactNativeProperties(
16
+ TextWireframe originalWireframe,
17
+ TextView view,
18
+ float pixelDensity
19
+ );
20
+ }
@@ -0,0 +1,78 @@
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.DrawableUtils;
13
+ import com.ft.sdk.reactnative.sessionreplay.utils.ReactViewBackgroundDrawableUtils;
14
+ import com.ft.sdk.sessionreplay.model.ShapeBorder;
15
+ import com.ft.sdk.sessionreplay.model.ShapeStyle;
16
+ import com.ft.sdk.sessionreplay.model.ShapeWireframe;
17
+ import com.ft.sdk.sessionreplay.model.Wireframe;
18
+ import com.ft.sdk.sessionreplay.recorder.MappingContext;
19
+ import com.ft.sdk.sessionreplay.recorder.mapper.BaseWireframeMapper;
20
+ import com.ft.sdk.sessionreplay.utils.AsyncJobStatusCallback;
21
+ import com.ft.sdk.sessionreplay.utils.DefaultColorStringFormatter;
22
+ import com.ft.sdk.sessionreplay.utils.DefaultViewBoundsResolver;
23
+ import com.ft.sdk.sessionreplay.utils.DefaultViewIdentifierResolver;
24
+ import com.ft.sdk.sessionreplay.utils.DrawableToColorMapperFactory;
25
+ import com.ft.sdk.sessionreplay.utils.GlobalBounds;
26
+ import com.ft.sdk.sessionreplay.utils.InternalLogger;
27
+
28
+ import java.util.Collections;
29
+ import java.util.List;
30
+
31
+ public class DefaultMapper<T extends View> extends BaseWireframeMapper<T> {
32
+ private final DrawableUtils drawableUtils;
33
+
34
+ public DefaultMapper(DrawableUtils drawableUtils) {
35
+ super(
36
+ DefaultViewIdentifierResolver.get(),
37
+ DefaultColorStringFormatter.get(),
38
+ DefaultViewBoundsResolver.get(),
39
+ DrawableToColorMapperFactory.getDefault()
40
+ );
41
+ this.drawableUtils = drawableUtils;
42
+ }
43
+
44
+ @Override
45
+ public List<Wireframe> map(
46
+ T view,
47
+ MappingContext mappingContext,
48
+ AsyncJobStatusCallback asyncJobStatusCallback,
49
+ InternalLogger internalLogger
50
+ ) {
51
+ float pixelDensity = mappingContext.getSystemInformation().getScreenDensity();
52
+ GlobalBounds viewGlobalBounds =
53
+ DefaultViewBoundsResolver.get().resolveViewGlobalBounds(view, pixelDensity);
54
+ Drawable backgroundDrawable = drawableUtils.getReactBackgroundFromDrawable(view.getBackground());
55
+
56
+ float opacity = view.getAlpha();
57
+
58
+ Pair<ShapeStyle, ShapeBorder> shapeAndBorder =
59
+ backgroundDrawable != null ?
60
+ drawableUtils.resolveShapeAndBorder(backgroundDrawable, opacity, pixelDensity)
61
+ : new Pair<>(null, null);
62
+
63
+ ShapeStyle shapeStyle = shapeAndBorder.first;
64
+ ShapeBorder border = shapeAndBorder.second;
65
+
66
+ ShapeWireframe shapeWireframe = new ShapeWireframe(
67
+ resolveViewId(view),
68
+ viewGlobalBounds.getX(),
69
+ viewGlobalBounds.getY(),
70
+ viewGlobalBounds.getWidth(),
71
+ viewGlobalBounds.getHeight(),
72
+ null,
73
+ shapeStyle,
74
+ border
75
+ );
76
+ return Collections.singletonList(shapeWireframe);
77
+ }
78
+ }
@@ -0,0 +1,11 @@
1
+ package com.ft.sdk.reactnative.sessionreplay.mappers;
2
+
3
+ public class Pair<F, S> {
4
+ public final F first;
5
+ public final S second;
6
+
7
+ public Pair(F first, S second) {
8
+ this.first = first;
9
+ this.second = second;
10
+ }
11
+ }