Add support for group call disposition.

Co-authored-by: Cody Henthorne <cody@signal.org>
This commit is contained in:
Alex Hart
2023-04-03 10:44:14 -03:00
parent e94a84d4ec
commit f9548dcffe
40 changed files with 2165 additions and 340 deletions

View File

@@ -0,0 +1,70 @@
package org.thoughtcrime.securesms.service
import android.app.Application
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import java.util.concurrent.TimeUnit
/**
* Manages deleting call events 8 hours after they've been marked deleted.
*/
class DeletedCallEventManager(
application: Application
) : TimedEventManager<DeletedCallEventManager.Event>(application, "ExpiringCallEventsManager") {
companion object {
private val TAG = Log.tag(DeletedCallEventManager::class.java)
private val CALL_EVENT_DELETION_LIFESPAN = TimeUnit.HOURS.toMillis(8)
}
init {
scheduleIfNecessary()
}
@WorkerThread
override fun getNextClosestEvent(): Event? {
val oldestTimestamp = SignalDatabase.calls.getOldestDeletionTimestamp()
if (oldestTimestamp <= 0) return null
val timeSinceSend = System.currentTimeMillis() - oldestTimestamp
val delay = (CALL_EVENT_DELETION_LIFESPAN - timeSinceSend).coerceAtLeast(0)
Log.i(TAG, "The oldest call event needs to be deleted in $delay ms.")
return Event(delay)
}
@WorkerThread
override fun executeEvent(event: Event) {
val threshold = System.currentTimeMillis() - CALL_EVENT_DELETION_LIFESPAN
val deletes = SignalDatabase.calls.deleteCallEventsDeletedBefore(threshold)
Log.i(TAG, "Deleted $deletes call events before $threshold")
}
@WorkerThread
override fun getDelayForEvent(event: Event): Long = event.delay
@WorkerThread
override fun scheduleAlarm(application: Application, event: Event, delay: Long) {
setAlarm(application, delay, DeleteCallEventsAlarm::class.java)
}
data class Event(val delay: Long)
class DeleteCallEventsAlarm : BroadcastReceiver() {
companion object {
private val TAG = Log.tag(DeleteCallEventsAlarm::class.java)
}
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "onReceive()")
ApplicationDependencies.getDeletedCallEventManager().scheduleIfNecessary()
}
}
}

View File

@@ -1,6 +1,9 @@
package org.thoughtcrime.securesms.service.webrtc
import com.google.protobuf.ByteString
import org.thoughtcrime.securesms.database.model.toProtoByteString
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.ringrtc.RemotePeer
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent
@@ -10,27 +13,70 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMe
object CallEventSyncMessageUtil {
@JvmStatic
fun createAcceptedSyncMessage(remotePeer: RemotePeer, timestamp: Long, isOutgoing: Boolean, isVideoCall: Boolean): CallEvent {
return CallEvent
.newBuilder()
.setPeerUuid(Recipient.resolved(remotePeer.id).requireServiceId().toByteString())
.setId(remotePeer.callId.longValue())
.setTimestamp(timestamp)
.setType(if (isVideoCall) CallEvent.Type.VIDEO_CALL else CallEvent.Type.AUDIO_CALL)
.setDirection(if (isOutgoing) CallEvent.Direction.OUTGOING else CallEvent.Direction.INCOMING)
.setEvent(CallEvent.Event.ACCEPTED)
.build()
return createCallEvent(
remotePeer.id,
remotePeer.callId.longValue(),
timestamp,
isOutgoing,
isVideoCall,
CallEvent.Event.ACCEPTED
)
}
@JvmStatic
fun createNotAcceptedSyncMessage(remotePeer: RemotePeer, timestamp: Long, isOutgoing: Boolean, isVideoCall: Boolean): CallEvent {
return createCallEvent(
remotePeer.id,
remotePeer.callId.longValue(),
timestamp,
isOutgoing,
isVideoCall,
CallEvent.Event.NOT_ACCEPTED
)
}
@JvmStatic
fun createDeleteCallEvent(remotePeer: RemotePeer, timestamp: Long, isOutgoing: Boolean, isVideoCall: Boolean): CallEvent {
return createCallEvent(
remotePeer.id,
remotePeer.callId.longValue(),
timestamp,
isOutgoing,
isVideoCall,
CallEvent.Event.DELETE
)
}
private fun createCallEvent(
recipientId: RecipientId,
callId: Long,
timestamp: Long,
isOutgoing: Boolean,
isVideoCall: Boolean,
event: CallEvent.Event
): CallEvent {
val recipient = Recipient.resolved(recipientId)
val isGroupCall = recipient.isGroup
val conversationId: ByteString = if (isGroupCall) {
recipient.requireGroupId().decodedId.toProtoByteString()
} else {
recipient.requireServiceId().toByteString()
}
return CallEvent
.newBuilder()
.setPeerUuid(Recipient.resolved(remotePeer.id).requireServiceId().toByteString())
.setId(remotePeer.callId.longValue())
.setConversationId(conversationId)
.setId(callId)
.setTimestamp(timestamp)
.setType(if (isVideoCall) CallEvent.Type.VIDEO_CALL else CallEvent.Type.AUDIO_CALL)
.setType(
when {
isGroupCall -> CallEvent.Type.GROUP_CALL
isVideoCall -> CallEvent.Type.VIDEO_CALL
else -> CallEvent.Type.AUDIO_CALL
}
)
.setDirection(if (isOutgoing) CallEvent.Direction.OUTGOING else CallEvent.Direction.INCOMING)
.setEvent(CallEvent.Event.NOT_ACCEPTED)
.setEvent(event)
.build()
}
}

View File

@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.events.CallParticipant;
import org.thoughtcrime.securesms.events.CallParticipantId;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState;
@@ -148,8 +149,9 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
return currentState;
}
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId);
boolean remoteUserRangTheCall = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingerRecipient() != Recipient.self();
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, remoteUserRangTheCall, true);
List<UUID> members = new ArrayList<>(peekInfo.getJoinedMembers());
if (!members.contains(SignalStore.account().requireAci().uuid())) {
@@ -176,7 +178,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
}
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId);
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, false, false);
List<UUID> members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireServiceId().uuid()).toList();
webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, false);

View File

@@ -102,9 +102,9 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
}
if (ringUpdate != CallManager.RingUpdate.REQUESTED) {
SignalDatabase.groupCallRings().insertOrUpdateGroupRing(ringId, System.currentTimeMillis(), ringUpdate);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(ringId, remotePeerGroup.getId(), sender, System.currentTimeMillis(), ringUpdate);
return currentState;
} else if (SignalDatabase.groupCallRings().isCancelled(ringId)) {
} else if (SignalDatabase.calls().isRingCancelled(ringId)) {
try {
Log.i(TAG, "Incoming ring request for already cancelled ring: " + ringId);
webRtcInteractor.getCallManager().cancelGroupRing(groupId.getDecodedId(), ringId, null);
@@ -118,7 +118,7 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
if (activeProfile != null && !(activeProfile.isRecipientAllowed(remotePeerGroup.getId()) || activeProfile.getAllowAllCalls())) {
try {
Log.i(TAG, "Incoming ring request for profile restricted recipient");
SignalDatabase.groupCallRings().insertOrUpdateGroupRing(ringId, System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(ringId, remotePeerGroup.getId(), sender, System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST);
webRtcInteractor.getCallManager().cancelGroupRing(groupId.getDecodedId(), ringId, CallManager.RingCancelReason.DeclinedByUser);
} catch (CallException e) {
Log.w(TAG, "Error while trying to cancel ring: " + ringId, e);
@@ -135,7 +135,7 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
protected @NonNull WebRtcServiceState handleReceivedGroupCallPeekForRingingCheck(@NonNull WebRtcServiceState currentState, @NonNull GroupCallRingCheckInfo info, @NonNull PeekInfo peekInfo) {
Log.i(tag, "handleReceivedGroupCallPeekForRingingCheck(): recipient: " + info.getRecipientId() + " ring: " + info.getRingId());
if (SignalDatabase.groupCallRings().isCancelled(info.getRingId())) {
if (SignalDatabase.calls().isRingCancelled(info.getRingId())) {
try {
Log.i(TAG, "Ring was cancelled while getting peek info ring: " + info.getRingId());
webRtcInteractor.getCallManager().cancelGroupRing(info.getGroupId().getDecodedId(), info.getRingId(), null);
@@ -147,11 +147,11 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
if (peekInfo.getDeviceCount() == 0) {
Log.i(TAG, "No one in the group call, mark as expired and do not ring");
SignalDatabase.groupCallRings().insertOrUpdateGroupRing(info.getRingId(), System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerUuid(), System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST);
return currentState;
} else if (peekInfo.getJoinedMembers().contains(Recipient.self().requireServiceId().uuid())) {
Log.i(TAG, "We are already in the call, mark accepted on another device and do not ring");
SignalDatabase.groupCallRings().insertOrUpdateGroupRing(info.getRingId(), System.currentTimeMillis(), CallManager.RingUpdate.ACCEPTED_ON_ANOTHER_DEVICE);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerUuid(), System.currentTimeMillis(), CallManager.RingUpdate.ACCEPTED_ON_ANOTHER_DEVICE);
return currentState;
}

View File

@@ -176,12 +176,12 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor {
activePeer.localRinging();
SignalDatabase.calls().insertCall(remotePeer.getCallId().longValue(),
System.currentTimeMillis(),
remotePeer.getId(),
SignalDatabase.calls().insertOneToOneCall(remotePeer.getCallId().longValue(),
System.currentTimeMillis(),
remotePeer.getId(),
currentState.getCallSetupState(activePeer).isRemoteVideoOffer() ? CallTable.Type.VIDEO_CALL : CallTable.Type.AUDIO_CALL,
CallTable.Direction.INCOMING,
CallTable.Event.ONGOING);
CallTable.Direction.INCOMING,
CallTable.Event.ONGOING);
webRtcInteractor.updatePhoneState(LockManager.PhoneState.INTERACTIVE);

View File

@@ -58,7 +58,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
boolean updateForCurrentRingId = ringId == currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingId();
boolean isCurrentlyRinging = currentState.getCallInfoState().getGroupCallState().isRinging();
if (SignalDatabase.groupCallRings().isCancelled(ringId)) {
if (SignalDatabase.calls().isRingCancelled(ringId)) {
try {
Log.i(TAG, "Ignoring incoming ring request for already cancelled ring: " + ringId);
webRtcInteractor.getCallManager().cancelGroupRing(groupId.getDecodedId(), ringId, null);
@@ -69,7 +69,11 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
}
if (ringUpdate != CallManager.RingUpdate.REQUESTED) {
SignalDatabase.groupCallRings().insertOrUpdateGroupRing(ringId, System.currentTimeMillis(), ringUpdate);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(ringId,
remotePeerGroup.getId(),
sender,
System.currentTimeMillis(),
ringUpdate);
if (updateForCurrentRingId && isCurrentlyRinging) {
Log.i(TAG, "Cancelling current ring: " + ringId);
@@ -104,7 +108,14 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
Log.i(TAG, "Requesting new ring: " + ringId);
SignalDatabase.groupCallRings().insertGroupRing(ringId, System.currentTimeMillis(), ringUpdate);
Recipient ringerRecipient = Recipient.externalPush(ServiceId.from(sender));
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(
ringId,
remotePeerGroup.getId(),
ringerRecipient.getId(),
System.currentTimeMillis(),
ringUpdate
);
currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState, RemotePeer.GROUP_CALL_ID.longValue());
@@ -138,7 +149,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
.changeCallSetupState(RemotePeer.GROUP_CALL_ID)
.isRemoteVideoOffer(true)
.ringId(ringId)
.ringerRecipient(Recipient.externalPush(ServiceId.from(sender)))
.ringerRecipient(ringerRecipient)
.commit()
.changeCallInfoState()
.activePeer(new RemotePeer(currentState.getCallInfoState().getCallRecipient().getId(), RemotePeer.GROUP_CALL_ID))
@@ -226,10 +237,13 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
Recipient recipient = currentState.getCallInfoState().getCallRecipient();
Optional<GroupId> groupId = recipient.getGroupId();
long ringId = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingId();
Recipient ringer = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingerRecipient();
SignalDatabase.groupCallRings().insertOrUpdateGroupRing(ringId,
System.currentTimeMillis(),
CallManager.RingUpdate.DECLINED_ON_ANOTHER_DEVICE);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(ringId,
recipient.getId(),
ringer.getId(),
System.currentTimeMillis(),
CallManager.RingUpdate.DECLINED_ON_ANOTHER_DEVICE);
try {
webRtcInteractor.getCallManager().cancelGroupRing(groupId.get().getDecodedId(),

View File

@@ -85,12 +85,12 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
RecipientUtil.setAndSendUniversalExpireTimerIfNecessary(context, Recipient.resolved(remotePeer.getId()), SignalDatabase.threads().getThreadIdIfExistsFor(remotePeer.getId()));
SignalDatabase.calls().insertCall(remotePeer.getCallId().longValue(),
System.currentTimeMillis(),
remotePeer.getId(),
SignalDatabase.calls().insertOneToOneCall(remotePeer.getCallId().longValue(),
System.currentTimeMillis(),
remotePeer.getId(),
isVideoCall ? CallTable.Type.VIDEO_CALL : CallTable.Type.AUDIO_CALL,
CallTable.Direction.OUTGOING,
CallTable.Event.ONGOING);
CallTable.Direction.OUTGOING,
CallTable.Event.ONGOING);
EglBaseWrapper.replaceHolder(EglBaseWrapper.OUTGOING_PLACEHOLDER, remotePeer.getCallId().longValue());

View File

@@ -39,6 +39,8 @@ import org.thoughtcrime.securesms.events.GroupCallPeekEvent;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobs.CallSyncEventJob;
import org.thoughtcrime.securesms.jobs.GroupCallUpdateSendJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
@@ -349,8 +351,8 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
Long threadId = SignalDatabase.threads().getThreadIdFor(group.getId());
if (threadId != null) {
SignalDatabase.messages()
.updatePreviousGroupCall(threadId,
SignalDatabase.calls()
.updateGroupCallFromPeek(threadId,
peekInfo.getEraId(),
peekInfo.getJoinedMembers(),
WebRtcUtil.isCallFull(peekInfo));
@@ -831,25 +833,25 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
public void insertMissedCall(@NonNull RemotePeer remotePeer, long timestamp, boolean isVideoOffer) {
CallTable.Call call = SignalDatabase.calls()
.updateCall(remotePeer.getCallId().longValue(), CallTable.Event.MISSED);
.updateOneToOneCall(remotePeer.getCallId().longValue(), CallTable.Event.MISSED);
if (call == null) {
CallTable.Type type = isVideoOffer ? CallTable.Type.VIDEO_CALL : CallTable.Type.AUDIO_CALL;
SignalDatabase.calls()
.insertCall(remotePeer.getCallId().longValue(), timestamp, remotePeer.getId(), type, CallTable.Direction.INCOMING, CallTable.Event.MISSED);
.insertOneToOneCall(remotePeer.getCallId().longValue(), timestamp, remotePeer.getId(), type, CallTable.Direction.INCOMING, CallTable.Event.MISSED);
}
}
public void insertReceivedCall(@NonNull RemotePeer remotePeer, boolean isVideoOffer) {
CallTable.Call call = SignalDatabase.calls()
.updateCall(remotePeer.getCallId().longValue(), CallTable.Event.ACCEPTED);
.updateOneToOneCall(remotePeer.getCallId().longValue(), CallTable.Event.ACCEPTED);
if (call == null) {
CallTable.Type type = isVideoOffer ? CallTable.Type.VIDEO_CALL : CallTable.Type.AUDIO_CALL;
SignalDatabase.calls()
.insertCall(remotePeer.getCallId().longValue(), System.currentTimeMillis(), remotePeer.getId(), type, CallTable.Direction.INCOMING, CallTable.Event.ACCEPTED);
.insertOneToOneCall(remotePeer.getCallId().longValue(), System.currentTimeMillis(), remotePeer.getId(), type, CallTable.Direction.INCOMING, CallTable.Event.ACCEPTED);
}
}
@@ -887,17 +889,32 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
});
}
public void sendGroupCallUpdateMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId) {
SignalExecutors.BOUNDED.execute(() -> ApplicationDependencies.getJobManager().add(GroupCallUpdateSendJob.create(recipient.getId(), groupCallEraId)));
public void sendGroupCallUpdateMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId, boolean isIncoming, boolean isJoinEvent) {
SignalExecutors.BOUNDED.execute(() -> {
GroupCallUpdateSendJob updateSendJob = GroupCallUpdateSendJob.create(recipient.getId(), groupCallEraId);
JobManager.Chain chain = ApplicationDependencies.getJobManager().startChain(updateSendJob);
if (isJoinEvent && groupCallEraId != null) {
chain.then(CallSyncEventJob.createForJoin(
recipient.getId(),
CallId.fromEra(groupCallEraId).longValue(),
isIncoming
));
} else if (isJoinEvent) {
Log.w(TAG, "Can't send join event sync message without an era id.");
}
chain.enqueue();
});
}
public void updateGroupCallUpdateMessage(@NonNull RecipientId groupId, @Nullable String groupCallEraId, @NonNull Collection<UUID> joinedMembers, boolean isCallFull) {
SignalExecutors.BOUNDED.execute(() -> SignalDatabase.messages().insertOrUpdateGroupCall(groupId,
Recipient.self().getId(),
System.currentTimeMillis(),
groupCallEraId,
joinedMembers,
isCallFull));
SignalExecutors.BOUNDED.execute(() -> SignalDatabase.calls().insertOrUpdateGroupCallFromLocalEvent(groupId,
Recipient.self().getId(),
System.currentTimeMillis(),
groupCallEraId,
joinedMembers,
isCallFull));
}
public void sendCallMessage(@NonNull final RemotePeer remotePeer,
@@ -935,7 +952,7 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
public void sendAcceptedCallEventSyncMessage(@NonNull RemotePeer remotePeer, boolean isOutgoing, boolean isVideoCall) {
SignalDatabase
.calls()
.updateCall(remotePeer.getCallId().longValue(), CallTable.Event.ACCEPTED);
.updateOneToOneCall(remotePeer.getCallId().longValue(), CallTable.Event.ACCEPTED);
if (TextSecurePreferences.isMultiDevice(context)) {
networkExecutor.execute(() -> {
@@ -952,7 +969,7 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
public void sendNotAcceptedCallEventSyncMessage(@NonNull RemotePeer remotePeer, boolean isOutgoing, boolean isVideoCall) {
SignalDatabase
.calls()
.updateCall(remotePeer.getCallId().longValue(), CallTable.Event.NOT_ACCEPTED);
.updateOneToOneCall(remotePeer.getCallId().longValue(), CallTable.Event.NOT_ACCEPTED);
if (TextSecurePreferences.isMultiDevice(context)) {
networkExecutor.execute(() -> {

View File

@@ -54,6 +54,7 @@ import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Collection;
import java.util.List;
@@ -798,9 +799,11 @@ public abstract class WebRtcActionProcessor {
if (ringUpdate != RingUpdate.BUSY_LOCALLY && ringUpdate != RingUpdate.BUSY_ON_ANOTHER_DEVICE) {
webRtcInteractor.getCallManager().cancelGroupRing(groupId.getDecodedId(), ringId, CallManager.RingCancelReason.Busy);
}
SignalDatabase.groupCallRings().insertOrUpdateGroupRing(ringId,
System.currentTimeMillis(),
ringUpdate == RingUpdate.REQUESTED ? RingUpdate.BUSY_LOCALLY : ringUpdate);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(ringId,
remotePeerGroup.getId(),
sender,
System.currentTimeMillis(),
ringUpdate == RingUpdate.REQUESTED ? RingUpdate.BUSY_LOCALLY : ringUpdate);
} catch (CallException e) {
Log.w(tag, "Unable to cancel ring", e);
}
@@ -826,7 +829,7 @@ public abstract class WebRtcActionProcessor {
Recipient recipient = currentState.getCallInfoState().getCallRecipient();
if (recipient != null && currentState.getCallInfoState().getGroupCallState().isConnected()) {
webRtcInteractor.sendGroupCallMessage(recipient, WebRtcUtil.getGroupCallEraId(groupCall));
webRtcInteractor.sendGroupCallMessage(recipient, WebRtcUtil.getGroupCallEraId(groupCall), false, false);
}
currentState = currentState.builder()

View File

@@ -84,8 +84,8 @@ public class WebRtcInteractor {
signalCallManager.sendCallMessage(remotePeer, callMessage);
}
void sendGroupCallMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId) {
signalCallManager.sendGroupCallUpdateMessage(recipient, groupCallEraId);
void sendGroupCallMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId, boolean isIncoming, boolean isJoinEvent) {
signalCallManager.sendGroupCallUpdateMessage(recipient, groupCallEraId, isIncoming, isJoinEvent);
}
void updateGroupCallUpdateMessage(@NonNull RecipientId groupId, @Nullable String groupCallEraId, @NonNull Collection<UUID> joinedMembers, boolean isCallFull) {