@stream-io/video-react-native-sdk 1.31.1-beta.0 → 1.31.1

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 (217) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/android/src/main/AndroidManifest.xml +1 -8
  3. package/android/src/main/AndroidManifestNew.xml +0 -11
  4. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +5 -42
  5. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +6 -70
  6. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +4 -6
  7. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +95 -0
  8. package/dist/commonjs/components/Participant/ParticipantView/ParticipantLabel.js +2 -6
  9. package/dist/commonjs/components/Participant/ParticipantView/ParticipantLabel.js.map +1 -1
  10. package/dist/commonjs/hooks/push/index.js +2 -0
  11. package/dist/commonjs/hooks/push/index.js.map +1 -1
  12. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +160 -0
  13. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  14. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  15. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  16. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +67 -0
  17. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +1 -0
  18. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +97 -64
  19. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  20. package/dist/commonjs/index.js +0 -1
  21. package/dist/commonjs/index.js.map +1 -1
  22. package/dist/commonjs/modules/call-manager/CallManager.js +0 -26
  23. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  24. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  25. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  26. package/dist/commonjs/utils/StreamVideoRN/index.js +21 -35
  27. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  28. package/dist/commonjs/utils/internal/registerSDKGlobals.js +3 -53
  29. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  30. package/dist/commonjs/utils/push/android.js +202 -135
  31. package/dist/commonjs/utils/push/android.js.map +1 -1
  32. package/dist/commonjs/utils/push/internal/ios.js +34 -17
  33. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  34. package/dist/commonjs/utils/push/internal/rxSubjects.js +45 -1
  35. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  36. package/dist/commonjs/utils/push/internal/utils.js +53 -71
  37. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  38. package/dist/commonjs/utils/push/ios.js.map +1 -1
  39. package/dist/commonjs/utils/push/libs/callkeep.js +17 -0
  40. package/dist/commonjs/utils/push/libs/callkeep.js.map +1 -0
  41. package/dist/commonjs/utils/push/libs/index.js +19 -8
  42. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  43. package/dist/commonjs/utils/push/libs/notifee/index.js +19 -0
  44. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  45. package/dist/commonjs/utils/push/libs/voipPushNotification.js +17 -0
  46. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +1 -0
  47. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +205 -0
  48. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +1 -0
  49. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +6 -7
  50. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  51. package/dist/commonjs/version.js +1 -1
  52. package/dist/commonjs/version.js.map +1 -1
  53. package/dist/module/components/Participant/ParticipantView/ParticipantLabel.js +2 -6
  54. package/dist/module/components/Participant/ParticipantView/ParticipantLabel.js.map +1 -1
  55. package/dist/module/hooks/push/index.js +2 -0
  56. package/dist/module/hooks/push/index.js.map +1 -1
  57. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +153 -0
  58. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  59. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  60. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  61. package/dist/module/hooks/push/useProcessPushCallEffect.js +60 -0
  62. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +1 -0
  63. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +99 -66
  64. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  65. package/dist/module/index.js +0 -1
  66. package/dist/module/index.js.map +1 -1
  67. package/dist/module/modules/call-manager/CallManager.js +0 -26
  68. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  69. package/dist/module/providers/StreamCall/index.js +6 -6
  70. package/dist/module/providers/StreamCall/index.js.map +1 -1
  71. package/dist/module/utils/StreamVideoRN/index.js +21 -35
  72. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  73. package/dist/module/utils/internal/registerSDKGlobals.js +3 -53
  74. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  75. package/dist/module/utils/push/android.js +204 -137
  76. package/dist/module/utils/push/android.js.map +1 -1
  77. package/dist/module/utils/push/internal/ios.js +34 -17
  78. package/dist/module/utils/push/internal/ios.js.map +1 -1
  79. package/dist/module/utils/push/internal/rxSubjects.js +44 -0
  80. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
  81. package/dist/module/utils/push/internal/utils.js +50 -67
  82. package/dist/module/utils/push/internal/utils.js.map +1 -1
  83. package/dist/module/utils/push/ios.js.map +1 -1
  84. package/dist/module/utils/push/libs/callkeep.js +11 -0
  85. package/dist/module/utils/push/libs/callkeep.js.map +1 -0
  86. package/dist/module/utils/push/libs/index.js +2 -1
  87. package/dist/module/utils/push/libs/index.js.map +1 -1
  88. package/dist/module/utils/push/libs/notifee/index.js +18 -0
  89. package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
  90. package/dist/module/utils/push/libs/voipPushNotification.js +11 -0
  91. package/dist/module/utils/push/libs/voipPushNotification.js.map +1 -0
  92. package/dist/module/utils/push/setupIosCallKeepEvents.js +199 -0
  93. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +1 -0
  94. package/dist/module/utils/push/setupIosVoipPushEvents.js +6 -7
  95. package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
  96. package/dist/module/version.js +1 -1
  97. package/dist/module/version.js.map +1 -1
  98. package/dist/typescript/components/Participant/ParticipantView/ParticipantLabel.d.ts.map +1 -1
  99. package/dist/typescript/hooks/push/index.d.ts.map +1 -1
  100. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +5 -0
  101. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +1 -0
  102. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  103. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +8 -0
  104. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +1 -0
  105. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  106. package/dist/typescript/index.d.ts +0 -1
  107. package/dist/typescript/index.d.ts.map +1 -1
  108. package/dist/typescript/modules/call-manager/CallManager.d.ts +0 -5
  109. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  110. package/dist/typescript/utils/StreamVideoRN/index.d.ts +2 -22
  111. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  112. package/dist/typescript/utils/StreamVideoRN/types.d.ts +25 -59
  113. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  114. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  115. package/dist/typescript/utils/push/android.d.ts +2 -1
  116. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  117. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  118. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +33 -0
  119. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  120. package/dist/typescript/utils/push/internal/utils.d.ts +8 -14
  121. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  122. package/dist/typescript/utils/push/ios.d.ts +2 -1
  123. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  124. package/dist/typescript/utils/push/libs/callkeep.d.ts +3 -0
  125. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +1 -0
  126. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts +2 -16
  127. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts.map +1 -1
  128. package/dist/typescript/utils/push/libs/index.d.ts +2 -1
  129. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  130. package/dist/typescript/utils/push/libs/notifee/index.d.ts +1 -0
  131. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  132. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +3 -0
  133. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +1 -0
  134. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +6 -0
  135. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +1 -0
  136. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  137. package/dist/typescript/version.d.ts +1 -1
  138. package/dist/typescript/version.d.ts.map +1 -1
  139. package/expo-config-plugin/dist/withAndroidManifest.js +33 -1
  140. package/expo-config-plugin/dist/withAndroidPermissions.js +7 -2
  141. package/expo-config-plugin/dist/withAppDelegate.js +197 -19
  142. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  143. package/expo-config-plugin/dist/withiOSInfoPlist.js +3 -2
  144. package/ios/StreamInCallManager.m +0 -2
  145. package/ios/StreamInCallManager.swift +7 -19
  146. package/ios/StreamVideoReactNative.h +4 -7
  147. package/ios/StreamVideoReactNative.m +82 -189
  148. package/package.json +16 -11
  149. package/src/components/Participant/ParticipantView/ParticipantLabel.tsx +2 -7
  150. package/src/hooks/push/index.ts +2 -0
  151. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +235 -0
  152. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +34 -21
  153. package/src/hooks/push/useProcessPushCallEffect.ts +108 -0
  154. package/src/hooks/useAndroidKeepCallAliveEffect.ts +120 -94
  155. package/src/index.ts +0 -1
  156. package/src/modules/call-manager/CallManager.ts +0 -36
  157. package/src/modules/call-manager/native-module.d.ts +0 -7
  158. package/src/providers/StreamCall/index.tsx +6 -6
  159. package/src/utils/StreamVideoRN/index.ts +30 -42
  160. package/src/utils/StreamVideoRN/types.ts +25 -61
  161. package/src/utils/internal/registerSDKGlobals.ts +4 -52
  162. package/src/utils/push/android.ts +311 -198
  163. package/src/utils/push/internal/ios.ts +44 -28
  164. package/src/utils/push/internal/rxSubjects.ts +61 -0
  165. package/src/utils/push/internal/utils.ts +64 -108
  166. package/src/utils/push/ios.ts +6 -1
  167. package/src/utils/push/libs/callkeep.ts +16 -0
  168. package/src/utils/push/libs/index.ts +2 -1
  169. package/src/utils/push/libs/notifee/index.ts +27 -0
  170. package/src/utils/push/libs/voipPushNotification.ts +17 -0
  171. package/src/utils/push/setupIosCallKeepEvents.ts +252 -0
  172. package/src/utils/push/setupIosVoipPushEvents.ts +7 -11
  173. package/src/version.ts +1 -1
  174. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +0 -83
  175. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +0 -149
  176. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +0 -144
  177. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  178. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +0 -68
  179. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  180. package/dist/commonjs/utils/internal/callingx/callingx.js +0 -150
  181. package/dist/commonjs/utils/internal/callingx/callingx.js.map +0 -1
  182. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +0 -48
  183. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +0 -1
  184. package/dist/commonjs/utils/push/libs/callingx.js +0 -75
  185. package/dist/commonjs/utils/push/libs/callingx.js.map +0 -1
  186. package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -105
  187. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +0 -1
  188. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +0 -137
  189. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  190. package/dist/module/utils/internal/callingx/audioSessionPromise.js +0 -61
  191. package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  192. package/dist/module/utils/internal/callingx/callingx.js +0 -140
  193. package/dist/module/utils/internal/callingx/callingx.js.map +0 -1
  194. package/dist/module/utils/keepCallAliveHeadlessTask.js +0 -42
  195. package/dist/module/utils/keepCallAliveHeadlessTask.js.map +0 -1
  196. package/dist/module/utils/push/libs/callingx.js +0 -67
  197. package/dist/module/utils/push/libs/callingx.js.map +0 -1
  198. package/dist/module/utils/push/setupCallingExpEvents.js +0 -99
  199. package/dist/module/utils/push/setupCallingExpEvents.js.map +0 -1
  200. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +0 -5
  201. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +0 -1
  202. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +0 -16
  203. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +0 -1
  204. package/dist/typescript/utils/internal/callingx/callingx.d.ts +0 -18
  205. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +0 -1
  206. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +0 -10
  207. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +0 -1
  208. package/dist/typescript/utils/push/libs/callingx.d.ts +0 -9
  209. package/dist/typescript/utils/push/libs/callingx.d.ts.map +0 -1
  210. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +0 -8
  211. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +0 -1
  212. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +0 -189
  213. package/src/utils/internal/callingx/audioSessionPromise.ts +0 -65
  214. package/src/utils/internal/callingx/callingx.ts +0 -194
  215. package/src/utils/keepCallAliveHeadlessTask.ts +0 -54
  216. package/src/utils/push/libs/callingx.ts +0 -89
  217. package/src/utils/push/setupCallingExpEvents.ts +0 -135
@@ -1,4 +1,5 @@
1
1
  import {
2
+ Call,
2
3
  CallingState,
3
4
  StreamVideoClient,
4
5
  videoLoggerSystem,
@@ -14,15 +15,30 @@ import {
14
15
  getExpoNotificationsLibNoThrow,
15
16
  getFirebaseMessagingLib,
16
17
  getFirebaseMessagingLibNoThrow,
18
+ getIncomingCallForegroundServiceTypes,
17
19
  getNotifeeLibThrowIfNotInstalledForPush,
18
20
  type NotifeeLib,
19
21
  } from './libs';
20
- import { pushNonRingingCallData$ } from './internal/rxSubjects';
22
+ import {
23
+ pushAcceptedIncomingCallCId$,
24
+ pushAndroidBackgroundDeliveredIncomingCallCId$,
25
+ pushNonRingingCallData$,
26
+ pushRejectedIncomingCallCId$,
27
+ pushTappedIncomingCallCId$,
28
+ } from './internal/rxSubjects';
21
29
  import { pushUnsubscriptionCallbacks } from './internal/constants';
22
- import { canListenToWS, shouldCallBeClosed } from './internal/utils';
30
+ import {
31
+ canAddPushWSSubscriptionsRef,
32
+ clearPushWSEventSubscriptions,
33
+ processCallFromPushInBackground,
34
+ shouldCallBeEnded,
35
+ } from './internal/utils';
23
36
  import { setPushLogoutCallback } from '../internal/pushLogoutCallback';
37
+ import { getAndroidDefaultRingtoneUrl } from '../getAndroidDefaultRingtoneUrl';
24
38
  import { StreamVideoRN } from '../StreamVideoRN';
25
- import { getCallingxLib } from './libs/callingx';
39
+
40
+ const ACCEPT_CALL_ACTION_ID = 'accept';
41
+ const DECLINE_CALL_ACTION_ID = 'decline';
26
42
 
27
43
  type PushConfig = NonNullable<StreamVideoConfig['push']>;
28
44
 
@@ -91,10 +107,11 @@ export async function initAndroidPushToken(
91
107
  await setDeviceToken(token);
92
108
  }
93
109
  }
94
-
95
- const messaging = pushConfig.isExpo
96
- ? getFirebaseMessagingLibNoThrow(true)
97
- : getFirebaseMessagingLib();
110
+ // TODO: remove the incomingCallChannel check and find a better way once we have telecom integration for android
111
+ const messaging =
112
+ pushConfig.isExpo && !pushConfig.android.incomingCallChannel
113
+ ? getFirebaseMessagingLibNoThrow(true)
114
+ : getFirebaseMessagingLib();
98
115
  if (messaging) {
99
116
  logger.debug(`setting firebase token listeners`);
100
117
  const unsubscribe = messaging().onTokenRefresh((refreshedToken) =>
@@ -110,10 +127,10 @@ export async function initAndroidPushToken(
110
127
  * Creates notification from the push message data.
111
128
  * For Ringing and Non-Ringing calls.
112
129
  */
113
-
114
130
  export const firebaseDataHandler = async (
115
131
  data: FirebaseMessagingTypes.RemoteMessage['data'],
116
132
  ) => {
133
+ if (Platform.OS !== 'android') return;
117
134
  /* Example data from firebase
118
135
  "message": {
119
136
  "data": {
@@ -129,217 +146,227 @@ export const firebaseDataHandler = async (
129
146
  // other stuff
130
147
  }
131
148
  */
132
- if (Platform.OS !== 'android') return;
133
-
134
- const logger = videoLoggerSystem.getLogger('firebaseDataHandler');
135
149
  const pushConfig = StreamVideoRN.getConfig().push;
136
150
  if (!pushConfig || !data || data.sender !== 'stream.video') {
137
151
  return;
138
152
  }
153
+ const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
154
+ const notifee = notifeeLib.default;
155
+ const settings = await notifee.getNotificationSettings();
156
+ if (settings.authorizationStatus !== 1) {
157
+ const logger = videoLoggerSystem.getLogger('firebaseDataHandler');
158
+ logger.debug(
159
+ `Notification permission not granted, unable to post ${data.type} notifications`,
160
+ );
161
+ return;
162
+ }
139
163
 
140
164
  if (data.type === 'call.ring') {
141
165
  const call_cid = data.call_cid as string;
142
- const callingx = getCallingxLib();
166
+ const created_by_id = data.created_by_id as string;
167
+ const receiver_id = data.receiver_id as string;
143
168
 
144
- const client = await pushConfig.createStreamVideoClient();
145
- if (!client) {
146
- logger.debug(
147
- `video client not found, skipping the call.ring notification`,
169
+ const video_client = await pushConfig.createStreamVideoClient();
170
+ await video_client?.onRingingCall(call_cid);
171
+
172
+ const shouldCallBeClosed = (callToCheck: Call) => {
173
+ const { mustEndCall } = shouldCallBeEnded(
174
+ callToCheck,
175
+ created_by_id,
176
+ receiver_id,
148
177
  );
149
- await callingx.stopService();
150
- return;
151
- }
178
+ return mustEndCall;
179
+ };
152
180
 
181
+ const canListenToWS = () =>
182
+ canAddPushWSSubscriptionsRef.current &&
183
+ AppState.currentState !== 'active';
153
184
  const asForegroundService = canListenToWS();
154
185
 
155
186
  if (asForegroundService) {
156
187
  // Listen to call events from WS through fg service
157
188
  // note: this will replace the current empty fg service runner
158
- //we need to start service (e.g. by calling display incoming call) and than launch bg task, consider making those steps independent
159
- await callingx.startBackgroundTask((_: unknown, stopTask: () => void) => {
160
- return new Promise((resolve) => {
161
- const finishBackgroundTask = () => {
162
- callingx.log(
163
- `Finishing background task for callCid: ${call_cid}`,
164
- 'debug',
165
- );
166
- resolve(undefined);
167
- stopTask();
168
- };
169
-
170
- (async () => {
171
- try {
172
- const _client = await pushConfig.createStreamVideoClient();
173
- if (!_client) {
174
- logger.debug(
175
- `Closing fg service as there is no client to create from push config`,
176
- );
177
- finishBackgroundTask();
178
- return;
179
- }
180
-
181
- const callFromPush = await _client.onRingingCall(call_cid);
182
- const { mustEndCall, endCallReason } = shouldCallBeClosed(
183
- callFromPush,
184
- data,
189
+ notifee.registerForegroundService(() => {
190
+ return new Promise(async () => {
191
+ const client = await pushConfig.createStreamVideoClient();
192
+ if (!client) {
193
+ videoLoggerSystem
194
+ .getLogger('firebaseMessagingOnMessageHandler')
195
+ .debug(
196
+ `Closing fg service as there is no client to create from push config`,
197
+ );
198
+ notifee.stopForegroundService();
199
+ return;
200
+ }
201
+ const callFromPush = await client.onRingingCall(call_cid);
202
+ let _shouldCallBeClosed = shouldCallBeClosed(callFromPush);
203
+ if (_shouldCallBeClosed) {
204
+ videoLoggerSystem
205
+ .getLogger('firebaseMessagingOnMessageHandler')
206
+ .debug(
207
+ `Closing fg service callCid: ${call_cid} shouldCallBeClosed: ${_shouldCallBeClosed}`,
185
208
  );
186
- if (mustEndCall) {
187
- logger.debug(
188
- `Closing fg service callCid: ${call_cid} endCallReason: ${endCallReason}`,
209
+ notifee.stopForegroundService();
210
+ return;
211
+ }
212
+ const unsubscribeFunctions: Array<() => void> = [];
213
+ // check if service needs to be closed if accept/decline event was done on another device
214
+ const unsubscribe = callFromPush.on('all', (event) => {
215
+ const _canListenToWS = canListenToWS();
216
+ if (!_canListenToWS) {
217
+ videoLoggerSystem
218
+ .getLogger('firebaseMessagingOnMessageHandler')
219
+ .debug(
220
+ `Closing fg service from event callCid: ${call_cid} canListenToWS: ${_canListenToWS}`,
221
+ { event },
189
222
  );
190
-
191
- callingx.log(
192
- `Ending call with callCid: ${call_cid} endCallReason: ${endCallReason}`,
193
- 'debug',
223
+ unsubscribeFunctions.forEach((fn) => fn());
224
+ notifee.stopForegroundService();
225
+ return;
226
+ }
227
+ _shouldCallBeClosed = shouldCallBeClosed(callFromPush);
228
+ if (_shouldCallBeClosed) {
229
+ videoLoggerSystem
230
+ .getLogger('firebaseMessagingOnMessageHandler')
231
+ .debug(
232
+ `Closing fg service from event callCid: ${call_cid} canListenToWS: ${_canListenToWS} shouldCallBeClosed: ${_shouldCallBeClosed}`,
233
+ { event },
194
234
  );
195
- callingx.endCallWithReason(call_cid, endCallReason);
196
- resolve(undefined);
197
- return;
198
- }
199
-
200
- const unsubscribeFunctions: Array<() => void> = [];
201
- // check if service needs to be closed if accept/decline event was done on another device
202
- const unsubscribe = callFromPush.on('all', (event) => {
203
- const _canListenToWS = canListenToWS();
204
- if (!_canListenToWS) {
205
- logger.debug(
206
- `Closing fg service from event callCid: ${call_cid} canListenToWS: ${_canListenToWS}`,
207
- { event },
208
- );
209
- unsubscribeFunctions.forEach((fn) => fn());
210
-
211
- finishBackgroundTask();
212
- return;
213
- }
214
-
215
- const {
216
- mustEndCall: mustEndCallFromEvent,
217
- endCallReason: endCallReasonFromEvent,
218
- } = shouldCallBeClosed(callFromPush, data);
219
- if (mustEndCallFromEvent) {
220
- logger.debug(
221
- `Closing fg service from event callCid: ${call_cid} canListenToWS: ${_canListenToWS} shouldCallBeClosed`,
222
- { event },
223
- );
224
- unsubscribeFunctions.forEach((fn) => fn());
225
-
226
- callingx.endCallWithReason(call_cid, endCallReasonFromEvent);
227
- resolve(undefined);
228
- }
229
- });
230
-
231
- // check if service needs to be closed if call was left
232
- const stateSubscription =
233
- callFromPush.state.callingState$.subscribe((callingState) => {
234
- if (
235
- callingState === CallingState.IDLE ||
236
- callingState === CallingState.LEFT
237
- ) {
238
- logger.debug(
239
- `Closing fg service from callingState callCid: ${call_cid} callingState: ${callingState}`,
240
- );
241
- unsubscribeFunctions.forEach((fn) => fn());
242
- callingx.log(
243
- `Ending call with callCid: ${call_cid} callingState: ${callingState}`,
244
- 'debug',
245
- );
246
- resolve(undefined);
247
- }
248
- });
249
-
250
- const endCallSubscription = callingx.addEventListener(
251
- 'endCall',
252
- async ({ callId }: { callId: string }) => {
253
- unsubscribeFunctions.forEach((fn) => fn());
254
- try {
255
- await callFromPush.leave({
256
- reject:
257
- callFromPush.state.callingState ===
258
- CallingState.RINGING,
259
- reason: 'decline',
260
- });
261
- } catch (error) {
262
- logger.error(
263
- `Failed to leave call with callCid: ${call_cid} error: ${error}`,
264
- );
265
- } finally {
266
- callingx.log(
267
- `Ending call with callCid: ${call_cid} callId: ${callId}`,
268
- 'debug',
269
- );
270
- resolve(undefined);
271
- }
272
- },
273
- );
274
-
275
- //stop background task when app comes to foreground
276
- const appStateSubscription = AppState.addEventListener(
277
- 'change',
278
- (nextAppState) => {
279
- const _canListenToWS = canListenToWS();
280
- callingx.log(
281
- `AppState changed to: ${nextAppState} for callCid: ${call_cid} canListenToWS: ${_canListenToWS}`,
282
- 'debug',
283
- );
284
- if (!_canListenToWS) {
285
- unsubscribeFunctions.forEach((fn) => fn());
286
- finishBackgroundTask();
287
- return;
288
- }
289
- },
290
- );
291
-
292
- unsubscribeFunctions.push(unsubscribe);
293
- unsubscribeFunctions.push(() => stateSubscription.unsubscribe());
294
- unsubscribeFunctions.push(() => endCallSubscription.remove());
295
- unsubscribeFunctions.push(() => appStateSubscription.remove());
296
- pushUnsubscriptionCallbacks.get(call_cid)?.forEach((cb) => cb());
297
- pushUnsubscriptionCallbacks.set(call_cid, unsubscribeFunctions);
298
- } catch (error) {
299
- callingx.log(
300
- `Failed to start background task with callCid: ${call_cid} error: ${error}`,
301
- 'error',
302
- );
303
- finishBackgroundTask();
235
+ unsubscribeFunctions.forEach((fn) => fn());
236
+ notifee.stopForegroundService();
304
237
  }
305
- })();
238
+ });
239
+ // check if service needs to be closed if call was left
240
+ const subscription = callFromPush.state.callingState$.subscribe(
241
+ (callingState) => {
242
+ if (
243
+ callingState === CallingState.IDLE ||
244
+ callingState === CallingState.LEFT
245
+ ) {
246
+ videoLoggerSystem
247
+ .getLogger('firebaseMessagingOnMessageHandler')
248
+ .debug(
249
+ `Closing fg service from callingState callCid: ${call_cid} callingState: ${callingState}`,
250
+ );
251
+ unsubscribeFunctions.forEach((fn) => fn());
252
+ notifee.stopForegroundService();
253
+ }
254
+ },
255
+ );
256
+ unsubscribeFunctions.push(unsubscribe);
257
+ unsubscribeFunctions.push(() => subscription.unsubscribe());
258
+ pushUnsubscriptionCallbacks.get(call_cid)?.forEach((cb) => cb());
259
+ pushUnsubscriptionCallbacks.set(call_cid, unsubscribeFunctions);
306
260
  });
307
261
  });
308
262
  }
263
+ const incomingCallChannel = pushConfig.android.incomingCallChannel;
264
+ const incomingCallNotificationTextGetters =
265
+ pushConfig.android.incomingCallNotificationTextGetters;
266
+ if (!incomingCallChannel || !incomingCallNotificationTextGetters) {
267
+ const logger = videoLoggerSystem.getLogger(
268
+ 'firebaseMessagingOnMessageHandler',
269
+ );
270
+ logger.error(
271
+ "Can't show incoming call notification as either or both incomingCallChannel and incomingCallNotificationTextGetters were not provided",
272
+ );
273
+ return;
274
+ }
275
+ /*
276
+ * Sound has to be set on channel level for android 8 and above and cant be updated later after creation!
277
+ * For android 7 and below, sound should be set on notification level
278
+ */
279
+ // set default ringtone if not provided
280
+ if (!incomingCallChannel.sound) {
281
+ incomingCallChannel.sound = await getAndroidDefaultRingtoneUrl();
282
+ }
283
+ await notifee.createChannel(incomingCallChannel);
284
+ const { getTitle, getBody, getAcceptButtonTitle, getDeclineButtonTitle } =
285
+ incomingCallNotificationTextGetters;
286
+ const createdUserName = data.created_by_display_name as string;
287
+
288
+ const title = getTitle(createdUserName);
289
+ const body = getBody(createdUserName);
290
+
291
+ videoLoggerSystem
292
+ .getLogger('firebaseMessagingOnMessageHandler')
293
+ .debug(
294
+ `Displaying incoming call notification with callCid: ${call_cid} title: ${title} body: ${body} asForegroundService: ${asForegroundService}`,
295
+ );
296
+
297
+ const channelId = incomingCallChannel.id;
298
+ await notifee.displayNotification({
299
+ id: call_cid,
300
+ title: getTitle(createdUserName),
301
+ body: getBody(createdUserName),
302
+ data,
303
+ android: {
304
+ channelId,
305
+ smallIcon: pushConfig.android.smallIcon,
306
+ importance: 4, // high importance
307
+ foregroundServiceTypes: getIncomingCallForegroundServiceTypes(),
308
+ asForegroundService,
309
+ ongoing: true,
310
+ sound: incomingCallChannel.sound,
311
+ vibrationPattern: incomingCallChannel.vibrationPattern,
312
+ loopSound: true,
313
+ pressAction: {
314
+ id: 'default',
315
+ launchActivity: 'default', // open the app when the notification is pressed
316
+ },
317
+ actions: [
318
+ {
319
+ title: getDeclineButtonTitle?.() ?? 'Decline',
320
+ pressAction: {
321
+ id: DECLINE_CALL_ACTION_ID,
322
+ },
323
+ },
324
+ {
325
+ title: getAcceptButtonTitle?.() ?? 'Accept',
326
+ pressAction: {
327
+ id: ACCEPT_CALL_ACTION_ID,
328
+ launchActivity: 'default', // open the app when the notification is pressed
329
+ },
330
+ },
331
+ ],
332
+ category: notifeeLib.AndroidCategory.CALL,
333
+ fullScreenAction: {
334
+ id: 'stream_ringing_incoming_call',
335
+ },
336
+ timeoutAfter: 60000, // 60 seconds, after which the notification will be dismissed automatically
337
+ },
338
+ });
309
339
 
310
340
  if (asForegroundService) {
311
341
  // no need to check if call has be closed as that will be handled by the fg service
312
342
  return;
313
343
  }
314
344
 
345
+ // check if call needs to be closed if accept/decline event was done
346
+ // before the notification was shown
347
+ const client = await pushConfig.createStreamVideoClient();
348
+ if (!client) {
349
+ return;
350
+ }
315
351
  const callFromPush = await client.onRingingCall(call_cid);
316
352
 
317
- const { mustEndCall, endCallReason } = shouldCallBeClosed(
318
- callFromPush,
319
- data,
320
- );
321
- if (mustEndCall) {
322
- logger.debug(
323
- `Removing incoming call notification immediately with callCid: ${call_cid} as it should be closed`,
324
- );
325
- callingx.endCallWithReason(call_cid, endCallReason);
353
+ if (shouldCallBeClosed(callFromPush)) {
354
+ videoLoggerSystem
355
+ .getLogger('firebaseMessagingOnMessageHandler')
356
+ .debug(
357
+ `Removing incoming call notification immediately with callCid: ${call_cid} as it should be closed`,
358
+ );
359
+ notifee.cancelDisplayedNotification(call_cid);
326
360
  }
327
361
  } else {
328
- const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
329
- const notifee = notifeeLib.default;
330
- const settings = await notifee.getNotificationSettings();
331
- if (settings.authorizationStatus !== 1) {
332
- logger.debug(
333
- `Notification permission not granted, unable to post ${data.type} notifications`,
334
- );
335
- return;
336
- }
337
-
338
362
  // the other types are call.live_started and call.notification
339
363
  const callChannel = pushConfig.android.callChannel;
340
364
  const callNotificationTextGetters =
341
365
  pushConfig.android.callNotificationTextGetters;
342
366
  if (!callChannel || !callNotificationTextGetters) {
367
+ const logger = videoLoggerSystem.getLogger(
368
+ 'firebaseMessagingOnMessageHandler',
369
+ );
343
370
  logger.debug(
344
371
  "Can't show call notification as either or both callChannel and callNotificationTextGetters is not provided",
345
372
  );
@@ -355,12 +382,14 @@ export const firebaseDataHandler = async (
355
382
  const title = getTitle(type, createdUserName);
356
383
  const body = getBody(type, createdUserName);
357
384
 
358
- logger.debug(
359
- `Displaying NonRingingPushEvent ${type} notification with title: ${title} body: ${body}`,
360
- );
385
+ videoLoggerSystem
386
+ .getLogger('firebaseMessagingOnMessageHandler')
387
+ .debug(
388
+ `Displaying NonRingingPushEvent ${type} notification with title: ${title} body: ${body}`,
389
+ );
361
390
  await notifee.displayNotification({
362
- title,
363
- body,
391
+ title: getTitle(type, createdUserName),
392
+ body: getBody(type, createdUserName),
364
393
  data,
365
394
  android: {
366
395
  sound: callChannel.sound,
@@ -380,10 +409,16 @@ export const firebaseDataHandler = async (
380
409
  }
381
410
  };
382
411
 
383
- export const onAndroidNotifeeEvent = async ({ event }: { event: Event }) => {
412
+ export const onAndroidNotifeeEvent = async ({
413
+ event,
414
+ isBackground,
415
+ }: {
416
+ event: Event;
417
+ isBackground: boolean;
418
+ }) => {
384
419
  if (Platform.OS !== 'android') return;
385
420
  const { type, detail } = event;
386
- const { notification } = detail;
421
+ const { notification, pressAction } = detail;
387
422
  const notificationId = notification?.id;
388
423
  const data = notification?.data;
389
424
  const pushConfig = StreamVideoRN.getConfig().push;
@@ -399,14 +434,92 @@ export const onAndroidNotifeeEvent = async ({ event }: { event: Event }) => {
399
434
  // we can safely cast to string because the data is from "stream.video"
400
435
  const call_cid = data.call_cid as string;
401
436
 
402
- const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
403
- if (type === notifeeLib.EventType.PRESS) {
404
- videoLoggerSystem
405
- .getLogger('onAndroidNotifeeEvent')
406
- .debug(`onTapNonRingingCallNotification with callCId: ${call_cid}`);
407
- pushConfig.onTapNonRingingCallNotification?.(
408
- call_cid,
409
- data.type as NonRingingPushEvent,
410
- );
437
+ if (data.type === 'call.ring') {
438
+ // check if we have observers for the call cid (this means the app is in the foreground state)
439
+ const hasObservers =
440
+ pushAcceptedIncomingCallCId$.observed &&
441
+ pushRejectedIncomingCallCId$.observed;
442
+
443
+ const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
444
+ const notifee = notifeeLib.default;
445
+ // Check if we need to decline the call
446
+ const didPressDecline =
447
+ type === notifeeLib.EventType.ACTION_PRESS &&
448
+ pressAction?.id === DECLINE_CALL_ACTION_ID;
449
+ const didDismiss = type === notifeeLib.EventType.DISMISSED;
450
+ const mustDecline = didPressDecline || didDismiss;
451
+ // Check if we need to accept the call
452
+ const mustAccept =
453
+ type === notifeeLib.EventType.ACTION_PRESS &&
454
+ pressAction?.id === ACCEPT_CALL_ACTION_ID;
455
+
456
+ if (
457
+ mustAccept ||
458
+ mustDecline ||
459
+ type === notifeeLib.EventType.ACTION_PRESS
460
+ ) {
461
+ videoLoggerSystem
462
+ .getLogger('onAndroidNotifeeEvent')
463
+ .debug(
464
+ `clearPushWSEventSubscriptions for callCId: ${call_cid} mustAccept: ${mustAccept} mustDecline: ${mustDecline}`,
465
+ );
466
+ clearPushWSEventSubscriptions(call_cid);
467
+ notifee.stopForegroundService();
468
+ }
469
+
470
+ if (mustAccept) {
471
+ videoLoggerSystem
472
+ .getLogger('onAndroidNotifeeEvent')
473
+ .debug(`pushAcceptedIncomingCallCId$ added with callCId: ${call_cid}`);
474
+ pushAcceptedIncomingCallCId$.next(call_cid);
475
+ // NOTE: accept will be handled by the app with rxjs observers as the app will go to foreground always
476
+ } else if (mustDecline) {
477
+ videoLoggerSystem
478
+ .getLogger('onAndroidNotifeeEvent')
479
+ .debug(`pushRejectedIncomingCallCId$ added with callCId: ${call_cid}`);
480
+ pushRejectedIncomingCallCId$.next(call_cid);
481
+ if (hasObservers) {
482
+ // if we had observers we can return here as the observers will handle the call as the app is in the foreground state
483
+ videoLoggerSystem
484
+ .getLogger('onAndroidNotifeeEvent')
485
+ .debug(
486
+ `Skipped processCallFromPushInBackground for Declining call with callCId: ${call_cid} as the app is in the foreground state`,
487
+ );
488
+ return;
489
+ }
490
+ videoLoggerSystem
491
+ .getLogger('onAndroidNotifeeEvent')
492
+ .debug(
493
+ `start processCallFromPushInBackground - Declining call with callCId: ${call_cid}`,
494
+ );
495
+ await processCallFromPushInBackground(pushConfig, call_cid, 'decline');
496
+ } else {
497
+ if (type === notifeeLib.EventType.PRESS) {
498
+ videoLoggerSystem
499
+ .getLogger('onAndroidNotifeeEvent')
500
+ .debug(`pushTappedIncomingCallCId$ added with callCId: ${call_cid}`);
501
+ pushTappedIncomingCallCId$.next(call_cid);
502
+ // pressed state will be handled by the app with rxjs observers as the app will go to foreground always
503
+ } else if (isBackground && type === notifeeLib.EventType.DELIVERED) {
504
+ videoLoggerSystem
505
+ .getLogger('onAndroidNotifeeEvent')
506
+ .debug(
507
+ `pushAndroidBackgroundDeliveredIncomingCallCId$ added with callCId: ${call_cid}`,
508
+ );
509
+ pushAndroidBackgroundDeliveredIncomingCallCId$.next(call_cid);
510
+ // background delivered state will be handled by the app with rxjs observers as processing needs to happen only when app is opened
511
+ }
512
+ }
513
+ } else {
514
+ const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
515
+ if (type === notifeeLib.EventType.PRESS) {
516
+ videoLoggerSystem
517
+ .getLogger('onAndroidNotifeeEvent')
518
+ .debug(`onTapNonRingingCallNotification with callCId: ${call_cid}`);
519
+ pushConfig.onTapNonRingingCallNotification?.(
520
+ call_cid,
521
+ data.type as NonRingingPushEvent,
522
+ );
523
+ }
411
524
  }
412
525
  };