From 9db33c3fec963ea61b00c64a5250832240052c98 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 18 Dec 2025 15:43:14 -0400 Subject: [PATCH] Display proper text when not in the active call on the local device. --- .../conversation/ConversationUpdateItem.java | 23 ++++++++++++++++--- .../securesms/util/CommunicationActions.java | 23 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index 5db58dd3fa..63109b5b74 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -56,9 +56,13 @@ import org.thoughtcrime.securesms.util.ProjectionList; import org.thoughtcrime.securesms.util.SpanUtil; import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.Util; +import org.thoughtcrime.securesms.util.CommunicationActions; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.verify.VerifyIdentityActivity; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.disposables.Disposable; import org.signal.core.models.ServiceId; import java.util.Collection; @@ -107,6 +111,8 @@ public final class ConversationUpdateItem extends FrameLayout private final PassthroughClickListener passthroughClickListener = new PassthroughClickListener(); + private Disposable activeCallDisposable = Disposable.disposed(); + public ConversationUpdateItem(Context context) { super(context); } @@ -234,6 +240,7 @@ public final class ConversationUpdateItem extends FrameLayout public void unbind() { this.displayBodyWithTimer.removeObserver(updateObserver); handler.removeCallbacks(timerUpdateRunnable); + activeCallDisposable.dispose(); } @Override @@ -487,6 +494,8 @@ public final class ConversationUpdateItem extends FrameLayout } }); } else if (conversationMessage.getMessageRecord().isGroupCall()) { + activeCallDisposable.dispose(); + GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()); boolean isRingingOnLocalDevice = groupCallUpdateDetails.isRingingOnLocalDevice; boolean endedRecently = GroupCallUpdateDetailsUtil.checkCallEndedRecently(groupCallUpdateDetails); @@ -495,9 +504,7 @@ public final class ConversationUpdateItem extends FrameLayout int text = 0; if (Util.hasItems(serviceIds) || isRingingOnLocalDevice) { - if (serviceIds.contains(SignalStore.account().requireAci())) { - text = R.string.ConversationUpdateItem_return_to_call; - } else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).isCallFull) { + if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).isCallFull) { text = R.string.ConversationUpdateItem_call_is_full; } else { text = R.string.ConversationUpdateItem_join_call; @@ -516,6 +523,16 @@ public final class ConversationUpdateItem extends FrameLayout passthroughClickListener.onClick(v); } }); + + if (text == R.string.ConversationUpdateItem_join_call) { + activeCallDisposable = CommunicationActions.isDeviceInCallWithRecipient(conversationRecipient.getId()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(isInCall -> { + if (isInCall) { + actionButton.setText(R.string.ConversationUpdateItem_return_to_call); + } + }); + } } else { actionButton.setVisibility(GONE); actionButton.setOnClickListener(null); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java index 599b954c47..29b8043741 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java @@ -47,12 +47,15 @@ import org.thoughtcrime.securesms.profiles.manage.UsernameRepository; import org.thoughtcrime.securesms.profiles.manage.UsernameRepository.UsernameLinkConversionResult; import org.thoughtcrime.securesms.proxy.ProxyBottomSheetFragment; import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.service.webrtc.ActiveCallData; import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.util.views.SimpleProgressDialog; import org.whispersystems.signalservice.api.push.UsernameLinkComponents; +import io.reactivex.rxjava3.core.Single; + import java.io.IOException; import java.net.URI; import java.util.Objects; @@ -574,6 +577,26 @@ public class CommunicationActions { } } + /** + * Returns a Single that emits true if this device is currently in an active call with the given recipient, + * false otherwise. + */ + public static @NonNull Single isDeviceInCallWithRecipient(@NonNull RecipientId recipientId) { + return Single.create(emitter -> { + AppDependencies.getSignalCallManager().isCallActive(new ResultReceiver(new Handler(Looper.getMainLooper())) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == 1 && resultData != null) { + ActiveCallData activeCallData = ActiveCallData.fromBundle(resultData); + emitter.onSuccess(Objects.equals(activeCallData.getRecipientId(), recipientId)); + } else { + emitter.onSuccess(false); + } + } + }); + }); + } + public interface OnUserAlreadyInAnotherCall { void onUserAlreadyInAnotherCall(); }