mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Fix avatar loading in OS views when app is not running.
This commit is contained in:
committed by
mtang-signal
parent
8a4d9fc635
commit
71b5a9f865
@@ -153,6 +153,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
DatabaseSecretProvider.getOrCreateDatabaseSecret(this),
|
||||
AttachmentSecretProvider.getInstance(this).getOrCreateAttachmentSecret());
|
||||
})
|
||||
.addBlocking("signal-store", () -> SignalStore.init(this))
|
||||
.addBlocking("logging", () -> {
|
||||
initializeLogging();
|
||||
Log.i(TAG, "onCreate()");
|
||||
|
||||
@@ -188,7 +188,7 @@ object BackupRepository {
|
||||
}
|
||||
|
||||
val db = KeyValueDatabase.createWithName(context, "$baseName.db")
|
||||
SignalStore(KeyValueStore(db))
|
||||
SignalStore(context, KeyValueStore(db))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.emoji
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.thoughtcrime.securesms.components.emoji.Emoji
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
|
||||
@@ -122,7 +123,8 @@ class EmojiSource(
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadAssetBasedEmojis(): EmojiSource {
|
||||
@VisibleForTesting
|
||||
fun loadAssetBasedEmojis(): EmojiSource {
|
||||
val emojiData: InputStream = AppDependencies.application.assets.open("emoji/emoji_data.json")
|
||||
|
||||
emojiData.use {
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.preference.PreferenceManager
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.libsignal.protocol.IdentityKey
|
||||
@@ -73,17 +72,10 @@ class AccountValues internal constructor(store: KeyValueStore) : SignalStoreValu
|
||||
private const val KEY_USERNAME_SYNC_STATE = "phoneNumberPrivacy.usernameSyncState"
|
||||
private const val KEY_USERNAME_SYNC_ERROR_COUNT = "phoneNumberPrivacy.usernameErrorCount"
|
||||
|
||||
@VisibleForTesting
|
||||
const val KEY_E164 = "account.e164"
|
||||
|
||||
@VisibleForTesting
|
||||
const val KEY_ACI = "account.aci"
|
||||
|
||||
@VisibleForTesting
|
||||
const val KEY_PNI = "account.pni"
|
||||
|
||||
@VisibleForTesting
|
||||
const val KEY_IS_REGISTERED = "account.is_registered"
|
||||
private const val KEY_E164 = "account.e164"
|
||||
private const val KEY_ACI = "account.aci"
|
||||
private const val KEY_PNI = "account.pni"
|
||||
private const val KEY_IS_REGISTERED = "account.is_registered"
|
||||
}
|
||||
|
||||
init {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.thoughtcrime.securesms.keyvalue
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
|
||||
/**
|
||||
* Values for managing enable/disable state and corresponding alerts for Notification Profiles.
|
||||
*/
|
||||
@@ -12,14 +10,9 @@ class NotificationProfileValues(store: KeyValueStore) : SignalStoreValues(store)
|
||||
private const val KEY_LAST_PROFILE_POPUP_TIME = "np.last_profile_popup_time"
|
||||
private const val KEY_SEEN_TOOLTIP = "np.seen_tooltip"
|
||||
|
||||
@VisibleForTesting
|
||||
const val KEY_MANUALLY_ENABLED_PROFILE = "np.manually_enabled_profile"
|
||||
|
||||
@VisibleForTesting
|
||||
const val KEY_MANUALLY_ENABLED_UNTIL = "np.manually_enabled_until"
|
||||
|
||||
@VisibleForTesting
|
||||
const val KEY_MANUALLY_DISABLED_AT = "np.manually_disabled_at"
|
||||
private const val KEY_MANUALLY_ENABLED_PROFILE = "np.manually_enabled_profile"
|
||||
private const val KEY_MANUALLY_ENABLED_UNTIL = "np.manually_enabled_until"
|
||||
private const val KEY_MANUALLY_DISABLED_AT = "np.manually_disabled_at"
|
||||
}
|
||||
|
||||
public override fun onFirstEverAppLaunch() = Unit
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.thoughtcrime.securesms.keyvalue
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
@@ -33,6 +32,7 @@ class PaymentsValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
companion object {
|
||||
private val TAG = Log.tag(PaymentsValues::class.java)
|
||||
|
||||
private const val MOB_PAYMENTS_ENABLED = "mob_payments_enabled"
|
||||
private const val PAYMENTS_ENTROPY = "payments_entropy"
|
||||
private const val MOB_LEDGER = "mob_ledger"
|
||||
private const val PAYMENTS_CURRENT_CURRENCY = "payments_current_currency"
|
||||
@@ -50,9 +50,6 @@ class PaymentsValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
private const val SHOW_SAVE_RECOVERY_PHRASE = "mob_show_save_recovery_phrase"
|
||||
|
||||
private val LARGE_BALANCE_THRESHOLD = Money.mobileCoin(BigDecimal.valueOf(500))
|
||||
|
||||
@VisibleForTesting
|
||||
const val MOB_PAYMENTS_ENABLED = "mob_payments_enabled"
|
||||
}
|
||||
|
||||
@get:JvmName("isPaymentLockEnabled")
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package org.thoughtcrime.securesms.keyvalue
|
||||
|
||||
import android.app.Application
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.preference.PreferenceDataStore
|
||||
import org.signal.core.util.ResettableLazy
|
||||
import org.thoughtcrime.securesms.database.KeyValueDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies.application
|
||||
|
||||
/**
|
||||
* Simple, encrypted key-value store.
|
||||
*/
|
||||
class SignalStore(private val store: KeyValueStore) {
|
||||
class SignalStore(context: Application, private val store: KeyValueStore) {
|
||||
|
||||
val accountValues = AccountValues(store)
|
||||
val svrValues = SvrValues(store)
|
||||
@@ -39,15 +38,22 @@ class SignalStore(private val store: KeyValueStore) {
|
||||
val apkUpdateValues = ApkUpdateValues(store)
|
||||
val backupValues = BackupValues(store)
|
||||
|
||||
val plainTextValues = PlainTextSharedPrefsDataStore(application)
|
||||
val plainTextValues = PlainTextSharedPrefsDataStore(context)
|
||||
|
||||
companion object {
|
||||
|
||||
private var instanceOverride: SignalStore? = null
|
||||
private val _instance = ResettableLazy {
|
||||
instanceOverride ?: SignalStore(KeyValueStore(KeyValueDatabase.getInstance(application)))
|
||||
private var instance: SignalStore? = null
|
||||
|
||||
@JvmStatic
|
||||
fun init(context: Application) {
|
||||
if (instance == null) {
|
||||
synchronized(SignalStore::class.java) {
|
||||
if (instance == null) {
|
||||
instance = SignalStore(context, KeyValueStore(KeyValueDatabase.getInstance(context)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private val instance by _instance
|
||||
|
||||
@JvmStatic
|
||||
fun onFirstEverAppLaunch() {
|
||||
@@ -114,7 +120,7 @@ class SignalStore(private val store: KeyValueStore) {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun resetCache() {
|
||||
instance.store.resetCache()
|
||||
instance!!.store.resetCache()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,144 +128,144 @@ class SignalStore(private val store: KeyValueStore) {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun onPostBackupRestore() {
|
||||
instance.store.resetCache()
|
||||
instance!!.store.resetCache()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("account")
|
||||
val account: AccountValues
|
||||
get() = instance.accountValues
|
||||
get() = instance!!.accountValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("svr")
|
||||
val svr: SvrValues
|
||||
get() = instance.svrValues
|
||||
get() = instance!!.svrValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("registration")
|
||||
val registration: RegistrationValues
|
||||
get() = instance.registrationValues
|
||||
get() = instance!!.registrationValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("pin")
|
||||
val pin: PinValues
|
||||
get() = instance.pinValues
|
||||
get() = instance!!.pinValues
|
||||
|
||||
val remoteConfig: RemoteConfigValues
|
||||
get() = instance.remoteConfigValues
|
||||
get() = instance!!.remoteConfigValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("storageService")
|
||||
val storageService: StorageServiceValues
|
||||
get() = instance.storageServiceValues
|
||||
get() = instance!!.storageServiceValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("uiHints")
|
||||
val uiHints: UiHintValues
|
||||
get() = instance.uiHintValues
|
||||
get() = instance!!.uiHintValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("tooltips")
|
||||
val tooltips: TooltipValues
|
||||
get() = instance.tooltipValues
|
||||
get() = instance!!.tooltipValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("misc")
|
||||
val misc: MiscellaneousValues
|
||||
get() = instance.miscValues
|
||||
get() = instance!!.miscValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("internal")
|
||||
val internal: InternalValues
|
||||
get() = instance.internalValues
|
||||
get() = instance!!.internalValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("emoji")
|
||||
val emoji: EmojiValues
|
||||
get() = instance.emojiValues
|
||||
get() = instance!!.emojiValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("settings")
|
||||
val settings: SettingsValues
|
||||
get() = instance.settingsValues
|
||||
get() = instance!!.settingsValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("certificate")
|
||||
val certificate: CertificateValues
|
||||
get() = instance.certificateValues
|
||||
get() = instance!!.certificateValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("phoneNumberPrivacy")
|
||||
val phoneNumberPrivacy: PhoneNumberPrivacyValues
|
||||
get() = instance.phoneNumberPrivacyValues
|
||||
get() = instance!!.phoneNumberPrivacyValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("onboarding")
|
||||
val onboarding: OnboardingValues
|
||||
get() = instance.onboardingValues
|
||||
get() = instance!!.onboardingValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("wallpaper")
|
||||
val wallpaper: WallpaperValues
|
||||
get() = instance.wallpaperValues
|
||||
get() = instance!!.wallpaperValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("payments")
|
||||
val payments: PaymentsValues
|
||||
get() = instance.paymentsValues
|
||||
get() = instance!!.paymentsValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("inAppPayments")
|
||||
val inAppPayments: InAppPaymentValues
|
||||
get() = instance.inAppPaymentValues
|
||||
get() = instance!!.inAppPaymentValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("proxy")
|
||||
val proxy: ProxyValues
|
||||
get() = instance.proxyValues
|
||||
get() = instance!!.proxyValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("rateLimit")
|
||||
val rateLimit: RateLimitValues
|
||||
get() = instance.rateLimitValues
|
||||
get() = instance!!.rateLimitValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("chatColors")
|
||||
val chatColors: ChatColorsValues
|
||||
get() = instance.chatColorsValues
|
||||
get() = instance!!.chatColorsValues
|
||||
|
||||
val imageEditor: ImageEditorValues
|
||||
get() = instance.imageEditorValues
|
||||
get() = instance!!.imageEditorValues
|
||||
|
||||
val notificationProfile: NotificationProfileValues
|
||||
get() = instance.notificationProfileValues
|
||||
get() = instance!!.notificationProfileValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("releaseChannel")
|
||||
val releaseChannel: ReleaseChannelValues
|
||||
get() = instance.releaseChannelValues
|
||||
get() = instance!!.releaseChannelValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("story")
|
||||
val story: StoryValues
|
||||
get() = instance.storyValues
|
||||
get() = instance!!.storyValues
|
||||
|
||||
val apkUpdate: ApkUpdateValues
|
||||
get() = instance.apkUpdateValues
|
||||
get() = instance!!.apkUpdateValues
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("backup")
|
||||
val backup: BackupValues
|
||||
get() = instance.backupValues
|
||||
get() = instance!!.backupValues
|
||||
|
||||
val groupsV2AciAuthorizationCache: GroupsV2AuthorizationSignalStoreCache
|
||||
get() = GroupsV2AuthorizationSignalStoreCache.createAciCache(instance.store)
|
||||
get() = GroupsV2AuthorizationSignalStoreCache.createAciCache(instance!!.store)
|
||||
|
||||
val plaintext: PlainTextSharedPrefsDataStore
|
||||
get() = instance.plainTextValues
|
||||
get() = instance!!.plainTextValues
|
||||
|
||||
fun getPreferenceDataStore(): PreferenceDataStore {
|
||||
return SignalPreferenceDataStore(instance.store)
|
||||
return SignalPreferenceDataStore(instance!!.store)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,25 +274,7 @@ class SignalStore(private val store: KeyValueStore) {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun blockUntilAllWritesFinished() {
|
||||
instance.store.blockUntilAllWritesFinished()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to set a custom KeyValueStore to read from. Only for testing!
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun testInject(store: KeyValueStore) {
|
||||
instanceOverride = SignalStore(store)
|
||||
_instance.reset()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to set a custom SignalStore to read from. Only for testing!
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun testInject(store: SignalStore) {
|
||||
instanceOverride = store
|
||||
_instance.reset()
|
||||
instance!!.store.blockUntilAllWritesFinished()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.thoughtcrime.securesms.providers
|
||||
|
||||
import android.app.Application
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
import android.content.Intent
|
||||
@@ -15,10 +16,16 @@ import android.net.Uri
|
||||
import android.os.ParcelFileDescriptor
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BuildConfig
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.SqlCipherLibraryLoader
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientCreator
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.AdaptiveBitmapMetrics
|
||||
@@ -54,6 +61,21 @@ class AvatarProvider : BaseContentProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun init(): Application? {
|
||||
val application = context as? ApplicationContext ?: return null
|
||||
|
||||
SqlCipherLibraryLoader.load()
|
||||
SignalDatabase.init(
|
||||
application,
|
||||
DatabaseSecretProvider.getOrCreateDatabaseSecret(application),
|
||||
AttachmentSecretProvider.getInstance(application).getOrCreateAttachmentSecret()
|
||||
)
|
||||
|
||||
SignalStore.init(application)
|
||||
|
||||
return application
|
||||
}
|
||||
|
||||
override fun onCreate(): Boolean {
|
||||
if (VERBOSE) Log.i(TAG, "onCreate called")
|
||||
return true
|
||||
@@ -63,7 +85,9 @@ class AvatarProvider : BaseContentProvider() {
|
||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
||||
if (VERBOSE) Log.i(TAG, "openFile() called!")
|
||||
|
||||
if (KeyCachingService.isLocked(context)) {
|
||||
val application = init() ?: return null
|
||||
|
||||
if (KeyCachingService.isLocked(application)) {
|
||||
Log.w(TAG, "masterSecret was null, abandoning.")
|
||||
return null
|
||||
}
|
||||
@@ -76,7 +100,7 @@ class AvatarProvider : BaseContentProvider() {
|
||||
if (uriMatcher.match(uri) == AVATAR) {
|
||||
if (VERBOSE) Log.i(TAG, "Loading avatar.")
|
||||
try {
|
||||
val recipient = getRecipientId(uri)?.let { Recipient.resolved(it) } ?: return null
|
||||
val recipient = getRecipientId(uri)?.let { RecipientCreator.forRecord(application, SignalDatabase.recipients.getRecord(it)) } ?: return null
|
||||
return getParcelFileDescriptorForAvatar(recipient)
|
||||
} catch (ioe: IOException) {
|
||||
Log.w(TAG, ioe)
|
||||
@@ -91,6 +115,8 @@ class AvatarProvider : BaseContentProvider() {
|
||||
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? {
|
||||
if (VERBOSE) Log.i(TAG, "query() called: $uri")
|
||||
|
||||
val application = init() ?: return null
|
||||
|
||||
if (SignalDatabase.instance == null) {
|
||||
Log.w(TAG, "SignalDatabase unavailable")
|
||||
return null
|
||||
@@ -99,8 +125,8 @@ class AvatarProvider : BaseContentProvider() {
|
||||
if (uriMatcher.match(uri) == AVATAR) {
|
||||
val recipientId = getRecipientId(uri) ?: return null
|
||||
|
||||
if (AvatarHelper.hasAvatar(context!!, recipientId)) {
|
||||
val file: File = AvatarHelper.getAvatarFile(context!!, recipientId)
|
||||
if (AvatarHelper.hasAvatar(application, recipientId)) {
|
||||
val file: File = AvatarHelper.getAvatarFile(application, recipientId)
|
||||
if (file.exists()) {
|
||||
return createCursor(projection, file.name, file.length())
|
||||
}
|
||||
@@ -115,6 +141,8 @@ class AvatarProvider : BaseContentProvider() {
|
||||
override fun getType(uri: Uri): String? {
|
||||
if (VERBOSE) Log.i(TAG, "getType() called: $uri")
|
||||
|
||||
init() ?: return null
|
||||
|
||||
if (SignalDatabase.instance == null) {
|
||||
Log.w(TAG, "SignalDatabase unavailable")
|
||||
return null
|
||||
|
||||
@@ -9,24 +9,15 @@ import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
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;
|
||||
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
|
||||
import org.thoughtcrime.securesms.database.model.RecipientRecord;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -198,62 +189,11 @@ public final class LiveRecipient {
|
||||
}
|
||||
|
||||
private @NonNull Recipient fetchAndCacheRecipientFromDisk(@NonNull RecipientId id) {
|
||||
RecipientRecord record = recipientTable.getRecord(id);
|
||||
|
||||
Recipient recipient;
|
||||
if (record.getGroupId() != null) {
|
||||
recipient = getGroupRecipientDetails(record);
|
||||
} else if (record.getDistributionListId() != null) {
|
||||
recipient = getDistributionListRecipientDetails(record);
|
||||
} else if (record.getCallLinkRoomId() != null) {
|
||||
recipient = getCallLinkRecipientDetails(record);
|
||||
} else {
|
||||
recipient = RecipientCreator.forIndividual(context, record);
|
||||
}
|
||||
|
||||
Recipient recipient = RecipientCreator.forRecord(context, recipientTable.getRecord(id));
|
||||
RecipientIdCache.INSTANCE.put(recipient);
|
||||
return recipient;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private @NonNull Recipient getGroupRecipientDetails(@NonNull RecipientRecord record) {
|
||||
Optional<GroupRecord> groupRecord = groupDatabase.getGroup(record.getId());
|
||||
|
||||
if (groupRecord.isPresent()) {
|
||||
return RecipientCreator.forGroup(groupRecord.get(), record);
|
||||
} else {
|
||||
return RecipientCreator.forUnknownGroup(record.getId(), record.getGroupId());
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private @NonNull Recipient getDistributionListRecipientDetails(@NonNull RecipientRecord record) {
|
||||
DistributionListRecord groupRecord = distributionListTables.getList(Objects.requireNonNull(record.getDistributionListId()));
|
||||
|
||||
// TODO [stories] We'll have to see what the perf is like for very large distribution lists. We may not be able to support fetching all the members.
|
||||
if (groupRecord != null) {
|
||||
String title = groupRecord.isUnknown() ? null : groupRecord.getName();
|
||||
List<RecipientId> members = Stream.of(groupRecord.getMembers()).filterNot(RecipientId::isUnknown).toList();
|
||||
|
||||
return RecipientCreator.forDistributionList(title, members, record);
|
||||
}
|
||||
|
||||
return RecipientCreator.forDistributionList(null, null, record);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private @NonNull Recipient getCallLinkRecipientDetails(@NonNull RecipientRecord record) {
|
||||
CallLinkTable.CallLink callLink = SignalDatabase.callLinks().getCallLinkByRoomId(Objects.requireNonNull(record.getCallLinkRoomId()));
|
||||
|
||||
if (callLink != null) {
|
||||
String name = callLink.getState().getName();
|
||||
|
||||
return RecipientCreator.forCallLink(name, record, callLink.getAvatarColor());
|
||||
}
|
||||
|
||||
return RecipientCreator.forCallLink(null, record, AvatarColor.UNKNOWN);
|
||||
}
|
||||
|
||||
synchronized void set(@NonNull Recipient recipient) {
|
||||
this.recipient.set(recipient);
|
||||
this.liveData.postValue(recipient);
|
||||
|
||||
@@ -2,8 +2,10 @@ package org.thoughtcrime.securesms.recipients
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||
import org.thoughtcrime.securesms.database.model.RecipientRecord
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
@@ -101,6 +103,22 @@ object RecipientCreator {
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@WorkerThread
|
||||
fun forRecord(context: Context, record: RecipientRecord): Recipient {
|
||||
val recipient = if (record.groupId != null) {
|
||||
getGroupRecipientDetails(record)
|
||||
} else if (record.distributionListId != null) {
|
||||
getDistributionListRecipientDetails(record)
|
||||
} else if (record.callLinkRoomId != null) {
|
||||
getCallLinkRecipientDetails(record)
|
||||
} else {
|
||||
forIndividual(context, record)
|
||||
}
|
||||
|
||||
return recipient
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun forUnknown(): Recipient {
|
||||
return Recipient.UNKNOWN
|
||||
@@ -186,4 +204,43 @@ object RecipientCreator {
|
||||
note = record.note
|
||||
)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun getGroupRecipientDetails(record: RecipientRecord): Recipient {
|
||||
val groupRecord = SignalDatabase.groups.getGroup(record.id)
|
||||
|
||||
return if (groupRecord.isPresent) {
|
||||
forGroup(groupRecord.get(), record)
|
||||
} else {
|
||||
forUnknownGroup(record.id, record.groupId)
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun getDistributionListRecipientDetails(record: RecipientRecord): Recipient {
|
||||
val groupRecord = SignalDatabase.distributionLists.getList(record.distributionListId!!)
|
||||
|
||||
// TODO [stories] We'll have to see what the perf is like for very large distribution lists. We may not be able to support fetching all the members.
|
||||
if (groupRecord != null) {
|
||||
val title = if (groupRecord.isUnknown) null else groupRecord.name
|
||||
val members = groupRecord.members.filterNot { it.isUnknown }
|
||||
|
||||
return forDistributionList(title, members, record)
|
||||
}
|
||||
|
||||
return forDistributionList(null, null, record)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun getCallLinkRecipientDetails(record: RecipientRecord): Recipient {
|
||||
val callLink = SignalDatabase.callLinks.getCallLinkByRoomId(record.callLinkRoomId!!)
|
||||
|
||||
if (callLink != null) {
|
||||
val name = callLink.state.name
|
||||
|
||||
return forCallLink(name, record, callLink.avatarColor)
|
||||
}
|
||||
|
||||
return forCallLink(null, record, AvatarColor.UNKNOWN)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user