omikit-plugin 3.3.5 → 3.3.7

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.
@@ -37,12 +37,70 @@ import vn.vihat.omicall.omisdk.utils.Utils
37
37
  import java.util.Timer
38
38
  import java.util.TimerTask
39
39
 
40
+ /**
41
+ * OmiSDK Registration Status Mapping
42
+ */
43
+ object OmiRegistrationStatus {
44
+ private val statusMap = mapOf(
45
+ // Success
46
+ 200 to ("ERROR_SUCCESS" to "Registration successful"),
47
+
48
+ // Parameter validation errors (4xx)
49
+ 400 to ("ERROR_MISSING_PARAMETERS" to "Missing required parameters. Please check your configuration."),
50
+ 401 to ("ERROR_INVALID_CREDENTIALS" to "Invalid credentials. Please check username/password."),
51
+
52
+ // Permission errors (45x) - Android specific
53
+ 450 to ("ERROR_MISSING_RECORD_AUDIO" to "RECORD_AUDIO permission required for Android 14+"),
54
+ 451 to ("ERROR_MISSING_FOREGROUND_SERVICE" to "FOREGROUND_SERVICE permission required"),
55
+ 452 to ("ERROR_MISSING_POST_NOTIFICATIONS" to "POST_NOTIFICATIONS permission required for Android 13+"),
56
+
57
+ // Service errors (5xx)
58
+ 500 to ("ERROR_SERVICE_START_FAILED" to "Failed to start SIP service"),
59
+ 501 to ("ERROR_SERVICE_NOT_AVAILABLE" to "SIP service not available"),
60
+ 502 to ("ERROR_SERVICE_DEGRADED" to "Service degraded - may miss calls when app killed"),
61
+
62
+ // Network errors (6xx)
63
+ 600 to ("ERROR_NETWORK_UNAVAILABLE" to "Network unavailable"),
64
+ 601 to ("ERROR_CONNECTION_TIMEOUT" to "Connection timeout"),
65
+
66
+ // Legacy compatibility
67
+ 403 to ("ERROR_FORBIDDEN" to "Access denied. Check realm/domain permissions."),
68
+ 404 to ("ERROR_REALM_NOT_FOUND" to "Realm not found. Check configuration."),
69
+ 408 to ("ERROR_TIMEOUT" to "Connection timeout"),
70
+ 503 to ("ERROR_SERVICE_UNAVAILABLE" to "Service temporarily unavailable"),
71
+
72
+ // Unknown
73
+ 999 to ("ERROR_UNKNOWN" to "Unknown error occurred")
74
+ )
75
+
76
+ fun getError(code: Int): Pair<String, String> {
77
+ return statusMap[code] ?: ("ERROR_REGISTRATION_FAILED" to "Registration failed (Status: $code)")
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Helper functions for parameter validation
83
+ */
84
+ object ValidationHelper {
85
+ fun validateRequired(params: Map<String, String?>, promise: Promise): Boolean {
86
+ params.forEach { (key, value) ->
87
+ if (value.isNullOrEmpty()) {
88
+ val errorCode = "ERROR_MISSING_${key.uppercase()}"
89
+ val message = "$key is required for OMICALL initialization. Please provide a valid $key."
90
+ promise.reject(errorCode, message)
91
+ return false
92
+ }
93
+ }
94
+ return true
95
+ }
96
+ }
40
97
 
41
98
  class OmikitPluginModule(reactContext: ReactApplicationContext?) :
42
99
  ReactContextBaseJavaModule(reactContext), ActivityEventListener, OmiListener {
43
100
  private val mainScope = CoroutineScope(Dispatchers.Main)
44
101
  private var isIncoming: Boolean = false
45
102
  private var isAnswerCall: Boolean = false
103
+ private var permissionPromise: Promise? = null
46
104
 
47
105
  override fun getName(): String {
48
106
  return NAME
@@ -522,58 +580,57 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
522
580
 
523
581
  currentActivity?.runOnUiThread {
524
582
  try {
525
- // Lấy các giá trị từ data với null safety
526
- val notificationIcon = data.getString("notificationIcon") ?: ""
527
- val prefix = data?.getString("prefix") ?: ""
528
- val incomingBackgroundColor = data?.getString("incomingBackgroundColor") ?: ""
529
- val incomingAcceptButtonImage = data?.getString("incomingAcceptButtonImage") ?: ""
530
- val incomingDeclineButtonImage = data?.getString("incomingDeclineButtonImage") ?: ""
531
- val prefixMissedCallMessage = data?.getString("prefixMissedCallMessage") ?: ""
532
- val backImage = data?.getString("backImage") ?: ""
533
- val userImage = data?.getString("userImage") ?: ""
534
- val userNameKey = data?.getString("userNameKey") ?: ""
535
- val channelId = data?.getString("channelId") ?: ""
536
- val missedCallTitle = data?.getString("missedCallTitle") ?: ""
537
- val audioNotificationDescription = data?.getString("audioNotificationDescription") ?: ""
538
- val videoNotificationDescription = data?.getString("videoNotificationDescription") ?: ""
539
- val displayNameType = data?.getString("displayNameType") ?: ""
540
- val appRepresentName = data?.getString("representName") ?: ""
541
- // Chuyển đổi isUserBusy thành Boolean
542
- val isUserBusy = data.getBoolean("isUserBusy") ?: true
543
-
544
- // Cấu hình push notification
545
- OmiClient.getInstance(context).configPushNotification(
583
+ // Extract parameters from data with proper defaults
584
+ val notificationIcon = data.getString("notificationIcon") ?: "ic_notification"
585
+ val incomingBackgroundColor = data.getString("incomingBackgroundColor") ?: "#FFFFFF"
586
+ val incomingAcceptButtonImage = data.getString("incomingAcceptButtonImage") ?: "ic_accept"
587
+ val incomingDeclineButtonImage = data.getString("incomingDeclineButtonImage") ?: "ic_decline"
588
+ val prefixMissedCallMessage = data.getString("prefixMissedCallMessage") ?: "Cuộc gọi nhỡ từ"
589
+ val backImage = data.getString("backImage") ?: "ic_back"
590
+ val userImage = data.getString("userImage") ?: "ic_user"
591
+ val userNameKey = data.getString("userNameKey") ?: "full_name"
592
+ val channelId = data.getString("channelId") ?: "omicall_channel"
593
+ val missedCallTitle = data.getString("missedCallTitle") ?: "Cuộc gọi nhỡ"
594
+ val audioNotificationDescription = data.getString("audioNotificationDescription") ?: "Cuộc gọi audio"
595
+ val videoNotificationDescription = data.getString("videoNotificationDescription") ?: "Cuộc gọi video"
596
+ val representName = data.getString("representName") ?: ""
597
+ val isUserBusy = data.getBoolean("isUserBusy")
598
+
599
+ // Configure push notification with extracted parameters
600
+ OmiClient.getInstance(context).configPushNotification(
546
601
  showMissedCall = true,
547
- notificationIcon = notificationIcon ?: "ic_notification",
548
- notificationAvatar = userImage ?: "ic_inbound_avatar_notification",
549
- fullScreenAvatar = userImage ?: "ic_inbound_avatar_fullscreen",
602
+ notificationIcon = notificationIcon,
603
+ notificationAvatar = userImage,
604
+ fullScreenAvatar = userImage,
550
605
  internalCallText = "Gọi nội bộ",
551
- videoCallText = "Gọi Video",
552
- inboundCallText = prefix,
606
+ videoCallText = videoNotificationDescription,
607
+ inboundCallText = audioNotificationDescription,
553
608
  unknownContactText = "Cuộc gọi không xác định",
554
609
  showUUID = false,
555
610
  inboundChannelId = "${channelId}-inbound",
556
611
  inboundChannelName = "Cuộc gọi đến",
557
612
  missedChannelId = "${channelId}-missed",
558
- missedChannelName = "Cuộc gọi nhỡ",
559
- displayNameType = userNameKey ?: "full_name",
560
- notificationMissedCallPrefix = prefixMissedCallMessage ?: "Cuộc gọi nhỡ từ",
561
- representName = appRepresentName ?: ""
562
- )
613
+ missedChannelName = missedCallTitle,
614
+ displayNameType = userNameKey,
615
+ notificationMissedCallPrefix = prefixMissedCallMessage,
616
+ representName = representName
617
+ )
563
618
 
564
- // Cấu hình decline call behavior
619
+ // Configure decline call behavior
565
620
  OmiClient.getInstance(context).configureDeclineCallBehavior(isUserBusy)
566
621
 
622
+ Log.d("OmikitPlugin", "✅ Push notification configured successfully")
567
623
  promise.resolve(true)
568
624
  } catch (e: Exception) {
569
- Log.e("OmikitPlugin", "Error configuring push notification: ${e.message}", e)
625
+ Log.e("OmikitPlugin", "Error configuring push notification: ${e.message}", e)
570
626
  promise.reject("E_CONFIG_FAILED", "Failed to configure push notification", e)
571
627
  }
572
628
  } ?: run {
629
+ Log.e("OmikitPlugin", "❌ Current activity is null")
573
630
  promise.reject("E_NULL_ACTIVITY", "Current activity is null")
574
631
  }
575
632
  } catch (e: Exception) {
576
- Log.e("OmikitPlugin", "Error in configPushNotification: ${e.message}", e)
633
+ Log.e("OmikitPlugin", "Error in configPushNotification: ${e.message}", e)
577
634
  promise.reject("E_UNKNOWN", "Unknown error occurred", e)
578
635
  }
579
636
  }
@@ -590,11 +647,12 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
590
647
  val projectId = data.getString("projectId") ?: ""
591
648
 
592
649
  // Validate required parameters
593
- if (userName.isNullOrEmpty() || password.isNullOrEmpty() || realm.isNullOrEmpty() || firebaseToken.isNullOrEmpty()) {
594
- Log.e("OmikitPlugin", "❌ Missing required parameters for SIP registration")
595
- promise.reject("ERROR_REGISTRATION", "Missing required parameters for OMISIP registration")
596
- return@launch
597
- }
650
+ if (!ValidationHelper.validateRequired(mapOf(
651
+ "userName" to userName,
652
+ "password" to password,
653
+ "realm" to realm,
654
+ "fcmToken" to firebaseToken
655
+ ), promise)) return@launch
598
656
 
599
657
  withContext(Dispatchers.Default) {
600
658
  try {
@@ -610,11 +668,11 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
610
668
  Log.d("OmikitPlugin", "🔇 Using Silent Registration API for user: $userName")
611
669
 
612
670
  OmiClient.getInstance(reactApplicationContext!!).silentRegister(
613
- userName = userName,
614
- password = password,
615
- realm = realm,
671
+ userName = userName ?: "",
672
+ password = password ?: "",
673
+ realm = realm ?: "",
616
674
  isVideo = isVideo ?: true,
617
- firebaseToken = firebaseToken,
675
+ firebaseToken = firebaseToken ?: "",
618
676
  host = host,
619
677
  projectId = projectId
620
678
  ) { success, statusCode, message ->
@@ -625,13 +683,18 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
625
683
  promise.resolve(success)
626
684
  } else {
627
685
  Log.e("OmikitPlugin", "❌ Silent registration failed: $message")
628
- promise.reject("ERROR_REGISTRATION", "OMISDK init account failed with status: $statusCode, message: $message")
686
+ if (statusCode == 200) {
687
+ promise.resolve(true)
688
+ } else {
689
+ val (errorCode, errorMessage) = OmiRegistrationStatus.getError(statusCode)
690
+ promise.reject(errorCode, "$errorMessage (Status: $statusCode)")
691
+ }
629
692
  }
630
693
  }
631
694
 
632
695
  } catch (e: Exception) {
633
696
  Log.e("OmikitPlugin", "❌ Error during silent registration: ${e.message}", e)
634
- promise.reject("ERROR_REGISTRATION", "OMISDK innit account Fail: ${e.message}", e)
697
+ promise.reject("ERROR_INITIALIZATION_EXCEPTION", "OMICALL initialization failed due to an unexpected error: ${e.message}. Please check your network connection and configuration.", e)
635
698
  }
636
699
  }
637
700
  }
@@ -652,27 +715,36 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
652
715
  requestPermission(isVideo)
653
716
  withContext(Dispatchers.Default) {
654
717
  try {
655
- if (usrName != null && usrUuid != null && apiKey != null && firebaseToken != null) {
656
- loginResult = OmiClient.registerWithApiKey(
657
- apiKey = apiKey,
658
- userName = usrName,
659
- uuid = usrUuid,
660
- phone = phone ?: "",
661
- isVideo = isVideo,
662
- firebaseToken,
663
- projectId
664
- )
665
-
666
- // Sử dụng API mới để ngăn chặn AUTO-UNREGISTER sau khi register thành công
667
- if (loginResult) {
668
- Log.d("OmikitPlugin", "🛡️ Preventing AUTO-UNREGISTER after successful API key registration")
669
- preventAutoUnregisterCrash("Successful API key registration - userName: $usrName")
670
- }
671
-
718
+ // Validate required parameters
719
+ if (!ValidationHelper.validateRequired(mapOf(
720
+ "fullName" to usrName,
721
+ "usrUuid" to usrUuid,
722
+ "apiKey" to apiKey,
723
+ "fcmToken" to firebaseToken
724
+ ), promise)) return@withContext
725
+
726
+ loginResult = OmiClient.registerWithApiKey(
727
+ apiKey = apiKey ?: "",
728
+ userName = usrName ?: "",
729
+ uuid = usrUuid ?: "",
730
+ phone = phone ?: "",
731
+ isVideo = isVideo,
732
+ firebaseToken,
733
+ projectId
734
+ )
735
+
736
+ // ✅ Sử dụng API mới để ngăn chặn AUTO-UNREGISTER sau khi register thành công
737
+ if (loginResult) {
738
+ Log.d("OmikitPlugin", "🛡️ Preventing AUTO-UNREGISTER after successful API key registration")
739
+ preventAutoUnregisterCrash("Successful API key registration - userName: $usrName")
672
740
  promise.resolve(true)
741
+ } else {
742
+ Log.e("OmikitPlugin", "❌ API key registration failed")
743
+ promise.reject("ERROR_API_KEY_REGISTRATION_FAILED", "OMICALL API key initialization failed. Please check your API key, UUID, and network connection.")
673
744
  }
674
- } catch (_: Throwable) {
675
- promise.resolve(loginResult)
745
+ } catch (e: Exception) {
746
+ Log.e("OmikitPlugin", "❌ Error during API key registration: ${e.message}", e)
747
+ promise.reject("ERROR_API_KEY_INITIALIZATION_EXCEPTION", "OMICALL API key initialization failed due to an unexpected error: ${e.message}. Please check your configuration and network connection.", e)
676
748
  }
677
749
  }
678
750
  }
@@ -1098,6 +1170,8 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
1098
1170
 
1099
1171
  companion object {
1100
1172
  const val NAME = "OmikitPlugin"
1173
+ const val REQUEST_PERMISSIONS_CODE = 1001
1174
+ const val REQUEST_OVERLAY_PERMISSION_CODE = 1002
1101
1175
 
1102
1176
  fun onDestroy() {
1103
1177
  try {
@@ -1122,9 +1196,55 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
1122
1196
  act: ReactActivity,
1123
1197
  ) {
1124
1198
  act.runOnUiThread {
1199
+ // Handle our custom permission request
1200
+ if (requestCode == REQUEST_PERMISSIONS_CODE) {
1201
+ handlePermissionResults(permissions, grantResults, act)
1202
+ }
1203
+
1204
+ // Also handle SDK permission request
1125
1205
  OmiSDKUtils.handlePermissionRequest(requestCode, permissions, grantResults, act)
1126
1206
  }
1127
1207
  }
1208
+
1209
+ private fun handlePermissionResults(
1210
+ permissions: Array<out String>,
1211
+ grantResults: IntArray,
1212
+ act: ReactActivity
1213
+ ) {
1214
+ try {
1215
+ val deniedPermissions = mutableListOf<String>()
1216
+ val grantedPermissions = mutableListOf<String>()
1217
+
1218
+ for (i in permissions.indices) {
1219
+ if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
1220
+ grantedPermissions.add(permissions[i])
1221
+ } else {
1222
+ deniedPermissions.add(permissions[i])
1223
+ }
1224
+ }
1225
+
1226
+ Log.d("OmikitPlugin", "✅ Granted: ${grantedPermissions.joinToString()}")
1227
+ if (deniedPermissions.isNotEmpty()) {
1228
+ Log.w("OmikitPlugin", "❌ Denied: ${deniedPermissions.joinToString()}")
1229
+ }
1230
+
1231
+ // Check if we have essential permissions for VoIP
1232
+ val hasRecordAudio = grantedPermissions.contains(Manifest.permission.RECORD_AUDIO)
1233
+ val hasCallPhone = grantedPermissions.contains(Manifest.permission.CALL_PHONE)
1234
+ val hasModifyAudio = grantedPermissions.contains(Manifest.permission.MODIFY_AUDIO_SETTINGS)
1235
+
1236
+ val canProceed = hasRecordAudio && hasCallPhone && hasModifyAudio
1237
+
1238
+ if (canProceed) {
1239
+ Log.d("OmikitPlugin", "🎉 Essential VoIP permissions granted!")
1240
+ } else {
1241
+ Log.e("OmikitPlugin", "⚠️ Missing essential VoIP permissions - app may not work properly")
1242
+ }
1243
+
1244
+ } catch (e: Exception) {
1245
+ Log.e("OmikitPlugin", "❌ Error handling permission results: ${e.message}", e)
1246
+ }
1247
+ }
1128
1248
 
1129
1249
  fun onGetIntentFromNotification(
1130
1250
  context: ReactApplicationContext,
@@ -1216,28 +1336,224 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
1216
1336
  )
1217
1337
  }
1218
1338
 
1219
- private fun requestPermission(isVideo: Boolean) {
1220
- var permissions = arrayOf(
1339
+ @ReactMethod
1340
+ fun checkAndRequestPermissions(isVideo: Boolean, promise: Promise) {
1341
+ try {
1342
+ val missingPermissions = getMissingPermissions(isVideo)
1343
+
1344
+ if (missingPermissions.isEmpty()) {
1345
+ Log.d("OmikitPlugin", "✅ All permissions already granted")
1346
+ promise.resolve(true)
1347
+ return
1348
+ }
1349
+
1350
+ Log.d("OmikitPlugin", "📋 Missing permissions: ${missingPermissions.joinToString()}")
1351
+
1352
+ // Store promise for callback
1353
+ permissionPromise = promise
1354
+
1355
+ ActivityCompat.requestPermissions(
1356
+ reactApplicationContext.currentActivity!!,
1357
+ missingPermissions.toTypedArray(),
1358
+ REQUEST_PERMISSIONS_CODE,
1359
+ )
1360
+ } catch (e: Exception) {
1361
+ Log.e("OmikitPlugin", "❌ Error checking permissions: ${e.message}", e)
1362
+ promise.resolve(false)
1363
+ }
1364
+ }
1365
+
1366
+ private fun getMissingPermissions(isVideo: Boolean): List<String> {
1367
+ val allPermissions = mutableListOf<String>()
1368
+
1369
+ // Basic permissions for VoIP
1370
+ allPermissions.addAll(arrayOf(
1221
1371
  Manifest.permission.USE_SIP,
1222
1372
  Manifest.permission.CALL_PHONE,
1223
1373
  Manifest.permission.MODIFY_AUDIO_SETTINGS,
1224
1374
  Manifest.permission.RECORD_AUDIO,
1225
- )
1375
+ ))
1376
+
1377
+ // Video call permissions
1226
1378
  if (isVideo) {
1227
- permissions = permissions.plus(Manifest.permission.CAMERA)
1379
+ allPermissions.add(Manifest.permission.CAMERA)
1228
1380
  }
1381
+
1382
+ // Android 13+ notifications
1229
1383
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
1230
- permissions = permissions.plus(Manifest.permission.POST_NOTIFICATIONS)
1384
+ allPermissions.add(Manifest.permission.POST_NOTIFICATIONS)
1231
1385
  }
1386
+
1387
+ // Android 14+ foreground service permissions
1232
1388
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
1233
- // Add foreground service permissions for SDK 34+
1234
- permissions = permissions.plus(Manifest.permission.FOREGROUND_SERVICE_MICROPHONE)
1235
- permissions = permissions.plus(Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL)
1389
+ allPermissions.addAll(arrayOf(
1390
+ Manifest.permission.FOREGROUND_SERVICE_MICROPHONE,
1391
+ Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL
1392
+ ))
1236
1393
  }
1394
+
1395
+ return allPermissions.filter { permission ->
1396
+ ContextCompat.checkSelfPermission(reactApplicationContext, permission) != PackageManager.PERMISSION_GRANTED
1397
+ }
1398
+ }
1399
+
1400
+ @ReactMethod
1401
+ fun checkPermissionStatus(promise: Promise) {
1402
+ try {
1403
+ val permissionStatus = mutableMapOf<String, Any>()
1404
+
1405
+ // Essential permissions
1406
+ val essentialPermissions = arrayOf(
1407
+ Manifest.permission.RECORD_AUDIO,
1408
+ Manifest.permission.CALL_PHONE,
1409
+ Manifest.permission.MODIFY_AUDIO_SETTINGS,
1410
+ Manifest.permission.USE_SIP
1411
+ )
1412
+
1413
+ // Check essential permissions
1414
+ val missingEssential = mutableListOf<String>()
1415
+ val grantedEssential = mutableListOf<String>()
1416
+
1417
+ essentialPermissions.forEach { permission ->
1418
+ if (ContextCompat.checkSelfPermission(reactApplicationContext, permission) == PackageManager.PERMISSION_GRANTED) {
1419
+ grantedEssential.add(permission)
1420
+ } else {
1421
+ missingEssential.add(permission)
1422
+ }
1423
+ }
1424
+
1425
+ // Check Android 14+ foreground service permissions
1426
+ val foregroundServiceStatus = mutableMapOf<String, Boolean>()
1427
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
1428
+ foregroundServiceStatus["FOREGROUND_SERVICE_MICROPHONE"] = ContextCompat.checkSelfPermission(
1429
+ reactApplicationContext,
1430
+ Manifest.permission.FOREGROUND_SERVICE_MICROPHONE
1431
+ ) == PackageManager.PERMISSION_GRANTED
1432
+
1433
+ foregroundServiceStatus["FOREGROUND_SERVICE_PHONE_CALL"] = ContextCompat.checkSelfPermission(
1434
+ reactApplicationContext,
1435
+ Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL
1436
+ ) == PackageManager.PERMISSION_GRANTED
1437
+ }
1438
+
1439
+ // Check system alert window permission
1440
+ val canDrawOverlays = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
1441
+ Settings.canDrawOverlays(reactApplicationContext)
1442
+ } else {
1443
+ true
1444
+ }
1445
+
1446
+ permissionStatus["essentialGranted"] = grantedEssential
1447
+ permissionStatus["essentialMissing"] = missingEssential
1448
+ permissionStatus["canMakeVoipCalls"] = missingEssential.isEmpty()
1449
+ permissionStatus["foregroundServicePermissions"] = foregroundServiceStatus
1450
+ permissionStatus["canDrawOverlays"] = canDrawOverlays
1451
+ permissionStatus["androidVersion"] = Build.VERSION.SDK_INT
1452
+ permissionStatus["targetSdk"] = reactApplicationContext.applicationInfo.targetSdkVersion
1453
+
1454
+ val map = Arguments.makeNativeMap(permissionStatus)
1455
+ promise.resolve(map)
1456
+
1457
+ } catch (e: Exception) {
1458
+ Log.e("OmikitPlugin", "❌ Error checking permission status: ${e.message}", e)
1459
+ promise.resolve(null)
1460
+ }
1461
+ }
1462
+
1463
+ @ReactMethod
1464
+ fun requestSystemAlertWindowPermission(promise: Promise) {
1465
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
1466
+ if (!Settings.canDrawOverlays(reactApplicationContext)) {
1467
+ permissionPromise = promise
1468
+ val intent = Intent(
1469
+ Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
1470
+ Uri.parse("package:${reactApplicationContext.packageName}")
1471
+ )
1472
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
1473
+ reactApplicationContext.currentActivity?.startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION_CODE)
1474
+ } else {
1475
+ promise.resolve(true)
1476
+ }
1477
+ } else {
1478
+ promise.resolve(true)
1479
+ }
1480
+ }
1481
+
1482
+ /**
1483
+ * Request specific permissions for error codes 450, 451, 452
1484
+ * Shows permission request popup for customers
1485
+ * @param codes - Array of permission codes to request (450, 451, 452)
1486
+ * @param promise - Promise to resolve with request result
1487
+ */
1488
+ @ReactMethod
1489
+ fun requestPermissionsByCodes(codes: ReadableArray, promise: Promise) {
1490
+ try {
1491
+ val permissionCodes = codes.toArrayList().map { it.toString().toInt() }
1492
+ val permissionsToRequest = mutableListOf<String>()
1493
+
1494
+ for (code in permissionCodes) {
1495
+ when (code) {
1496
+ 450 -> { // RECORD_AUDIO permission
1497
+ if (ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
1498
+ permissionsToRequest.add(Manifest.permission.RECORD_AUDIO)
1499
+ }
1500
+ }
1501
+ 451 -> { // FOREGROUND_SERVICE permissions
1502
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
1503
+ if (ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.FOREGROUND_SERVICE_MICROPHONE) != PackageManager.PERMISSION_GRANTED) {
1504
+ permissionsToRequest.add(Manifest.permission.FOREGROUND_SERVICE_MICROPHONE)
1505
+ }
1506
+ if (ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL) != PackageManager.PERMISSION_GRANTED) {
1507
+ permissionsToRequest.add(Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL)
1508
+ }
1509
+ }
1510
+ }
1511
+ 452 -> { // POST_NOTIFICATIONS permission
1512
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
1513
+ if (ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
1514
+ permissionsToRequest.add(Manifest.permission.POST_NOTIFICATIONS)
1515
+ }
1516
+ }
1517
+ }
1518
+ }
1519
+ }
1520
+
1521
+ if (permissionsToRequest.isEmpty()) {
1522
+ promise.resolve(true)
1523
+ return
1524
+ }
1525
+
1526
+ // Store promise for callback
1527
+ permissionPromise = promise
1528
+
1529
+ Log.d("OmikitPlugin", "🔐 Requesting permissions for codes ${permissionCodes.joinToString()}: ${permissionsToRequest.joinToString()}")
1530
+
1531
+ ActivityCompat.requestPermissions(
1532
+ reactApplicationContext.currentActivity!!,
1533
+ permissionsToRequest.toTypedArray(),
1534
+ REQUEST_PERMISSIONS_CODE
1535
+ )
1536
+
1537
+ } catch (e: Exception) {
1538
+ Log.e("OmikitPlugin", "❌ Error requesting permissions by codes: ${e.message}", e)
1539
+ promise.reject("ERROR_PERMISSION_REQUEST", "Failed to request permissions: ${e.message}")
1540
+ }
1541
+ }
1542
+
1543
+ private fun requestPermission(isVideo: Boolean) {
1544
+ val missingPermissions = getMissingPermissions(isVideo)
1545
+
1546
+ if (missingPermissions.isEmpty()) {
1547
+ Log.d("OmikitPlugin", "✅ All permissions already granted")
1548
+ return
1549
+ }
1550
+
1551
+ Log.d("OmikitPlugin", "📋 Requesting missing permissions for Android ${Build.VERSION.SDK_INT}: ${missingPermissions.joinToString()}")
1552
+
1237
1553
  ActivityCompat.requestPermissions(
1238
1554
  reactApplicationContext.currentActivity!!,
1239
- permissions,
1240
- 0,
1555
+ missingPermissions.toTypedArray(),
1556
+ REQUEST_PERMISSIONS_CODE,
1241
1557
  )
1242
1558
  }
1243
1559
 
@@ -1426,10 +1742,10 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
1426
1742
  Log.d("OmikitPlugin", "🔍 Checking credentials for user: $userName")
1427
1743
 
1428
1744
  OmiClient.getInstance(reactApplicationContext!!).checkCredentials(
1429
- userName = userName,
1430
- password = password,
1431
- realm = realm,
1432
- firebaseToken = firebaseToken,
1745
+ userName = userName ?: "",
1746
+ password = password ?: "",
1747
+ realm = realm ?: "",
1748
+ firebaseToken = firebaseToken ?: "",
1433
1749
  host = host,
1434
1750
  projectId = projectId
1435
1751
  ) { success, statusCode, message ->
@@ -1482,12 +1798,12 @@ class OmikitPluginModule(reactContext: ReactApplicationContext?) :
1482
1798
  Log.d("OmikitPlugin", "⚙️ Registering with options for user: $userName - showNotification: $showNotification, enableAutoUnregister: $enableAutoUnregister")
1483
1799
 
1484
1800
  OmiClient.getInstance(reactApplicationContext!!).registerWithOptions(
1485
- userName = userName,
1486
- password = password,
1487
- realm = realm,
1801
+ userName = userName ?: "",
1802
+ password = password ?: "",
1803
+ realm = realm ?: "",
1488
1804
  isVideo = isVideo ?: true,
1489
- firebaseToken = firebaseToken,
1490
- host = host,
1805
+ firebaseToken = firebaseToken ?: "",
1806
+ host = host ,
1491
1807
  projectId = projectId,
1492
1808
  showNotification = showNotification,
1493
1809
  enableAutoUnregister = enableAutoUnregister
@@ -1 +1 @@
1
- {"version":3,"names":["_omikit","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_omi_local_camera","_omi_remote_camera","_omi_call_state","_omi_start_call_status"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,OAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,OAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,OAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,iBAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,iBAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,iBAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,iBAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,kBAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,kBAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,kBAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,kBAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,eAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,eAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,eAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,eAAA,CAAAP,GAAA;IAAA;EAAA;AAAA;AACA,IAAAQ,sBAAA,GAAAZ,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAU,sBAAA,EAAAT,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,sBAAA,CAAAR,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAI,sBAAA,CAAAR,GAAA;IAAA;EAAA;AAAA"}
1
+ {"version":3,"names":["_omikit","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_omi_local_camera","_omi_remote_camera","_omi_call_state","_omi_start_call_status"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,OAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,OAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,OAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,iBAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,iBAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,iBAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,iBAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,kBAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,kBAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,kBAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,kBAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,eAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,eAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,eAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,eAAA,CAAAP,GAAA;IAAA;EAAA;AAAA;AACA,IAAAQ,sBAAA,GAAAZ,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAU,sBAAA,EAAAT,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,sBAAA,CAAAR,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAI,sBAAA,CAAAR,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
@@ -4,9 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.OmiCallState = void 0;
7
- let OmiCallState;
8
- exports.OmiCallState = OmiCallState;
9
- (function (OmiCallState) {
7
+ let OmiCallState = exports.OmiCallState = /*#__PURE__*/function (OmiCallState) {
10
8
  OmiCallState[OmiCallState["unknown"] = 0] = "unknown";
11
9
  OmiCallState[OmiCallState["calling"] = 1] = "calling";
12
10
  OmiCallState[OmiCallState["incoming"] = 2] = "incoming";
@@ -15,5 +13,6 @@ exports.OmiCallState = OmiCallState;
15
13
  OmiCallState[OmiCallState["confirmed"] = 5] = "confirmed";
16
14
  OmiCallState[OmiCallState["disconnected"] = 6] = "disconnected";
17
15
  OmiCallState[OmiCallState["hold"] = 7] = "hold";
18
- })(OmiCallState || (exports.OmiCallState = OmiCallState = {}));
16
+ return OmiCallState;
17
+ }({});
19
18
  //# sourceMappingURL=omi_call_state.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["OmiCallState","exports"],"sourceRoot":"../../src","sources":["omi_call_state.tsx"],"mappings":";;;;;;IAAYA,YAAY;AAAAC,OAAA,CAAAD,YAAA,GAAAA,YAAA;AAAA,WAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;AAAA,GAAZA,YAAY,KAAAC,OAAA,CAAAD,YAAA,GAAZA,YAAY"}
1
+ {"version":3,"names":["OmiCallState","exports"],"sourceRoot":"../../src","sources":["omi_call_state.tsx"],"mappings":";;;;;;IAAYA,YAAY,GAAAC,OAAA,CAAAD,YAAA,0BAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA","ignoreList":[]}
@@ -7,8 +7,7 @@ exports.OmiLocalCameraView = void 0;
7
7
  exports.refreshLocalCamera = refreshLocalCamera;
8
8
  var _reactNative = require("react-native");
9
9
  const FLLocalCamera = _reactNative.NativeModules.FLLocalCameraView;
10
- const OmiLocalCameraView = (0, _reactNative.requireNativeComponent)('FLLocalCameraView');
11
- exports.OmiLocalCameraView = OmiLocalCameraView;
10
+ const OmiLocalCameraView = exports.OmiLocalCameraView = (0, _reactNative.requireNativeComponent)('FLLocalCameraView');
12
11
  function refreshLocalCamera() {
13
12
  return FLLocalCamera.refresh();
14
13
  }
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","FLLocalCamera","NativeModules","FLLocalCameraView","OmiLocalCameraView","requireNativeComponent","exports","refreshLocalCamera","refresh"],"sourceRoot":"../../src","sources":["omi_local_camera.tsx"],"mappings":";;;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GAAGC,0BAAa,CAACC,iBAAiB;AAE9C,MAAMC,kBAA4C,GACvD,IAAAC,mCAAsB,EAAC,mBAAmB,CAAC;AAACC,OAAA,CAAAF,kBAAA,GAAAA,kBAAA;AAEvC,SAASG,kBAAkBA,CAAA,EAAqB;EACrD,OAAON,aAAa,CAACO,OAAO,EAAE;AAChC"}
1
+ {"version":3,"names":["_reactNative","require","FLLocalCamera","NativeModules","FLLocalCameraView","OmiLocalCameraView","exports","requireNativeComponent","refreshLocalCamera","refresh"],"sourceRoot":"../../src","sources":["omi_local_camera.tsx"],"mappings":";;;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GAAGC,0BAAa,CAACC,iBAAiB;AAE9C,MAAMC,kBAA4C,GAAAC,OAAA,CAAAD,kBAAA,GACvD,IAAAE,mCAAsB,EAAC,mBAAmB,CAAC;AAEtC,SAASC,kBAAkBA,CAAA,EAAqB;EACrD,OAAON,aAAa,CAACO,OAAO,CAAC,CAAC;AAChC","ignoreList":[]}