Fix potential crash when searching contacts in forward sheet.

This commit is contained in:
Alex Hart
2022-09-23 14:32:39 -03:00
committed by Cody Henthorne
parent 8d7393e4b5
commit bdbdcccaff
7 changed files with 139 additions and 22 deletions

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.contacts.paged
import androidx.annotation.VisibleForTesting
import org.thoughtcrime.securesms.contacts.HeaderAction
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
import org.thoughtcrime.securesms.recipients.Recipient
@@ -36,4 +37,10 @@ sealed class ContactSearchData(val contactSearchKey: ContactSearchKey) {
* A row which the user can click to view all entries for a given section.
*/
class Expand(val sectionKey: ContactSearchConfiguration.SectionKey) : ContactSearchData(ContactSearchKey.Expand(sectionKey))
/**
* A row which contains an integer, for testing.
*/
@VisibleForTesting
class TestRow(val value: Int) : ContactSearchData(ContactSearchKey.Expand(ContactSearchConfiguration.SectionKey.RECENTS))
}

View File

@@ -76,6 +76,7 @@ object ContactSearchItems {
is ContactSearchData.KnownRecipient -> RecipientModel(it, selection.contains(it.contactSearchKey))
is ContactSearchData.Expand -> ExpandModel(it)
is ContactSearchData.Header -> HeaderModel(it)
is ContactSearchData.TestRow -> error("This row exists for testing only.")
}
}
)

View File

@@ -243,7 +243,7 @@ class ContactSearchPagedDataSource(
): ContactSearchCollection<R> {
return when (section) {
is ContactSearchConfiguration.Section.Stories -> StoriesSearchCollection(section, records, extraData, recordMapper, activeStoryCount, StoryComparator(latestStorySends))
else -> ContactSearchCollection(section, records, recordsPredicate, extraData, recordMapper, 0)
else -> ContactSearchCollection(section, records, recordsPredicate, recordMapper, 0)
}
}

View File

@@ -12,23 +12,20 @@ open class ContactSearchCollection<ContactRecord>(
private val section: ContactSearchConfiguration.Section,
private val records: ContactSearchIterator<ContactRecord>,
private val recordPredicate: ((ContactRecord) -> Boolean)? = null,
private val extraData: List<ContactSearchData>,
private val recordMapper: (ContactRecord) -> ContactSearchData,
private val activeContactCount: Int
) {
private val recordsCount: Int = if (recordPredicate != null) {
private val contentSize: Int = if (recordPredicate != null) {
records.asSequence().filter(recordPredicate).count()
} else {
records.getCount()
}
private val contentSize: Int
private val aggregateData: SparseArrayCompat<ContactSearchData> = SparseArrayCompat()
init {
records.moveToPosition(-1)
contentSize = recordsCount + extraData.count()
}
fun getSize(): Int {
@@ -57,7 +54,11 @@ open class ContactSearchCollection<ContactRecord>(
null to 0
}
fillDataWindow(start, end - start)
val windowOffset = start + startOffset - if (section.includeHeader) 1 else 0
val windowLimit = end - windowOffset - if (section.includeHeader) 1 else 0
fillDataWindow(windowOffset, windowLimit)
for (i in (start + startOffset) until (end - endOffset)) {
val correctedIndex = if (section.includeHeader) i - 1 else i
results.add(getItemAtCorrectedIndex(correctedIndex))
@@ -95,20 +96,9 @@ open class ContactSearchCollection<ContactRecord>(
key++
}
if (isAggregateDataFilled(offset, limit)) {
return
if (!isAggregateDataFilled(offset, limit)) {
error("Data integrity failure: ${section.sectionKey} requesting $offset , $limit")
}
extraData.forEach {
aggregateData.put(key, it)
key++
}
if (isAggregateDataFilled(offset, limit)) {
return
}
throw IllegalStateException("Could not fill aggregate data for bounds $offset $limit")
}
private fun isAggregateDataFilled(startOffset: Int, limit: Int): Boolean {

View File

@@ -13,7 +13,7 @@ class StoriesSearchCollection<ContactRecord>(
recordMapper: (ContactRecord) -> ContactSearchData,
activeContactCount: Int,
private val storyComparator: Comparator<ContactSearchData.Story>
) : ContactSearchCollection<ContactRecord>(section, records, null, extraData, recordMapper, activeContactCount) {
) : ContactSearchCollection<ContactRecord>(section, records, null, recordMapper, activeContactCount) {
private val aggregateStoryData: List<ContactSearchData.Story> by lazy {
if (section !is ContactSearchConfiguration.Section.Stories) {
error("Aggregate data creation is only necessary for stories.")

View File

@@ -38,7 +38,6 @@ import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.groupsv2.GroupChangeReconstruct;
@@ -47,7 +46,6 @@ import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.exceptions.GroupNotFoundException;
import java.io.Closeable;
import java.security.SecureRandom;