Allow 1:1 polls and raise character limit.

This commit is contained in:
Michelle Tang
2026-01-05 12:56:13 -05:00
committed by jeffrey-signal
parent fd635542c0
commit f7d87f3436
19 changed files with 138 additions and 156 deletions

View File

@@ -135,10 +135,6 @@ object ExportSkips {
return log(sentTimestamp, "Poll option was invalid.")
}
fun pollNotInGroupChat(sentTimestamp: Long): String {
return log(sentTimestamp, "Poll was not in a group chat.")
}
fun pinMessageIsInvalid(sentTimestamp: Long): String {
return log(sentTimestamp, "Pin message update was invalid.")
}

View File

@@ -122,6 +122,7 @@ private val TAG = Log.tag(ChatItemArchiveExporter::class.java)
private val MAX_INLINED_BODY_SIZE = 128.kibiBytes.bytes.toInt()
private val MAX_INLINED_BODY_SIZE_WITH_LONG_ATTACHMENT_POINTER = 2.kibiBytes.bytes.toInt()
private val MAX_INLINED_QUOTE_BODY_SIZE = 2.kibiBytes.bytes.toInt()
private const val MAX_POLL_QUESTION_CHARACTER_LENGTH = 200
private const val MAX_POLL_CHARACTER_LENGTH = 100
private const val MAX_POLL_OPTIONS = 10
@@ -398,13 +399,8 @@ class ChatItemArchiveExporter(
}
extraData.pollsById[record.id] != null -> {
if (exportState.threadIdToRecipientId[builder.chatId] !in exportState.groupRecipientIds) {
Log.w(TAG, ExportSkips.pollNotInGroupChat(record.dateSent))
continue
}
val poll = extraData.pollsById[record.id]!!
if (poll.question.isEmpty() || poll.question.length > MAX_POLL_CHARACTER_LENGTH) {
if (poll.question.isEmpty() || poll.question.length > MAX_POLL_QUESTION_CHARACTER_LENGTH) {
Log.w(TAG, ExportSkips.invalidPollQuestion(record.dateSent))
continue
}

View File

@@ -218,12 +218,11 @@ class ConversationRepository(
val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(messageRecord.threadId)!!
val pollSentTimestamp = messageRecord.dateSent
if (threadRecipient.groupId.getOrNull()?.isV2 != true) {
if (threadRecipient.isPushV2Group && threadRecipient.groupId.getOrNull()?.isV2 != true) {
Log.w(TAG, "Missing group id")
emitter.tryOnError(Exception("Poll terminate failed"))
}
val groupId = threadRecipient.requireGroupId().requireV2()
val message = OutgoingMessage.pollTerminateMessage(
threadRecipient = threadRecipient,
sentTimeMillis = System.currentTimeMillis(),
@@ -233,12 +232,17 @@ class ConversationRepository(
Log.i(TAG, "Sending poll terminate to " + message.threadRecipient.id + ", thread: " + messageRecord.threadId)
val possibleTargets: List<Recipient> = SignalDatabase.groups.getGroupMembers(groupId, GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF)
.map { it.resolve() }
.distinctBy { it.id }
val possibleTargets: List<Recipient> = if (threadRecipient.isPushV2Group) {
SignalDatabase.groups.getGroupMembers(threadRecipient.requireGroupId().requireV2(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF)
.map { it.resolve() }
.distinctBy { it.id }
} else {
listOf(threadRecipient)
}
val isSelf = threadRecipient.isSelf
val eligibleTargets: List<Recipient> = RecipientUtil.getEligibleForSending(possibleTargets)
val results = sendEndPoll(threadRecipient, message, eligibleTargets, poll.messageId)
val results = sendEndPoll(threadRecipient, message, eligibleTargets, isSelf, poll.messageId)
val sendResults = GroupSendJobHelper.getCompletedSends(eligibleTargets, results)
if (sendResults.completed.isNotEmpty() || possibleTargets.isEmpty()) {
@@ -271,9 +275,9 @@ class ConversationRepository(
}
@Throws(IOException::class, GroupNotAMemberException::class, UndeliverableMessageException::class)
fun sendEndPoll(group: Recipient, message: OutgoingMessage, destinations: List<Recipient>, messageId: Long): List<SendMessageResult?> {
val groupId = group.requireGroupId().requireV2()
val groupRecord: GroupRecord? = SignalDatabase.groups.getGroup(group.requireGroupId()).getOrNull()
fun sendEndPoll(threadRecipient: Recipient, message: OutgoingMessage, destinations: List<Recipient>, isSelf: Boolean, messageId: Long): List<SendMessageResult?> {
val groupId = if (threadRecipient.isPushV2Group) threadRecipient.requireGroupId().requireV2() else null
val groupRecord: GroupRecord? = if (threadRecipient.isPushV2Group) SignalDatabase.groups.getGroup(threadRecipient.requireGroupId()).getOrNull() else null
if (groupRecord != null && groupRecord.isAnnouncementGroup && !groupRecord.isAdmin(Recipient.self())) {
throw UndeliverableMessageException("Non-admins cannot send messages in announcement groups!")
@@ -281,29 +285,35 @@ class ConversationRepository(
val builder = newBuilder()
GroupUtil.setDataMessageGroupContext(AppDependencies.application, builder, groupId)
if (groupId != null) {
GroupUtil.setDataMessageGroupContext(AppDependencies.application, builder, groupId)
}
val sentTime = System.currentTimeMillis()
val groupMessage = builder
val message = builder
.withTimestamp(sentTime)
.withExpiration((message.expiresIn / 1000).toInt())
.withProfileKey(ProfileKeyUtil.getSelfProfileKey().serialize())
.withPollTerminate(SignalServiceDataMessage.PollTerminate(message.messageExtras!!.pollTerminate!!.targetTimestamp))
.build()
return GroupSendUtil.sendResendableDataMessage(
applicationContext,
groupId,
null,
destinations,
false,
ContentHint.RESENDABLE,
MessageId(messageId),
groupMessage,
true,
false,
null
) { System.currentTimeMillis() - sentTime > POLL_TERMINATE_TIMEOUT.inWholeMilliseconds }
return if (isSelf) {
listOf(AppDependencies.signalServiceMessageSender.sendSyncMessage(message))
} else {
GroupSendUtil.sendResendableDataMessage(
applicationContext,
groupId,
null,
destinations,
false,
ContentHint.RESENDABLE,
MessageId(messageId),
message,
true,
false,
null
) { System.currentTimeMillis() - sentTime > POLL_TERMINATE_TIMEOUT.inWholeMilliseconds }
}
}
fun getPinnedMessages(threadId: Long): List<MmsMessageRecord> {

View File

@@ -67,6 +67,7 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.compose.ComposeDialogFragment
import org.thoughtcrime.securesms.polls.Poll
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.ViewUtil
import kotlin.time.Duration.Companion.milliseconds
@@ -78,6 +79,7 @@ class CreatePollFragment : ComposeDialogFragment() {
companion object {
private val TAG = Log.tag(CreatePollFragment::class)
val MAX_QUESTION_CHARACTER_LENGTH = if (RemoteConfig.pollsV2) 200 else 100
const val MAX_CHARACTER_LENGTH = 100
const val MAX_OPTIONS = 10
const val MIN_OPTIONS = 2
@@ -222,7 +224,7 @@ private fun CreatePollScreen(
TextFieldWithCountdown(
value = question,
label = { Text(text = stringResource(R.string.CreatePollFragment__ask_a_question)) },
onValueChange = { question = it.substring(0, minOf(it.length, CreatePollFragment.MAX_CHARACTER_LENGTH)) },
onValueChange = { question = it.substring(0, minOf(it.length, CreatePollFragment.MAX_QUESTION_CHARACTER_LENGTH)) },
keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
colors = TextFieldDefaults.colors(
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
@@ -232,6 +234,7 @@ private fun CreatePollScreen(
.fillMaxWidth()
.onFocusChanged { focusState -> if (focusState.isFocused) focusedOption = -1 }
.focusRequester(focusRequester),
maxCharacterLength = CreatePollFragment.MAX_QUESTION_CHARACTER_LENGTH,
countdownThreshold = CreatePollFragment.CHARACTER_COUNTDOWN_THRESHOLD
)
@@ -266,6 +269,7 @@ private fun CreatePollScreen(
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
},
maxCharacterLength = CreatePollFragment.MAX_CHARACTER_LENGTH,
countdownThreshold = CreatePollFragment.CHARACTER_COUNTDOWN_THRESHOLD
)
}
@@ -316,9 +320,10 @@ private fun TextFieldWithCountdown(
colors: TextFieldColors,
modifier: Modifier,
trailingIcon: @Composable () -> Unit = {},
maxCharacterLength: Int,
countdownThreshold: Int
) {
val charactersRemaining = CreatePollFragment.MAX_CHARACTER_LENGTH - value.length
val charactersRemaining = maxCharacterLength - value.length
val displayCountdown = charactersRemaining <= countdownThreshold
Box(modifier = Modifier.padding(start = 24.dp, end = 24.dp, bottom = 16.dp)) {

View File

@@ -131,7 +131,7 @@ class AttachmentKeyboardFragment : LoggingFragment(R.layout.attachment_keyboard_
private fun updateButtonsAvailable(recipient: Recipient) {
val paymentsValues = SignalStore.payments
val isPaymentsAvailable = paymentsValues.paymentsAvailability.isSendAllowed && !recipient.isSelf && !recipient.isGroup && recipient.isRegistered
val isPollsAvailable = recipient.isPushV2Group && RemoteConfig.polls
val isPollsAvailable = recipient.isPushV2Group || RemoteConfig.pollsV2
if (!isPaymentsAvailable && !isPollsAvailable) {
attachmentKeyboardView.filterAttachmentKeyboardButtons(removePaymentFilter.and(removePollFilter))

View File

@@ -286,6 +286,8 @@ public class IndividualSendJob extends PushSendJob {
SignalServiceDataMessage.GiftBadge giftBadge = getGiftBadgeFor(message);
SignalServiceDataMessage.Payment payment = getPayment(message);
List<BodyRange> bodyRanges = getBodyRanges(message);
SignalServiceDataMessage.PollCreate pollCreate = getPollCreate(message);
SignalServiceDataMessage.PollTerminate pollTerminate = getPollTerminate(message);
SignalServiceDataMessage.PinnedMessage pinnedMessage = getPinnedMessage(message);
SignalServiceDataMessage.Builder mediaMessageBuilder = SignalServiceDataMessage.newBuilder()
.withBody(message.getBody())
@@ -303,6 +305,8 @@ public class IndividualSendJob extends PushSendJob {
.asEndSessionMessage(message.isEndSession())
.withPayment(payment)
.withBodyRanges(bodyRanges)
.withPollCreate(pollCreate)
.withPollTerminate(pollTerminate)
.withPinnedMessage(pinnedMessage);
if (message.getParentStoryId() != null) {

View File

@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
@@ -49,7 +50,11 @@ class PollVoteJob(
return null
}
val recipients = conversationRecipient.participantIds.filter { it != Recipient.self().id }.map { it.toLong() }
val recipients = if (conversationRecipient.isGroup) {
conversationRecipient.participantIds.filter { it != Recipient.self().id }.map { it.toLong() }
} else {
listOf(conversationRecipient.id.toLong())
}
return PollVoteJob(
messageId = messageId,
@@ -108,7 +113,7 @@ class PollVoteJob(
val targetSentTimestamp = message.dateSent
val recipients = Recipient.resolvedList(recipientIds.filter { it != Recipient.self().id.toLong() }.map { RecipientId.from(it) })
val recipients = Recipient.resolvedList(recipientIds.map { RecipientId.from(it) })
val registered = RecipientUtil.getEligibleForSending(recipients)
val unregistered = recipients - registered.toSet()
val completions: List<Recipient> = deliver(conversationRecipient, registered, targetAuthor, targetSentTimestamp, poll)
@@ -140,15 +145,18 @@ class PollVoteJob(
)
)
GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush())
if (conversationRecipient.isPushV2Group) {
GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush())
}
val dataMessage = dataMessageBuilder.build()
val nonSelfDestinations = destinations.filter { !it.isSelf }
val results = GroupSendUtil.sendResendableDataMessage(
context,
conversationRecipient.groupId.map { obj: GroupId -> obj.requireV2() }.orElse(null),
null,
destinations,
nonSelfDestinations,
false,
ContentHint.RESENDABLE,
MessageId(messageId),
@@ -159,6 +167,10 @@ class PollVoteJob(
null
)
if (conversationRecipient.isSelf) {
results.add(AppDependencies.signalServiceMessageSender.sendSyncMessage(dataMessage))
}
val groupResult = GroupSendJobHelper.getCompletedSends(destinations, results)
for (unregistered in groupResult.unregistered) {

View File

@@ -37,7 +37,6 @@ import org.thoughtcrime.securesms.messages.StorySendUtil;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingMessage;
import org.thoughtcrime.securesms.polls.Poll;
import org.thoughtcrime.securesms.ratelimit.ProofRequiredExceptionHandler;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@@ -285,8 +284,8 @@ public final class PushGroupSendJob extends PushSendJob {
List<SignalServicePreview> previews = getPreviewsFor(message);
List<SignalServiceDataMessage.Mention> mentions = getMentionsFor(message.getMentions());
List<BodyRange> bodyRanges = getBodyRanges(message);
Optional<SignalServiceDataMessage.PollCreate> pollCreate = getPollCreate(message);
Optional<SignalServiceDataMessage.PollTerminate> pollTerminate = getPollTerminate(message);
SignalServiceDataMessage.PollCreate pollCreate = getPollCreate(message);
SignalServiceDataMessage.PollTerminate pollTerminate = getPollTerminate(message);
SignalServiceDataMessage.PinnedMessage pinnedMessage = getPinnedMessage(message);
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(attachments);
@@ -371,8 +370,8 @@ public final class PushGroupSendJob extends PushSendJob {
.withPreviews(previews)
.withMentions(mentions)
.withBodyRanges(bodyRanges)
.withPollCreate(pollCreate.orElse(null))
.withPollTerminate(pollTerminate.orElse(null))
.withPollCreate(pollCreate)
.withPollTerminate(pollTerminate)
.withPinnedMessage(pinnedMessage);
if (message.getParentStoryId() != null) {
@@ -419,23 +418,6 @@ public final class PushGroupSendJob extends PushSendJob {
}
}
private Optional<SignalServiceDataMessage.PollCreate> getPollCreate(OutgoingMessage message) {
Poll poll = message.getPoll();
if (poll == null) {
return Optional.empty();
}
return Optional.of(new SignalServiceDataMessage.PollCreate(poll.getQuestion(), poll.getAllowMultipleVotes(), poll.getPollOptions()));
}
private Optional<SignalServiceDataMessage.PollTerminate> getPollTerminate(OutgoingMessage message) {
if (message.getMessageExtras() == null || message.getMessageExtras().pollTerminate == null) {
return Optional.empty();
}
return Optional.of(new SignalServiceDataMessage.PollTerminate(message.getMessageExtras().pollTerminate.targetTimestamp));
}
public static long getMessageId(@Nullable byte[] serializedData) {
JsonJobData data = JsonJobData.deserialize(serializedData);
return data.getLong(KEY_MESSAGE_ID);

View File

@@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.QuoteModel;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.notifications.v2.ConversationId;
import org.thoughtcrime.securesms.polls.Poll;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
@@ -486,6 +487,23 @@ public abstract class PushSendJob extends SendJob {
return getBodyRanges(message.getBodyRanges());
}
protected @Nullable SignalServiceDataMessage.PollCreate getPollCreate(OutgoingMessage message) {
Poll poll = message.getPoll();
if (poll == null) {
return null;
}
return new SignalServiceDataMessage.PollCreate(poll.getQuestion(), poll.getAllowMultipleVotes(), poll.getPollOptions());
}
protected @Nullable SignalServiceDataMessage.PollTerminate getPollTerminate(OutgoingMessage message) {
if (message.getMessageExtras() == null || message.getMessageExtras().pollTerminate == null) {
return null;
}
return new SignalServiceDataMessage.PollTerminate(message.getMessageExtras().pollTerminate.targetTimestamp);
}
protected @Nullable List<BodyRange> getBodyRanges(@Nullable BodyRangeList bodyRanges) {
if (bodyRanges == null || bodyRanges.ranges.size() == 0) {
return null;

View File

@@ -124,6 +124,7 @@ import kotlin.time.Duration.Companion.seconds
object DataMessageProcessor {
private const val BODY_RANGE_PROCESSING_LIMIT = 250
private const val POLL_QUESTION_CHARACTER_LIMIT = 200
private const val POLL_CHARACTER_LIMIT = 100
private const val POLL_OPTIONS_LIMIT = 10
@@ -1066,28 +1067,23 @@ object DataMessageProcessor {
groupId: GroupId.V2?,
receivedTime: Long
): InsertResult? {
if (!RemoteConfig.receivePolls) {
log(envelope.timestamp!!, "Poll creation not allowed due to remote config.")
return null
}
log(envelope.timestamp!!, "Handle poll creation")
val poll: DataMessage.PollCreate = message.pollCreate!!
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
if (groupId == null) {
warn(envelope.timestamp!!, "[handlePollCreate] Polls can only be sent to groups. author: $senderRecipient")
if (groupId != null) {
val groupRecord = SignalDatabase.groups.getGroup(groupId).orNull()
if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) {
warn(envelope.timestamp!!, "[handlePollCreate] Poll author is not in the group. author $senderRecipient")
return null
}
} else if (senderRecipient.id != threadRecipient.id && senderRecipient.id != Recipient.self().id) {
warn(envelope.timestamp!!, "[handlePollCreate] Sender is not a part of the 1:1 thread!")
return null
}
val groupRecord = SignalDatabase.groups.getGroup(groupId).orNull()
if (groupRecord == null || !groupRecord.members.contains(senderRecipient.id)) {
warn(envelope.timestamp!!, "[handlePollCreate] Poll author is not in the group. author $senderRecipient")
return null
}
if (poll.question == null || poll.question!!.isEmpty() || poll.question!!.length > POLL_CHARACTER_LIMIT) {
if (poll.question == null || poll.question!!.isEmpty() || poll.question!!.length > POLL_QUESTION_CHARACTER_LIMIT) {
warn(envelope.timestamp!!, "[handlePollCreate] Poll question is invalid.")
return null
}
@@ -1136,11 +1132,6 @@ object DataMessageProcessor {
groupId: GroupId.V2?,
receivedTime: Long
): InsertResult? {
if (!RemoteConfig.receivePolls) {
log(envelope.timestamp!!, "Poll terminate not allowed due to remote config.")
return null
}
val pollTerminate: DataMessage.PollTerminate = message.pollTerminate!!
val targetSentTimestamp = pollTerminate.targetSentTimestamp!!
@@ -1189,11 +1180,6 @@ object DataMessageProcessor {
senderRecipient: Recipient,
earlyMessageCacheEntry: EarlyMessageCacheEntry?
): MessageId? {
if (!RemoteConfig.receivePolls) {
log(envelope.timestamp!!, "Poll vote not allowed due to remote config.")
return null
}
val pollVote: DataMessage.PollVote = message.pollVote!!
val targetSentTimestamp = pollVote.targetSentTimestamp!!
@@ -1578,14 +1564,12 @@ object DataMessageProcessor {
}
val groupRecord = SignalDatabase.groups.getGroup(targetThread.recipient.id).orNull()
if (groupRecord == null) {
warn(envelope.timestamp!!, "[handlePollValidation] Target thread needs to be a group. timestamp: $targetSentTimestamp author: ${targetAuthor.id}")
return null
}
if (!groupRecord.members.contains(senderRecipient.id)) {
if (groupRecord != null && !groupRecord.members.contains(senderRecipient.id)) {
warn(envelope.timestamp!!, "[handlePollValidation] Sender is not in the group. timestamp: $targetSentTimestamp author: ${targetAuthor.id}")
return null
} else if (groupRecord == null && senderRecipient.id != targetThread.recipient.id && senderRecipient.id != Recipient.self().id) {
warn(envelope.timestamp!!, "[handlePollValidation] Sender is not a part of the 1:1 thread!")
return null
}
return MessageId(targetMessage.id)

View File

@@ -1744,18 +1744,9 @@ object SyncMessageProcessor {
sent: Sent,
senderRecipient: Recipient
): Long {
if (!RemoteConfig.receivePolls) {
log(envelope.timestamp!!, "Sync poll create not allowed due to remote config.")
}
log(envelope.timestamp!!, "Synchronize sent poll creation message.")
val recipient = getSyncMessageDestination(sent)
if (!recipient.isGroup) {
warn(envelope.timestamp!!, "Poll creation messages should only be synced in groups. Dropping.")
return -1
}
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
val expiresInMillis = message.expireTimerDuration.inWholeMilliseconds
@@ -1777,8 +1768,12 @@ object SyncMessageProcessor {
question = poll.question!!
)
val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null).messageId
updateGroupReceiptStatus(sent, messageId, recipient.requireGroupId())
val receiptStatus = if (recipient.isGroup) GroupReceiptTable.STATUS_UNKNOWN else GroupReceiptTable.STATUS_UNDELIVERED
val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, receiptStatus, null).messageId
if (recipient.isGroup) {
updateGroupReceiptStatus(sent, messageId, recipient.requireGroupId())
}
log(envelope.timestamp!!, "Inserted sync poll create message as messageId $messageId")
@@ -1799,18 +1794,9 @@ object SyncMessageProcessor {
senderRecipient: Recipient,
earlyMessageCacheEntry: EarlyMessageCacheEntry?
): Long {
if (!RemoteConfig.receivePolls) {
log(envelope.timestamp!!, "Sync poll end not allowed due to remote config.")
}
log(envelope.timestamp!!, "Synchronize sent poll terminate message")
val recipient = getSyncMessageDestination(sent)
if (!recipient.isGroup) {
warn(envelope.timestamp!!, "Poll termination messages should only be synced in groups. Dropping.")
return -1
}
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
val expiresInMillis = message.expireTimerDuration.inWholeMilliseconds
@@ -1847,7 +1833,8 @@ object SyncMessageProcessor {
)
)
val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null).messageId
val receiptStatus = if (recipient.isGroup) GroupReceiptTable.STATUS_UNKNOWN else GroupReceiptTable.STATUS_UNDELIVERED
val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, receiptStatus, null).messageId
SignalDatabase.messages.markAsSent(messageId, true)
log(envelope.timestamp!!, "Inserted sync poll end message as messageId $messageId")

View File

@@ -265,12 +265,11 @@ public class MessageSender {
long messageId = insertResult.getMessageId();
if (!recipient.isPushV2Group()) {
Log.w(TAG, "Can only send polls to groups.");
return threadId;
SignalLocalMetrics.IndividualMessageSend.onInsertedIntoDatabase(messageId, metricId);
} else {
SignalLocalMetrics.GroupMessageSend.onInsertedIntoDatabase(messageId, metricId);
}
SignalLocalMetrics.GroupMessageSend.onInsertedIntoDatabase(messageId, metricId);
sendMessageInternal(context, recipient, sendType, messageId, insertResult.getQuoteAttachmentId(), Collections.emptyList());
onMessageSent();
SignalDatabase.threads().update(allocatedThreadId, true, true);

View File

@@ -1166,14 +1166,6 @@ object RemoteConfig {
hotSwappable = true
)
@JvmStatic
@get:JvmName("polls")
val polls: Boolean by remoteBoolean(
key = "android.polls.2",
defaultValue = false,
hotSwappable = true
)
/** Whether or not to send over binary service ids (alongside string service ids). */
@JvmStatic
@get:JvmName("useBinaryId")
@@ -1183,14 +1175,6 @@ object RemoteConfig {
hotSwappable = false
)
@JvmStatic
@get:JvmName("receivePolls")
val receivePolls: Boolean by remoteBoolean(
key = "android.receivePolls",
defaultValue = false,
hotSwappable = true
)
@JvmStatic
@get:JvmName("backupsBetaMegaphone")
val backupsBetaMegaphone: Boolean by remoteBoolean(
@@ -1238,5 +1222,16 @@ object RemoteConfig {
defaultValue = "*:10000",
hotSwappable = true
)
/**
* Whether or not to allow 1:1 polls and a higher character limit for questions
*/
@JvmStatic
@get:JvmName("pollsV2")
val pollsV2: Boolean by remoteBoolean(
key = "android.pollsV2",
defaultValue = false,
hotSwappable = true
)
// endregion
}