cobrowse-sdk-react-native 2.13.0 → 2.15.0

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.
@@ -3,9 +3,8 @@ package io.cobrowse.reactnative;
3
3
  import android.app.Activity;
4
4
  import android.os.Handler;
5
5
  import android.util.Log;
6
- import android.view.View;
7
- import android.view.ViewGroup;
8
- import android.view.ViewParent;
6
+
7
+ import androidx.annotation.NonNull;
9
8
 
10
9
  import com.facebook.react.bridge.Promise;
11
10
  import com.facebook.react.bridge.ReactApplicationContext;
@@ -13,367 +12,232 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
13
12
  import com.facebook.react.bridge.ReactMethod;
14
13
  import com.facebook.react.bridge.ReadableArray;
15
14
  import com.facebook.react.bridge.ReadableMap;
16
- import com.facebook.react.modules.core.DeviceEventManagerModule;
17
- import com.facebook.react.uimanager.NativeViewHierarchyManager;
18
- import com.facebook.react.uimanager.UIBlock;
19
- import com.facebook.react.uimanager.UIManagerModule;
15
+ import com.facebook.react.bridge.UnexpectedNativeTypeException;
20
16
 
21
- import java.util.ArrayList;
22
- import java.util.HashSet;
23
- import java.util.List;
24
- import java.util.Set;
17
+ import java.lang.reflect.Proxy;
25
18
 
26
- import androidx.annotation.NonNull;
27
- import androidx.core.util.Predicate;
19
+ import io.cobrowse.CobrowseAccessibilityService;
28
20
  import io.cobrowse.CobrowseIO;
29
21
  import io.cobrowse.Session;
30
- import io.cobrowse.CobrowseAccessibilityService;
22
+ import io.cobrowse.Session.FullDeviceState;
31
23
 
32
- public class CobrowseIOModule extends ReactContextBaseJavaModule
33
- implements CobrowseIO.Delegate, CobrowseIO.SessionRequestDelegate,
34
- CobrowseIO.SessionLoadDelegate, CobrowseIO.RedactionDelegate,
35
- CobrowseIO.RemoteControlRequestDelegate {
36
-
37
- private static final String SESSION_LOADED = "session.loaded";
38
- private static final String SESSION_UPDATED = "session.updated";
39
- private static final String SESSION_ENDED = "session.ended";
40
- private static final String SESSION_REQUESTED = "session.requested";
41
-
42
- private final HashSet<Integer> unredactedTags = new HashSet<>();
43
- private NativeViewHierarchyManager nodeManager;
44
-
45
- CobrowseIOModule(ReactApplicationContext reactContext) {
46
- super(reactContext);
47
- CobrowseIO.instance().setDelegate(this);
48
- }
49
-
50
- private void findNodeManager() {
51
- if (nodeManager != null) return;
52
- final UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class);
53
- assert uiManager != null;
54
- uiManager.prependUIBlock(new UIBlock() {
55
- @Override
56
- public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
57
- nodeManager = nativeViewHierarchyManager;
58
- }
59
- });
60
- }
61
-
62
- public static io.cobrowse.reactnative.CobrowseIO.Delegate delegate;
63
-
64
- @NonNull
65
- public String getName() {
66
- return "CobrowseIO";
67
- }
68
-
69
- @Override
70
- public void sessionDidLoad(@NonNull Session session) {
71
- getReactApplicationContext()
72
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
73
- .emit(SESSION_LOADED, Conversion.convert(session));
74
- }
75
-
76
- @Override
77
- public void sessionDidUpdate(@NonNull Session session) {
78
- getReactApplicationContext()
79
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
80
- .emit(SESSION_UPDATED, Conversion.convert(session));
81
- }
82
-
83
- @Override
84
- public void sessionDidEnd(@NonNull Session session) {
85
- getReactApplicationContext()
86
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
87
- .emit(SESSION_ENDED, Conversion.convert(session));
88
- }
89
-
90
- @Override
91
- public void handleSessionRequest(@NonNull Activity activity, @NonNull Session session) {
92
- getReactApplicationContext()
93
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
94
- .emit(SESSION_REQUESTED, Conversion.convert(session));
95
- }
96
-
97
- @Override
98
- public void handleRemoteControlRequest(@NonNull Activity activity, @NonNull Session session) {
99
- // no-op, this will be handed on the JS side via an "updated" event handler
100
- // this stub just disables the default native prompt in the SDK
101
- }
102
- @ReactMethod
103
- public void setUnredactedTags(final ReadableArray reactTags, final Promise promise) {
104
- synchronized (unredactedTags) {
105
- unredactedTags.clear();
106
- for (int i = 0; i < reactTags.size(); i++)
107
- unredactedTags.add(reactTags.getInt(i));
108
- promise.resolve(null);
109
- }
110
- }
111
-
112
- private Set<View> getUnredactedViews(@NonNull final Activity activity) {
113
- synchronized (unredactedTags) {
114
- HashSet<View> unredacted = new HashSet<>();
115
- for (Integer i : unredactedTags) {
116
- try {
117
- unredacted.add(nodeManager.resolveView(i));
118
- } catch (Exception e) {
119
- Log.i("CobrowseIO", "Failed to find unredacted view for tag " + i + ", error = " + e.getMessage());
120
- }
121
- }
122
- if (delegate instanceof io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) {
123
- List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) delegate).unredactedViews(activity);
124
- if (views != null) unredacted.addAll(views);
125
- }
126
- return unredacted;
127
- }
128
- }
24
+ public class CobrowseIOModule extends ReactContextBaseJavaModule {
129
25
 
130
- private Set<View> getRedactedViews(@NonNull final Activity activity) {
131
- HashSet<View> redacted = new HashSet<>(RedactedViewManager.redactedViews.keySet());
132
- if (delegate instanceof io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) {
133
- List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) delegate).redactedViews(activity);
134
- if (views != null) redacted.addAll(views);
135
- }
136
- return redacted;
137
- }
138
-
139
- @Override
140
- public List<View> redactedViews(@NonNull final Activity activity) {
141
- final Set<View> redacted = this.getRedactedViews(activity);
142
- final Set<View> unredacted = this.getUnredactedViews(activity);
143
-
144
- // Project all unredactions to the root to get the full set of unredacted nodes
145
- HashSet<View> projectedUnredacted = new HashSet<>();
146
- for (View view : unredacted) {
147
- projectedUnredacted.add(view);
148
- projectedUnredacted.addAll(TreeUtils.allParents(view));
149
- }
26
+ private CobrowseIOCommonDelegates delegates;
150
27
 
151
- // Work out which nodes are explicitly redacted but need to be unredacted
152
- // due to a nested unredaction tag (these redactions will be moved towards the
153
- // leaves of the view hierarchy instead)
154
- HashSet<View> redactedProjectedUnredactions = new HashSet<>(redacted);
155
- redactedProjectedUnredactions.retainAll(projectedUnredacted);
156
-
157
- // Start to build the set of redactions we should actually apply. We start off with
158
- // the set of explicitly redacted nodes
159
- HashSet<View> toRedact = new HashSet<>(redacted);
160
-
161
- // remove any redactions that have unredacted decendants (i.e. any that appear in the
162
- // projection of the unredaction). These are the redacted nodes we need to move towards
163
- // the leaves of the tree
164
- toRedact.removeAll(redactedProjectedUnredactions);
165
-
166
- // Work out the set of all nodes that are siblings of any projected unredacted node
167
- HashSet<View> projectedUnredactionSiblings = new HashSet<>();
168
- for (View view : projectedUnredacted) {
169
- ViewParent parent = view.getParent();
170
- if (parent instanceof ViewGroup)
171
- projectedUnredactionSiblings.addAll(TreeUtils.directChildren((ViewGroup) parent));
172
- }
28
+ CobrowseIOModule(ReactApplicationContext reactContext) {
29
+ super(reactContext);
30
+
31
+ delegates = new CommonDelegates(reactContext);
32
+ CobrowseIO.instance().setDelegate(delegates);
33
+ }
173
34
 
174
- // Subtract the projected unredactions from the set of all siblings of projected
175
- // unredactions. i.e. subtract things that should be definitely unredacted to leave
176
- // a set we're not sure yet whether to redact or not
177
- HashSet<View> potentiallyRedactedUnredactedSiblings = new HashSet<View>(projectedUnredactionSiblings);
178
- potentiallyRedactedUnredactedSiblings.removeAll(projectedUnredacted);
35
+ public static io.cobrowse.reactnative.CobrowseIO.Delegate delegate;
179
36
 
180
- // for each node we're not sure about yet, check if the closest redacted or unredacted ancestor
181
- // is a redacted node, if so this descendant should also be redacted
182
- for (View view : potentiallyRedactedUnredactedSiblings) {
183
- View closest = TreeUtils.closest(view, new Predicate<View>() {
37
+ @NonNull
38
+ public String getName() {
39
+ return "CobrowseIO";
40
+ }
41
+
42
+ @ReactMethod
43
+ public void setUnredactedTags(final ReadableArray reactTags, final Promise promise) {
44
+ delegates.setUnredactedTags(reactTags, promise);
45
+ }
46
+
47
+ @ReactMethod
48
+ public void start() {
49
+ delegates.findNodeManager();
50
+ final Activity activity = getReactApplicationContext().getCurrentActivity();
51
+ if (activity != null)
52
+ activity.runOnUiThread(new Runnable() {
53
+ @Override
54
+ public void run() {
55
+ CobrowseIO.instance().start(activity);
56
+ }
57
+ });
58
+ else
59
+ Log.w("CobrowseIO", "Activity was null during start() call.");
60
+ }
61
+
62
+ @ReactMethod
63
+ public void stop() {
64
+ CobrowseIO.instance().stop();
65
+ }
66
+
67
+ @ReactMethod
68
+ public void api(String api) {
69
+ CobrowseIO.instance().api(api);
70
+ }
71
+
72
+ @ReactMethod
73
+ public void license(String license) {
74
+ CobrowseIO.instance().license(license);
75
+ }
76
+
77
+ @ReactMethod
78
+ public void customData(ReadableMap customData) {
79
+ CobrowseIO.instance().customData(customData.toHashMap());
80
+ }
81
+
82
+ @ReactMethod
83
+ public void deviceToken(String token) {
84
+ if (getReactApplicationContext().getCurrentActivity() != null)
85
+ CobrowseIO.instance().setDeviceToken(
86
+ getReactApplicationContext().getCurrentActivity().getApplication(),
87
+ token);
88
+ }
89
+
90
+ @ReactMethod
91
+ public void currentSession(final Promise promise) {
92
+ promise.resolve(Conversion.convert(CobrowseIO.instance().currentSession()));
93
+ }
94
+
95
+ @ReactMethod
96
+ public void createSession(final Promise promise) {
97
+ Handler handler = new Handler(getReactApplicationContext().getMainLooper());
98
+ handler.post(new Runnable() {
99
+ public void run() {
100
+ CobrowseIO.instance().createSession(new io.cobrowse.Callback<Error, Session>() {
184
101
  @Override
185
- public boolean test(View view) {
186
- return redacted.contains(view) || unredacted.contains(view);
102
+ public void call(Error error, Session session) {
103
+ if (error != null) promise.reject("cbio_create_session_failed", error);
104
+ else promise.resolve(Conversion.convert(session));
187
105
  }
188
106
  });
189
- if (redacted.contains(closest)) toRedact.add(view);
190
107
  }
191
-
192
- // Remove any empty ViewGroup from the redacted set, they're often used for wrapping
193
- // or sizing other elements, and do not usually need to be redacted
194
- // If it's absolutely necessary they are redacted, they can always be replaced with
195
- // a <Redacted> tag instead
196
- for (View v : new HashSet<>(toRedact)) {
197
- if (v instanceof ViewGroup && ((ViewGroup) v).getChildCount() == 0) {
198
- toRedact.remove(v);
108
+ });
109
+ }
110
+
111
+ @ReactMethod
112
+ public void getSession(final String idOrCode, final Promise promise) {
113
+ Handler handler = new Handler(getReactApplicationContext().getMainLooper());
114
+ handler.post(new Runnable() {
115
+ public void run() {
116
+ CobrowseIO.instance().getSession(idOrCode, new io.cobrowse.Callback<Error, Session>() {
117
+ @Override
118
+ public void call(Error error, Session session) {
119
+ if (error != null) promise.reject("cbio_get_session_failed", error);
120
+ else promise.resolve(Conversion.convert(session));
121
+ }
122
+ });
123
+ }
124
+ });
125
+ }
126
+
127
+ @ReactMethod
128
+ public void activateSession(final Promise promise) {
129
+ Handler handler = new Handler(getReactApplicationContext().getMainLooper());
130
+ handler.post(new Runnable() {
131
+ public void run() {
132
+ Session current = CobrowseIO.instance().currentSession();
133
+ if (current == null) {
134
+ promise.reject("no current session", new Error("No session"));
135
+ return;
136
+ }
137
+ current.activate(new io.cobrowse.Callback<Error, Session>() {
138
+ @Override
139
+ public void call(Error error, Session session) {
140
+ if (error != null) promise.reject("cbio_activate_session_failed", error);
141
+ else promise.resolve(Conversion.convert(session));
142
+ }
143
+ });
144
+ }
145
+ });
146
+ }
147
+
148
+ @ReactMethod
149
+ public void endSession(final Promise promise) {
150
+ Handler handler = new Handler(getReactApplicationContext().getMainLooper());
151
+ handler.post(new Runnable() {
152
+ public void run() {
153
+ Session current = CobrowseIO.instance().currentSession();
154
+ if (current == null) {
155
+ promise.resolve(null);
156
+ return;
199
157
  }
158
+ current.end(new io.cobrowse.Callback<Error, Session>() {
159
+ @Override
160
+ public void call(Error error, Session session) {
161
+ if (error != null) promise.reject("cbio_end_session_failed", error);
162
+ else promise.resolve(null);
163
+ }
164
+ });
200
165
  }
166
+ });
167
+ }
168
+
169
+ @ReactMethod
170
+ public void updateSession(final ReadableMap options, final Promise promise) {
171
+ Handler handler = new Handler(getReactApplicationContext().getMainLooper());
172
+ handler.post(new Runnable() {
173
+ public void run() {
174
+ Session current = CobrowseIO.instance().currentSession();
175
+
176
+ if (current == null) {
177
+ promise.resolve(null);
178
+ return;
179
+ }
201
180
 
202
- return new ArrayList<>(toRedact);
203
- }
204
-
205
- @ReactMethod
206
- public void start() {
207
- findNodeManager();
208
- final Activity activity = getReactApplicationContext().getCurrentActivity();
209
- if (activity != null)
210
- activity.runOnUiThread(new Runnable() {
211
- @Override
212
- public void run() {
213
- CobrowseIO.instance().start(activity);
214
- }
181
+ if (options.hasKey("full_device")) {
182
+ try {
183
+ String fullDeviceStr = options.getString("full_device");
184
+ FullDeviceState fullDeviceState = Conversion.fullDeviceState(fullDeviceStr);
185
+
186
+ current.setFullDeviceState(fullDeviceState, new io.cobrowse.Callback<Error, Session>() {
187
+ @Override
188
+ public void call(Error error, Session session) {
189
+ if (error != null) promise.reject("cbio_full_device_failed", error);
190
+ else promise.resolve(null);
191
+ }
215
192
  });
216
- else
217
- Log.w("CobrowseIO", "Activity was null during start() call.");
218
- }
219
-
220
- @ReactMethod
221
- public void stop() {
222
- CobrowseIO.instance().stop();
223
- }
224
-
225
- @ReactMethod
226
- public void api(String api) {
227
- CobrowseIO.instance().api(api);
228
- }
229
-
230
- @ReactMethod
231
- public void license(String license) {
232
- CobrowseIO.instance().license(license);
233
- }
234
-
235
- @ReactMethod
236
- public void customData(ReadableMap customData) {
237
- CobrowseIO.instance().customData(customData.toHashMap());
238
- }
239
-
240
- @ReactMethod
241
- public void deviceToken(String token) {
242
- if (getReactApplicationContext().getCurrentActivity() != null)
243
- CobrowseIO.instance().setDeviceToken(
244
- getReactApplicationContext().getCurrentActivity().getApplication(),
245
- token);
246
- }
247
-
248
- @ReactMethod
249
- public void currentSession(final Promise promise) {
250
- promise.resolve(Conversion.convert(CobrowseIO.instance().currentSession()));
251
- }
252
-
253
- @ReactMethod
254
- public void createSession(final Promise promise) {
255
- Handler handler = new Handler(getReactApplicationContext().getMainLooper());
256
- handler.post(new Runnable() {
257
- public void run() {
258
- CobrowseIO.instance().createSession(new io.cobrowse.Callback<Error, Session>() {
259
- @Override
260
- public void call(Error error, Session session) {
261
- if (error != null) promise.reject("cbio_create_session_failed", error);
262
- else promise.resolve(Conversion.convert(session));
263
- }
264
- });
265
- }
266
- });
267
- }
268
-
269
- @ReactMethod
270
- public void getSession(final String idOrCode, final Promise promise) {
271
- Handler handler = new Handler(getReactApplicationContext().getMainLooper());
272
- handler.post(new Runnable() {
273
- public void run() {
274
- CobrowseIO.instance().getSession(idOrCode, new io.cobrowse.Callback<Error, Session>() {
275
- @Override
276
- public void call(Error error, Session session) {
277
- if (error != null) promise.reject("cbio_get_session_failed", error);
278
- else promise.resolve(Conversion.convert(session));
279
- }
280
- });
281
- }
282
- });
283
- }
284
-
285
- @ReactMethod
286
- public void activateSession(final Promise promise) {
287
- Handler handler = new Handler(getReactApplicationContext().getMainLooper());
288
- handler.post(new Runnable() {
289
- public void run() {
290
- Session current = CobrowseIO.instance().currentSession();
291
- if (current == null) {
292
- promise.reject("no current session", new Error("No session"));
293
- return;
294
- }
295
- current.activate(new io.cobrowse.Callback<Error, Session>() {
296
- @Override
297
- public void call(Error error, Session session) {
298
- if (error != null) promise.reject("cbio_activate_session_failed", error);
299
- else promise.resolve(Conversion.convert(session));
300
- }
301
- });
302
- }
303
- });
304
- }
305
-
306
- @ReactMethod
307
- public void endSession(final Promise promise) {
308
- Handler handler = new Handler(getReactApplicationContext().getMainLooper());
309
- handler.post(new Runnable() {
310
- public void run() {
311
- Session current = CobrowseIO.instance().currentSession();
312
- if (current == null) {
313
- promise.resolve(null);
314
- return;
315
- }
316
- current.end(new io.cobrowse.Callback<Error, Session>() {
317
- @Override
318
- public void call(Error error, Session session) {
319
- if (error != null) promise.reject("cbio_end_session_failed", error);
320
- else promise.resolve(null);
321
- }
322
- });
323
- }
324
- });
325
- }
326
-
327
- @ReactMethod
328
- public void updateSession (final ReadableMap options, final Promise promise) {
329
- Handler handler = new Handler(getReactApplicationContext().getMainLooper());
330
- handler.post(new Runnable() {
331
- public void run() {
332
- Session current = CobrowseIO.instance().currentSession();
333
-
334
- if (current == null) {
335
- promise.resolve(null);
336
- return;
337
- }
338
-
339
- if (options.hasKey("full_device")) {
340
- boolean fullDevice = options.getBoolean("full_device");
341
-
342
- current.setFullDevice(fullDevice, new io.cobrowse.Callback<Error, Session>() {
343
- @Override
344
- public void call(Error error, Session session) {
345
- if (error != null) promise.reject("cbio_full_device_failed", error);
346
- else promise.resolve(null);
347
- }
348
- });
349
-
350
- return;
351
- }
352
-
353
- if (options.hasKey("remote_control")) {
354
- String remoteControl = options.getString("remote_control");
355
-
356
- current.setRemoteControl(Conversion.remoteControl(remoteControl), new io.cobrowse.Callback<Error, Session>() {
357
- @Override
358
- public void call(Error error, Session session) {
359
- if (error != null) promise.reject("cbio_remote_control_failed", error);
360
- else promise.resolve(null);
361
- }
362
- });
363
- }
364
- }
365
- });
366
- }
193
+ } catch (UnexpectedNativeTypeException ref) {
194
+ boolean fullDeviceBool = options.getBoolean("full_device");
195
+
196
+ current.setFullDevice(fullDeviceBool, new io.cobrowse.Callback<Error, Session>() {
197
+ @Override
198
+ public void call(Error error, Session session) {
199
+ if (error != null) promise.reject("cbio_full_device_failed", error);
200
+ else promise.resolve(null);
201
+ }
202
+ });
203
+ }
367
204
 
368
- @ReactMethod
369
- public void accessibilityServiceShowSetup (final Promise promise) {
370
- CobrowseAccessibilityService.showSetup(getReactApplicationContext());
371
- promise.resolve(null);
372
- }
205
+ return;
206
+ }
373
207
 
374
- @ReactMethod
375
- public void accessibilityServiceIsRunning(final Promise promise) {
376
- promise.resolve(CobrowseAccessibilityService.isRunning(getReactApplicationContext()));
377
- }
208
+ if (options.hasKey("remote_control")) {
209
+ String remoteControl = options.getString("remote_control");
378
210
 
211
+ current.setRemoteControl(Conversion.remoteControl(remoteControl), new io.cobrowse.Callback<Error, Session>() {
212
+ @Override
213
+ public void call(Error error, Session session) {
214
+ if (error != null) promise.reject("cbio_remote_control_failed", error);
215
+ else promise.resolve(null);
216
+ }
217
+ });
218
+ }
219
+ }
220
+ });
221
+ }
222
+
223
+ @ReactMethod
224
+ public void accessibilityServiceShowSetup(final Promise promise) {
225
+ CobrowseAccessibilityService.showSetup(getReactApplicationContext());
226
+ promise.resolve(null);
227
+ }
228
+
229
+ @ReactMethod
230
+ public void accessibilityServiceIsRunning(final Promise promise) {
231
+ promise.resolve(CobrowseAccessibilityService.isRunning(getReactApplicationContext()));
232
+ }
233
+
234
+ @ReactMethod
235
+ public void overwriteSessionIndicator() {
236
+ CobrowseIOCommonDelegates delegatesWithSessionControls = (CobrowseIOCommonDelegates) Proxy.newProxyInstance(
237
+ CobrowseIOCommonDelegates.class.getClassLoader(),
238
+ new Class[] { CobrowseIOCommonDelegates.class, CobrowseIO.SessionControlsDelegate.class },
239
+ new DynamicSessionControlInvocationHandler(this.delegates));
240
+
241
+ CobrowseIO.instance().setDelegate(delegatesWithSessionControls);
242
+ }
379
243
  }