mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-08 09:18:39 +01:00
Add group call NOT_ACCEPTED sync handling.
This commit is contained in:
@@ -367,6 +367,28 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
|||||||
Log.d(TAG, "Transitioned group call ${call.callId} from ${call.event} to $newEvent")
|
Log.d(TAG, "Transitioned group call ${call.callId} from ${call.event} to $newEvent")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun declineIncomingGroupCall(call: Call) {
|
||||||
|
checkIsGroupOrAdHocCall(call)
|
||||||
|
check(call.direction == Direction.INCOMING)
|
||||||
|
|
||||||
|
val newEvent = when (call.event) {
|
||||||
|
Event.RINGING, Event.MISSED -> Event.DECLINED
|
||||||
|
else -> {
|
||||||
|
Log.d(TAG, "Call in state ${call.event} cannot be transitioned by DECLINED")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writableDatabase
|
||||||
|
.update(TABLE_NAME)
|
||||||
|
.values(EVENT to Event.serialize(newEvent))
|
||||||
|
.run()
|
||||||
|
|
||||||
|
ApplicationDependencies.getMessageNotifier().updateNotification(context)
|
||||||
|
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
|
||||||
|
Log.d(TAG, "Transitioned group call ${call.callId} from ${call.event} to $newEvent")
|
||||||
|
}
|
||||||
|
|
||||||
fun insertAcceptedGroupCall(
|
fun insertAcceptedGroupCall(
|
||||||
callId: Long,
|
callId: Long,
|
||||||
recipientId: RecipientId,
|
recipientId: RecipientId,
|
||||||
@@ -410,6 +432,46 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
|||||||
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
|
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun insertDeclinedGroupCall(
|
||||||
|
callId: Long,
|
||||||
|
recipientId: RecipientId,
|
||||||
|
timestamp: Long
|
||||||
|
) {
|
||||||
|
val recipient = Recipient.resolved(recipientId)
|
||||||
|
val type = if (recipient.isCallLink) Type.AD_HOC_CALL else Type.GROUP_CALL
|
||||||
|
|
||||||
|
writableDatabase.withinTransaction { db ->
|
||||||
|
val messageId: MessageId? = if (type == Type.GROUP_CALL) {
|
||||||
|
SignalDatabase.messages.insertGroupCall(
|
||||||
|
groupRecipientId = recipientId,
|
||||||
|
sender = Recipient.self().id,
|
||||||
|
timestamp,
|
||||||
|
"",
|
||||||
|
emptyList(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
db
|
||||||
|
.insertInto(TABLE_NAME)
|
||||||
|
.values(
|
||||||
|
CALL_ID to callId,
|
||||||
|
MESSAGE_ID to messageId?.id,
|
||||||
|
PEER to recipientId.toLong(),
|
||||||
|
EVENT to Event.serialize(Event.DECLINED),
|
||||||
|
TYPE to Type.serialize(type),
|
||||||
|
DIRECTION to Direction.serialize(Direction.INCOMING),
|
||||||
|
TIMESTAMP to timestamp,
|
||||||
|
RINGER to null
|
||||||
|
)
|
||||||
|
.run(SQLiteDatabase.CONFLICT_ABORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
|
||||||
|
}
|
||||||
|
|
||||||
fun insertOrUpdateGroupCallFromExternalEvent(
|
fun insertOrUpdateGroupCallFromExternalEvent(
|
||||||
groupRecipientId: RecipientId,
|
groupRecipientId: RecipientId,
|
||||||
sender: RecipientId,
|
sender: RecipientId,
|
||||||
|
|||||||
@@ -46,6 +46,21 @@ class CallSyncEventJob private constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun createForNotAccepted(conversationRecipientId: RecipientId, callId: Long, isIncoming: Boolean): CallSyncEventJob {
|
||||||
|
return CallSyncEventJob(
|
||||||
|
getParameters(),
|
||||||
|
listOf(
|
||||||
|
CallSyncEventJobRecord(
|
||||||
|
recipientId = conversationRecipientId.toLong(),
|
||||||
|
callId = callId,
|
||||||
|
direction = CallTable.Direction.serialize(if (isIncoming) CallTable.Direction.INCOMING else CallTable.Direction.OUTGOING),
|
||||||
|
event = CallTable.Event.serialize(CallTable.Event.NOT_ACCEPTED)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createForDelete(calls: List<CallTable.Call>): CallSyncEventJob {
|
private fun createForDelete(calls: List<CallTable.Call>): CallSyncEventJob {
|
||||||
return CallSyncEventJob(
|
return CallSyncEventJob(
|
||||||
getParameters(),
|
getParameters(),
|
||||||
@@ -129,6 +144,13 @@ class CallSyncEventJob private constructor(
|
|||||||
isVideoCall = callType != CallTable.Type.AUDIO_CALL
|
isVideoCall = callType != CallTable.Type.AUDIO_CALL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
CallTable.Event.NOT_ACCEPTED -> CallEventSyncMessageUtil.createNotAcceptedSyncMessage(
|
||||||
|
remotePeer = RemotePeer(callSyncEvent.deserializeRecipientId(), CallId(callSyncEvent.callId)),
|
||||||
|
timestamp = syncTimestamp,
|
||||||
|
isOutgoing = callSyncEvent.deserializeDirection() == CallTable.Direction.OUTGOING,
|
||||||
|
isVideoCall = callType != CallTable.Type.AUDIO_CALL
|
||||||
|
)
|
||||||
|
|
||||||
CallTable.Event.DELETE -> CallEventSyncMessageUtil.createDeleteCallEvent(
|
CallTable.Event.DELETE -> CallEventSyncMessageUtil.createDeleteCallEvent(
|
||||||
remotePeer = RemotePeer(callSyncEvent.deserializeRecipientId(), CallId(callSyncEvent.callId)),
|
remotePeer = RemotePeer(callSyncEvent.deserializeRecipientId(), CallId(callSyncEvent.callId)),
|
||||||
timestamp = syncTimestamp,
|
timestamp = syncTimestamp,
|
||||||
|
|||||||
@@ -1314,7 +1314,7 @@ object SyncMessageProcessor {
|
|||||||
when (event) {
|
when (event) {
|
||||||
CallTable.Event.DELETE -> SignalDatabase.calls.deleteGroupCall(call)
|
CallTable.Event.DELETE -> SignalDatabase.calls.deleteGroupCall(call)
|
||||||
CallTable.Event.ACCEPTED -> {
|
CallTable.Event.ACCEPTED -> {
|
||||||
if (call.timestamp < timestamp) {
|
if (call.timestamp > timestamp) {
|
||||||
SignalDatabase.calls.setTimestamp(call.callId, recipient.id, timestamp)
|
SignalDatabase.calls.setTimestamp(call.callId, recipient.id, timestamp)
|
||||||
}
|
}
|
||||||
if (callEvent.direction == SyncMessage.CallEvent.Direction.INCOMING) {
|
if (callEvent.direction == SyncMessage.CallEvent.Direction.INCOMING) {
|
||||||
@@ -1323,15 +1323,30 @@ object SyncMessageProcessor {
|
|||||||
warn(envelopeTimestamp, "Invalid direction OUTGOING for event ACCEPTED")
|
warn(envelopeTimestamp, "Invalid direction OUTGOING for event ACCEPTED")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CallTable.Event.NOT_ACCEPTED -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId")
|
CallTable.Event.NOT_ACCEPTED -> {
|
||||||
|
if (call.timestamp > timestamp) {
|
||||||
|
SignalDatabase.calls.setTimestamp(call.callId, recipient.id, timestamp)
|
||||||
|
}
|
||||||
|
if (callEvent.direction == SyncMessage.CallEvent.Direction.INCOMING) {
|
||||||
|
SignalDatabase.calls.declineIncomingGroupCall(call)
|
||||||
|
} else {
|
||||||
|
warn(envelopeTimestamp, "Invalid direction OUTGOING for event NOT_ACCEPTED")
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId")
|
else -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
when (event) {
|
when (event) {
|
||||||
CallTable.Event.DELETE -> SignalDatabase.calls.insertDeletedGroupCallFromSyncEvent(callEvent.id!!, recipient.id, direction, timestamp)
|
CallTable.Event.DELETE -> SignalDatabase.calls.insertDeletedGroupCallFromSyncEvent(callEvent.id!!, recipient.id, direction, timestamp)
|
||||||
CallTable.Event.ACCEPTED -> SignalDatabase.calls.insertAcceptedGroupCall(callEvent.id!!, recipient.id, direction, timestamp)
|
CallTable.Event.ACCEPTED -> SignalDatabase.calls.insertAcceptedGroupCall(callEvent.id!!, recipient.id, direction, timestamp)
|
||||||
CallTable.Event.NOT_ACCEPTED -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId")
|
CallTable.Event.NOT_ACCEPTED -> {
|
||||||
else -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId")
|
if (callEvent.direction == SyncMessage.CallEvent.Direction.INCOMING) {
|
||||||
|
SignalDatabase.calls.insertDeclinedGroupCall(callEvent.id!!, recipient.id, timestamp)
|
||||||
|
} else {
|
||||||
|
warn(envelopeTimestamp, "Invalid direction OUTGOING for event NOT_ACCEPTED for non-existing call")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId call: null")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -155,7 +155,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
|
|||||||
|
|
||||||
boolean remoteUserRangTheCall = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingerRecipient() != Recipient.self();
|
boolean remoteUserRangTheCall = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingerRecipient() != Recipient.self();
|
||||||
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
|
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
|
||||||
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, remoteUserRangTheCall, true);
|
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, null, remoteUserRangTheCall, true);
|
||||||
|
|
||||||
List<UUID> members = new ArrayList<>(peekInfo.getJoinedMembers());
|
List<UUID> members = new ArrayList<>(peekInfo.getJoinedMembers());
|
||||||
if (!members.contains(SignalStore.account().requireAci().getRawUuid())) {
|
if (!members.contains(SignalStore.account().requireAci().getRawUuid())) {
|
||||||
@@ -182,7 +182,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
|
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
|
||||||
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, false, false);
|
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, null, false, false);
|
||||||
|
|
||||||
List<UUID> members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireServiceId().getRawUuid()).toList();
|
List<UUID> members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireServiceId().getRawUuid()).toList();
|
||||||
webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, false);
|
webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, false);
|
||||||
|
|||||||
+4
@@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
|||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.signal.ringrtc.CallException;
|
import org.signal.ringrtc.CallException;
|
||||||
|
import org.signal.ringrtc.CallId;
|
||||||
import org.signal.ringrtc.CallManager;
|
import org.signal.ringrtc.CallManager;
|
||||||
import org.signal.ringrtc.GroupCall;
|
import org.signal.ringrtc.GroupCall;
|
||||||
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
|
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
|
||||||
@@ -233,6 +234,8 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @NonNull WebRtcServiceState handleDenyCall(@NonNull WebRtcServiceState currentState) {
|
protected @NonNull WebRtcServiceState handleDenyCall(@NonNull WebRtcServiceState currentState) {
|
||||||
|
Log.i(TAG, "handleDenyCall():");
|
||||||
|
|
||||||
Recipient recipient = currentState.getCallInfoState().getCallRecipient();
|
Recipient recipient = currentState.getCallInfoState().getCallRecipient();
|
||||||
Optional<GroupId> groupId = recipient.getGroupId();
|
Optional<GroupId> groupId = recipient.getGroupId();
|
||||||
long ringId = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingId();
|
long ringId = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingId();
|
||||||
@@ -252,6 +255,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
|
|||||||
Log.w(TAG, "Error while trying to cancel ring " + ringId, e);
|
Log.w(TAG, "Error while trying to cancel ring " + ringId, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), null, new CallId(ringId), true, false);
|
||||||
webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING);
|
webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING);
|
||||||
webRtcInteractor.stopAudio(false);
|
webRtcInteractor.stopAudio(false);
|
||||||
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE);
|
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE);
|
||||||
|
|||||||
@@ -1009,7 +1009,9 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendGroupCallUpdateMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId, boolean isIncoming, boolean isJoinEvent) {
|
public void sendGroupCallUpdateMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId, final @Nullable CallId callId, boolean isIncoming, boolean isJoinEvent) {
|
||||||
|
Log.i(TAG, "sendGroupCallUpdateMessage id: " + recipient.getId() + " era: " + groupCallEraId + " isIncoming: " + isIncoming + " isJoinEvent: " + isJoinEvent);
|
||||||
|
|
||||||
if (recipient.isCallLink()) {
|
if (recipient.isCallLink()) {
|
||||||
Log.i(TAG, "sendGroupCallUpdateMessage -- ignoring for call link");
|
Log.i(TAG, "sendGroupCallUpdateMessage -- ignoring for call link");
|
||||||
return;
|
return;
|
||||||
@@ -1018,15 +1020,28 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
|
|||||||
SignalExecutors.BOUNDED.execute(() -> {
|
SignalExecutors.BOUNDED.execute(() -> {
|
||||||
GroupCallUpdateSendJob updateSendJob = GroupCallUpdateSendJob.create(recipient.getId(), groupCallEraId);
|
GroupCallUpdateSendJob updateSendJob = GroupCallUpdateSendJob.create(recipient.getId(), groupCallEraId);
|
||||||
JobManager.Chain chain = ApplicationDependencies.getJobManager().startChain(updateSendJob);
|
JobManager.Chain chain = ApplicationDependencies.getJobManager().startChain(updateSendJob);
|
||||||
|
CallId callIdLocal = callId;
|
||||||
|
|
||||||
if (isJoinEvent && groupCallEraId != null) {
|
if (callIdLocal == null && groupCallEraId != null) {
|
||||||
chain.then(CallSyncEventJob.createForJoin(
|
callIdLocal = CallId.fromEra(groupCallEraId);
|
||||||
recipient.getId(),
|
}
|
||||||
CallId.fromEra(groupCallEraId).longValue(),
|
|
||||||
isIncoming
|
if (callIdLocal != null) {
|
||||||
));
|
if (isJoinEvent) {
|
||||||
} else if (isJoinEvent) {
|
chain.then(CallSyncEventJob.createForJoin(
|
||||||
Log.w(TAG, "Can't send join event sync message without an era id.");
|
recipient.getId(),
|
||||||
|
callIdLocal.longValue(),
|
||||||
|
isIncoming
|
||||||
|
));
|
||||||
|
} else if (isIncoming) {
|
||||||
|
chain.then(CallSyncEventJob.createForNotAccepted(
|
||||||
|
recipient.getId(),
|
||||||
|
callIdLocal.longValue(),
|
||||||
|
isIncoming
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Can't send sync message without a call id. isIncoming: " + isIncoming + " isJoinEvent: " + isJoinEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.enqueue();
|
chain.enqueue();
|
||||||
|
|||||||
+1
-1
@@ -828,7 +828,7 @@ public abstract class WebRtcActionProcessor {
|
|||||||
Recipient recipient = currentState.getCallInfoState().getCallRecipient();
|
Recipient recipient = currentState.getCallInfoState().getCallRecipient();
|
||||||
|
|
||||||
if (recipient != null && currentState.getCallInfoState().getGroupCallState().isConnected()) {
|
if (recipient != null && currentState.getCallInfoState().getGroupCallState().isConnected()) {
|
||||||
webRtcInteractor.sendGroupCallMessage(recipient, WebRtcUtil.getGroupCallEraId(groupCall), false, false);
|
webRtcInteractor.sendGroupCallMessage(recipient, WebRtcUtil.getGroupCallEraId(groupCall), null, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentState = currentState.builder()
|
currentState = currentState.builder()
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import android.net.Uri;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
|
|
||||||
|
import org.signal.ringrtc.CallId;
|
||||||
import org.signal.ringrtc.CallManager;
|
import org.signal.ringrtc.CallManager;
|
||||||
import org.signal.ringrtc.GroupCall;
|
import org.signal.ringrtc.GroupCall;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
@@ -85,8 +85,8 @@ public class WebRtcInteractor {
|
|||||||
signalCallManager.sendCallMessage(remotePeer, callMessage);
|
signalCallManager.sendCallMessage(remotePeer, callMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendGroupCallMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId, boolean isIncoming, boolean isJoinEvent) {
|
void sendGroupCallMessage(@NonNull Recipient recipient, @Nullable String groupCallEraId, @Nullable CallId callId, boolean isIncoming, boolean isJoinEvent) {
|
||||||
signalCallManager.sendGroupCallUpdateMessage(recipient, groupCallEraId, isIncoming, isJoinEvent);
|
signalCallManager.sendGroupCallUpdateMessage(recipient, groupCallEraId, callId, isIncoming, isJoinEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateGroupCallUpdateMessage(@NonNull RecipientId groupId, @Nullable String groupCallEraId, @NonNull Collection<UUID> joinedMembers, boolean isCallFull) {
|
void updateGroupCallUpdateMessage(@NonNull RecipientId groupId, @Nullable String groupCallEraId, @NonNull Collection<UUID> joinedMembers, boolean isCallFull) {
|
||||||
|
|||||||
Reference in New Issue
Block a user