Remove avatar color from CallLink table.

This commit is contained in:
Alex Hart 2023-06-14 14:58:04 -03:00 committed by Cody Henthorne
parent b9835584d8
commit 51222738df
22 changed files with 115 additions and 96 deletions

View file

@ -21,8 +21,8 @@ import org.thoughtcrime.securesms.testing.assertIsNot
import org.thoughtcrime.securesms.testing.parsedRequestBody
import org.thoughtcrime.securesms.testing.success
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity
import org.whispersystems.signalservice.internal.push.OneTimePreKeyCounts
import org.whispersystems.signalservice.internal.push.PreKeyState
import org.whispersystems.signalservice.internal.push.PreKeyStatus
@RunWith(AndroidJUnit4::class)
class PreKeysSyncJobTest {
@ -106,8 +106,8 @@ class PreKeysSyncJobTest {
val currentPniKeyId = pniPreKeyMeta.activeSignedPreKeyId
InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers(
Get("/v2/keys?identity=aci") { MockResponse().success(PreKeyStatus(100)) },
Get("/v2/keys?identity=pni") { MockResponse().success(PreKeyStatus(100)) }
Get("/v2/keys?identity=aci") { MockResponse().success(OneTimePreKeyCounts(100, 100)) },
Get("/v2/keys?identity=pni") { MockResponse().success(OneTimePreKeyCounts(100, 100)) }
)
// WHEN
@ -133,7 +133,7 @@ class PreKeysSyncJobTest {
val currentPniKeyId = pniPreKeyMeta.activeSignedPreKeyId
InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers(
Get("/v2/keys?identity=aci") { MockResponse().success(PreKeyStatus(100)) },
Get("/v2/keys?identity=aci") { MockResponse().success(OneTimePreKeyCounts(100, 100)) },
Put("/v2/keys/signed?identity=pni") { MockResponse().success() }
)
@ -157,15 +157,15 @@ class PreKeysSyncJobTest {
val currentAciKeyId = aciPreKeyMeta.activeSignedPreKeyId
val currentPniKeyId = pniPreKeyMeta.activeSignedPreKeyId
val currentNextAciPreKeyId = aciPreKeyMeta.nextOneTimePreKeyId
val currentNextPniPreKeyId = pniPreKeyMeta.nextOneTimePreKeyId
val currentNextAciPreKeyId = aciPreKeyMeta.nextEcOneTimePreKeyId
val currentNextPniPreKeyId = pniPreKeyMeta.nextEcOneTimePreKeyId
lateinit var aciPreKeyStateRequest: PreKeyState
lateinit var pniPreKeyStateRequest: PreKeyState
InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers(
Get("/v2/keys?identity=aci") { MockResponse().success(PreKeyStatus(5)) },
Get("/v2/keys?identity=pni") { MockResponse().success(PreKeyStatus(5)) },
Get("/v2/keys?identity=aci") { MockResponse().success(OneTimePreKeyCounts(5, 5)) },
Get("/v2/keys?identity=pni") { MockResponse().success(OneTimePreKeyCounts(5, 5)) },
Put("/v2/keys/?identity=aci") { r ->
aciPreKeyStateRequest = r.parsedRequestBody()
MockResponse().success()
@ -184,8 +184,8 @@ class PreKeysSyncJobTest {
aciPreKeyMeta.activeSignedPreKeyId assertIsNot currentAciKeyId
pniPreKeyMeta.activeSignedPreKeyId assertIsNot currentPniKeyId
aciPreKeyMeta.nextOneTimePreKeyId assertIsNot currentNextAciPreKeyId
pniPreKeyMeta.nextOneTimePreKeyId assertIsNot currentNextPniPreKeyId
aciPreKeyMeta.nextEcOneTimePreKeyId assertIsNot currentNextAciPreKeyId
pniPreKeyMeta.nextEcOneTimePreKeyId assertIsNot currentNextPniPreKeyId
ApplicationDependencies.getProtocolStore().aci().identityKeyPair.publicKey.let { aciIdentityKey ->
aciPreKeyStateRequest.identityKey assertIs aciIdentityKey

View file

@ -32,6 +32,7 @@ import org.whispersystems.signalservice.api.push.DistributionId
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
import java.lang.UnsupportedOperationException
import java.util.Optional
import java.util.UUID
import java.util.concurrent.locks.ReentrantLock
@ -168,6 +169,10 @@ class BobClient(val serviceId: ServiceId, val e164: String, val identityKeyPair:
override fun getSenderKeySharedWith(distributionId: DistributionId?): MutableSet<SignalProtocolAddress> = throw UnsupportedOperationException()
override fun markSenderKeySharedWith(distributionId: DistributionId?, addresses: MutableCollection<SignalProtocolAddress>?) = throw UnsupportedOperationException()
override fun clearSenderKeySharedWith(addresses: MutableCollection<SignalProtocolAddress>?) = throw UnsupportedOperationException()
override fun storeLastResortKyberPreKey(kyberPreKeyId: Int, kyberPreKeyRecord: KyberPreKeyRecord) = throw UnsupportedOperationException()
override fun removeKyberPreKey(kyberPreKeyId: Int) = throw UnsupportedOperationException()
override fun loadLastResortKyberPreKeys(): List<KyberPreKeyRecord> = throw UnsupportedOperationException()
override fun isMultiDevice(): Boolean = throw UnsupportedOperationException()
}
}

View file

@ -101,6 +101,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
handleGroupLinkInIntent(intent);
handleProxyInIntent(intent);
handleSignalMeIntent(intent);
handleCallLinkInIntent(intent);
}
@Override

View file

@ -21,11 +21,12 @@ import java.net.URLDecoder
*/
object CallLinks {
private const val ROOT_KEY = "key"
private const val LINK_PREFIX = "https://signal.link/call/#key="
private const val HTTPS_LINK_PREFIX = "https://signal.link/call/#key="
private const val SNGL_LINK_PREFIX = "sgnl://signal.link/#key="
private val TAG = Log.tag(CallLinks::class.java)
fun url(linkKeyBytes: ByteArray) = "$LINK_PREFIX${CallLinkRootKey(linkKeyBytes)}"
fun url(linkKeyBytes: ByteArray) = "$HTTPS_LINK_PREFIX${CallLinkRootKey(linkKeyBytes)}"
fun watchCallLink(roomId: CallLinkRoomId): Observable<CallLinkTable.CallLink> {
return Observable.create { emitter ->
@ -52,7 +53,8 @@ object CallLinks {
@JvmStatic
fun parseUrl(url: String): CallLinkRootKey? {
if (!url.startsWith(LINK_PREFIX)) {
if (!url.startsWith(HTTPS_LINK_PREFIX) && !url.startsWith(SNGL_LINK_PREFIX)) {
Log.w(TAG, "Invalid url prefix.")
return null
}

View file

@ -37,7 +37,6 @@ import org.signal.core.ui.Buttons
import org.signal.core.ui.theme.SignalTheme
import org.signal.ringrtc.CallLinkRootKey
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
import org.thoughtcrime.securesms.conversation.colors.AvatarColorPair
import org.thoughtcrime.securesms.database.CallLinkTable
import org.thoughtcrime.securesms.recipients.RecipientId
@ -49,7 +48,6 @@ import java.time.Instant
@Preview
@Composable
private fun SignalCallRowPreview() {
val avatarColor = remember { AvatarColor.random() }
val callLink = remember {
val credentials = CallLinkCredentials.generate()
CallLinkTable.CallLink(
@ -61,8 +59,7 @@ private fun SignalCallRowPreview() {
restrictions = org.signal.ringrtc.CallLinkState.Restrictions.NONE,
expiration = Instant.MAX,
revoked = false
),
avatarColor = avatarColor
)
)
}
SignalTheme(false) {

View file

@ -7,7 +7,6 @@ package org.thoughtcrime.securesms.calls.links.create
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
import org.thoughtcrime.securesms.database.CallLinkTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
@ -24,7 +23,7 @@ import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkManager
class CreateCallLinkRepository(
private val callLinkManager: SignalCallLinkManager = ApplicationDependencies.getSignalCallManager().callLinkManager
) {
fun ensureCallLinkCreated(credentials: CallLinkCredentials, avatarColor: AvatarColor): Single<EnsureCallLinkCreatedResult> {
fun ensureCallLinkCreated(credentials: CallLinkCredentials): Single<EnsureCallLinkCreatedResult> {
val callLinkRecipientId = Single.fromCallable {
SignalDatabase.recipients.getByCallLinkRoomId(credentials.roomId)
}
@ -41,8 +40,7 @@ class CreateCallLinkRepository(
recipientId = RecipientId.UNKNOWN,
roomId = credentials.roomId,
credentials = credentials,
state = it.state,
avatarColor = avatarColor
state = it.state
)
)

View file

@ -16,7 +16,6 @@ import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.ringrtc.CallLinkState.Restrictions
import org.thoughtcrime.securesms.calls.links.CallLinks
import org.thoughtcrime.securesms.calls.links.UpdateCallLinkRepository
import org.thoughtcrime.securesms.conversation.colors.AvatarColorHash
import org.thoughtcrime.securesms.database.CallLinkTable
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkCredentials
@ -29,7 +28,6 @@ class CreateCallLinkViewModel(
private val mutationRepository: UpdateCallLinkRepository = UpdateCallLinkRepository()
) : ViewModel() {
private val credentials = CallLinkCredentials.generate()
private val avatarColor = AvatarColorHash.forCallLink(credentials.linkKeyBytes)
private val _callLink: MutableState<CallLinkTable.CallLink> = mutableStateOf(
CallLinkTable.CallLink(
recipientId = RecipientId.UNKNOWN,
@ -40,8 +38,7 @@ class CreateCallLinkViewModel(
restrictions = Restrictions.NONE,
revoked = false,
expiration = Instant.MAX
),
avatarColor = avatarColor
)
)
)
@ -63,7 +60,7 @@ class CreateCallLinkViewModel(
}
fun commitCallLink(): Single<EnsureCallLinkCreatedResult> {
return repository.ensureCallLinkCreated(credentials, avatarColor)
return repository.ensureCallLinkCreated(credentials)
}
fun setApproveAllMembers(approveAllMembers: Boolean): Single<UpdateCallLinkResult> {

View file

@ -200,8 +200,7 @@ private fun CallLinkDetailsPreview() {
revoked = false,
restrictions = Restrictions.NONE,
expiration = Instant.MAX
),
avatarColor = avatarColor
)
)
}

View file

@ -65,7 +65,6 @@ import org.thoughtcrime.securesms.calls.links.SignalCallRow
import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsViewModel
import org.thoughtcrime.securesms.components.AvatarImageView
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
import org.thoughtcrime.securesms.database.CallLinkTable
import org.thoughtcrime.securesms.events.WebRtcViewModel
import org.thoughtcrime.securesms.recipients.Recipient
@ -209,8 +208,7 @@ private fun SheetPreview() {
linkKeyBytes = byteArrayOf(1, 2, 3, 4, 5),
adminPassBytes = byteArrayOf(1, 2, 3, 4, 5)
),
state = SignalCallLinkState(),
avatarColor = AvatarColor.random()
state = SignalCallLinkState()
),
participants = listOf(Recipient.UNKNOWN).toImmutableList(),
onShareLinkClicked = {},

View file

@ -265,7 +265,8 @@ public class WebRtcCallViewModel extends ViewModel {
webRtcViewModel.getActiveDevice(),
webRtcViewModel.getAvailableDevices(),
webRtcViewModel.getRemoteDevicesCount().orElse(0),
webRtcViewModel.getParticipantLimit());
webRtcViewModel.getParticipantLimit(),
webRtcViewModel.getRecipient().isCallLink());
if (newState.isInOutgoingRingingMode()) {
cancelTimer();
@ -339,7 +340,8 @@ public class WebRtcCallViewModel extends ViewModel {
@NonNull SignalAudioManager.AudioDevice activeDevice,
@NonNull Set<SignalAudioManager.AudioDevice> availableDevices,
long remoteDevicesCount,
@Nullable Long participantLimit)
@Nullable Long participantLimit,
boolean isCallLink)
{
final WebRtcControls.CallState callState;
@ -407,7 +409,8 @@ public class WebRtcCallViewModel extends ViewModel {
participantLimit,
WebRtcControls.FoldableState.flat(),
activeDevice,
availableDevices));
availableDevices,
isCallLink));
}
private @NonNull WebRtcControls updateControlsFoldableState(@NonNull WebRtcControls.FoldableState foldableState, @NonNull WebRtcControls controls) {

View file

@ -27,7 +27,8 @@ public final class WebRtcControls {
null,
FoldableState.flat(),
SignalAudioManager.AudioDevice.NONE,
emptySet());
emptySet(),
false);
private final boolean isRemoteVideoEnabled;
private final boolean isLocalVideoEnabled;
@ -40,6 +41,7 @@ public final class WebRtcControls {
private final FoldableState foldableState;
private final SignalAudioManager.AudioDevice activeDevice;
private final Set<SignalAudioManager.AudioDevice> availableDevices;
private final boolean isCallLink;
private WebRtcControls() {
this(false,
@ -52,7 +54,8 @@ public final class WebRtcControls {
null,
FoldableState.flat(),
SignalAudioManager.AudioDevice.NONE,
emptySet());
emptySet(),
false);
}
WebRtcControls(boolean isLocalVideoEnabled,
@ -65,7 +68,8 @@ public final class WebRtcControls {
@Nullable Long participantLimit,
@NonNull FoldableState foldableState,
@NonNull SignalAudioManager.AudioDevice activeDevice,
@NonNull Set<SignalAudioManager.AudioDevice> availableDevices)
@NonNull Set<SignalAudioManager.AudioDevice> availableDevices,
boolean isCallLink)
{
this.isLocalVideoEnabled = isLocalVideoEnabled;
this.isRemoteVideoEnabled = isRemoteVideoEnabled;
@ -78,6 +82,7 @@ public final class WebRtcControls {
this.foldableState = foldableState;
this.activeDevice = activeDevice;
this.availableDevices = availableDevices;
this.isCallLink = isCallLink;
}
public @NonNull WebRtcControls withFoldableState(FoldableState foldableState) {
@ -91,7 +96,8 @@ public final class WebRtcControls {
participantLimit,
foldableState,
activeDevice,
availableDevices);
availableDevices,
isCallLink);
}
boolean displayErrorControls() {
@ -222,7 +228,7 @@ public final class WebRtcControls {
}
boolean displayRingToggle() {
return isPreJoin() && isGroupCall() && !hasAtLeastOneRemote;
return isPreJoin() && isGroupCall() && !isCallLink && !hasAtLeastOneRemote;
}
private boolean isError() {

View file

@ -18,7 +18,6 @@ import org.signal.core.util.requireInt
import org.signal.core.util.requireLong
import org.signal.core.util.requireNonNullBlob
import org.signal.core.util.requireNonNullString
import org.signal.core.util.requireString
import org.signal.core.util.select
import org.signal.core.util.update
import org.signal.core.util.withinTransaction
@ -53,7 +52,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
const val RESTRICTIONS = "restrictions"
const val REVOKED = "revoked"
const val EXPIRATION = "expiration"
const val AVATAR_COLOR = "avatar_color"
const val RECIPIENT_ID = "recipient_id"
//language=sql
@ -67,7 +65,6 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
$RESTRICTIONS INTEGER NOT NULL,
$REVOKED INTEGER NOT NULL,
$EXPIRATION INTEGER NOT NULL,
$AVATAR_COLOR TEXT NOT NULL,
$RECIPIENT_ID INTEGER UNIQUE REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}) ON DELETE CASCADE
)
"""
@ -76,7 +73,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
return contentValuesOf(
NAME to name,
RESTRICTIONS to restrictions.mapToInt(),
EXPIRATION to expiration.toEpochMilli(),
EXPIRATION to if (expiration == Instant.MAX) -1L else expiration.toEpochMilli(),
REVOKED to revoked
)
}
@ -94,7 +91,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
callLink: CallLink
) {
writableDatabase.withinTransaction { db ->
val recipientId = SignalDatabase.recipients.getOrInsertFromCallLinkRoomId(callLink.roomId, callLink.avatarColor)
val recipientId = SignalDatabase.recipients.getOrInsertFromCallLinkRoomId(callLink.roomId)
db
.insertInto(TABLE_NAME)
@ -174,8 +171,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
linkKeyBytes = callLinkRootKey.keyBytes,
adminPassBytes = null
),
state = SignalCallLinkState(),
avatarColor = AvatarColorHash.forCallLink(callLinkRootKey.keyBytes)
state = SignalCallLinkState()
)
insertCallLink(link)
@ -194,8 +190,7 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
recipientId = RecipientId.UNKNOWN,
roomId = callLinkRoomId,
credentials = null,
state = SignalCallLinkState(),
avatarColor = AvatarColor.random()
state = SignalCallLinkState()
)
insertCallLink(link)
return getCallLinkByRoomId(callLinkRoomId)!!
@ -327,8 +322,7 @@ 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,
ADMIN_KEY to data.credentials?.adminPassBytes,
AVATAR_COLOR to data.avatarColor.serialize()
ADMIN_KEY to data.credentials?.adminPassBytes
).apply {
putAll(data.state.serialize())
}
@ -356,9 +350,14 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
name = data.requireNonNullString(NAME),
restrictions = data.requireInt(RESTRICTIONS).mapToRestrictions(),
revoked = data.requireBoolean(REVOKED),
expiration = Instant.ofEpochMilli(data.requireLong(EXPIRATION)).truncatedTo(ChronoUnit.DAYS)
),
avatarColor = AvatarColor.deserialize(data.requireString(AVATAR_COLOR))
expiration = data.requireLong(EXPIRATION).let {
if (it == -1L) {
Instant.MAX
} else {
Instant.ofEpochMilli(it).truncatedTo(ChronoUnit.DAYS)
}
}
)
)
}
@ -375,9 +374,10 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
val recipientId: RecipientId,
val roomId: CallLinkRoomId,
val credentials: CallLinkCredentials?,
val state: SignalCallLinkState,
val avatarColor: AvatarColor
)
val state: SignalCallLinkState
) {
val avatarColor: AvatarColor = credentials?.let { AvatarColorHash.forCallLink(it.linkKeyBytes) } ?: AvatarColor.UNKNOWN
}
override fun remapRecipient(fromId: RecipientId, toId: RecipientId) {
writableDatabase.update(TABLE_NAME)

View file

@ -568,15 +568,14 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
).recipientId
}
fun getOrInsertFromCallLinkRoomId(callLinkRoomId: CallLinkRoomId, avatarColor: AvatarColor): RecipientId {
fun getOrInsertFromCallLinkRoomId(callLinkRoomId: CallLinkRoomId): RecipientId {
return getOrInsertByColumn(
CALL_LINK_ROOM_ID,
callLinkRoomId.serialize(),
contentValuesOf(
GROUP_TYPE to GroupType.CALL_LINK.id,
CALL_LINK_ROOM_ID to callLinkRoomId.serialize(),
PROFILE_SHARING to 1,
AVATAR_COLOR to avatarColor.serialize()
PROFILE_SHARING to 1
)
).recipientId
}

View file

@ -1794,7 +1794,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
recipientSettings,
null,
false,
group.isActive
group.isActive,
null
)
Recipient(recipientId, details, false)
} ?: Recipient.live(recipientId).get()

View file

@ -52,6 +52,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V193_BackCallLinksW
import org.thoughtcrime.securesms.database.helpers.migration.V194_KyberPreKeyMigration
import org.thoughtcrime.securesms.database.helpers.migration.V195_GroupMemberForeignKeyMigration
import org.thoughtcrime.securesms.database.helpers.migration.V196_BackCallLinksWithRecipientV2
import org.thoughtcrime.securesms.database.helpers.migration.V197_DropAvatarColorFromCallLinks
/**
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
@ -60,7 +61,7 @@ object SignalDatabaseMigrations {
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
const val DATABASE_VERSION = 196
const val DATABASE_VERSION = 197
@JvmStatic
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
@ -255,6 +256,10 @@ object SignalDatabaseMigrations {
if (oldVersion < 196) {
V196_BackCallLinksWithRecipientV2.migrate(context, db, oldVersion, newVersion)
}
if (oldVersion < 197) {
V197_DropAvatarColorFromCallLinks.migrate(context, db, oldVersion, newVersion)
}
}
@JvmStatic

View file

@ -0,0 +1,18 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.database.helpers.migration
import android.app.Application
import net.zetetic.database.sqlcipher.SQLiteDatabase
/**
* Because getting the color is a simple modulo operation, there is no need to store it in the database.
*/
object V197_DropAvatarColorFromCallLinks : SignalDatabaseMigration {
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("ALTER TABLE call_link DROP COLUMN avatar_color")
}
}

View file

@ -8,13 +8,11 @@ import org.signal.core.util.orNull
import org.signal.libsignal.protocol.util.Pair
import org.signal.ringrtc.CallException
import org.signal.ringrtc.CallLinkRootKey
import org.signal.ringrtc.CallLinkState
import org.thoughtcrime.securesms.attachments.Attachment
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
import org.thoughtcrime.securesms.attachments.TombstoneAttachment
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
import org.thoughtcrime.securesms.contactshare.Contact
import org.thoughtcrime.securesms.conversation.colors.AvatarColorHash
import org.thoughtcrime.securesms.crypto.SecurityEvent
import org.thoughtcrime.securesms.database.CallLinkTable
import org.thoughtcrime.securesms.database.CallTable
@ -119,7 +117,6 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMe
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.StickerPackOperation
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.ViewOnceOpen
import java.io.IOException
import java.time.Instant
import java.util.Optional
import java.util.UUID
import kotlin.time.Duration.Companion.seconds
@ -1200,13 +1197,7 @@ object SyncMessageProcessor {
linkKeyBytes = callLinkRootKey.keyBytes,
adminPassBytes = callLinkUpdate.adminPassKey?.toByteArray()
),
state = SignalCallLinkState(
name = "",
restrictions = CallLinkState.Restrictions.UNKNOWN,
revoked = false,
expiration = Instant.MIN
),
avatarColor = AvatarColorHash.forCallLink(callLinkRootKey.keyBytes)
state = SignalCallLinkState()
)
)

View file

@ -13,6 +13,7 @@ import com.annimon.stream.Stream;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.database.CallLinkTable;
import org.thoughtcrime.securesms.database.DistributionListTables;
import org.thoughtcrime.securesms.database.GroupTable;
@ -219,10 +220,10 @@ public final class LiveRecipient {
avatarId = Optional.of(groupRecord.get().getAvatarId());
}
return new RecipientDetails(title, null, avatarId, false, false, record.getRegistered(), record, members, false, groupRecord.get().isActive());
return new RecipientDetails(title, null, avatarId, false, false, record.getRegistered(), record, members, false, groupRecord.get().isActive(), null);
}
return new RecipientDetails(null, null, Optional.empty(), false, false, record.getRegistered(), record, null, false, false);
return new RecipientDetails(null, null, Optional.empty(), false, false, record.getRegistered(), record, null, false, false, null);
}
@WorkerThread
@ -247,10 +248,10 @@ public final class LiveRecipient {
if (callLink != null) {
String name = callLink.getState().getName();
return RecipientDetails.forCallLink(name, record);
return RecipientDetails.forCallLink(name, record, callLink.getAvatarColor());
}
return RecipientDetails.forCallLink(null, record);
return RecipientDetails.forCallLink(null, record, AvatarColor.UNKNOWN);
}
synchronized void set(@NonNull Recipient recipient) {

View file

@ -98,7 +98,8 @@ public class RecipientDetails {
@NonNull RecipientRecord record,
@Nullable List<RecipientId> participantIds,
boolean isReleaseChannel,
boolean isActiveGroup)
boolean isActiveGroup,
@Nullable AvatarColor avatarColor)
{
this.groupAvatarId = groupAvatarId;
this.systemContactPhoto = Util.uri(record.getSystemContactPhotoUri());
@ -141,7 +142,7 @@ public class RecipientDetails {
this.mentionSetting = record.getMentionSetting();
this.wallpaper = record.getWallpaper();
this.chatColors = record.getChatColors();
this.avatarColor = record.getAvatarColor();
this.avatarColor = avatarColor != null ? avatarColor : record.getAvatarColor();
this.about = record.getAbout();
this.aboutEmoji = record.getAboutEmoji();
this.systemProfileName = record.getSystemProfileName();
@ -227,15 +228,15 @@ public class RecipientDetails {
}
}
return new RecipientDetails(null, settings.getSystemDisplayName(), Optional.empty(), systemContact, isSelf, registeredState, settings, null, isReleaseChannel, false);
return new RecipientDetails(null, settings.getSystemDisplayName(), Optional.empty(), systemContact, isSelf, registeredState, settings, null, isReleaseChannel, false, null);
}
public static @NonNull RecipientDetails forDistributionList(String title, @Nullable List<RecipientId> members, @NonNull RecipientRecord record) {
return new RecipientDetails(title, null, Optional.empty(), false, false, record.getRegistered(), record, members, false, false);
return new RecipientDetails(title, null, Optional.empty(), false, false, record.getRegistered(), record, members, false, false, null);
}
public static @NonNull RecipientDetails forCallLink(String name, @NonNull RecipientRecord record) {
return new RecipientDetails(name, null, Optional.empty(), false, false, record.getRegistered(), record, Collections.emptyList(), false, false);
public static @NonNull RecipientDetails forCallLink(String name, @NonNull RecipientRecord record, @NonNull AvatarColor avatarColor) {
return new RecipientDetails(name, null, Optional.empty(), false, false, record.getRegistered(), record, Collections.emptyList(), false, false, avatarColor);
}
public static @NonNull RecipientDetails forUnknown() {

View file

@ -26,15 +26,12 @@ 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.CallLinkRootKey;
import org.signal.ringrtc.CallLinkState;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.WebRtcCallActivity;
import org.thoughtcrime.securesms.calls.links.CallLinks;
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.conversation.colors.AvatarColorHash;
import org.thoughtcrime.securesms.database.CallLinkTable;
import org.thoughtcrime.securesms.database.CallTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.GroupRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@ -45,16 +42,12 @@ import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.proxy.ProxyBottomSheetFragment;
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.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.IOException;
import java.time.Instant;
import java.util.Optional;
public class CommunicationActions {
@ -343,8 +336,7 @@ public class CommunicationActions {
public static void handlePotentialCallLinkUrl(@NonNull FragmentActivity activity, @NonNull String potentialUrl) {
CallLinkRootKey rootKey = CallLinks.parseUrl(potentialUrl);
if (rootKey == null) {
Log.w(TAG, "Failed to parse root key from call link.");
// TODO [alex] -- Display a dialog informing them that the URL was invalid.
Log.w(TAG, "Failed to parse root key from call link");
return;
}
@ -356,13 +348,17 @@ public class CommunicationActions {
* the user's database if one does not already exist.
*
* @param fragment The fragment, which will be used for context and permissions routing.
* @param rootKey The root key of the call link.
*/
public static void startVideoCall(@NonNull Fragment fragment, @NonNull CallLinkRootKey rootKey) {
startVideoCall(new FragmentCallContext(fragment), rootKey);
}
private static void startVideoCall(@NonNull CallContext callContext, @NonNull CallLinkRootKey rootKey) {
if (!FeatureFlags.adHocCalling()) {
Toast.makeText(callContext.getContext(), R.string.CommunicationActions_cant_join_call, Toast.LENGTH_SHORT).show();
return;
}
SimpleTask.run(() -> {
CallLinkRoomId roomId = CallLinkRoomId.fromBytes(rootKey.deriveRoomId());
CallLinkTable.CallLink callLink = SignalDatabase.callLinks().getOrCreateCallLinkByRootKey(rootKey);

View file

@ -104,7 +104,7 @@ public final class FeatureFlags {
private static final String PAYPAL_RECURRING_DONATIONS = "android.recurringPayPalDonations.3";
private static final String TEXT_FORMATTING = "android.textFormatting.2";
private static final String ANY_ADDRESS_PORTS_KILL_SWITCH = "android.calling.fieldTrial.anyAddressPortsKillSwitch";
private static final String AD_HOC_CALLING = "android.calling.ad.hoc";
private static final String AD_HOC_CALLING = "android.calling.ad.hoc.2";
private static final String EDIT_MESSAGE_RECEIVE = "android.editMessage.receive";
private static final String EDIT_MESSAGE_SEND = "android.editMessage.send";
private static final String MAX_ATTACHMENT_COUNT = "android.attachments.maxCount";
@ -169,13 +169,13 @@ public final class FeatureFlags {
EDIT_MESSAGE_RECEIVE,
EDIT_MESSAGE_SEND,
MAX_ATTACHMENT_COUNT,
MAX_ATTACHMENT_SIZE_MB
MAX_ATTACHMENT_SIZE_MB,
AD_HOC_CALLING
);
@VisibleForTesting
static final Set<String> NOT_REMOTE_CAPABLE = SetUtil.newHashSet(
PHONE_NUMBER_PRIVACY,
AD_HOC_CALLING
PHONE_NUMBER_PRIVACY
);
/**

View file

@ -158,7 +158,8 @@ object RecipientDatabaseTestUtils {
),
participants,
isReleaseChannel,
isActive
isActive,
null
),
resolved
)