cuoral-ionic 0.0.1 → 0.0.3

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 (85) hide show
  1. package/README.md +81 -4
  2. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  3. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  4. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  5. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  6. package/android/.gradle/8.9/gc.properties +0 -0
  7. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  8. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  9. package/android/.gradle/vcs-1/gc.properties +0 -0
  10. package/android/build/.transforms/2c48e1f34ca03014b78fcb3e0ab7197b/results.bin +1 -0
  11. package/android/build/.transforms/2c48e1f34ca03014b78fcb3e0ab7197b/transformed/classes/classes_dex/classes.dex +0 -0
  12. package/android/build/.transforms/980c51bd075f726f311ad662d5d20ba0/results.bin +1 -0
  13. package/android/build/.transforms/980c51bd075f726f311ad662d5d20ba0/transformed/classes/classes_dex/classes.dex +0 -0
  14. package/android/build/.transforms/bb54161301273cf9b5b94a21c0fb3f23/results.bin +1 -0
  15. package/android/build/.transforms/bb54161301273cf9b5b94a21c0fb3f23/transformed/classes/classes_dex/classes.dex +0 -0
  16. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/results.bin +1 -0
  17. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin$1.dex +0 -0
  18. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin$2.dex +0 -0
  19. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin.dex +0 -0
  20. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/ScreenRecordService.dex +0 -0
  21. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/desugar_graph.bin +0 -0
  22. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml +22 -0
  23. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json +18 -0
  24. package/android/build/intermediates/aar_main_jar/debug/classes.jar +0 -0
  25. package/android/build/intermediates/aar_metadata/debug/aar-metadata.properties +6 -0
  26. package/android/build/intermediates/annotation_processor_list/debug/annotationProcessors.json +1 -0
  27. package/android/build/intermediates/annotations_typedef_file/debug/typedefs.txt +0 -0
  28. package/android/build/intermediates/compile_library_classes_jar/debug/classes.jar +0 -0
  29. package/android/build/intermediates/compile_r_class_jar/debug/R.jar +0 -0
  30. package/android/build/intermediates/compile_symbol_list/debug/R.txt +0 -0
  31. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
  32. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
  33. package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
  34. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
  35. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
  36. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
  37. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin$1.class +0 -0
  38. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin$2.class +0 -0
  39. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin.class +0 -0
  40. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/ScreenRecordService.class +0 -0
  41. package/android/build/intermediates/local_only_symbol_list/debug/R-def.txt +2 -0
  42. package/android/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt +38 -0
  43. package/android/build/intermediates/merged_java_res/debug/feature-cuoral-ionic.jar +0 -0
  44. package/android/build/intermediates/merged_manifest/debug/AndroidManifest.xml +22 -0
  45. package/android/build/intermediates/navigation_json/debug/navigation.json +1 -0
  46. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin$1.class +0 -0
  47. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin$2.class +0 -0
  48. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin.class +0 -0
  49. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/ScreenRecordService.class +0 -0
  50. package/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar +0 -0
  51. package/android/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt +1 -0
  52. package/android/build/outputs/aar/cuoral-ionic-debug.aar +0 -0
  53. package/android/build/outputs/logs/manifest-merger-debug-report.txt +49 -0
  54. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$1.class.uniqueId1 +0 -0
  55. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$2.class.uniqueId2 +0 -0
  56. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin.class.uniqueId0 +0 -0
  57. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  58. package/android/build.gradle +61 -0
  59. package/android/src/main/AndroidManifest.xml +9 -0
  60. package/android/src/main/java/com/cuoral/ionic/CuoralPlugin.java +290 -33
  61. package/android/src/main/java/com/cuoral/ionic/ScreenRecordService.java +59 -0
  62. package/dist/cuoral.d.ts +30 -1
  63. package/dist/cuoral.d.ts.map +1 -1
  64. package/dist/cuoral.js +168 -1
  65. package/dist/index.d.ts +1 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.esm.js +706 -127
  68. package/dist/index.esm.js.map +1 -1
  69. package/dist/index.js +706 -126
  70. package/dist/index.js.map +1 -1
  71. package/dist/intelligence.d.ts +66 -0
  72. package/dist/intelligence.d.ts.map +1 -0
  73. package/dist/intelligence.js +508 -0
  74. package/dist/plugin.d.ts +1 -1
  75. package/dist/plugin.d.ts.map +1 -1
  76. package/dist/plugin.js +24 -6
  77. package/dist/web.d.ts.map +1 -1
  78. package/dist/web.js +0 -3
  79. package/ios/Plugin/CuoralPlugin.swift +78 -1
  80. package/package.json +1 -1
  81. package/src/cuoral.ts +205 -1
  82. package/src/index.ts +1 -0
  83. package/src/intelligence.ts +609 -0
  84. package/src/plugin.ts +26 -6
  85. package/src/web.ts +0 -6
@@ -16,6 +16,7 @@ import android.view.View;
16
16
 
17
17
  import androidx.core.app.ActivityCompat;
18
18
  import androidx.core.content.ContextCompat;
19
+ import androidx.activity.result.ActivityResult;
19
20
 
20
21
  import com.getcapacitor.JSObject;
21
22
  import com.getcapacitor.Plugin;
@@ -24,10 +25,16 @@ import com.getcapacitor.PluginMethod;
24
25
  import com.getcapacitor.annotation.CapacitorPlugin;
25
26
  import com.getcapacitor.annotation.Permission;
26
27
  import com.getcapacitor.annotation.ActivityCallback;
28
+ import com.getcapacitor.annotation.PermissionCallback;
27
29
 
28
30
  import java.io.ByteArrayOutputStream;
29
31
  import java.io.File;
30
32
  import java.io.IOException;
33
+ import java.io.PrintWriter;
34
+ import java.io.StringWriter;
35
+
36
+ import org.json.JSONObject;
37
+ import org.json.JSONException;
31
38
 
32
39
  @CapacitorPlugin(name = "CuoralPlugin", permissions = {
33
40
  @Permission(strings = { Manifest.permission.RECORD_AUDIO }, alias = "audio"),
@@ -38,13 +45,18 @@ public class CuoralPlugin extends Plugin {
38
45
  private static final int SCREEN_CAPTURE_REQUEST_CODE = 1001;
39
46
  private static final int PERMISSION_REQUEST_CODE = 1002;
40
47
 
48
+ private Thread.UncaughtExceptionHandler defaultExceptionHandler;
49
+ private String intelligenceBackendUrl;
50
+
41
51
  private MediaProjectionManager projectionManager;
42
52
  private MediaProjection mediaProjection;
43
53
  private MediaRecorder mediaRecorder;
54
+ private android.hardware.display.VirtualDisplay virtualDisplay;
44
55
  private boolean isRecording = false;
45
56
  private long recordingStartTime = 0;
46
57
  private String videoFilePath;
47
58
  private PluginCall currentCall;
59
+ private Intent serviceIntent;
48
60
 
49
61
  @Override
50
62
  public void load() {
@@ -53,6 +65,139 @@ public class CuoralPlugin extends Plugin {
53
65
  .getSystemService(Context.MEDIA_PROJECTION_SERVICE);
54
66
  }
55
67
 
68
+ @PluginMethod
69
+ public void setupNativeErrorCapture(PluginCall call) {
70
+ try {
71
+ String backendUrl = call.getString("backendUrl");
72
+ String sessionId = call.getString("sessionId");
73
+
74
+ if (backendUrl == null || sessionId == null) {
75
+ call.reject("Backend URL and Session ID are required");
76
+ return;
77
+ }
78
+
79
+ this.intelligenceBackendUrl = backendUrl;
80
+
81
+ // Save the default exception handler
82
+ defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
83
+
84
+ // Set custom exception handler with maximum safety
85
+ Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
86
+ @Override
87
+ public void uncaughtException(Thread thread, Throwable throwable) {
88
+ try {
89
+ // Try to send error, but never let this fail the crash
90
+ handleNativeError(throwable, sessionId);
91
+ } catch (Throwable t) {
92
+ // Completely silently ignore any errors in our error handler
93
+ // This ensures we never interfere with the app's crash
94
+ } finally {
95
+ // ALWAYS call the default handler, no matter what
96
+ if (defaultExceptionHandler != null) {
97
+ try {
98
+ defaultExceptionHandler.uncaughtException(thread, throwable);
99
+ } catch (Throwable t) {
100
+ // Even if default handler fails, don't throw
101
+ }
102
+ }
103
+ }
104
+ }
105
+ });
106
+
107
+ JSObject ret = new JSObject();
108
+ ret.put("success", true);
109
+ ret.put("message", "Native error capture enabled");
110
+ call.resolve(ret);
111
+
112
+ } catch (Exception e) {
113
+ // If setup fails, fail gracefully - don't crash the app
114
+ call.reject("Failed to setup native error capture", e);
115
+ }
116
+ }
117
+
118
+ private void handleNativeError(Throwable throwable, String sessionId) {
119
+ try {
120
+ // Get stack trace as string
121
+ StringWriter sw = new StringWriter();
122
+ PrintWriter pw = new PrintWriter(sw);
123
+ throwable.printStackTrace(pw);
124
+ String stackTrace = sw.toString();
125
+
126
+ // Create metadata
127
+ JSONObject metadata = new JSONObject();
128
+ metadata.put("device_model", Build.MODEL);
129
+ metadata.put("os_version", Build.VERSION.RELEASE);
130
+ metadata.put("thread", Thread.currentThread().getName());
131
+ metadata.put("error_type", "native_crash");
132
+ try {
133
+ metadata.put("app_version", getContext().getPackageManager()
134
+ .getPackageInfo(getContext().getPackageName(), 0).versionName);
135
+ } catch (Exception e) {
136
+ metadata.put("app_version", "unknown");
137
+ }
138
+
139
+ // Create error data matching backend format (console error endpoint expects
140
+ // array)
141
+ JSONObject errorData = new JSONObject();
142
+ errorData.put("message",
143
+ throwable.getMessage() != null ? throwable.getMessage() : throwable.getClass().getName());
144
+ errorData.put("stack_trace", stackTrace);
145
+ errorData.put("log_level", "error"); // Backend accepts: error, warn, info, debug
146
+ errorData.put("url", "native://android");
147
+ errorData.put("session_id", sessionId);
148
+ errorData.put("source", "mobile");
149
+ errorData.put("console_metadata", metadata);
150
+
151
+ // Backend expects an array of events
152
+ org.json.JSONArray payload = new org.json.JSONArray();
153
+ payload.put(errorData);
154
+
155
+ // Send SYNCHRONOUSLY - must complete before app terminates
156
+ sendNativeErrorToBackendSync(payload.toString());
157
+
158
+ } catch (Exception e) {
159
+ // Silently fail - don't crash the crash handler
160
+ e.printStackTrace();
161
+ }
162
+ }
163
+
164
+ private void sendNativeErrorToBackendSync(String jsonPayload) {
165
+ java.net.HttpURLConnection conn = null;
166
+ try {
167
+ java.net.URL url = new java.net.URL(intelligenceBackendUrl);
168
+ conn = (java.net.HttpURLConnection) url.openConnection();
169
+ conn.setRequestMethod("POST");
170
+ conn.setRequestProperty("Content-Type", "application/json");
171
+ conn.setDoOutput(true);
172
+ conn.setConnectTimeout(2000); // 2 second timeout - fast fail
173
+ conn.setReadTimeout(2000); // 2 second timeout - fast fail
174
+
175
+ java.io.OutputStream os = conn.getOutputStream();
176
+ os.write(jsonPayload.getBytes("UTF-8"));
177
+ os.flush();
178
+ os.close();
179
+
180
+ // Get response code to ensure request completed
181
+ int responseCode = conn.getResponseCode();
182
+
183
+ } catch (java.net.SocketTimeoutException e) {
184
+ // Silently fail - timeout
185
+ } catch (java.io.IOException e) {
186
+ // Silently fail - IO error
187
+ } catch (Exception e) {
188
+ // Silently fail - error
189
+ } finally {
190
+ // Always disconnect, even if error
191
+ if (conn != null) {
192
+ try {
193
+ conn.disconnect();
194
+ } catch (Exception e) {
195
+ // Ignore disconnect errors
196
+ }
197
+ }
198
+ }
199
+ }
200
+
56
201
  @PluginMethod
57
202
  public void startRecording(PluginCall call) {
58
203
  if (isRecording) {
@@ -70,43 +215,98 @@ public class CuoralPlugin extends Plugin {
70
215
  return;
71
216
  }
72
217
 
73
- // Request screen capture
74
- Intent captureIntent = projectionManager.createScreenCaptureIntent();
218
+ // Request screen capture - force entire screen mode only
219
+ Intent captureIntent;
220
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
221
+ // Android 14+ (API 34+): Use MediaProjectionConfig to force entire screen
222
+ // capture
223
+ android.media.projection.MediaProjectionConfig config = android.media.projection.MediaProjectionConfig
224
+ .createConfigForDefaultDisplay();
225
+ captureIntent = projectionManager.createScreenCaptureIntent(config);
226
+ } else {
227
+ // Older versions: Default to entire screen
228
+ captureIntent = projectionManager.createScreenCaptureIntent();
229
+ }
75
230
  startActivityForResult(call, captureIntent, "screenCaptureCallback");
76
231
  }
77
232
 
78
233
  @ActivityCallback
79
- private void screenCaptureCallback(PluginCall call, com.getcapacitor.PluginResult result) {
234
+ private void screenCaptureCallback(PluginCall call, ActivityResult result) {
80
235
  if (result.getResultCode() != Activity.RESULT_OK) {
81
236
  call.reject("Screen capture permission denied");
82
237
  return;
83
238
  }
84
239
 
85
- Intent data = result.getData();
86
- mediaProjection = projectionManager.getMediaProjection(result.getResultCode(), data);
87
-
88
- // Setup media recorder
89
- boolean includeAudio = call.getBoolean("includeAudio", false);
90
- float quality = call.getFloat("quality", 1.0f);
91
-
92
- try {
93
- setupMediaRecorder(includeAudio, quality);
94
- mediaRecorder.start();
95
- isRecording = true;
96
- recordingStartTime = System.currentTimeMillis();
97
-
98
- JSObject ret = new JSObject();
99
- ret.put("success", true);
100
- call.resolve(ret);
101
-
102
- // Notify listeners
103
- JSObject eventData = new JSObject();
104
- eventData.put("timestamp", recordingStartTime);
105
- notifyListeners("recordingStarted", eventData);
106
-
107
- } catch (Exception e) {
108
- call.reject("Failed to start recording: " + e.getMessage());
240
+ // Start foreground service for media projection
241
+ serviceIntent = new Intent(getContext(), ScreenRecordService.class);
242
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
243
+ getContext().startForegroundService(serviceIntent);
244
+ } else {
245
+ getContext().startService(serviceIntent);
109
246
  }
247
+
248
+ // Wait for service to enter foreground state before getting MediaProjection
249
+ // This is required on Android 14+ (API 34+)
250
+ getActivity().runOnUiThread(() -> {
251
+ android.os.Handler handler = new android.os.Handler();
252
+ handler.postDelayed(() -> {
253
+ try {
254
+ Intent data = result.getData();
255
+ mediaProjection = projectionManager.getMediaProjection(result.getResultCode(), data);
256
+
257
+ // Register callback for Android 14+ (required before creating virtual display)
258
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
259
+ mediaProjection.registerCallback(new android.media.projection.MediaProjection.Callback() {
260
+ @Override
261
+ public void onStop() {
262
+ super.onStop();
263
+ // Cleanup when projection stops
264
+ try {
265
+ if (isRecording) {
266
+ stopRecordingInternal();
267
+ }
268
+ } catch (Exception e) {
269
+ // Ignore cleanup errors
270
+ }
271
+ }
272
+ }, null);
273
+ }
274
+
275
+ // Setup media recorder
276
+ boolean includeAudio = call.getBoolean("includeAudio", false);
277
+ float quality = call.getFloat("quality", 1.0f);
278
+
279
+ setupMediaRecorder(includeAudio, quality);
280
+
281
+ // Create virtual display to capture screen
282
+ DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
283
+ virtualDisplay = mediaProjection.createVirtualDisplay(
284
+ "CuoralScreenCapture",
285
+ metrics.widthPixels,
286
+ metrics.heightPixels,
287
+ metrics.densityDpi,
288
+ android.view.Display.DEFAULT_DISPLAY,
289
+ mediaRecorder.getSurface(),
290
+ null,
291
+ null);
292
+
293
+ mediaRecorder.start();
294
+ isRecording = true;
295
+ recordingStartTime = System.currentTimeMillis();
296
+
297
+ JSObject ret = new JSObject();
298
+ ret.put("success", true);
299
+ call.resolve(ret);
300
+ } catch (Exception e) {
301
+ call.reject("Failed to start recording: " + e.getMessage());
302
+ // Stop service if recording failed
303
+ if (serviceIntent != null) {
304
+ getContext().stopService(serviceIntent);
305
+ serviceIntent = null;
306
+ }
307
+ }
308
+ }, 500); // 500ms delay to ensure service is in foreground
309
+ });
110
310
  }
111
311
 
112
312
  @ActivityCallback
@@ -119,6 +319,44 @@ public class CuoralPlugin extends Plugin {
119
319
  startRecording(call);
120
320
  }
121
321
 
322
+ /**
323
+ * Internal method to stop recording without resolving a PluginCall
324
+ * Used by MediaProjection callback
325
+ */
326
+ private void stopRecordingInternal() {
327
+ if (!isRecording) {
328
+ return;
329
+ }
330
+
331
+ try {
332
+ if (mediaRecorder != null) {
333
+ mediaRecorder.stop();
334
+ mediaRecorder.reset();
335
+ mediaRecorder.release();
336
+ mediaRecorder = null;
337
+ }
338
+
339
+ if (virtualDisplay != null) {
340
+ virtualDisplay.release();
341
+ virtualDisplay = null;
342
+ }
343
+
344
+ if (mediaProjection != null) {
345
+ mediaProjection.stop();
346
+ mediaProjection = null;
347
+ }
348
+
349
+ if (serviceIntent != null) {
350
+ getContext().stopService(serviceIntent);
351
+ serviceIntent = null;
352
+ }
353
+
354
+ isRecording = false;
355
+ } catch (Exception e) {
356
+ // Silently fail during cleanup
357
+ }
358
+ }
359
+
122
360
  @PluginMethod
123
361
  public void stopRecording(PluginCall call) {
124
362
  if (!isRecording) {
@@ -132,11 +370,22 @@ public class CuoralPlugin extends Plugin {
132
370
  mediaRecorder.release();
133
371
  mediaRecorder = null;
134
372
 
373
+ if (virtualDisplay != null) {
374
+ virtualDisplay.release();
375
+ virtualDisplay = null;
376
+ }
377
+
135
378
  if (mediaProjection != null) {
136
379
  mediaProjection.stop();
137
380
  mediaProjection = null;
138
381
  }
139
382
 
383
+ // Stop foreground service
384
+ if (serviceIntent != null) {
385
+ getContext().stopService(serviceIntent);
386
+ serviceIntent = null;
387
+ }
388
+
140
389
  isRecording = false;
141
390
  long duration = (System.currentTimeMillis() - recordingStartTime) / 1000;
142
391
 
@@ -230,7 +479,7 @@ public class CuoralPlugin extends Plugin {
230
479
  }
231
480
  }
232
481
 
233
- @ActivityCallback
482
+ @PermissionCallback
234
483
  private void permissionsCallback(PluginCall call) {
235
484
  JSObject ret = new JSObject();
236
485
  ret.put("granted", hasRequiredPermissions());
@@ -275,11 +524,19 @@ public class CuoralPlugin extends Plugin {
275
524
  Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
276
525
  }
277
526
 
278
- private boolean hasRequiredPermissions() {
279
- return hasAudioPermission() &&
280
- (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q ||
281
- ContextCompat.checkSelfPermission(getContext(),
282
- Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
527
+ @Override
528
+ public boolean hasRequiredPermissions() {
529
+ boolean hasAudio = hasAudioPermission();
530
+
531
+ // Android 10+ (API 29+) doesn't need WRITE_EXTERNAL_STORAGE for app-specific
532
+ // storage
533
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
534
+ return hasAudio;
535
+ }
536
+
537
+ // Android 9 and below need both RECORD_AUDIO and WRITE_EXTERNAL_STORAGE
538
+ return hasAudio && ContextCompat.checkSelfPermission(getContext(),
539
+ Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
283
540
  }
284
541
 
285
542
  private JSObject createErrorResult(String message) {
@@ -0,0 +1,59 @@
1
+ package com.cuoral.ionic;
2
+
3
+ import android.app.Notification;
4
+ import android.app.NotificationChannel;
5
+ import android.app.NotificationManager;
6
+ import android.app.Service;
7
+ import android.content.Intent;
8
+ import android.os.Build;
9
+ import android.os.IBinder;
10
+ import androidx.core.app.NotificationCompat;
11
+
12
+ public class ScreenRecordService extends Service {
13
+ private static final String CHANNEL_ID = "cuoral_screen_record_channel";
14
+ private static final int NOTIFICATION_ID = 1001;
15
+
16
+ @Override
17
+ public void onCreate() {
18
+ super.onCreate();
19
+ createNotificationChannel();
20
+ }
21
+
22
+ @Override
23
+ public int onStartCommand(Intent intent, int flags, int startId) {
24
+ Notification notification = createNotification();
25
+ startForeground(NOTIFICATION_ID, notification);
26
+ return START_NOT_STICKY;
27
+ }
28
+
29
+ @Override
30
+ public IBinder onBind(Intent intent) {
31
+ return null;
32
+ }
33
+
34
+ private void createNotificationChannel() {
35
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
36
+ NotificationChannel channel = new NotificationChannel(
37
+ CHANNEL_ID,
38
+ "Screen Recording",
39
+ NotificationManager.IMPORTANCE_LOW);
40
+ channel.setDescription("Screen recording in progress");
41
+
42
+ NotificationManager manager = getSystemService(NotificationManager.class);
43
+ if (manager != null) {
44
+ manager.createNotificationChannel(channel);
45
+ }
46
+ }
47
+ }
48
+
49
+ private Notification createNotification() {
50
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
51
+ .setContentTitle("Screen Recording")
52
+ .setContentText("Recording your screen...")
53
+ .setSmallIcon(android.R.drawable.ic_menu_view)
54
+ .setPriority(NotificationCompat.PRIORITY_LOW)
55
+ .setOngoing(true);
56
+
57
+ return builder.build();
58
+ }
59
+ }
package/dist/cuoral.d.ts CHANGED
@@ -15,6 +15,7 @@ export declare class Cuoral {
15
15
  private bridge;
16
16
  private recorder;
17
17
  private modal?;
18
+ private intelligence?;
18
19
  private options;
19
20
  private static readonly PRODUCTION_WIDGET_URL;
20
21
  private static readonly DEV_WIDGET_URL;
@@ -22,7 +23,23 @@ export declare class Cuoral {
22
23
  /**
23
24
  * Initialize Cuoral
24
25
  */
25
- initialize(): void;
26
+ initialize(): Promise<void>;
27
+ /**
28
+ * Initialize intelligence based on backend configuration
29
+ */
30
+ private initializeIntelligence;
31
+ /**
32
+ * Fetch session configuration from backend
33
+ */
34
+ private fetchSessionConfiguration;
35
+ /**
36
+ * Track a page/screen view
37
+ */
38
+ trackPageView(screen: string, metadata?: any): void;
39
+ /**
40
+ * Track an error manually
41
+ */
42
+ trackError(message: string, stackTrace?: string, metadata?: any): void;
26
43
  /**
27
44
  * Open the widget modal
28
45
  */
@@ -43,6 +60,18 @@ export declare class Cuoral {
43
60
  * Clean up resources
44
61
  */
45
62
  destroy(): void;
63
+ /**
64
+ * Get or create session ID
65
+ */
66
+ private getOrCreateSessionId;
67
+ /**
68
+ * Initiate a new session with backend (like inline.js does)
69
+ */
70
+ private initiateSession;
71
+ /**
72
+ * Set user profile for the session
73
+ */
74
+ private setProfile;
46
75
  /**
47
76
  * Setup automatic message handlers
48
77
  */
@@ -1 +1 @@
1
- {"version":3,"file":"cuoral.d.ts","sourceRoot":"","sources":["../src/cuoral.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,KAAK,CAAC,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAuC;IACpF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAwB;gBAElD,OAAO,EAAE,aAAa;IAsClC;;OAEG;IACI,UAAU,IAAI,IAAI;IASzB;;OAEG;IACI,SAAS,IAAI,IAAI;IAMxB;;OAEG;IACI,UAAU,IAAI,IAAI;IAMzB;;OAEG;IACI,WAAW,IAAI,OAAO;IAI7B;;OAEG;IACI,YAAY,IAAI,MAAM;IAe7B;;OAEG;IACI,OAAO,IAAI,IAAI;IAStB;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAuE7B"}
1
+ {"version":3,"file":"cuoral.d.ts","sourceRoot":"","sources":["../src/cuoral.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAeD;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,KAAK,CAAC,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAC,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAuC;IACpF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAwB;gBAElD,OAAO,EAAE,aAAa;IA2ClC;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYxC;;OAEG;YACW,sBAAsB;IAwCpC;;OAEG;YACW,yBAAyB;IAoCvC;;OAEG;IACI,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,IAAI;IAM1D;;OAEG;IACI,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,IAAI;IAM7E;;OAEG;IACI,SAAS,IAAI,IAAI;IAMxB;;OAEG;IACI,UAAU,IAAI,IAAI;IAMzB;;OAEG;IACI,WAAW,IAAI,OAAO;IAI7B;;OAEG;IACI,YAAY,IAAI,MAAM;IAe7B;;OAEG;IACI,OAAO,IAAI,IAAI;IActB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;OAEG;YACW,eAAe;IAmC7B;;OAEG;YACW,UAAU;IAmBxB;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAuE7B"}