@@ -22,13 +22,16 @@ import io.element.android.features.call.test.aCallNotificationData
2222import io.element.android.libraries.matrix.api.core.EventId
2323import io.element.android.libraries.matrix.api.core.RoomId
2424import io.element.android.libraries.matrix.api.core.SessionId
25+ import io.element.android.libraries.matrix.api.room.JoinedRoom
2526import io.element.android.libraries.matrix.test.AN_EVENT_ID
27+ import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
2628import io.element.android.libraries.matrix.test.A_ROOM_ID
2729import io.element.android.libraries.matrix.test.A_ROOM_ID_2
2830import io.element.android.libraries.matrix.test.A_SESSION_ID
2931import io.element.android.libraries.matrix.test.FakeMatrixClient
3032import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
3133import io.element.android.libraries.matrix.test.room.FakeBaseRoom
34+ import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
3235import io.element.android.libraries.matrix.test.room.aRoomInfo
3336import io.element.android.libraries.push.api.notifications.ForegroundServiceType
3437import io.element.android.libraries.push.api.notifications.NotificationIdProvider
@@ -38,6 +41,7 @@ import io.element.android.libraries.push.test.notifications.push.FakeNotificatio
3841import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
3942import io.element.android.tests.testutils.lambda.lambdaRecorder
4043import io.element.android.tests.testutils.lambda.value
44+ import io.mockk.coVerify
4145import io.mockk.mockk
4246import io.mockk.verify
4347import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -49,6 +53,7 @@ import org.junit.Test
4953import org.junit.runner.RunWith
5054import org.robolectric.RobolectricTestRunner
5155import org.robolectric.Shadows.shadowOf
56+ import timber.log.Timber
5257
5358@RunWith(RobolectricTestRunner ::class )
5459class DefaultActiveCallManagerTest {
@@ -164,6 +169,107 @@ class DefaultActiveCallManagerTest {
164169 verify { notificationManagerCompat.cancel(notificationId) }
165170 }
166171
172+ @Test
173+ fun `Decline event - Hangup on a ringing call should send a decline event` () = runTest {
174+ setupShadowPowerManager()
175+ val notificationManagerCompat = mockk<NotificationManagerCompat >(relaxed = true )
176+
177+ val room = mockk<JoinedRoom >(relaxed = true )
178+
179+ val matrixClient = FakeMatrixClient ().apply {
180+ givenGetRoomResult(A_ROOM_ID , room)
181+ }
182+ val clientProvider = FakeMatrixClientProvider ({ Result .success(matrixClient) })
183+
184+ val manager = createActiveCallManager(
185+ matrixClientProvider = clientProvider,
186+ notificationManagerCompat = notificationManagerCompat
187+ )
188+
189+ val notificationData = aCallNotificationData(roomId = A_ROOM_ID )
190+ manager.registerIncomingCall(notificationData)
191+
192+ manager.hungUpCall(CallType .RoomCall (notificationData.sessionId, notificationData.roomId))
193+
194+ coVerify {
195+ room.declineCall(notificationEventId = notificationData.eventId)
196+ }
197+ }
198+
199+ @OptIn(ExperimentalCoroutinesApi ::class )
200+ @Test
201+ fun `Decline event - Declining from another session should stop ringing` () = runTest {
202+ setupShadowPowerManager()
203+ val notificationManagerCompat = mockk<NotificationManagerCompat >(relaxed = true )
204+
205+ val room = FakeJoinedRoom ()
206+
207+ val matrixClient = FakeMatrixClient ().apply {
208+ givenGetRoomResult(A_ROOM_ID , room)
209+ }
210+ val clientProvider = FakeMatrixClientProvider ({ Result .success(matrixClient) })
211+
212+ val manager = createActiveCallManager(
213+ matrixClientProvider = clientProvider,
214+ notificationManagerCompat = notificationManagerCompat
215+ )
216+
217+ val notificationData = aCallNotificationData(roomId = A_ROOM_ID )
218+ manager.registerIncomingCall(notificationData)
219+
220+ runCurrent()
221+
222+ // Simulate declined from other session
223+ room.baseRoom.givenDecliner(matrixClient.sessionId, notificationData.eventId)
224+
225+ runCurrent()
226+
227+ assertThat(manager.activeCall.value).isNull()
228+ assertThat(manager.activeWakeLock?.isHeld).isFalse()
229+
230+ verify { notificationManagerCompat.cancel(notificationId) }
231+ }
232+
233+ @OptIn(ExperimentalCoroutinesApi ::class )
234+ @Test
235+ fun `Decline event - Should ignore decline for other notification events` () = runTest {
236+ Timber .plant(object : Timber .Tree () {
237+ override fun log (priority : Int , tag : String? , message : String , t : Throwable ? ) {
238+ println (" $tag : $message " )
239+ }
240+ })
241+
242+ setupShadowPowerManager()
243+ val notificationManagerCompat = mockk<NotificationManagerCompat >(relaxed = true )
244+
245+ val room = FakeJoinedRoom ()
246+
247+ val matrixClient = FakeMatrixClient ().apply {
248+ givenGetRoomResult(A_ROOM_ID , room)
249+ }
250+ val clientProvider = FakeMatrixClientProvider ({ Result .success(matrixClient) })
251+
252+ val manager = createActiveCallManager(
253+ matrixClientProvider = clientProvider,
254+ notificationManagerCompat = notificationManagerCompat
255+ )
256+
257+ val notificationData = aCallNotificationData(roomId = A_ROOM_ID )
258+ manager.registerIncomingCall(notificationData)
259+
260+ runCurrent()
261+
262+ // Simulate declined for another notification event
263+ room.baseRoom.givenDecliner(matrixClient.sessionId, AN_EVENT_ID_2 )
264+
265+ runCurrent()
266+
267+ assertThat(manager.activeCall.value).isNotNull()
268+ assertThat(manager.activeWakeLock?.isHeld).isTrue()
269+
270+ verify(exactly = 0 ) { notificationManagerCompat.cancel(notificationId) }
271+ }
272+
167273 @Test
168274 fun `hungUpCall - does nothing if the CallType doesn't match` () = runTest {
169275 setupShadowPowerManager()
0 commit comments