mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 00:29:11 +01:00
Update RingRTC to 2.65.0
Co-authored-by: emir-signal <emir@signal.org> Co-authored-by: Cody Henthorne <cody@signal.org>
This commit is contained in:
@@ -11,7 +11,6 @@ import androidx.lifecycle.Observer;
|
||||
|
||||
import com.bumptech.glide.RequestManager;
|
||||
|
||||
import org.signal.ringrtc.CallLinkEpoch;
|
||||
import org.signal.ringrtc.CallLinkRootKey;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
@@ -30,8 +29,8 @@ import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory;
|
||||
import org.thoughtcrime.securesms.polls.PollRecord;
|
||||
import org.thoughtcrime.securesms.polls.PollOption;
|
||||
import org.thoughtcrime.securesms.polls.PollRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
@@ -136,7 +135,7 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable,
|
||||
void goToMediaPreview(ConversationItem parent, View sharedElement, MediaIntentFactory.MediaPreviewArgs args);
|
||||
void onEditedIndicatorClicked(@NonNull ConversationMessage conversationMessage);
|
||||
void onShowGroupDescriptionClicked(@NonNull String groupName, @NonNull String description, boolean shouldLinkifyWebLinks);
|
||||
void onJoinCallLink(@NonNull CallLinkRootKey callLinkRootKey, @Nullable CallLinkEpoch callLinkEpoch);
|
||||
void onJoinCallLink(@NonNull CallLinkRootKey callLinkRootKey);
|
||||
void onShowSafetyTips(boolean forGroup);
|
||||
void onReportSpamLearnMoreClicked();
|
||||
void onMessageRequestAcceptOptionsClicked();
|
||||
|
||||
@@ -40,7 +40,6 @@ class CallLinkArchiveExporter(private val cursor: Cursor) : Iterator<ArchiveReci
|
||||
id = callLink.recipientId.toLong(),
|
||||
callLink = CallLink(
|
||||
rootKey = callLink.credentials!!.linkKeyBytes.toByteString(),
|
||||
epoch = callLink.credentials.epochBytes?.takeIf { it.size == 4 }?.toByteString(),
|
||||
adminKey = callLink.credentials.adminPassBytes?.toByteString()?.nullIfEmpty(),
|
||||
name = callLink.state.name,
|
||||
expirationMs = expirationTime.takeIf { it != Long.MAX_VALUE }?.clampToValidBackupRange() ?: 0,
|
||||
|
||||
@@ -42,11 +42,7 @@ object CallLinkArchiveImporter {
|
||||
CallLinkTable.CallLink(
|
||||
recipientId = RecipientId.UNKNOWN,
|
||||
roomId = CallLinkRoomId.fromCallLinkRootKey(rootKey),
|
||||
credentials = CallLinkCredentials(
|
||||
callLink.rootKey.toByteArray(),
|
||||
callLink.epoch?.toByteArray(),
|
||||
callLink.adminKey?.toByteArray()
|
||||
),
|
||||
credentials = CallLinkCredentials(callLink.rootKey.toByteArray(), callLink.adminKey?.toByteArray()),
|
||||
state = SignalCallLinkState(
|
||||
name = callLink.name,
|
||||
restrictions = callLink.restrictions.toLocal(),
|
||||
|
||||
@@ -8,7 +8,6 @@ package org.thoughtcrime.securesms.calls.links
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.ringrtc.CallException
|
||||
import org.signal.ringrtc.CallLinkEpoch
|
||||
import org.signal.ringrtc.CallLinkRootKey
|
||||
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||
import org.thoughtcrime.securesms.database.DatabaseObserver
|
||||
@@ -23,7 +22,6 @@ import java.net.URLDecoder
|
||||
*/
|
||||
object CallLinks {
|
||||
private const val ROOT_KEY = "key"
|
||||
private const val EPOCH = "epoch"
|
||||
private const val LEGACY_HTTPS_LINK_PREFIX = "https://signal.link/call#key="
|
||||
private const val LEGACY_SGNL_LINK_PREFIX = "sgnl://signal.link/call#key="
|
||||
private const val HTTPS_LINK_PREFIX = "https://signal.link/call/#key="
|
||||
@@ -31,13 +29,7 @@ object CallLinks {
|
||||
|
||||
private val TAG = Log.tag(CallLinks::class.java)
|
||||
|
||||
fun url(rootKeyBytes: ByteArray, epochBytes: ByteArray?): String {
|
||||
return if (epochBytes == null) {
|
||||
"$HTTPS_LINK_PREFIX${CallLinkRootKey(rootKeyBytes)}"
|
||||
} else {
|
||||
"$HTTPS_LINK_PREFIX${CallLinkRootKey(rootKeyBytes)}&epoch=${CallLinkEpoch.fromBytes(epochBytes)}"
|
||||
}
|
||||
}
|
||||
fun url(rootKeyBytes: ByteArray): String = "$HTTPS_LINK_PREFIX${CallLinkRootKey(rootKeyBytes)}"
|
||||
|
||||
fun watchCallLink(roomId: CallLinkRoomId): Observable<CallLinkTable.CallLink> {
|
||||
return Observable.create { emitter ->
|
||||
@@ -78,13 +70,8 @@ object CallLinks {
|
||||
return url.split("#").last().startsWith("key=")
|
||||
}
|
||||
|
||||
data class CallLinkParseResult(
|
||||
val rootKey: CallLinkRootKey,
|
||||
val epoch: CallLinkEpoch?
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun parseUrl(url: String): CallLinkParseResult? {
|
||||
fun parseUrl(url: String): CallLinkRootKey? {
|
||||
if (!isPrefixedCallLink(url)) {
|
||||
Log.w(TAG, "Invalid url prefix.")
|
||||
return null
|
||||
@@ -132,13 +119,9 @@ object CallLinks {
|
||||
}
|
||||
|
||||
return try {
|
||||
val epoch = fragmentQuery[EPOCH]?.let { s -> CallLinkEpoch(s) }
|
||||
CallLinkParseResult(
|
||||
rootKey = CallLinkRootKey(key),
|
||||
epoch = epoch
|
||||
)
|
||||
return CallLinkRootKey(key)
|
||||
} catch (e: CallException) {
|
||||
Log.w(TAG, "Invalid root key or epoch found in fragment query string.")
|
||||
Log.w(TAG, "Invalid root key found in fragment query string.")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ import org.signal.core.ui.R as CoreUiR
|
||||
@Composable
|
||||
private fun SignalCallRowPreview() {
|
||||
val callLink = remember {
|
||||
val credentials = CallLinkCredentials(byteArrayOf(1, 2, 3, 4), byteArrayOf(0, 1, 2, 3), byteArrayOf(5, 6, 7, 8))
|
||||
val credentials = CallLinkCredentials(byteArrayOf(1, 2, 3, 4), byteArrayOf(5, 6, 7, 8))
|
||||
CallLinkTable.CallLink(
|
||||
recipientId = RecipientId.UNKNOWN,
|
||||
roomId = CallLinkRoomId.fromBytes(byteArrayOf(1, 3, 5, 7)),
|
||||
@@ -97,7 +97,7 @@ fun SignalCallRow(
|
||||
"https://signal.call.example.com"
|
||||
} else {
|
||||
remember(callLink.credentials) {
|
||||
callLink.credentials?.let { CallLinks.url(it.linkKeyBytes, it.epochBytes) } ?: ""
|
||||
callLink.credentials?.let { CallLinks.url(it.linkKeyBytes) } ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
||||
startActivity(
|
||||
ShareActivity.sendSimpleText(
|
||||
requireContext(),
|
||||
getString(R.string.CreateCallLink__use_this_link_to_join_a_signal_call, CallLinks.url(viewModel.linkKeyBytes, viewModel.epochBytes))
|
||||
getString(R.string.CreateCallLink__use_this_link_to_join_a_signal_call, CallLinks.url(viewModel.linkKeyBytes))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -176,7 +176,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
||||
lifecycleDisposable += viewModel.commitCallLink().subscribeBy(onSuccess = {
|
||||
when (it) {
|
||||
is EnsureCallLinkCreatedResult.Success -> {
|
||||
Util.copyToClipboard(requireContext(), CallLinks.url(viewModel.linkKeyBytes, viewModel.epochBytes))
|
||||
Util.copyToClipboard(requireContext(), CallLinks.url(viewModel.linkKeyBytes))
|
||||
Toast.makeText(requireContext(), R.string.CreateCallLinkBottomSheetDialogFragment__copied_to_clipboard, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
||||
is EnsureCallLinkCreatedResult.Success -> {
|
||||
val mimeType = Intent.normalizeMimeType("text/plain")
|
||||
val shareIntent = ShareCompat.IntentBuilder(requireContext())
|
||||
.setText(CallLinks.url(viewModel.linkKeyBytes, viewModel.epochBytes))
|
||||
.setText(CallLinks.url(viewModel.linkKeyBytes))
|
||||
.setType(mimeType)
|
||||
.createChooserIntent()
|
||||
|
||||
|
||||
@@ -52,9 +52,6 @@ class CreateCallLinkViewModel(
|
||||
val linkKeyBytes: ByteArray
|
||||
get() = callLink.value.credentials!!.linkKeyBytes
|
||||
|
||||
val epochBytes: ByteArray?
|
||||
get() = callLink.value.credentials!!.epochBytes
|
||||
|
||||
private val internalShowAlreadyInACall = MutableStateFlow(false)
|
||||
val showAlreadyInACall: StateFlow<Boolean> = internalShowAlreadyInACall
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ class DefaultCallLinkDetailsCallback(
|
||||
override fun onShareClicked() {
|
||||
val mimeType = Intent.normalizeMimeType("text/plain")
|
||||
val shareIntent = ShareCompat.IntentBuilder(activity)
|
||||
.setText(CallLinks.url(viewModel.rootKeySnapshot, viewModel.epochSnapshot))
|
||||
.setText(CallLinks.url(viewModel.rootKeySnapshot))
|
||||
.setType(mimeType)
|
||||
.createChooserIntent()
|
||||
|
||||
@@ -131,7 +131,7 @@ class DefaultCallLinkDetailsCallback(
|
||||
}
|
||||
|
||||
override fun onCopyClicked() {
|
||||
Util.copyToClipboard(activity, CallLinks.url(viewModel.rootKeySnapshot, viewModel.epochSnapshot))
|
||||
Util.copyToClipboard(activity, CallLinks.url(viewModel.rootKeySnapshot))
|
||||
Toast.makeText(activity, R.string.CreateCallLinkBottomSheetDialogFragment__copied_to_clipboard, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ class DefaultCallLinkDetailsCallback(
|
||||
activity.startActivity(
|
||||
ShareActivity.sendSimpleText(
|
||||
activity,
|
||||
activity.getString(R.string.CreateCallLink__use_this_link_to_join_a_signal_call, CallLinks.url(viewModel.rootKeySnapshot, viewModel.epochSnapshot))
|
||||
activity.getString(R.string.CreateCallLink__use_this_link_to_join_a_signal_call, CallLinks.url(viewModel.rootKeySnapshot))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -324,7 +324,6 @@ private fun CallLinkDetailsScreenPreview() {
|
||||
val callLink = remember {
|
||||
val credentials = CallLinkCredentials(
|
||||
byteArrayOf(1, 2, 3, 4),
|
||||
byteArrayOf(0, 1, 2, 3),
|
||||
byteArrayOf(3, 4, 5, 6)
|
||||
)
|
||||
CallLinkTable.CallLink(
|
||||
|
||||
@@ -48,9 +48,6 @@ class CallLinkDetailsViewModel(
|
||||
val rootKeySnapshot: ByteArray
|
||||
get() = state.value.callLink?.credentials?.linkKeyBytes ?: error("Call link not loaded yet.")
|
||||
|
||||
val epochSnapshot: ByteArray?
|
||||
get() = state.value.callLink?.credentials?.epochBytes
|
||||
|
||||
private val recipientSubject = BehaviorSubject.create<Recipient>()
|
||||
val recipientSnapshot: Recipient?
|
||||
get() = recipientSubject.value
|
||||
|
||||
@@ -172,11 +172,11 @@ public class LinkPreviewView extends FrameLayout {
|
||||
spinner.setVisibility(GONE);
|
||||
noPreview.setVisibility(GONE);
|
||||
|
||||
CallLinks.CallLinkParseResult callLinkParseResult = CallLinks.isCallLink(linkPreview.getUrl()) ? CallLinks.parseUrl(linkPreview.getUrl()) : null;
|
||||
CallLinkRootKey callLinkRootKey = CallLinks.isCallLink(linkPreview.getUrl()) ? CallLinks.parseUrl(linkPreview.getUrl()) : null;
|
||||
if (!Util.isEmpty(linkPreview.getTitle())) {
|
||||
title.setText(linkPreview.getTitle());
|
||||
title.setVisibility(VISIBLE);
|
||||
} else if (callLinkParseResult != null) {
|
||||
} else if (callLinkRootKey != null) {
|
||||
title.setText(R.string.Recipient_signal_call);
|
||||
title.setVisibility(VISIBLE);
|
||||
} else {
|
||||
@@ -186,7 +186,7 @@ public class LinkPreviewView extends FrameLayout {
|
||||
if (showDescription && !Util.isEmpty(linkPreview.getDescription())) {
|
||||
description.setText(linkPreview.getDescription());
|
||||
description.setVisibility(VISIBLE);
|
||||
} else if (callLinkParseResult != null) {
|
||||
} else if (callLinkRootKey != null) {
|
||||
description.setText(R.string.LinkPreviewView__use_this_link_to_join_a_signal_call);
|
||||
description.setVisibility(VISIBLE);
|
||||
} else {
|
||||
@@ -221,14 +221,14 @@ public class LinkPreviewView extends FrameLayout {
|
||||
thumbnail.get().setImageResource(requestManager, new ImageSlide(linkPreview.getThumbnail().get()), type == TYPE_CONVERSATION && !scheduleMessageMode, false);
|
||||
thumbnail.get().showSecondaryText(false);
|
||||
thumbnail.get().setOutlineEnabled(true);
|
||||
} else if (callLinkParseResult != null) {
|
||||
} else if (callLinkRootKey != null) {
|
||||
thumbnail.setVisibility(VISIBLE);
|
||||
thumbnailState.applyState(thumbnail);
|
||||
thumbnail.get().setImageDrawable(
|
||||
requestManager,
|
||||
new FallbackAvatarDrawable(
|
||||
getContext(),
|
||||
new FallbackAvatar.Resource.CallLink(AvatarColorHash.forCallLink(callLinkParseResult.getRootKey().getKeyBytes()))
|
||||
new FallbackAvatar.Resource.CallLink(AvatarColorHash.forCallLink(callLinkRootKey.getKeyBytes()))
|
||||
).circleCrop()
|
||||
);
|
||||
thumbnail.get().showSecondaryText(false);
|
||||
@@ -272,7 +272,7 @@ public class LinkPreviewView extends FrameLayout {
|
||||
thumbnailState.applyState(thumbnail);
|
||||
}
|
||||
|
||||
private @StringRes static int getLinkPreviewErrorString(@Nullable LinkPreviewRepository.Error customError) {
|
||||
private @StringRes static int getLinkPreviewErrorString(@Nullable LinkPreviewRepository.Error customError) {
|
||||
return customError == LinkPreviewRepository.Error.GROUP_LINK_INACTIVE ? R.string.LinkPreviewView_this_group_link_is_not_active
|
||||
: R.string.LinkPreviewView_no_link_preview_available;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ class ControlsAndInfoViewModel(
|
||||
|
||||
val rootKeySnapshot: ByteArray
|
||||
get() = state.value.callLink?.credentials?.linkKeyBytes ?: error("Call link not loaded yet.")
|
||||
val epochSnapshot: ByteArray?
|
||||
get() = state.value.callLink?.credentials?.epochBytes
|
||||
|
||||
fun setRecipient(recipient: Recipient) {
|
||||
if (recipient.isCallLink && callRecipientId != recipient.id) {
|
||||
|
||||
@@ -31,7 +31,7 @@ class CallInfoCallbacks(
|
||||
override fun onShareLinkClicked() {
|
||||
val mimeType = Intent.normalizeMimeType("text/plain")
|
||||
val shareIntent = ShareCompat.IntentBuilder(activity)
|
||||
.setText(CallLinks.url(controlsAndInfoViewModel.rootKeySnapshot, controlsAndInfoViewModel.epochSnapshot))
|
||||
.setText(CallLinks.url(controlsAndInfoViewModel.rootKeySnapshot))
|
||||
.setType(mimeType)
|
||||
.createChooserIntent()
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ import org.signal.core.util.DimensionUnit;
|
||||
import org.signal.core.util.StringUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.core.ui.view.Stub;
|
||||
import org.signal.ringrtc.CallLinkRootKey;
|
||||
import org.thoughtcrime.securesms.BindableConversationItem;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
@@ -1234,14 +1235,14 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||
//noinspection ConstantConditions
|
||||
LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
|
||||
|
||||
CallLinks.CallLinkParseResult callLinkParseResult = CallLinks.isCallLink(linkPreview.getUrl()) ? CallLinks.parseUrl(linkPreview.getUrl()) : null;
|
||||
if (callLinkParseResult != null) {
|
||||
CallLinkRootKey callLinkRootKey = CallLinks.isCallLink(linkPreview.getUrl()) ? CallLinks.parseUrl(linkPreview.getUrl()) : null;
|
||||
if (callLinkRootKey != null) {
|
||||
joinCallLinkStub.setVisibility(View.VISIBLE);
|
||||
joinCallLinkStub.get().setTextColor(ContextCompat.getColor(context, messageRecord.isOutgoing() ? org.signal.core.ui.R.color.signal_light_colorOnPrimary : org.signal.core.ui.R.color.signal_colorOnPrimaryContainer));
|
||||
joinCallLinkStub.get().setBackgroundColor(ContextCompat.getColor(context, messageRecord.isOutgoing() ? org.signal.core.ui.R.color.signal_light_colorTransparent2 : org.signal.core.ui.R.color.signal_colorOnPrimary));
|
||||
joinCallLinkStub.get().setOnClickListener(v -> {
|
||||
if (eventListener != null) {
|
||||
eventListener.onJoinCallLink(callLinkParseResult.getRootKey(), callLinkParseResult.getEpoch());
|
||||
eventListener.onJoinCallLink(callLinkRootKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -121,7 +121,6 @@ import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.orNull
|
||||
import org.signal.core.util.setActionItemTint
|
||||
import org.signal.donations.InAppPaymentType
|
||||
import org.signal.ringrtc.CallLinkEpoch
|
||||
import org.signal.ringrtc.CallLinkRootKey
|
||||
import org.thoughtcrime.securesms.BlockUnblockDialog
|
||||
import org.thoughtcrime.securesms.GroupMembersDialog
|
||||
@@ -3740,8 +3739,8 @@ class ConversationFragment :
|
||||
GroupDescriptionDialog.show(childFragmentManager, groupName, description, shouldLinkifyWebLinks)
|
||||
}
|
||||
|
||||
override fun onJoinCallLink(callLinkRootKey: CallLinkRootKey, callLinkEpoch: CallLinkEpoch?) {
|
||||
CommunicationActions.startVideoCall(this@ConversationFragment, callLinkRootKey, callLinkEpoch) {
|
||||
override fun onJoinCallLink(callLinkRootKey: CallLinkRootKey) {
|
||||
CommunicationActions.startVideoCall(this@ConversationFragment, callLinkRootKey) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,21 +21,18 @@ import org.signal.core.util.requireNonNullString
|
||||
import org.signal.core.util.select
|
||||
import org.signal.core.util.update
|
||||
import org.signal.core.util.withinTransaction
|
||||
import org.signal.ringrtc.CallLinkEpoch
|
||||
import org.signal.ringrtc.CallLinkRootKey
|
||||
import org.signal.ringrtc.CallLinkState.Restrictions
|
||||
import org.thoughtcrime.securesms.calls.log.CallLogRow
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColorHash
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobs.CallLinkUpdateSendJob
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkCredentials
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkState
|
||||
import org.whispersystems.signalservice.api.storage.StorageId
|
||||
import org.whispersystems.signalservice.internal.push.SyncMessage
|
||||
import java.time.Instant
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
@@ -50,7 +47,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
const val TABLE_NAME = "call_link"
|
||||
const val ID = "_id"
|
||||
const val ROOT_KEY = "root_key"
|
||||
const val EPOCH = "epoch"
|
||||
const val ROOM_ID = "room_id"
|
||||
const val ADMIN_KEY = "admin_key"
|
||||
const val NAME = "name"
|
||||
@@ -72,8 +68,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
$REVOKED INTEGER NOT NULL,
|
||||
$EXPIRATION INTEGER NOT NULL,
|
||||
$RECIPIENT_ID INTEGER UNIQUE REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}) ON DELETE CASCADE,
|
||||
$DELETION_TIMESTAMP INTEGER DEFAULT 0 NOT NULL,
|
||||
$EPOCH BLOB DEFAULT NULL
|
||||
$DELETION_TIMESTAMP INTEGER DEFAULT 0 NOT NULL
|
||||
)
|
||||
"""
|
||||
|
||||
@@ -133,7 +128,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
.values(
|
||||
contentValuesOf(
|
||||
ROOT_KEY to credentials.linkKeyBytes,
|
||||
EPOCH to credentials.epochBytes,
|
||||
ADMIN_KEY to credentials.adminPassBytes
|
||||
)
|
||||
)
|
||||
@@ -193,10 +187,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
.readToSingleObject { CallLinkDeserializer.deserialize(it) }
|
||||
}
|
||||
|
||||
fun getOrCreateCallLinkByRootKey(
|
||||
callLinkRootKey: CallLinkRootKey,
|
||||
callLinkEpoch: CallLinkEpoch?
|
||||
): CallLink {
|
||||
fun getOrCreateCallLinkByRootKey(callLinkRootKey: CallLinkRootKey): CallLink {
|
||||
val roomId = CallLinkRoomId.fromBytes(callLinkRootKey.deriveRoomId())
|
||||
val callLink = getCallLinkByRoomId(roomId)
|
||||
return if (callLink == null) {
|
||||
@@ -205,7 +196,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
roomId = roomId,
|
||||
credentials = CallLinkCredentials(
|
||||
linkKeyBytes = callLinkRootKey.keyBytes,
|
||||
epochBytes = callLinkEpoch?.bytes,
|
||||
adminPassBytes = null
|
||||
),
|
||||
state = SignalCallLinkState(),
|
||||
@@ -215,33 +205,12 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
insertCallLink(link)
|
||||
return getCallLinkByRoomId(roomId)!!
|
||||
} else {
|
||||
if (callLink.credentials?.epoch != callLinkEpoch) {
|
||||
val modifiedCallLink = overwriteEpoch(callLink, callLinkEpoch)
|
||||
AppDependencies.jobManager.add(
|
||||
CallLinkUpdateSendJob(
|
||||
callLink.credentials!!.roomId,
|
||||
SyncMessage.CallLinkUpdate.Type.UPDATE
|
||||
)
|
||||
)
|
||||
modifiedCallLink
|
||||
} else {
|
||||
callLink
|
||||
}
|
||||
callLink
|
||||
}
|
||||
}
|
||||
|
||||
private fun overwriteEpoch(callLink: CallLink, callLinkEpoch: CallLinkEpoch?): CallLink {
|
||||
val modifiedCallLink = callLink.copy(
|
||||
deletionTimestamp = 0,
|
||||
credentials = callLink.credentials!!.copy(epochBytes = callLinkEpoch?.bytes)
|
||||
)
|
||||
updateCallLinkCredentials(modifiedCallLink.roomId, modifiedCallLink.credentials!!)
|
||||
return modifiedCallLink
|
||||
}
|
||||
|
||||
fun insertOrUpdateCallLinkByRootKey(
|
||||
callLinkRootKey: CallLinkRootKey,
|
||||
callLinkEpoch: CallLinkEpoch?,
|
||||
adminPassKey: ByteArray?,
|
||||
deletionTimestamp: Long = 0L,
|
||||
storageId: StorageId? = null
|
||||
@@ -256,7 +225,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
roomId = roomId,
|
||||
credentials = CallLinkCredentials(
|
||||
linkKeyBytes = callLinkRootKey.keyBytes,
|
||||
epochBytes = callLinkEpoch?.bytes,
|
||||
adminPassBytes = adminPassKey
|
||||
),
|
||||
state = SignalCallLinkState(),
|
||||
@@ -283,8 +251,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
writableDatabase.update(TABLE_NAME)
|
||||
.values(
|
||||
ADMIN_KEY to adminPassKey,
|
||||
ROOT_KEY to callLinkRootKey.keyBytes,
|
||||
EPOCH to callLinkEpoch?.bytes
|
||||
ROOT_KEY to callLinkRootKey.keyBytes
|
||||
)
|
||||
.where("$ROOM_ID = ?", callLink.roomId.serialize())
|
||||
.run()
|
||||
@@ -495,7 +462,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
RECIPIENT_ID to data.recipientId.takeIf { it != RecipientId.UNKNOWN }?.toLong(),
|
||||
ROOM_ID to data.roomId.serialize(),
|
||||
ROOT_KEY to data.credentials?.linkKeyBytes,
|
||||
EPOCH to data.credentials?.epochBytes,
|
||||
ADMIN_KEY to data.credentials?.adminPassBytes
|
||||
).apply {
|
||||
putAll(data.state.serialize())
|
||||
@@ -519,7 +485,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
||||
credentials = data.requireBlob(ROOT_KEY)?.let { linkKey ->
|
||||
CallLinkCredentials(
|
||||
linkKeyBytes = linkKey,
|
||||
epochBytes = data.requireBlob(EPOCH),
|
||||
adminPassBytes = data.requireBlob(ADMIN_KEY)
|
||||
)
|
||||
},
|
||||
|
||||
@@ -154,6 +154,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V297_AddPinnedMessa
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V298_DoNotBackupReleaseNotes
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V299_AddAttachmentMetadataTable
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V300_AddKeyTransparencyColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V301_RemoveCallLinkEpoch
|
||||
import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSqliteDatabase
|
||||
|
||||
/**
|
||||
@@ -314,10 +315,11 @@ object SignalDatabaseMigrations {
|
||||
297 to V297_AddPinnedMessageColumns,
|
||||
298 to V298_DoNotBackupReleaseNotes,
|
||||
299 to V299_AddAttachmentMetadataTable,
|
||||
300 to V300_AddKeyTransparencyColumn
|
||||
300 to V300_AddKeyTransparencyColumn,
|
||||
301 to V301_RemoveCallLinkEpoch
|
||||
)
|
||||
|
||||
const val DATABASE_VERSION = 300
|
||||
const val DATABASE_VERSION = 301
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SignalSqliteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import org.thoughtcrime.securesms.database.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* We planned to introduce CallLink epochs as a first-class field to clients.
|
||||
* Now, we plan to introduce epochs as an internal detail in CallLink root keys.
|
||||
* Epochs were never enabled in production so no clients should have them.
|
||||
*/
|
||||
object V301_RemoveCallLinkEpoch : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("ALTER TABLE call_link DROP COLUMN epoch")
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,6 @@ class CallLinkUpdateSendJob private constructor(
|
||||
val callLinkUpdate = CallLinkUpdate(
|
||||
rootKey = callLink.credentials.linkKeyBytes.toByteString(),
|
||||
adminPasskey = callLink.credentials.adminPassBytes?.toByteString(),
|
||||
epoch = callLink.credentials.epochBytes?.toByteString(),
|
||||
type = callLinkUpdateType
|
||||
)
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ class RefreshCallLinkDetailsJob private constructor(
|
||||
val manager: SignalCallLinkManager = AppDependencies.signalCallManager.callLinkManager
|
||||
val credentials = CallLinkCredentials(
|
||||
linkKeyBytes = callLinkUpdate.rootKey!!.toByteArray(),
|
||||
epochBytes = callLinkUpdate.epoch?.toByteArray(),
|
||||
adminPassBytes = callLinkUpdate.adminPasskey?.toByteArray()
|
||||
)
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.signal.core.util.logging.Log;
|
||||
import org.signal.libsignal.protocol.InvalidMessageException;
|
||||
import org.signal.libsignal.zkgroup.VerificationFailedException;
|
||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
||||
import org.signal.ringrtc.CallLinkEpoch;
|
||||
import org.signal.ringrtc.CallLinkRootKey;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupJoinInfo;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -328,20 +327,15 @@ public class LinkPreviewRepository {
|
||||
@NonNull String callLinkUrl,
|
||||
@NonNull Callback callback) {
|
||||
|
||||
CallLinks.CallLinkParseResult linkParseResult = CallLinks.parseUrl(callLinkUrl);
|
||||
if (linkParseResult == null) {
|
||||
CallLinkRootKey callLinkRootKey = CallLinks.parseUrl(callLinkUrl);
|
||||
if (callLinkRootKey == null) {
|
||||
callback.onError(Error.PREVIEW_NOT_AVAILABLE);
|
||||
return () -> { };
|
||||
}
|
||||
|
||||
CallLinkEpoch epoch = linkParseResult.getEpoch();
|
||||
byte[] epochBytes = epoch != null ? epoch.getBytes() : null;
|
||||
|
||||
Disposable disposable = AppDependencies.getSignalCallManager()
|
||||
.getCallLinkManager()
|
||||
.readCallLink(new CallLinkCredentials(linkParseResult.getRootKey().getKeyBytes(),
|
||||
epochBytes,
|
||||
null))
|
||||
.readCallLink(new CallLinkCredentials(callLinkRootKey.getKeyBytes(), null))
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(
|
||||
result -> {
|
||||
|
||||
@@ -13,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.ringrtc.CallLinkEpoch
|
||||
import org.signal.ringrtc.CallLinkRootKey
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.FullScreenDialogFragment
|
||||
@@ -362,7 +361,7 @@ class MessageDetailsFragment : FullScreenDialogFragment(), MessageDetailsAdapter
|
||||
Log.w(TAG, "Not yet implemented!", Exception())
|
||||
}
|
||||
|
||||
override fun onJoinCallLink(callLinkRootKey: CallLinkRootKey, callLinkEpoch: CallLinkEpoch?) {
|
||||
override fun onJoinCallLink(callLinkRootKey: CallLinkRootKey) {
|
||||
Log.w(TAG, "Not yet implemented!", Exception())
|
||||
}
|
||||
|
||||
|
||||
@@ -1391,7 +1391,6 @@ object SyncMessageProcessor {
|
||||
roomId,
|
||||
CallLinkCredentials(
|
||||
callLinkUpdate.rootKey!!.toByteArray(),
|
||||
callLinkUpdate.epoch?.toByteArray(),
|
||||
callLinkUpdate.adminPasskey?.toByteArray()
|
||||
)
|
||||
)
|
||||
@@ -1403,7 +1402,6 @@ object SyncMessageProcessor {
|
||||
roomId = roomId,
|
||||
credentials = CallLinkCredentials(
|
||||
linkKeyBytes = callLinkRootKey.keyBytes,
|
||||
epochBytes = callLinkUpdate.epoch?.toByteArray(),
|
||||
adminPassBytes = callLinkUpdate.adminPasskey?.toByteArray()
|
||||
),
|
||||
state = SignalCallLinkState(),
|
||||
|
||||
@@ -70,7 +70,6 @@ class CallLinkPreJoinActionProcessor(
|
||||
serverPublicParams.endorsementPublicKey,
|
||||
callLinkAuthCredentialPresentation.serialize(),
|
||||
callLinkRootKey,
|
||||
callLink.credentials.epoch,
|
||||
callLink.credentials.adminPassBytes,
|
||||
ByteArray(0),
|
||||
AUDIO_LEVELS_INTERVAL,
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.signal.libsignal.zkgroup.calllinks.CallLinkSecretParams;
|
||||
import org.signal.libsignal.zkgroup.groups.GroupIdentifier;
|
||||
import org.signal.ringrtc.CallException;
|
||||
import org.signal.ringrtc.CallId;
|
||||
import org.signal.ringrtc.CallLinkEpoch;
|
||||
import org.signal.ringrtc.CallLinkRootKey;
|
||||
import org.signal.ringrtc.CallManager;
|
||||
import org.signal.ringrtc.CallSummary;
|
||||
@@ -420,7 +419,6 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
|
||||
}
|
||||
|
||||
CallLinkRootKey callLinkRootKey = new CallLinkRootKey(callLink.getCredentials().getLinkKeyBytes());
|
||||
CallLinkEpoch callLinkEpoch = callLink.getCredentials().getEpoch();
|
||||
GenericServerPublicParams genericServerPublicParams = new GenericServerPublicParams(AppDependencies.getSignalServiceNetworkAccess()
|
||||
.getConfiguration()
|
||||
.getGenericServerPublicParams());
|
||||
@@ -432,7 +430,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
|
||||
CallLinkSecretParams.deriveFromRootKey(callLinkRootKey.getKeyBytes())
|
||||
);
|
||||
|
||||
callManager.peekCallLinkCall(SignalStore.internal().getGroupCallingServer(), callLinkAuthCredentialPresentation.serialize(), callLinkRootKey, callLinkEpoch, peekInfo -> {
|
||||
callManager.peekCallLinkCall(SignalStore.internal().getGroupCallingServer(), callLinkAuthCredentialPresentation.serialize(), callLinkRootKey, peekInfo -> {
|
||||
PeekInfo info = peekInfo.getValue();
|
||||
if (info == null) {
|
||||
Log.w(TAG, "Failed to get peek info: " + peekInfo.getStatus());
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.thoughtcrime.securesms.service.webrtc.links
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.signal.ringrtc.CallLinkEpoch
|
||||
import org.signal.ringrtc.CallLinkRootKey
|
||||
|
||||
/**
|
||||
@@ -16,7 +15,6 @@ import org.signal.ringrtc.CallLinkRootKey
|
||||
@Parcelize
|
||||
data class CallLinkCredentials(
|
||||
val linkKeyBytes: ByteArray,
|
||||
val epochBytes: ByteArray?,
|
||||
val adminPassBytes: ByteArray?
|
||||
) : Parcelable {
|
||||
|
||||
@@ -24,10 +22,6 @@ data class CallLinkCredentials(
|
||||
CallLinkRoomId.fromCallLinkRootKey(CallLinkRootKey(linkKeyBytes))
|
||||
}
|
||||
|
||||
val epoch: CallLinkEpoch? by lazy {
|
||||
epochBytes?.let { CallLinkEpoch.fromBytes(it) }
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
@@ -41,12 +35,6 @@ data class CallLinkCredentials(
|
||||
} else if (other.adminPassBytes != null) {
|
||||
return false
|
||||
}
|
||||
if (epochBytes != null) {
|
||||
if (other.epochBytes == null) return false
|
||||
if (!epochBytes.contentEquals(other.epochBytes)) return false
|
||||
} else if (other.epochBytes != null) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -64,7 +52,6 @@ data class CallLinkCredentials(
|
||||
fun generate(): CallLinkCredentials {
|
||||
return CallLinkCredentials(
|
||||
CallLinkRootKey.generate().keyBytes,
|
||||
null,
|
||||
CallLinkRootKey.generateAdminPasskey()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ class SignalCallLinkManager(
|
||||
) { result ->
|
||||
if (result.isSuccess) {
|
||||
Log.d(TAG, "Successfully created call link.")
|
||||
val epoch = result.value!!.epoch
|
||||
val rootKey = result.value!!.rootKey
|
||||
emitter.onSuccess(
|
||||
CreateCallLinkResult.Success(
|
||||
credentials = CallLinkCredentials(rootKey.keyBytes, epoch?.bytes, adminPassKey),
|
||||
credentials = CallLinkCredentials(rootKey.keyBytes, adminPassKey),
|
||||
state = result.value!!.toAppState()
|
||||
)
|
||||
)
|
||||
@@ -142,8 +142,7 @@ class SignalCallLinkManager(
|
||||
callManager.readCallLink(
|
||||
SignalStore.internal.groupCallingServer,
|
||||
requestCallLinkAuthCredentialPresentation(credentials.linkKeyBytes).serialize(),
|
||||
CallLinkRootKey(credentials.linkKeyBytes),
|
||||
credentials.epoch
|
||||
CallLinkRootKey(credentials.linkKeyBytes)
|
||||
) {
|
||||
if (it.isSuccess) {
|
||||
emitter.onSuccess(ReadCallLinkResult.Success(it.value!!.toAppState()))
|
||||
@@ -170,7 +169,6 @@ class SignalCallLinkManager(
|
||||
SignalStore.internal.groupCallingServer,
|
||||
credentialPresentation.serialize(),
|
||||
CallLinkRootKey(credentials.linkKeyBytes),
|
||||
credentials.epoch,
|
||||
credentials.adminPassBytes,
|
||||
name
|
||||
) { result ->
|
||||
@@ -198,7 +196,6 @@ class SignalCallLinkManager(
|
||||
SignalStore.internal.groupCallingServer,
|
||||
credentialPresentation.serialize(),
|
||||
CallLinkRootKey(credentials.linkKeyBytes),
|
||||
credentials.epoch,
|
||||
credentials.adminPassBytes,
|
||||
restrictions
|
||||
) { result ->
|
||||
@@ -225,7 +222,6 @@ class SignalCallLinkManager(
|
||||
SignalStore.internal.groupCallingServer,
|
||||
credentialPresentation.serialize(),
|
||||
CallLinkRootKey(credentials.linkKeyBytes),
|
||||
credentials.epoch,
|
||||
credentials.adminPassBytes
|
||||
) { result ->
|
||||
if (result.isSuccess && result.value == true) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import okio.ByteString.Companion.toByteString
|
||||
import org.signal.core.util.isNotEmpty
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.toOptional
|
||||
import org.signal.ringrtc.CallLinkEpoch
|
||||
import org.signal.ringrtc.CallLinkRootKey
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
@@ -49,7 +48,6 @@ class CallLinkRecordProcessor : DefaultStorageRecordProcessor<SignalCallLinkReco
|
||||
if (callLink != null && callLink.credentials?.adminPassBytes != null) {
|
||||
return SignalCallLinkRecord.newBuilder(null).apply {
|
||||
rootKey = callRootKey.keyBytes.toByteString()
|
||||
epoch = callLink.credentials.epochBytes?.toByteString()
|
||||
adminPasskey = callLink.credentials.adminPassBytes.toByteString()
|
||||
deletedAtTimestampMs = callLink.deletionTimestamp
|
||||
}.build().toSignalCallLinkRecord(StorageId.forCallLink(keyGenerator.generate())).toOptional()
|
||||
@@ -90,11 +88,8 @@ class CallLinkRecordProcessor : DefaultStorageRecordProcessor<SignalCallLinkReco
|
||||
private fun insertOrUpdateRecord(record: SignalCallLinkRecord) {
|
||||
val rootKey = CallLinkRootKey(record.proto.rootKey.toByteArray())
|
||||
|
||||
val epoch = record.proto.epoch?.let { CallLinkEpoch.fromBytes(it.toByteArray()) }
|
||||
|
||||
SignalDatabase.callLinks.insertOrUpdateCallLinkByRootKey(
|
||||
callLinkRootKey = rootKey,
|
||||
callLinkEpoch = epoch,
|
||||
adminPassKey = record.proto.adminPasskey.toByteArray(),
|
||||
deletionTimestamp = record.proto.deletedAtTimestampMs,
|
||||
storageId = record.id
|
||||
|
||||
@@ -274,7 +274,6 @@ object StorageSyncModels {
|
||||
|
||||
return SignalCallLinkRecord.newBuilder(null).apply {
|
||||
rootKey = callLink.credentials.linkKeyBytes.toByteString()
|
||||
epoch = callLink.credentials.epochBytes?.toByteString()
|
||||
adminPasskey = adminPassword.toByteString()
|
||||
deletedAtTimestampMs = deletedTimestamp
|
||||
}.build().toSignalCallLinkRecord(StorageId.forCallLink(rawStorageId))
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.signal.core.util.concurrent.JvmRxExtensions;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.ringrtc.CallLinkEpoch;
|
||||
import org.signal.ringrtc.CallLinkRootKey;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.calls.links.CallLinks;
|
||||
@@ -334,8 +333,8 @@ public class CommunicationActions {
|
||||
return;
|
||||
}
|
||||
|
||||
CallLinks.CallLinkParseResult linkParseResult = CallLinks.parseUrl(potentialUrl);
|
||||
if (linkParseResult == null) {
|
||||
CallLinkRootKey callLinkRootKey = CallLinks.parseUrl(potentialUrl);
|
||||
if (callLinkRootKey == null) {
|
||||
Log.w(TAG, "Failed to parse root key from call link");
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.CommunicationActions_invalid_link)
|
||||
@@ -345,7 +344,7 @@ public class CommunicationActions {
|
||||
return;
|
||||
}
|
||||
|
||||
startVideoCall(new ActivityCallContext(activity), linkParseResult.getRootKey(), linkParseResult.getEpoch(), onUserAlreadyInAnotherCall);
|
||||
startVideoCall(new ActivityCallContext(activity), callLinkRootKey, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,14 +373,14 @@ public class CommunicationActions {
|
||||
*
|
||||
* @param fragment The fragment, which will be used for context and permissions routing.
|
||||
*/
|
||||
public static void startVideoCall(@NonNull Fragment fragment, @NonNull CallLinkRootKey rootKey, @Nullable CallLinkEpoch epoch, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
startVideoCall(new FragmentCallContext(fragment), rootKey, epoch, onUserAlreadyInAnotherCall);
|
||||
public static void startVideoCall(@NonNull Fragment fragment, @NonNull CallLinkRootKey rootKey, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
startVideoCall(new FragmentCallContext(fragment), rootKey, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
private static void startVideoCall(@NonNull CallContext callContext, @NonNull CallLinkRootKey rootKey, @Nullable CallLinkEpoch epoch, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
private static void startVideoCall(@NonNull CallContext callContext, @NonNull CallLinkRootKey rootKey, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
SimpleTask.run(() -> {
|
||||
CallLinkRoomId roomId = CallLinkRoomId.fromBytes(rootKey.deriveRoomId());
|
||||
CallLinkTable.CallLink callLink = SignalDatabase.callLinks().getOrCreateCallLinkByRootKey(rootKey, epoch);
|
||||
CallLinkTable.CallLink callLink = SignalDatabase.callLinks().getOrCreateCallLinkByRootKey(rootKey);
|
||||
|
||||
if (callLink.getState().hasBeenRevoked()) {
|
||||
return Optional.<Recipient>empty();
|
||||
|
||||
Reference in New Issue
Block a user