Move settings out of TextSecurePreferences and into SettingsValues.

This commit is contained in:
Greyson Parrelli
2026-09-30 13:34:01 -03:00
committed by Alex Hart
parent 5f35b0ec48
commit 38c62bce46
65 changed files with 537 additions and 760 deletions
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.testing.MessageContentFuzzer
import org.thoughtcrime.securesms.testing.SignalActivityRule
import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.internal.push.AddressableMessage
import org.whispersystems.signalservice.internal.push.AttachmentPointer
@@ -54,12 +53,9 @@ class SyncMessageProcessorTest_attachmentBackfill {
SignalStore.account.deviceId = 2
// Prevent AttachmentDownloadJob onAdded from async changing the attachment state.
TextSecurePreferences.getSharedPreferences(harness.application)
.edit()
.putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF, emptySet())
.putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF, emptySet())
.putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF, emptySet())
.commit()
SignalStore.settings.wifiMediaDownloadAllowed = emptySet()
SignalStore.settings.mobileMediaDownloadAllowed = emptySet()
SignalStore.settings.roamingMediaDownloadAllowed = emptySet()
}
@After
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.mms.OutgoingMessage
import org.thoughtcrime.securesms.profiles.ProfileName
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.registration.util.RegistrationUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
class BenchmarkSetupActivity : BaseActivity() {
@@ -269,7 +268,7 @@ class BenchmarkSetupActivity : BaseActivity() {
}
if (enableReadReceipts) {
TextSecurePreferences.setReadReceiptsEnabled(this, true)
SignalStore.settings.isReadReceiptsEnabled = true
}
}
}
@@ -40,8 +40,8 @@ public final class AppInitialization {
PlainTextKeyValueStore.setLastVersionCode(BuildConfig.VERSION_CODE);
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
SignalStore.settings().setPassphraseDisabled(true);
TextSecurePreferences.setReadReceiptsEnabled(context, true);
TextSecurePreferences.setTypingIndicatorsEnabled(context, true);
SignalStore.settings().setReadReceiptsEnabled(true);
SignalStore.settings().setTypingIndicatorsEnabled(true);
AppDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onFirstEverAppLaunch();
AppDependencies.getJobManager().addAll(BlessedPacks.getFirstInstallJobs());
@@ -29,7 +29,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.restore.restorelocalbackup.PassphraseAsYouTypeFormatter;
import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.util.BackupUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.signal.core.util.Util;
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
@@ -74,7 +73,7 @@ public class BackupDialog {
}
BackupPassphrase.set(context, Util.join(password, " "));
TextSecurePreferences.setNextBackupTime(context, 0);
SignalStore.settings().setLocalBackupNextTime(0);
SignalStore.settings().setBackupEnabled(true);
LocalBackupListener.schedule(context);
@@ -52,7 +52,6 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.io.File;
import java.io.FileNotFoundException;
@@ -195,14 +194,6 @@ public class FullBackupExporter extends FullBackupBase {
stopwatch.split("table::" + table);
}
for (SharedPreference preference : TextSecurePreferences.getPreferencesToSaveToBackup(context)) {
throwIfCanceled(cancellationSignal);
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));
outputStream.write(preference);
}
stopwatch.split("prefs");
count = exportKeyValues(outputStream, SignalStore.getKeysToIncludeInBackup(), count, estimatedCount, cancellationSignal);
stopwatch.split("key_values");
@@ -248,8 +239,6 @@ public class FullBackupExporter extends FullBackupBase {
count += IDENTITY_KEY_BACKUP_RECORD_COUNT;
count += TextSecurePreferences.getPreferencesToSaveToBackupCount(context);
KeyValueDataSet dataSet = KeyValueDatabase.getInstance(AppDependencies.getApplication())
.getDataSet();
for (String key : SignalStore.getKeysToIncludeInBackup()) {
@@ -5,7 +5,6 @@
package org.thoughtcrime.securesms.backup.v2.processor
import android.content.Context
import okio.ByteString.Companion.EMPTY
import okio.ByteString.Companion.toByteString
import org.signal.archive.proto.AccountData
@@ -44,7 +43,6 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.Environment
import org.thoughtcrime.securesms.util.ProfileUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.webrtc.CallDataMode
import org.whispersystems.signalservice.api.push.UsernameLinkComponents
import org.whispersystems.signalservice.api.storage.IAPSubscriptionId.AppleIAPOriginalTransactionId
@@ -82,8 +80,8 @@ object AccountDataArchiveProcessor {
null
}
val mobileAutoDownload = TextSecurePreferences.getMobileMediaDownloadAllowed(context)
val wifiAutoDownload = TextSecurePreferences.getWifiMediaDownloadAllowed(context)
val mobileAutoDownload = SignalStore.settings.mobileMediaDownloadAllowed
val wifiAutoDownload = SignalStore.settings.wifiMediaDownloadAllowed
val username = selfRecord.username?.takeIf { it.isValidUsername() }
@@ -107,10 +105,10 @@ object AccountDataArchiveProcessor {
},
accountSettings = AccountData.AccountSettings(
storyViewReceiptsEnabled = signalStore.storyValues.viewedReceiptsEnabled,
typingIndicators = TextSecurePreferences.isTypingIndicatorsEnabled(context),
readReceipts = TextSecurePreferences.isReadReceiptsEnabled(context),
sealedSenderIndicators = TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
allowSealedSenderFromAnyone = TextSecurePreferences.isUniversalUnidentifiedAccess(context),
typingIndicators = SignalStore.settings.isTypingIndicatorsEnabled,
readReceipts = SignalStore.settings.isReadReceiptsEnabled,
sealedSenderIndicators = SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled,
allowSealedSenderFromAnyone = SignalStore.settings.isUniversalUnidentifiedAccess,
linkPreviews = signalStore.settingsValues.isLinkPreviewsEnabled,
notDiscoverableByPhoneNumber = signalStore.phoneNumberPrivacyValues.phoneNumberDiscoverabilityMode == PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE,
phoneNumberSharingMode = signalStore.phoneNumberPrivacyValues.phoneNumberSharingMode.toRemotePhoneNumberSharingMode(),
@@ -160,7 +158,7 @@ object AccountDataArchiveProcessor {
backupsSubscriberData = backupSubscriberRecord?.toIAPSubscriberData(),
androidSpecificSettings = AccountData.AndroidSpecificSettings(
useSystemEmoji = signalStore.settingsValues.isPreferSystemEmoji,
screenshotSecurity = TextSecurePreferences.isScreenSecurityEnabled(context),
screenshotSecurity = SignalStore.settings.isScreenSecurityEnabled,
navigationBarSize = signalStore.settingsValues.useCompactNavigationBar.toRemoteNavigationBarSize()
).takeUnless { Environment.IS_INSTRUMENTATION && SignalStore.backup.importedEmptyAndroidSettings },
bioText = selfRecord.about ?: "",
@@ -178,17 +176,16 @@ object AccountDataArchiveProcessor {
SignalStore.svr.setPin(accountData.svrPin)
}
val context = AppDependencies.application
val settings = accountData.accountSettings
if (settings != null) {
importSettings(context, settings, importState)
importSettings(settings, importState)
}
val androidSpecificSettings = accountData.androidSpecificSettings
if (androidSpecificSettings != null) {
SignalStore.settings.isPreferSystemEmoji = androidSpecificSettings.useSystemEmoji
TextSecurePreferences.setScreenSecurityEnabled(context, androidSpecificSettings.screenshotSecurity)
SignalStore.settings.isScreenSecurityEnabled = androidSpecificSettings.screenshotSecurity
SignalStore.settings.useCompactNavigationBar = androidSpecificSettings.navigationBarSize.toLocalNavigationBarSize()
} else if (Environment.IS_INSTRUMENTATION) {
SignalStore.backup.importedEmptyAndroidSettings = true
@@ -265,11 +262,11 @@ object AccountDataArchiveProcessor {
Recipient.self().live().refresh()
}
private fun importSettings(context: Context, settings: AccountData.AccountSettings, importState: ImportState) {
TextSecurePreferences.setReadReceiptsEnabled(context, settings.readReceipts)
TextSecurePreferences.setTypingIndicatorsEnabled(context, settings.typingIndicators)
TextSecurePreferences.setShowUnidentifiedDeliveryIndicatorsEnabled(context, settings.sealedSenderIndicators)
TextSecurePreferences.setIsUniversalUnidentifiedAccess(context, settings.allowSealedSenderFromAnyone)
private fun importSettings(settings: AccountData.AccountSettings, importState: ImportState) {
SignalStore.settings.isReadReceiptsEnabled = settings.readReceipts
SignalStore.settings.isTypingIndicatorsEnabled = settings.typingIndicators
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled = settings.sealedSenderIndicators
SignalStore.settings.isUniversalUnidentifiedAccess = settings.allowSealedSenderFromAnyone
SignalStore.settings.isLinkPreviewsEnabled = settings.linkPreviews
SignalStore.phoneNumberPrivacy.phoneNumberDiscoverabilityMode = if (settings.notDiscoverableByPhoneNumber) PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE else PhoneNumberDiscoverabilityMode.DISCOVERABLE
SignalStore.phoneNumberPrivacy.phoneNumberSharingMode = settings.phoneNumberSharingMode.toLocalPhoneNumberMode()
@@ -303,11 +300,8 @@ object AccountDataArchiveProcessor {
val mobileAndWifiDownloadSet = autoDownloadSettings.toLocalAutoDownloadSet(AccountData.AutoDownloadSettings.AutoDownloadOption.WIFI_AND_CELLULAR)
val wifiDownloadSet = mobileAndWifiDownloadSet + autoDownloadSettings.toLocalAutoDownloadSet(AccountData.AutoDownloadSettings.AutoDownloadOption.WIFI)
TextSecurePreferences.getSharedPreferences(context).edit().apply {
putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF, mobileAndWifiDownloadSet)
putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF, wifiDownloadSet)
apply()
}
SignalStore.settings.mobileMediaDownloadAllowed = mobileAndWifiDownloadSet
SignalStore.settings.wifiMediaDownloadAllowed = wifiDownloadSet
}
val screenLockTimeoutMinutes = settings.screenLockTimeoutMinutes
@@ -48,7 +48,6 @@ import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.List;
import java.util.Objects;
@@ -336,7 +335,7 @@ public class ComposeText extends EmojiEditText {
setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
}
if (TextSecurePreferences.isIncognitoKeyboardEnabled(getContext())) {
if (SignalStore.settings().isIncognitoKeyboardEnabled()) {
setImeOptions(getImeOptions() | 16777216);
}
@@ -20,9 +20,9 @@ import androidx.annotation.StringRes;
import androidx.core.widget.TextViewCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.EditTextExtensionsKt;
import org.signal.core.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
/**
@@ -60,7 +60,7 @@ public final class ContactFilterView extends FrameLayout {
this.clearToggle = findViewById(R.id.search_clear);
this.toggleContainer = findViewById(R.id.toggle_container);
EditTextExtensionsKt.setIncognitoKeyboardEnabled(searchText, TextSecurePreferences.isIncognitoKeyboardEnabled(context));
EditTextExtensionsKt.setIncognitoKeyboardEnabled(searchText, SignalStore.settings().isIncognitoKeyboardEnabled());
this.keyboardToggle.setOnClickListener(new View.OnClickListener() {
@Override
@@ -14,7 +14,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.keyvalue.SignalStore
import java.util.WeakHashMap
/**
@@ -58,7 +58,7 @@ object TemporaryScreenshotSecurity {
val window = activity.window
val previous = activeHolds[window] ?: 0
activeHolds[window] = previous + 1
if (previous == 0 && !TextSecurePreferences.isScreenSecurityEnabled(activity)) {
if (previous == 0 && !SignalStore.settings.isScreenSecurityEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
}
@@ -68,7 +68,7 @@ object TemporaryScreenshotSecurity {
val next = ((activeHolds[window] ?: 0) - 1).coerceAtLeast(0)
if (next == 0) {
activeHolds.remove(window)
if (!TextSecurePreferences.isScreenSecurityEnabled(activity)) {
if (!SignalStore.settings.isScreenSecurityEnabled) {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
} else {
@@ -19,7 +19,6 @@ import org.signal.emoji.EmojiProvider.EmojiDrawable;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.EditTextExtensionsKt;
import org.signal.core.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.signal.core.util.Util;
import java.util.HashSet;
@@ -58,7 +57,7 @@ public class EmojiEditText extends AppCompatEditText {
});
if (!isInEditMode()) {
EditTextExtensionsKt.setIncognitoKeyboardEnabled(this, TextSecurePreferences.isIncognitoKeyboardEnabled(context));
EditTextExtensionsKt.setIncognitoKeyboardEnabled(this, SignalStore.settings().isIncognitoKeyboardEnabled());
}
}
@@ -10,7 +10,8 @@ import androidx.appcompat.widget.AppCompatImageButton;
import org.signal.core.util.ContextUtil;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyboard.KeyboardPage;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.keyvalue.SettingsValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
public class EmojiToggle extends AppCompatImageButton implements MediaKeyboard.MediaKeyboardListener {
@@ -94,13 +95,13 @@ public class EmojiToggle extends AppCompatImageButton implements MediaKeyboard.M
setStickerMode(page);
switch (page) {
case EMOJI:
TextSecurePreferences.setMediaKeyboardMode(getContext(), TextSecurePreferences.MediaKeyboardMode.EMOJI);
SignalStore.settings().setMediaKeyboardMode(SettingsValues.MediaKeyboardMode.EMOJI);
break;
case STICKER:
TextSecurePreferences.setMediaKeyboardMode(getContext(), TextSecurePreferences.MediaKeyboardMode.STICKER);
SignalStore.settings().setMediaKeyboardMode(SettingsValues.MediaKeyboardMode.STICKER);
break;
case GIF:
TextSecurePreferences.setMediaKeyboardMode(getContext(), TextSecurePreferences.MediaKeyboardMode.GIF);
SignalStore.settings().setMediaKeyboardMode(SettingsValues.MediaKeyboardMode.GIF);
break;
}
}
@@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.service.LocalBackupListener
import org.thoughtcrime.securesms.util.BackupUtil
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.navigation.safeNavigate
sealed interface LocalBackupsSettingsCallback {
@@ -87,7 +86,7 @@ class DefaultLocalBackupsSettingsCallback(
picker.addOnPositiveButtonClickListener {
SignalStore.settings.setBackupSchedule(picker.hour, picker.minute)
TextSecurePreferences.setNextBackupTime(fragment.requireContext(), 0)
SignalStore.settings.localBackupNextTime = 0
LocalBackupListener.schedule(fragment.requireContext())
viewModel.refreshSettingsState()
}
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components.settings.app.chats
import android.content.Context
import org.signal.core.util.concurrent.SignalExecutors
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.AppDependencies
@@ -9,12 +8,9 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.TextSecurePreferences
class ChatsSettingsRepository {
private val context: Context = AppDependencies.application
fun syncLinkPreviewsState() {
SignalExecutors.BOUNDED.execute {
val isLinkPreviewsEnabled = SignalStore.settings.isLinkPreviewsEnabled
@@ -23,9 +19,9 @@ class ChatsSettingsRepository {
StorageSyncHelper.scheduleSyncForDataChange()
AppDependencies.jobManager.add(
MultiDeviceConfigurationUpdateJob(
TextSecurePreferences.isReadReceiptsEnabled(context),
TextSecurePreferences.isTypingIndicatorsEnabled(context),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
SignalStore.settings.isReadReceiptsEnabled,
SignalStore.settings.isTypingIndicatorsEnabled,
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled,
isLinkPreviewsEnabled
)
)
@@ -14,7 +14,6 @@ import androidx.compose.ui.res.stringResource
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import org.signal.core.ui.compose.ComposeFragment
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Dialogs
@@ -36,9 +35,8 @@ class DataAndStorageSettingsFragment : ComposeFragment() {
private val viewModel: DataAndStorageSettingsViewModel by viewModels(
factoryProducer = {
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val repository = DataAndStorageSettingsRepository()
DataAndStorageSettingsViewModel.Factory(preferences, repository)
DataAndStorageSettingsViewModel.Factory(repository)
}
)
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components.settings.app.data
import android.content.SharedPreferences
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.flow.MutableStateFlow
@@ -12,11 +11,9 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SettingsValues.ForceWebsocketMode
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.messages.IncomingMessageObserver
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.webrtc.CallDataMode
class DataAndStorageSettingsViewModel(
private val sharedPreferences: SharedPreferences,
private val repository: DataAndStorageSettingsRepository
) : ViewModel() {
@@ -31,17 +28,17 @@ class DataAndStorageSettingsViewModel(
}
fun setMobileAutoDownloadValues(resultSet: Set<String>) {
sharedPreferences.edit().putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF, resultSet).apply()
SignalStore.settings.mobileMediaDownloadAllowed = resultSet
getStateAndCopyStorageUsage()
}
fun setWifiAutoDownloadValues(resultSet: Set<String>) {
sharedPreferences.edit().putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF, resultSet).apply()
SignalStore.settings.wifiMediaDownloadAllowed = resultSet
getStateAndCopyStorageUsage()
}
fun setRoamingAutoDownloadValues(resultSet: Set<String>) {
sharedPreferences.edit().putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF, resultSet).apply()
SignalStore.settings.roamingMediaDownloadAllowed = resultSet
getStateAndCopyStorageUsage()
}
@@ -88,15 +85,9 @@ class DataAndStorageSettingsViewModel(
private fun getState() = DataAndStorageSettingsState(
totalStorageUse = 0,
mobileAutoDownloadValues = TextSecurePreferences.getMobileMediaDownloadAllowed(
AppDependencies.application
),
wifiAutoDownloadValues = TextSecurePreferences.getWifiMediaDownloadAllowed(
AppDependencies.application
),
roamingAutoDownloadValues = TextSecurePreferences.getRoamingMediaDownloadAllowed(
AppDependencies.application
),
mobileAutoDownloadValues = SignalStore.settings.mobileMediaDownloadAllowed,
wifiAutoDownloadValues = SignalStore.settings.wifiMediaDownloadAllowed,
roamingAutoDownloadValues = SignalStore.settings.roamingMediaDownloadAllowed,
callDataMode = SignalStore.settings.callDataMode,
isProxyEnabled = SignalStore.proxy.isProxyEnabled,
sentMediaQuality = SignalStore.settings.sentMediaQuality,
@@ -106,12 +97,10 @@ class DataAndStorageSettingsViewModel(
)
class Factory(
private val sharedPreferences: SharedPreferences,
private val repository: DataAndStorageSettingsRepository
) :
ViewModelProvider.Factory {
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return requireNotNull(modelClass.cast(DataAndStorageSettingsViewModel(sharedPreferences, repository)))
return requireNotNull(modelClass.cast(DataAndStorageSettingsViewModel(repository)))
}
}
}
@@ -80,7 +80,6 @@ import org.thoughtcrime.securesms.registration.data.QuickstartCredentialExporter
import org.thoughtcrime.securesms.ringrtc.CameraFpsRanges
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.setIncognitoKeyboardEnabled
@@ -180,7 +179,7 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
searchMenuItem?.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
searchView.setIncognitoKeyboardEnabled(TextSecurePreferences.isIncognitoKeyboardEnabled(requireContext()))
searchView.setIncognitoKeyboardEnabled(SignalStore.settings.isIncognitoKeyboardEnabled)
searchView.setOnQueryTextListener(queryListener)
return true
}
@@ -1145,7 +1144,7 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
.setMessage("Are you sure? You'll have to re-register to use Signal again -- no promises that the process will go smoothly.")
.setPositiveButton(android.R.string.ok) { _, _ ->
lifecycleScope.launch {
when (AdvancedPrivacySettingsRepository(requireContext()).disablePushMessages()) {
when (AdvancedPrivacySettingsRepository().disablePushMessages()) {
AdvancedPrivacySettingsRepository.DisablePushMessagesResult.SUCCESS -> {
SignalStore.account.setRegistered(false)
SignalStore.registration.clearRegistrationComplete()
@@ -38,7 +38,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import kotlinx.coroutines.launch
import org.signal.core.ui.BottomSheetUtil
import org.signal.core.ui.compose.ComposeFragment
@@ -65,9 +64,7 @@ import org.thoughtcrime.securesms.util.viewModel
class NotificationsSettingsFragment : ComposeFragment() {
private val viewModel: NotificationsSettingsViewModel by viewModel {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
NotificationsSettingsViewModel.Factory(sharedPreferences).create(NotificationsSettingsViewModel::class.java)
NotificationsSettingsViewModel.Factory().create(NotificationsSettingsViewModel::class.java)
}
private val appSettingsRouter: AppSettingsRouter by viewModel {
@@ -1,8 +1,8 @@
package org.thoughtcrime.securesms.components.settings.app.notifications
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
@@ -14,7 +14,6 @@ import kotlinx.coroutines.launch
import org.signal.core.util.concurrent.SignalDispatchers
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.notifications.DeviceSpecificNotificationConfig
import org.thoughtcrime.securesms.notifications.NotificationChannels
@@ -23,9 +22,8 @@ import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPrefere
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.TextSecurePreferences
class NotificationsSettingsViewModel(private val sharedPreferences: SharedPreferences) : ViewModel(), RecipientForeverObserver {
class NotificationsSettingsViewModel : ViewModel(), RecipientForeverObserver {
companion object {
private val TAG = Log.tag(NotificationsSettingsViewModel::class)
@@ -109,7 +107,7 @@ class NotificationsSettingsViewModel(private val sharedPreferences: SharedPrefer
}
fun setMessageNotificationPriority(priority: Int) {
sharedPreferences.edit().putString(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF, priority.toString()).apply()
SignalStore.settings.messageNotificationPriority = priority
refresh()
}
@@ -149,7 +147,7 @@ class NotificationsSettingsViewModel(private val sharedPreferences: SharedPrefer
fun resetSettings() {
Log.i(TAG, "Resetting all notifications.")
// Global
setMessageNotificationsSound(TextSecurePreferences.getNotificationRingtone(AppDependencies.application))
setMessageNotificationsSound(Settings.System.DEFAULT_NOTIFICATION_URI)
SignalStore.settings.isMessageNotificationsInChatSoundsEnabled = true
SignalStore.settings.messageNotificationsPrivacy = NotificationPrivacyPreference("all")
SignalStore.settings.allowCallsWhileMuted = false
@@ -192,7 +190,7 @@ class NotificationsSettingsViewModel(private val sharedPreferences: SharedPrefer
inChatSoundsEnabled = SignalStore.settings.isMessageNotificationsInChatSoundsEnabled,
repeatAlerts = SignalStore.settings.messageNotificationsRepeatAlerts,
messagePrivacy = SignalStore.settings.messageNotificationsPrivacy.toString(),
priority = TextSecurePreferences.getNotificationPriority(AppDependencies.application),
priority = SignalStore.settings.messageNotificationPriority,
troubleshootNotifications = if (calculateSlowNotifications) {
(SlowNotificationHeuristics.isBatteryOptimizationsOn() && SlowNotificationHeuristics.isHavingDelayedNotifications()) ||
SlowNotificationHeuristics.getDeviceSpecificShowCondition() == DeviceSpecificNotificationConfig.ShowCondition.ALWAYS
@@ -227,9 +225,9 @@ class NotificationsSettingsViewModel(private val sharedPreferences: SharedPrefer
return !areNotificationsDisabledBySystem
}
class Factory(private val sharedPreferences: SharedPreferences) : ViewModelProvider.Factory {
class Factory : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return requireNotNull(modelClass.cast(NotificationsSettingsViewModel(sharedPreferences)))
return requireNotNull(modelClass.cast(NotificationsSettingsViewModel()))
}
}
}
@@ -19,7 +19,6 @@ import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.navArgs
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import org.signal.core.util.ServiceUtil
@@ -43,7 +42,6 @@ import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.ExpirationUtil
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@@ -101,9 +99,8 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
override fun bindAdapter(adapter: MappingAdapter) {
adapter.registerFactory(ValueClickPreference::class.java, LayoutFactory(::ValueClickPreferenceViewHolder, R.layout.value_click_preference_item))
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val repository = PrivacySettingsRepository()
val factory = PrivacySettingsViewModel.Factory(sharedPreferences, repository)
val factory = PrivacySettingsViewModel.Factory(repository)
viewModel = ViewModelProvider(this, factory)[PrivacySettingsViewModel::class.java]
val args: PrivacySettingsFragmentArgs by navArgs()
var showPaymentLock = true
@@ -279,7 +276,7 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
onClick = {
viewModel.setScreenSecurityEnabled(!state.screenSecurity)
if (TextSecurePreferences.isScreenSecurityEnabled(requireContext())) {
if (SignalStore.settings.isScreenSecurityEnabled) {
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
} else {
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components.settings.app.privacy
import android.content.Context
import org.signal.core.util.concurrent.SignalExecutors
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.AppDependencies
@@ -8,12 +7,9 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.TextSecurePreferences
class PrivacySettingsRepository {
private val context: Context = AppDependencies.application
fun getBlockedCount(consumer: (Int) -> Unit) {
SignalExecutors.BOUNDED.execute {
val recipientDatabase = SignalDatabase.recipients
@@ -28,9 +24,9 @@ class PrivacySettingsRepository {
StorageSyncHelper.scheduleSyncForDataChange()
AppDependencies.jobManager.add(
MultiDeviceConfigurationUpdateJob(
TextSecurePreferences.isReadReceiptsEnabled(context),
TextSecurePreferences.isTypingIndicatorsEnabled(context),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
SignalStore.settings.isReadReceiptsEnabled,
SignalStore.settings.isTypingIndicatorsEnabled,
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled,
SignalStore.settings.isLinkPreviewsEnabled
)
)
@@ -38,15 +34,15 @@ class PrivacySettingsRepository {
}
fun syncTypingIndicatorsState() {
val enabled = TextSecurePreferences.isTypingIndicatorsEnabled(context)
val enabled = SignalStore.settings.isTypingIndicatorsEnabled
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
StorageSyncHelper.scheduleSyncForDataChange()
AppDependencies.jobManager.add(
MultiDeviceConfigurationUpdateJob(
TextSecurePreferences.isReadReceiptsEnabled(context),
SignalStore.settings.isReadReceiptsEnabled,
enabled,
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled,
SignalStore.settings.isLinkPreviewsEnabled
)
)
@@ -1,16 +1,12 @@
package org.thoughtcrime.securesms.components.settings.app.privacy
import android.content.SharedPreferences
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.livedata.Store
class PrivacySettingsViewModel(
private val sharedPreferences: SharedPreferences,
private val repository: PrivacySettingsRepository
) : ViewModel() {
@@ -26,24 +22,24 @@ class PrivacySettingsViewModel(
}
fun setReadReceiptsEnabled(enabled: Boolean) {
sharedPreferences.edit().putBoolean(TextSecurePreferences.READ_RECEIPTS_PREF, enabled).apply()
SignalStore.settings.isReadReceiptsEnabled = enabled
repository.syncReadReceiptState()
refresh()
}
fun setTypingIndicatorsEnabled(enabled: Boolean) {
sharedPreferences.edit().putBoolean(TextSecurePreferences.TYPING_INDICATORS, enabled).apply()
SignalStore.settings.isTypingIndicatorsEnabled = enabled
repository.syncTypingIndicatorsState()
refresh()
}
fun setScreenSecurityEnabled(enabled: Boolean) {
sharedPreferences.edit().putBoolean(TextSecurePreferences.SCREEN_SECURITY_PREF, enabled).apply()
SignalStore.settings.isScreenSecurityEnabled = enabled
refresh()
}
fun setIncognitoKeyboard(enabled: Boolean) {
sharedPreferences.edit().putBoolean(TextSecurePreferences.INCOGNITO_KEYBOARD_PREF, enabled).apply()
SignalStore.settings.isIncognitoKeyboardEnabled = enabled
refresh()
}
@@ -70,12 +66,12 @@ class PrivacySettingsViewModel(
return PrivacySettingsState(
hasPhoneNumber = !SignalStore.account.isPhoneNumberless,
blockedCount = 0,
readReceipts = TextSecurePreferences.isReadReceiptsEnabled(AppDependencies.application),
typingIndicators = TextSecurePreferences.isTypingIndicatorsEnabled(AppDependencies.application),
readReceipts = SignalStore.settings.isReadReceiptsEnabled,
typingIndicators = SignalStore.settings.isTypingIndicatorsEnabled,
screenLock = SignalStore.settings.screenLockEnabled,
screenLockActivityTimeout = SignalStore.settings.screenLockTimeout,
screenSecurity = TextSecurePreferences.isScreenSecurityEnabled(AppDependencies.application),
incognitoKeyboard = TextSecurePreferences.isIncognitoKeyboardEnabled(AppDependencies.application),
screenSecurity = SignalStore.settings.isScreenSecurityEnabled,
incognitoKeyboard = SignalStore.settings.isIncognitoKeyboardEnabled,
paymentLock = SignalStore.payments.paymentLock,
isObsoletePasswordEnabled = !SignalStore.settings.passphraseDisabled,
isObsoletePasswordTimeoutEnabled = SignalStore.settings.passphraseTimeoutEnabled,
@@ -89,11 +85,10 @@ class PrivacySettingsViewModel(
}
class Factory(
private val sharedPreferences: SharedPreferences,
private val repository: PrivacySettingsRepository
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return requireNotNull(modelClass.cast(PrivacySettingsViewModel(sharedPreferences, repository)))
return requireNotNull(modelClass.cast(PrivacySettingsViewModel(repository)))
}
}
}
@@ -32,7 +32,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.PreferenceManager
import kotlinx.coroutines.launch
import org.signal.core.ui.compose.ComposeFragment
import org.signal.core.ui.compose.DayNightPreviews
@@ -53,13 +52,7 @@ import org.thoughtcrime.securesms.util.viewModel
class AdvancedPrivacySettingsFragment : ComposeFragment() {
private val viewModel: AdvancedPrivacySettingsViewModel by viewModel {
val repository = AdvancedPrivacySettingsRepository(requireContext())
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
AdvancedPrivacySettingsViewModel(
preferences,
repository
)
AdvancedPrivacySettingsViewModel(AdvancedPrivacySettingsRepository())
}
private var networkReceiver: NetworkReceiver? = null
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components.settings.app.privacy.advanced
import android.content.Context
import com.google.android.gms.tasks.Tasks
import com.google.firebase.installations.FirebaseInstallations
import kotlinx.coroutines.Dispatchers
@@ -16,13 +15,12 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.SignalNetwork
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.TextSecurePreferences
import java.io.IOException
import java.util.concurrent.ExecutionException
private val TAG = Log.tag(AdvancedPrivacySettingsRepository::class.java)
class AdvancedPrivacySettingsRepository(private val context: Context) {
class AdvancedPrivacySettingsRepository {
suspend fun disablePushMessages(): DisablePushMessagesResult = withContext(Dispatchers.IO) {
val clearTokenError: Throwable? = when (val result = SignalNetwork.accountApi.clearFcmToken()) {
@@ -61,9 +59,9 @@ class AdvancedPrivacySettingsRepository(private val context: Context) {
StorageSyncHelper.scheduleSyncForDataChange()
AppDependencies.jobManager.add(
MultiDeviceConfigurationUpdateJob(
TextSecurePreferences.isReadReceiptsEnabled(context),
TextSecurePreferences.isTypingIndicatorsEnabled(context),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
SignalStore.settings.isReadReceiptsEnabled,
SignalStore.settings.isTypingIndicatorsEnabled,
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled,
SignalStore.settings.isLinkPreviewsEnabled
)
)
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components.settings.app.privacy.advanced
import android.content.SharedPreferences
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@@ -22,11 +21,9 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.SignalE164Util
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
class AdvancedPrivacySettingsViewModel(
private val sharedPreferences: SharedPreferences,
private val repository: AdvancedPrivacySettingsRepository
) : ViewModel() {
@@ -46,18 +43,18 @@ class AdvancedPrivacySettingsViewModel(
}
fun setAlwaysRelayCalls(enabled: Boolean) {
sharedPreferences.edit().putBoolean(TextSecurePreferences.ALWAYS_RELAY_CALLS_PREF, enabled).apply()
SignalStore.settings.isTurnOnly = enabled
refresh()
}
fun setShowStatusIconForSealedSender(enabled: Boolean) {
sharedPreferences.edit().putBoolean(TextSecurePreferences.SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, enabled).apply()
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled = enabled
repository.syncShowSealedSenderIconState()
refresh()
}
fun setAllowSealedSenderFromAnyone(enabled: Boolean) {
sharedPreferences.edit().putBoolean(TextSecurePreferences.UNIVERSAL_UNIDENTIFIED_ACCESS, enabled).apply()
SignalStore.settings.isUniversalUnidentifiedAccess = enabled
AppDependencies.jobManager.startChain(RefreshAttributesJob()).then(RefreshOwnProfileJob()).enqueue()
refresh()
}
@@ -97,15 +94,11 @@ class AdvancedPrivacySettingsViewModel(
return AdvancedPrivacySettingsState(
isPushEnabled = SignalStore.account.isRegistered,
alwaysRelayCalls = TextSecurePreferences.isTurnOnly(AppDependencies.application),
alwaysRelayCalls = SignalStore.settings.isTurnOnly,
censorshipCircumventionState = censorshipCircumventionState,
censorshipCircumventionEnabled = getCensorshipCircumventionEnabled(censorshipCircumventionState),
showSealedSenderStatusIcon = TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(
AppDependencies.application
),
allowSealedSenderFromAnyone = TextSecurePreferences.isUniversalUnidentifiedAccess(
AppDependencies.application
),
showSealedSenderStatusIcon = SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled,
allowSealedSenderFromAnyone = SignalStore.settings.isUniversalUnidentifiedAccess,
showProgressSpinner = false,
allowAutomaticKeyVerification = SignalStore.settings.automaticVerificationEnabled,
isPrimaryDevice = SignalStore.account.isPrimaryDevice
@@ -86,7 +86,6 @@ import org.thoughtcrime.securesms.service.webrtc.SignalCallManager
import org.thoughtcrime.securesms.sms.MessageSender
import org.thoughtcrime.securesms.util.FullscreenHelper
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.VibrateUtil
import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
@@ -1156,7 +1155,7 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
}
private fun initializeScreenshotSecurity() {
if (TextSecurePreferences.isScreenSecurityEnabled(this)) {
if (SignalStore.settings.isScreenSecurityEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
@@ -310,6 +310,7 @@ import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob
import org.thoughtcrime.securesms.keyboard.KeyboardPage
import org.thoughtcrime.securesms.keyboard.KeyboardUtil
import org.thoughtcrime.securesms.keyboard.sticker.StickerSearchDialogFragment
import org.thoughtcrime.securesms.keyvalue.SettingsValues.MediaKeyboardMode
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModelV2
@@ -2780,10 +2781,10 @@ class ConversationFragment :
/** Which keyboard the toggle should offer, from the mode remembered across runs. */
private fun preferredKeyboardPage(): KeyboardPage {
return when (TextSecurePreferences.getMediaKeyboardMode(requireContext())) {
TextSecurePreferences.MediaKeyboardMode.EMOJI -> KeyboardPage.EMOJI
TextSecurePreferences.MediaKeyboardMode.STICKER -> KeyboardPage.STICKER
TextSecurePreferences.MediaKeyboardMode.GIF -> if (RemoteConfig.gifSearchAvailable) KeyboardPage.GIF else KeyboardPage.STICKER
return when (SignalStore.settings.mediaKeyboardMode) {
MediaKeyboardMode.EMOJI -> KeyboardPage.EMOJI
MediaKeyboardMode.STICKER -> KeyboardPage.STICKER
MediaKeyboardMode.GIF -> if (RemoteConfig.gifSearchAvailable) KeyboardPage.GIF else KeyboardPage.STICKER
}
}
@@ -2794,7 +2795,7 @@ class ConversationFragment :
inputPanel.setMediaKeyboardToggleMode(preferredKeyboardPage())
if (stickerIntro) {
TextSecurePreferences.setMediaKeyboardMode(requireContext(), TextSecurePreferences.MediaKeyboardMode.STICKER)
SignalStore.settings.mediaKeyboardMode = MediaKeyboardMode.STICKER
inputPanel.setMediaKeyboardToggleMode(KeyboardPage.STICKER)
conversationTooltips.displayStickerIntroductionTooltip(inputPanel.mediaKeyboardToggleAnchorView) {
EventBus.getDefault().removeStickyEvent(StickerPackInstallEvent::class.java)
@@ -4747,7 +4748,7 @@ class ConversationFragment :
searchMenuItem!!.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
searchView.setIncognitoKeyboardEnabled(TextSecurePreferences.isIncognitoKeyboardEnabled(requireContext()))
searchView.setIncognitoKeyboardEnabled(SignalStore.settings.isIncognitoKeyboardEnabled)
searchView.setOnQueryTextListener(queryListener)
isSearchRequested = true
searchViewModel.onSearchOpened()
@@ -150,7 +150,6 @@ import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.MessageConstraintsUtil
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.SignalTrace
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.isStory
import org.whispersystems.signalservice.internal.push.SyncMessage
import java.io.Closeable
@@ -7152,7 +7151,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val messageExtraBytes = cursor.requireBlob(MESSAGE_EXTRAS)
val messageExtras = messageExtraBytes?.let { MessageExtras.ADAPTER.decode(it) }
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
if (!SignalStore.settings.isReadReceiptsEnabled) {
hasReadReceipt = false
if (MessageTypes.isOutgoingMessageType(box) && !storyType.isStory) {
isViewed = false
@@ -77,7 +77,6 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.SignalTrace
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.isPoll
import org.thoughtcrime.securesms.util.isScheduled
import org.whispersystems.signalservice.api.storage.SignalAccountRecord
@@ -2462,7 +2461,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
RecipientCreator.forIndividual(context, recipientSettings)
}
val hasReadReceipt = TextSecurePreferences.isReadReceiptsEnabled(context) && cursor.requireBoolean(HAS_READ_RECEIPT)
val hasReadReceipt = SignalStore.settings.isReadReceiptsEnabled && cursor.requireBoolean(HAS_READ_RECEIPT)
val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS))
val messageExtraBytes = cursor.getBlob(cursor.getColumnIndexOrThrow(SNIPPET_MESSAGE_EXTRAS))
val messageExtras = if (messageExtraBytes != null) MessageExtras.ADAPTER.decode(messageExtraBytes) else null
@@ -7,7 +7,7 @@ package org.thoughtcrime.securesms.dependencies
import org.signal.core.ui.CoreUiDependencies
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.keyvalue.SignalStore
object CoreUiDependenciesProvider : CoreUiDependencies.Provider {
override fun providePackageId(): String {
@@ -15,10 +15,10 @@ object CoreUiDependenciesProvider : CoreUiDependencies.Provider {
}
override fun provideIsIncognitoKeyboardEnabled(): Boolean {
return TextSecurePreferences.isIncognitoKeyboardEnabled(AppDependencies.application)
return SignalStore.settings.isIncognitoKeyboardEnabled
}
override fun provideIsScreenSecurityEnabled(): Boolean {
return TextSecurePreferences.isScreenSecurityEnabled(AppDependencies.application)
return SignalStore.settings.isScreenSecurityEnabled
}
}
@@ -45,7 +45,6 @@ import org.thoughtcrime.securesms.mms.OutgoingMessage
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil
import org.whispersystems.signalservice.api.groupsv2.GroupChangeReconstruct
import org.whispersystems.signalservice.api.groupsv2.GroupHistoryPage
@@ -947,7 +946,7 @@ class GroupsV2StateProcessor private constructor(
}
fun stopAllTypingForGroup() {
if (TextSecurePreferences.isTypingIndicatorsEnabled(AppDependencies.application)) {
if (SignalStore.settings.isTypingIndicatorsEnabled) {
val threadId = SignalDatabase.threads.getThreadIdFor(SignalDatabase.recipients.getOrInsertFromGroupId(groupId))
if (threadId != null) {
AppDependencies.typingStatusRepository.stopAllTypingForThread(threadId)
@@ -7,8 +7,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import org.thoughtcrime.securesms.jobmanager.Constraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Collections;
import java.util.Set;
@@ -41,8 +41,8 @@ public class AutoDownloadEmojiConstraint implements Constraint {
@RequiresApi(26)
@Override
public void applyToJobInfo(@NonNull JobInfo.Builder jobInfoBuilder) {
boolean canDownloadWhileRoaming = TextSecurePreferences.getRoamingMediaDownloadAllowed(context).contains(IMAGE_TYPE);
boolean canDownloadWhileMobile = TextSecurePreferences.getMobileMediaDownloadAllowed(context).contains(IMAGE_TYPE);
boolean canDownloadWhileRoaming = SignalStore.settings().getRoamingMediaDownloadAllowed().contains(IMAGE_TYPE);
boolean canDownloadWhileMobile = SignalStore.settings().getMobileMediaDownloadAllowed().contains(IMAGE_TYPE);
if (canDownloadWhileRoaming) {
jobInfoBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
@@ -62,9 +62,9 @@ public class AutoDownloadEmojiConstraint implements Constraint {
}
private static @NonNull Set<String> getAllowedAutoDownloadTypes(@NonNull Context context, boolean forceWifi) {
if (NetworkUtil.isConnectedWifi(context)) return forceWifi ? Collections.singleton(IMAGE_TYPE) : TextSecurePreferences.getWifiMediaDownloadAllowed(context);
else if (NetworkUtil.isConnectedRoaming(context)) return TextSecurePreferences.getRoamingMediaDownloadAllowed(context);
else if (NetworkUtil.isConnectedMobile(context)) return TextSecurePreferences.getMobileMediaDownloadAllowed(context);
if (NetworkUtil.isConnectedWifi(context)) return forceWifi ? Collections.singleton(IMAGE_TYPE) : SignalStore.settings().getWifiMediaDownloadAllowed();
else if (NetworkUtil.isConnectedRoaming(context)) return SignalStore.settings().getRoamingMediaDownloadAllowed();
else if (NetworkUtil.isConnectedMobile(context)) return SignalStore.settings().getMobileMediaDownloadAllowed();
else return Collections.emptySet();
}
@@ -141,7 +141,7 @@ public class RefreshAttributesJob extends BaseJob {
int registrationId = SignalStore.account().getRegistrationId();
boolean fetchesMessages = !SignalStore.account().isFcmEnabled() || SignalStore.settings().getForceWebsocketMode().isEnabled();
byte[] unidentifiedAccessKey = UnidentifiedAccess.deriveAccessKeyFrom(ProfileKeyUtil.getSelfProfileKey());
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
boolean universalUnidentifiedAccess = SignalStore.settings().isUniversalUnidentifiedAccess();
String registrationLockV2 = null;
int pniRegistrationId = RegistrationRepository.getPniRegistrationId();
String recoveryPassword = svrValues.getMasterKey().deriveRegistrationRecoveryPassword();
@@ -29,7 +29,6 @@ import org.thoughtcrime.securesms.profiles.ProfileName
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.ProfileUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException
import org.whispersystems.signalservice.api.crypto.ProfileCipher
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential
@@ -213,8 +212,8 @@ class RefreshOwnProfileJob private constructor(parameters: Parameters) : BaseJob
return
}
if (TextSecurePreferences.isUniversalUnidentifiedAccess(context) != universalUnidentifiedAccess) {
Log.w(TAG, "The universal access flag doesn't match our local value (local: " + TextSecurePreferences.isUniversalUnidentifiedAccess(context) + ", remote: " + universalUnidentifiedAccess + ")! Refreshing attributes.")
if (SignalStore.settings.isUniversalUnidentifiedAccess != universalUnidentifiedAccess) {
Log.w(TAG, "The universal access flag doesn't match our local value (local: " + SignalStore.settings.isUniversalUnidentifiedAccess + ", remote: " + universalUnidentifiedAccess + ")! Refreshing attributes.")
AppDependencies.jobManager.add(RefreshAttributesJob())
return
}
@@ -19,12 +19,12 @@ import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.signal.core.util.Util;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.ContentHint;
@@ -100,7 +100,7 @@ public class SendReadReceiptJob extends BaseJob {
* maximum size.
*/
public static void enqueue(long threadId, @NonNull RecipientId recipientId, List<MarkedMessageInfo> markedMessageInfos) {
if (!TextSecurePreferences.isReadReceiptsEnabled(AppDependencies.getApplication())) {
if (!SignalStore.settings().isReadReceiptsEnabled()) {
return;
}
@@ -151,7 +151,7 @@ public class SendReadReceiptJob extends BaseJob {
throw new NotPushRegisteredException();
}
if (!TextSecurePreferences.isReadReceiptsEnabled(context) || messageSentTimestamps.isEmpty()) return;
if (!SignalStore.settings().isReadReceiptsEnabled() || messageSentTimestamps.isEmpty()) return;
if (!RecipientUtil.isMessageRequestAccepted(threadId)) {
Log.w(TAG, "Refusing to send receipts to untrusted recipient");
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.signal.core.util.Util;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.ContentHint;
@@ -139,7 +138,7 @@ public class SendViewedReceiptJob extends BaseJob {
@Override
public void onRun() throws IOException, UntrustedIdentityException {
boolean canSendNonStoryReceipts = TextSecurePreferences.isReadReceiptsEnabled(context);
boolean canSendNonStoryReceipts = SignalStore.settings().isReadReceiptsEnabled();
boolean canSendStoryReceipts = SignalStore.story().getViewedReceiptsEnabled();
List<MessageId> foundMessageIds = new LinkedList<>();
@@ -158,7 +157,7 @@ public class SendViewedReceiptJob extends BaseJob {
throw new NotPushRegisteredException();
}
if (storyTypes.isEmpty() && !TextSecurePreferences.isReadReceiptsEnabled(context)) {
if (storyTypes.isEmpty() && !SignalStore.settings().isReadReceiptsEnabled()) {
Log.w(TAG, "Read receipts not enabled!");
return;
}
@@ -13,11 +13,11 @@ import org.thoughtcrime.securesms.jobmanager.JsonJobData;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.messages.GroupSendUtil;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage.Action;
@@ -81,7 +81,7 @@ public class TypingSendJob extends BaseJob {
throw new NotPushRegisteredException();
}
if (!TextSecurePreferences.isTypingIndicatorsEnabled(context)) {
if (!SignalStore.settings().isTypingIndicatorsEnabled()) {
return;
}
@@ -0,0 +1,68 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.keyvalue
import android.content.Context
import android.net.Uri
import androidx.preference.PreferenceManager
/**
* Read-only access to the app's default [android.content.SharedPreferences] for the purpose of easing migration to [SignalStore].
*/
object LegacySharedPrefs {
fun contains(context: Context, key: String): Boolean {
return prefs(context).contains(key)
}
fun getBoolean(context: Context, key: String, defaultValue: Boolean): Boolean {
return prefs(context).getBoolean(key, defaultValue)
}
fun getInteger(context: Context, key: String, defaultValue: Int): Int {
return prefs(context).getInt(key, defaultValue)
}
fun getLong(context: Context, key: String, defaultValue: Long): Long {
return prefs(context).getLong(key, defaultValue)
}
fun getString(context: Context, key: String, defaultValue: String): String {
return prefs(context).getString(key, defaultValue) ?: defaultValue
}
/** Some values were stored as strings, but some installs ended up with ints. */
fun getIntegerFromString(context: Context, key: String, defaultValue: Int): Int {
return try {
getString(context, key, defaultValue.toString()).toInt()
} catch (e: ClassCastException) {
getInteger(context, key, defaultValue)
} catch (e: NumberFormatException) {
defaultValue
}
}
/** Mirrors the URI fixup the old ringtone getters did. */
fun getRingtone(context: Context, key: String, defaultValue: Uri): String {
val result = getString(context, key, defaultValue.toString())
return if (result.startsWith("file:")) {
defaultValue.toString()
} else {
result
}
}
fun getStringSet(context: Context, key: String, defaultValues: Set<String>?): Set<String>? {
return if (prefs(context).contains(key)) {
prefs(context).getStringSet(key, emptySet()) ?: emptySet()
} else {
defaultValues
}
}
private fun prefs(context: Context) = PreferenceManager.getDefaultSharedPreferences(context)
}
@@ -3,22 +3,25 @@ package org.thoughtcrime.securesms.keyvalue
import android.content.Context
import android.net.Uri
import android.provider.Settings
import androidx.annotation.ArrayRes
import androidx.core.app.NotificationCompat
import androidx.lifecycle.LiveData
import org.signal.core.util.StringStringSerializer
import org.signal.core.util.logging.Log
import org.signal.mediasend.SentMediaQuality
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.database.model.databaseprotos.SignalStoreList
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference
import org.thoughtcrime.securesms.util.DynamicTheme
import org.thoughtcrime.securesms.util.Environment
import org.thoughtcrime.securesms.util.SingleLiveEvent
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.webrtc.CallDataMode
import java.util.Arrays
import java.util.Random
import kotlin.math.abs
@Suppress("DEPRECATION")
class SettingsValues internal constructor(store: KeyValueStore, context: Context) : SignalStoreValues(store) {
class SettingsValues internal constructor(store: KeyValueStore, private val context: Context) : SignalStoreValues(store) {
companion object {
private val TAG = Log.tag(SettingsValues::class.java)
@@ -79,6 +82,21 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
private const val SCREEN_LOCK_TIMEOUT = "settings.screen.lock.timeout"
private const val AUTOMATIC_VERIFICATION_ENABLED = "settings.automatic.verification.enabled"
private const val FORCE_WEBSOCKET_MODE = "settings.force.websocket.mode.2"
private const val MESSAGE_LED_BLINK_PATTERN_CUSTOM = "settings.message.led.blink.custom"
private const val MESSAGE_NOTIFICATION_PRIORITY = "settings.message.notification.priority"
private const val MEDIA_KEYBOARD_MODE = "settings.media.keyboard.mode"
private const val LOCAL_BACKUP_NEXT_TIME = "settings.backups.next.time"
private const val MEDIA_DOWNLOAD_MOBILE = "settings.media.download.mobile"
private const val MEDIA_DOWNLOAD_WIFI = "settings.media.download.wifi"
private const val MEDIA_DOWNLOAD_ROAMING = "settings.media.download.roaming"
const val SCREEN_SECURITY_ENABLED = "settings.screen.security.enabled"
const val INCOGNITO_KEYBOARD_ENABLED = "settings.incognito.keyboard.enabled"
const val READ_RECEIPTS_ENABLED = "settings.read.receipts.enabled"
const val TYPING_INDICATORS_ENABLED = "settings.typing.indicators.enabled"
const val SHOW_UNIDENTIFIED_DELIVERY_INDICATORS = "settings.show.unidentified.delivery.indicators"
const val UNIVERSAL_UNIDENTIFIED_ACCESS = "settings.universal.unidentified.access"
const val ALWAYS_RELAY_CALLS = "settings.always.relay.calls"
const val BACKUP_DEFAULT_HOUR = 2
const val BACKUP_DEFAULT_MINUTE = 0
@@ -90,6 +108,10 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
if (!store.containsKey(SCREEN_LOCK_ENABLED) && !Environment.IS_INSTRUMENTATION) {
migrateFromSharedPrefsV1(context)
}
if (!store.containsKey(SCREEN_SECURITY_ENABLED) && !Environment.IS_INSTRUMENTATION) {
migrateFromSharedPrefsV2(context)
}
}
public override fun onFirstEverAppLaunch() {
@@ -138,7 +160,17 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
PASSPHRASE_TIMEOUT_ENABLED,
PASSPHRASE_TIMEOUT,
SCREEN_LOCK_ENABLED,
SCREEN_LOCK_TIMEOUT
SCREEN_LOCK_TIMEOUT,
SCREEN_SECURITY_ENABLED,
INCOGNITO_KEYBOARD_ENABLED,
READ_RECEIPTS_ENABLED,
TYPING_INDICATORS_ENABLED,
SHOW_UNIDENTIFIED_DELIVERY_INDICATORS,
UNIVERSAL_UNIDENTIFIED_ACCESS,
ALWAYS_RELAY_CALLS,
MEDIA_DOWNLOAD_MOBILE,
MEDIA_DOWNLOAD_WIFI,
MEDIA_DOWNLOAD_ROAMING
)
val onConfigurationSettingChanged: LiveData<String>
@@ -191,17 +223,13 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
}
var theme: Theme
get() = Theme.deserialize(getString(THEME, TextSecurePreferences.getTheme(AppDependencies.application)))
get() = Theme.deserialize(getString(THEME, if (DynamicTheme.systemThemeAvailable()) "system" else "light"))
set(value) {
putString(THEME, value.serialize())
configurationSettingChanged.postValue(THEME)
}
var messageFontSize: Int
get() = getInteger(MESSAGE_FONT_SIZE, TextSecurePreferences.getMessageBodyTextSize(AppDependencies.application))
set(value) {
putInteger(MESSAGE_FONT_SIZE, value)
}
var messageFontSize: Int by integerValue(MESSAGE_FONT_SIZE, 16)
fun getMessageQuoteFontSize(context: Context): Int {
val currentMessageSize = messageFontSize
@@ -220,23 +248,11 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
return possibleQuoteSizes[sizeIndex]
}
var isPreferSystemEmoji: Boolean
get() = getBoolean(PREFER_SYSTEM_EMOJI, TextSecurePreferences.isSystemEmojiPreferred(AppDependencies.application))
set(value) {
putBoolean(PREFER_SYSTEM_EMOJI, value)
}
var isPreferSystemEmoji: Boolean by booleanValue(PREFER_SYSTEM_EMOJI, false)
var isEnterKeySends: Boolean
get() = getBoolean(ENTER_KEY_SENDS, TextSecurePreferences.isEnterSendsEnabled(AppDependencies.application))
set(value) {
putBoolean(ENTER_KEY_SENDS, value)
}
var isEnterKeySends: Boolean by booleanValue(ENTER_KEY_SENDS, false)
var isBackupEnabled: Boolean
get() = getBoolean(BACKUPS_ENABLED, TextSecurePreferences.isBackupEnabled(AppDependencies.application))
set(value) {
putBoolean(BACKUPS_ENABLED, value)
}
var isBackupEnabled: Boolean by booleanValue(BACKUPS_ENABLED, false)
val backupHour: Int
get() = getInteger(BACKUPS_SCHEDULE_HOUR, BACKUP_DEFAULT_HOUR)
@@ -280,27 +296,17 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
putInteger(SIGNAL_BACKUPS_SCHEDULE_MINUTE, minute)
}
var isSmsDeliveryReportsEnabled: Boolean
get() = getBoolean(SMS_DELIVERY_REPORTS_ENABLED, TextSecurePreferences.isSmsDeliveryReportsEnabled(AppDependencies.application))
set(value) {
putBoolean(SMS_DELIVERY_REPORTS_ENABLED, value)
}
var localBackupNextTime: Long by longValue(LOCAL_BACKUP_NEXT_TIME, -1)
var isWifiCallingCompatibilityModeEnabled: Boolean
get() = getBoolean(WIFI_CALLING_COMPATIBILITY_MODE_ENABLED, TextSecurePreferences.isWifiSmsEnabled(AppDependencies.application))
set(value) {
putBoolean(WIFI_CALLING_COMPATIBILITY_MODE_ENABLED, value)
}
var isSmsDeliveryReportsEnabled: Boolean by booleanValue(SMS_DELIVERY_REPORTS_ENABLED, false)
var isMessageNotificationsEnabled: Boolean
get() = getBoolean(MESSAGE_NOTIFICATIONS_ENABLED, TextSecurePreferences.isNotificationsEnabled(AppDependencies.application))
set(value) {
putBoolean(MESSAGE_NOTIFICATIONS_ENABLED, value)
}
var isWifiCallingCompatibilityModeEnabled: Boolean by booleanValue(WIFI_CALLING_COMPATIBILITY_MODE_ENABLED, false)
var isMessageNotificationsEnabled: Boolean by booleanValue(MESSAGE_NOTIFICATIONS_ENABLED, true)
var messageNotificationSound: Uri
get() {
var result = getString(MESSAGE_NOTIFICATION_SOUND, TextSecurePreferences.getNotificationRingtone(AppDependencies.application).toString())
var result = getString(MESSAGE_NOTIFICATION_SOUND, Settings.System.DEFAULT_NOTIFICATION_URI.toString())
if (result.startsWith("file:")) {
result = Settings.System.DEFAULT_NOTIFICATION_URI.toString()
@@ -312,38 +318,23 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
putString(MESSAGE_NOTIFICATION_SOUND, value.toString())
}
var isMessageVibrateEnabled: Boolean
get() = getBoolean(MESSAGE_VIBRATE_ENABLED, TextSecurePreferences.isNotificationVibrateEnabled(AppDependencies.application))
set(value) {
putBoolean(MESSAGE_VIBRATE_ENABLED, value)
}
var isMessageVibrateEnabled: Boolean by booleanValue(MESSAGE_VIBRATE_ENABLED, true)
var messageLedColor: String
get() = getString(MESSAGE_LED_COLOR, TextSecurePreferences.getNotificationLedColor(AppDependencies.application))
set(value) {
putString(MESSAGE_LED_COLOR, value)
}
var messageLedColor: String by stringValue(MESSAGE_LED_COLOR, "blue")
var messageLedBlinkPattern: String
get() = getString(MESSAGE_LED_BLINK_PATTERN, TextSecurePreferences.getNotificationLedPattern(AppDependencies.application))
set(value) {
putString(MESSAGE_LED_BLINK_PATTERN, value)
}
var messageLedBlinkPattern: String by stringValue(MESSAGE_LED_BLINK_PATTERN, "500,2000")
var isMessageNotificationsInChatSoundsEnabled: Boolean
get() = getBoolean(MESSAGE_IN_CHAT_SOUNDS_ENABLED, TextSecurePreferences.isInThreadNotifications(AppDependencies.application))
set(value) {
putBoolean(MESSAGE_IN_CHAT_SOUNDS_ENABLED, value)
}
val messageLedBlinkPatternCustom: String
get() = getString(MESSAGE_LED_BLINK_PATTERN_CUSTOM, "500,2000")
var messageNotificationsRepeatAlerts: Int
get() = getInteger(MESSAGE_REPEAT_ALERTS, TextSecurePreferences.getRepeatAlertsCount(AppDependencies.application))
set(value) {
putInteger(MESSAGE_REPEAT_ALERTS, value)
}
var isMessageNotificationsInChatSoundsEnabled: Boolean by booleanValue(MESSAGE_IN_CHAT_SOUNDS_ENABLED, true)
var messageNotificationsRepeatAlerts: Int by integerValue(MESSAGE_REPEAT_ALERTS, 0)
var messageNotificationPriority: Int by integerValue(MESSAGE_NOTIFICATION_PRIORITY, NotificationCompat.PRIORITY_HIGH)
var messageNotificationsPrivacy: NotificationPrivacyPreference
get() = NotificationPrivacyPreference(getString(MESSAGE_NOTIFICATION_PRIVACY, TextSecurePreferences.getNotificationPrivacy(AppDependencies.application).toString()))
get() = NotificationPrivacyPreference(getString(MESSAGE_NOTIFICATION_PRIVACY, "all"))
set(value) {
putString(MESSAGE_NOTIFICATION_PRIVACY, value.toString())
}
@@ -377,15 +368,11 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
putBoolean(INCLUDE_MUTED_IN_BADGE_COUNT, include)
}
var isCallNotificationsEnabled: Boolean
get() = getBoolean(CALL_NOTIFICATIONS_ENABLED, TextSecurePreferences.isCallNotificationsEnabled(AppDependencies.application))
set(value) {
putBoolean(CALL_NOTIFICATIONS_ENABLED, value)
}
var isCallNotificationsEnabled: Boolean by booleanValue(CALL_NOTIFICATIONS_ENABLED, true)
var callRingtone: Uri
get() {
var result = getString(CALL_RINGTONE, TextSecurePreferences.getCallNotificationRingtone(AppDependencies.application).toString())
var result = getString(CALL_RINGTONE, Settings.System.DEFAULT_RINGTONE_URI.toString())
if (result != null && result.startsWith("file:")) {
result = Settings.System.DEFAULT_RINGTONE_URI.toString()
@@ -397,17 +384,9 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
putString(CALL_RINGTONE, value.toString())
}
var isCallVibrateEnabled: Boolean
get() = getBoolean(CALL_VIBRATE_ENABLED, TextSecurePreferences.isCallNotificationVibrateEnabled(AppDependencies.application))
set(value) {
putBoolean(CALL_VIBRATE_ENABLED, value)
}
var isCallVibrateEnabled: Boolean by booleanValue(CALL_VIBRATE_ENABLED, true)
var isNotifyWhenContactJoinsSignal: Boolean
get() = getBoolean(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL, TextSecurePreferences.isNewContactsNotificationEnabled(AppDependencies.application))
set(value) {
putBoolean(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL, value)
}
var isNotifyWhenContactJoinsSignal: Boolean by booleanValue(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL, false)
var universalExpireTimer: Int by integerValue(UNIVERSAL_EXPIRE_TIMER, 0)
@@ -439,6 +418,20 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
var screenLockTimeout: Long by longValue(SCREEN_LOCK_TIMEOUT, 0)
var isScreenSecurityEnabled: Boolean by booleanValue(SCREEN_SECURITY_ENABLED, false)
var isIncognitoKeyboardEnabled: Boolean by booleanValue(INCOGNITO_KEYBOARD_ENABLED, false)
var isReadReceiptsEnabled: Boolean by booleanValue(READ_RECEIPTS_ENABLED, false)
var isTypingIndicatorsEnabled: Boolean by booleanValue(TYPING_INDICATORS_ENABLED, false)
var isShowUnidentifiedDeliveryIndicatorsEnabled: Boolean by booleanValue(SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, false)
var isUniversalUnidentifiedAccess: Boolean by booleanValue(UNIVERSAL_UNIDENTIFIED_ACCESS, false)
var isTurnOnly: Boolean by booleanValue(ALWAYS_RELAY_CALLS, false)
var automaticVerificationEnabled: Boolean
get() = getBoolean(AUTOMATIC_VERIFICATION_ENABLED, true)
set(value) {
@@ -460,6 +453,42 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
putInteger(FORCE_WEBSOCKET_MODE, value.serialize())
}
var mediaKeyboardMode: MediaKeyboardMode
get() = MediaKeyboardMode.valueOf(getString(MEDIA_KEYBOARD_MODE, MediaKeyboardMode.EMOJI.name))
set(value) {
putString(MEDIA_KEYBOARD_MODE, value.name)
}
var mobileMediaDownloadAllowed: Set<String>
get() = getMediaDownloadAllowed(MEDIA_DOWNLOAD_MOBILE, R.array.pref_media_download_mobile_data_default)
set(value) {
setMediaDownloadAllowed(MEDIA_DOWNLOAD_MOBILE, value)
}
var wifiMediaDownloadAllowed: Set<String>
get() = getMediaDownloadAllowed(MEDIA_DOWNLOAD_WIFI, R.array.pref_media_download_wifi_default)
set(value) {
setMediaDownloadAllowed(MEDIA_DOWNLOAD_WIFI, value)
}
var roamingMediaDownloadAllowed: Set<String>
get() = getMediaDownloadAllowed(MEDIA_DOWNLOAD_ROAMING, R.array.pref_media_download_roaming_default)
set(value) {
setMediaDownloadAllowed(MEDIA_DOWNLOAD_ROAMING, value)
}
private fun getMediaDownloadAllowed(key: String, @ArrayRes defaultValuesRes: Int): Set<String> {
if (!store.containsKey(key)) {
return context.resources.getStringArray(defaultValuesRes).toSet()
}
return getList(key, StringStringSerializer).requireNoNulls().toSet()
}
private fun setMediaDownloadAllowed(key: String, allowed: Set<String>) {
putList(key, allowed.toList(), StringStringSerializer)
}
private fun getUri(key: String): Uri? {
val uri = getString(key, "")
@@ -473,11 +502,111 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating screen lock values from shared prefs.")
putBoolean(PASSPHRASE_DISABLED, TextSecurePreferences.getBooleanPreference(context, "pref_disable_passphrase", true))
putBoolean(PASSPHRASE_TIMEOUT_ENABLED, TextSecurePreferences.getBooleanPreference(context, "pref_timeout_passphrase", false))
putInteger(PASSPHRASE_TIMEOUT, TextSecurePreferences.getIntegerPreference(context, "pref_timeout_interval", 5 * 60))
putBoolean(SCREEN_LOCK_ENABLED, TextSecurePreferences.getBooleanPreference(context, "pref_android_screen_lock", false))
putLong(SCREEN_LOCK_TIMEOUT, TextSecurePreferences.getLongPreference(context, "pref_android_screen_lock_timeout", 0))
putBoolean(PASSPHRASE_DISABLED, LegacySharedPrefs.getBoolean(context, "pref_disable_passphrase", true))
putBoolean(PASSPHRASE_TIMEOUT_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_timeout_passphrase", false))
putInteger(PASSPHRASE_TIMEOUT, LegacySharedPrefs.getInteger(context, "pref_timeout_interval", 5 * 60))
putBoolean(SCREEN_LOCK_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_android_screen_lock", false))
putLong(SCREEN_LOCK_TIMEOUT, LegacySharedPrefs.getLong(context, "pref_android_screen_lock_timeout", 0))
}
/**
* These settings used to live in shared prefs. Some of them were already mirrored into this store, but with a shared-prefs read as
* their default, so for those we only migrate the ones this store doesn't already have a value for.
*/
private fun migrateFromSharedPrefsV2(context: Context) {
Log.i(TAG, "[V2] Migrating settings from shared prefs.")
val writer = store.beginWrite()
if (!store.containsKey(THEME)) {
writer.putString(THEME, LegacySharedPrefs.getString(context, "pref_theme", if (DynamicTheme.systemThemeAvailable()) "system" else "light"))
}
if (!store.containsKey(MESSAGE_FONT_SIZE)) {
writer.putInteger(MESSAGE_FONT_SIZE, LegacySharedPrefs.getIntegerFromString(context, "pref_message_body_text_size", 16))
}
if (!store.containsKey(PREFER_SYSTEM_EMOJI)) {
writer.putBoolean(PREFER_SYSTEM_EMOJI, LegacySharedPrefs.getBoolean(context, "pref_system_emoji", false))
}
if (!store.containsKey(ENTER_KEY_SENDS)) {
writer.putBoolean(ENTER_KEY_SENDS, LegacySharedPrefs.getBoolean(context, "pref_enter_sends", false))
}
if (!store.containsKey(BACKUPS_ENABLED)) {
writer.putBoolean(BACKUPS_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_backup_enabled", false))
}
if (!store.containsKey(SMS_DELIVERY_REPORTS_ENABLED)) {
writer.putBoolean(SMS_DELIVERY_REPORTS_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_delivery_report_sms", false))
}
if (!store.containsKey(WIFI_CALLING_COMPATIBILITY_MODE_ENABLED)) {
writer.putBoolean(WIFI_CALLING_COMPATIBILITY_MODE_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_wifi_sms", false))
}
if (!store.containsKey(MESSAGE_NOTIFICATIONS_ENABLED)) {
writer.putBoolean(MESSAGE_NOTIFICATIONS_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_key_enable_notifications", true))
}
if (!store.containsKey(MESSAGE_NOTIFICATION_SOUND)) {
writer.putString(MESSAGE_NOTIFICATION_SOUND, LegacySharedPrefs.getRingtone(context, "pref_key_ringtone", Settings.System.DEFAULT_NOTIFICATION_URI))
}
if (!store.containsKey(MESSAGE_VIBRATE_ENABLED)) {
writer.putBoolean(MESSAGE_VIBRATE_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_key_vibrate", true))
}
if (!store.containsKey(MESSAGE_LED_COLOR)) {
writer.putString(MESSAGE_LED_COLOR, LegacySharedPrefs.getString(context, "pref_led_color", "blue"))
}
if (!store.containsKey(MESSAGE_LED_BLINK_PATTERN)) {
writer.putString(MESSAGE_LED_BLINK_PATTERN, LegacySharedPrefs.getString(context, "pref_led_blink", "500,2000"))
}
if (!store.containsKey(MESSAGE_IN_CHAT_SOUNDS_ENABLED)) {
writer.putBoolean(MESSAGE_IN_CHAT_SOUNDS_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_key_inthread_notifications", true))
}
if (!store.containsKey(MESSAGE_REPEAT_ALERTS)) {
writer.putInteger(MESSAGE_REPEAT_ALERTS, LegacySharedPrefs.getIntegerFromString(context, "pref_repeat_alerts", 0))
}
if (!store.containsKey(MESSAGE_NOTIFICATION_PRIVACY)) {
writer.putString(MESSAGE_NOTIFICATION_PRIVACY, LegacySharedPrefs.getString(context, "pref_notification_privacy", "all"))
}
if (!store.containsKey(CALL_NOTIFICATIONS_ENABLED)) {
writer.putBoolean(CALL_NOTIFICATIONS_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_call_notifications", true))
}
if (!store.containsKey(CALL_RINGTONE)) {
writer.putString(CALL_RINGTONE, LegacySharedPrefs.getRingtone(context, "pref_call_ringtone", Settings.System.DEFAULT_RINGTONE_URI))
}
if (!store.containsKey(CALL_VIBRATE_ENABLED)) {
val systemVibrateWhenRinging = Settings.System.getInt(context.contentResolver, Settings.System.VIBRATE_WHEN_RINGING, 1) == 1
writer.putBoolean(CALL_VIBRATE_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_call_vibrate", systemVibrateWhenRinging))
}
if (!store.containsKey(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL)) {
writer.putBoolean(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL, LegacySharedPrefs.getBoolean(context, "pref_enable_new_contacts_notifications", false))
}
writer.putString(MESSAGE_LED_BLINK_PATTERN_CUSTOM, LegacySharedPrefs.getString(context, "pref_led_blink_custom", "500,2000"))
writer.putInteger(MESSAGE_NOTIFICATION_PRIORITY, LegacySharedPrefs.getIntegerFromString(context, "pref_notification_priority", NotificationCompat.PRIORITY_HIGH))
writer.putString(MEDIA_KEYBOARD_MODE, LegacySharedPrefs.getString(context, "pref_media_keyboard_mode", MediaKeyboardMode.EMOJI.name))
writer.putLong(LOCAL_BACKUP_NEXT_TIME, LegacySharedPrefs.getLong(context, "pref_backup_next_time", -1))
writer.putBoolean(INCOGNITO_KEYBOARD_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_incognito_keyboard", false))
writer.putBoolean(READ_RECEIPTS_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_read_receipts", false))
writer.putBoolean(TYPING_INDICATORS_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_typing_indicators", false))
writer.putBoolean(SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, LegacySharedPrefs.getBoolean(context, "pref_show_unidentifed_delivery_indicators", false))
writer.putBoolean(UNIVERSAL_UNIDENTIFIED_ACCESS, LegacySharedPrefs.getBoolean(context, "pref_universal_unidentified_access", false))
writer.putBoolean(ALWAYS_RELAY_CALLS, LegacySharedPrefs.getBoolean(context, "pref_turn_only", false))
// Only migrate an explicit choice -- when there was none, the getters fall back to the same resource defaults shared prefs used to.
val mediaDownloadKeys = mapOf(
"pref_media_download_mobile" to MEDIA_DOWNLOAD_MOBILE,
"pref_media_download_wifi" to MEDIA_DOWNLOAD_WIFI,
"pref_media_download_roaming" to MEDIA_DOWNLOAD_ROAMING
)
for ((legacyKey, key) in mediaDownloadKeys) {
val legacyValue = LegacySharedPrefs.getStringSet(context, legacyKey, null)
if (legacyValue != null) {
writer.putBlob(key, SignalStoreList(contents = legacyValue.toList()).encode())
}
}
// Written last so that it acts as the marker for this migration having run.
writer.putBoolean(SCREEN_SECURITY_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_screen_security", false))
writer.commit()
}
enum class CensorshipCircumventionEnabled(private val value: Int) {
@@ -513,6 +642,13 @@ class SettingsValues internal constructor(store: KeyValueStore, context: Context
}
}
/** NEVER rename these -- they're persisted by name. */
enum class MediaKeyboardMode {
EMOJI,
STICKER,
GIF
}
enum class Theme(private val value: String) {
SYSTEM("system"),
LIGHT("light"),
@@ -32,12 +32,12 @@ final class LogSectionKeyPreferences implements LogSection {
.append("Thread Trimming : ").append(getThreadTrimmingString()).append("\n")
.append("Censorship Setting : ").append(SignalStore.settings().getCensorshipCircumventionEnabled()).append("\n")
.append("Network Reachable : ").append(SignalStore.misc().isServiceReachableWithoutCircumvention()).append(", last checked: ").append(SignalStore.misc().getLastCensorshipServiceReachabilityCheckTime()).append("\n")
.append("Wifi Download : ").append(Util.join(TextSecurePreferences.getWifiMediaDownloadAllowed(context), ",")).append("\n")
.append("Roaming Download : ").append(Util.join(TextSecurePreferences.getRoamingMediaDownloadAllowed(context), ",")).append("\n")
.append("Mobile Download : ").append(Util.join(TextSecurePreferences.getMobileMediaDownloadAllowed(context), ",")).append("\n")
.append("Wifi Download : ").append(Util.join(SignalStore.settings().getWifiMediaDownloadAllowed(), ",")).append("\n")
.append("Roaming Download : ").append(Util.join(SignalStore.settings().getRoamingMediaDownloadAllowed(), ",")).append("\n")
.append("Mobile Download : ").append(Util.join(SignalStore.settings().getMobileMediaDownloadAllowed(), ",")).append("\n")
.append("Phone Number Sharing : ").append(SignalStore.phoneNumberPrivacy().isPhoneNumberSharingEnabled()).append(" (").append(SignalStore.phoneNumberPrivacy().getPhoneNumberSharingMode()).append(")\n")
.append("Phone Number Discoverable: ").append(SignalStore.phoneNumberPrivacy().getPhoneNumberDiscoverabilityMode()).append("\n")
.append("Incognito keyboard : ").append(TextSecurePreferences.isIncognitoKeyboardEnabled(context)).append("\n");
.append("Incognito keyboard : ").append(SignalStore.settings().isIncognitoKeyboardEnabled()).append("\n");
}
private static String getThreadTrimmingString() {
@@ -10,11 +10,11 @@ import androidx.fragment.app.viewModels
import com.google.android.material.snackbar.Snackbar
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.KeyboardEntryDialogFragment
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
import org.thoughtcrime.securesms.stories.StoryLinkPreviewView
import org.thoughtcrime.securesms.util.LinkUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.activityViewModel
import org.thoughtcrime.securesms.util.setIncognitoKeyboardEnabled
@@ -47,7 +47,7 @@ class TextStoryPostLinkEntryFragment(private val shouldPreset: Boolean = false)
val confirmButton: View = view.findViewById(R.id.confirm_button)
val shareALinkGroup: Group = view.findViewById(R.id.share_a_link_group)
input.setIncognitoKeyboardEnabled(TextSecurePreferences.isIncognitoKeyboardEnabled(requireContext()))
input.setIncognitoKeyboardEnabled(SignalStore.settings.isIncognitoKeyboardEnabled)
input.addTextChangedListener(
afterTextChanged = {
val scheme = "https://"
@@ -28,13 +28,13 @@ import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.concurrent.LifecycleDisposable
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.KeyboardEntryDialogFragment
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mediasend.v2.MediaAnimations
import org.thoughtcrime.securesms.scribbles.HSVColorSlider
import org.thoughtcrime.securesms.scribbles.HSVColorSlider.getColor
import org.thoughtcrime.securesms.scribbles.HSVColorSlider.setColor
import org.thoughtcrime.securesms.scribbles.HSVColorSlider.setUpForColor
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.activityViewModel
import org.thoughtcrime.securesms.util.fragments.findListener
@@ -121,7 +121,7 @@ class TextStoryPostTextEntryFragment : KeyboardEntryDialogFragment(
viewModel.setTemporaryBody(text?.toString() ?: "")
}
input.setText(viewModel.getBody())
input.setIncognitoKeyboardEnabled(TextSecurePreferences.isIncognitoKeyboardEnabled(requireContext()))
input.setIncognitoKeyboardEnabled(SignalStore.settings.isIncognitoKeyboardEnabled)
}
private fun presentHint() {
@@ -13,9 +13,9 @@ import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.List;
import java.util.Locale;
@@ -45,7 +45,7 @@ final class RecipientViewHolder extends RecyclerView.ViewHolder {
}
void bind(RecipientDeliveryStatus data) {
unidentifiedDeliveryIcon.setVisibility(TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(itemView.getContext()) && data.isUnidentified() ? View.VISIBLE : View.GONE);
unidentifiedDeliveryIcon.setVisibility(SignalStore.settings().isShowUnidentifiedDeliveryIndicatorsEnabled() && data.isUnidentified() ? View.VISIBLE : View.GONE);
fromView.setText(data.getRecipient(), data.getRecipient().getDisplayName(itemView.getContext()), null, true, true);
avatar.setRecipient(data.getRecipient());
badge.setBadgeFromRecipient(data.getRecipient());
@@ -101,7 +101,6 @@ import org.thoughtcrime.securesms.util.MessageConstraintsUtil
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.SignalLocalMetrics
import org.thoughtcrime.securesms.util.SignalTrace
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.hasGiftBadge
import org.thoughtcrime.securesms.util.isStory
import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata
@@ -1483,7 +1482,7 @@ object DataMessageProcessor {
fun notifyTypingStoppedFromIncomingMessage(context: Context, senderRecipient: Recipient, threadRecipientId: RecipientId, device: Int) {
val threadId = SignalDatabase.threads.getThreadIdIfExistsFor(threadRecipientId)
if (threadId > 0 && TextSecurePreferences.isTypingIndicatorsEnabled(context)) {
if (threadId > 0 && SignalStore.settings.isTypingIndicatorsEnabled) {
debug("Typing stopped on thread $threadId due to an incoming message.")
AppDependencies.typingStatusRepository.onTypingStopped(threadId, senderRecipient, device, true)
}
@@ -48,7 +48,6 @@ import org.thoughtcrime.securesms.util.EarlyMessageCacheEntry
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.SignalLocalMetrics
import org.thoughtcrime.securesms.util.SignalTrace
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata
import org.whispersystems.signalservice.api.push.DistributionId
import org.whispersystems.signalservice.api.push.SignalServiceAddress
@@ -582,7 +581,7 @@ open class MessageContentProcessor(private val context: Context) {
typingMessage: TypingMessage,
senderRecipient: Recipient
) {
if (!TextSecurePreferences.isTypingIndicatorsEnabled(context)) {
if (!SignalStore.settings.isTypingIndicatorsEnabled) {
return
}
@@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.EarlyMessageCacheEntry
import org.thoughtcrime.securesms.util.SignalTrace
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata
import org.whispersystems.signalservice.internal.push.Content
import org.whispersystems.signalservice.internal.push.Envelope
@@ -77,7 +76,7 @@ object ReceiptMessageProcessor {
earlyMessageCacheEntry: EarlyMessageCacheEntry?,
batchCache: BatchCache
) {
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
if (!SignalStore.settings.isReadReceiptsEnabled) {
log(envelope.clientTimestamp!!, "Ignoring read receipts for IDs: " + readReceipt.timestamp.joinToString(", "))
return
}
@@ -113,7 +112,7 @@ object ReceiptMessageProcessor {
earlyMessageCacheEntry: EarlyMessageCacheEntry?,
batchCache: BatchCache
) {
val readReceipts = TextSecurePreferences.isReadReceiptsEnabled(context)
val readReceipts = SignalStore.settings.isReadReceiptsEnabled
val storyViewedReceipts = SignalStore.story.viewedReceiptsEnabled
if (!readReceipts && !storyViewedReceipts) {
@@ -123,7 +123,6 @@ import org.thoughtcrime.securesms.util.IdentityUtil
import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.MessageConstraintsUtil
import org.thoughtcrime.securesms.util.SignalE164Util
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.hasGiftBadge
import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer
@@ -993,9 +992,9 @@ object SyncMessageProcessor {
Request.Type.CONFIGURATION -> {
AppDependencies.jobManager.add(
MultiDeviceConfigurationUpdateJob(
TextSecurePreferences.isReadReceiptsEnabled(context),
TextSecurePreferences.isTypingIndicatorsEnabled(context),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
SignalStore.settings.isReadReceiptsEnabled,
SignalStore.settings.isTypingIndicatorsEnabled,
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled,
SignalStore.settings.isLinkPreviewsEnabled
)
)
@@ -1140,15 +1139,15 @@ object SyncMessageProcessor {
log(envelopeTimestamp, "Synchronize configuration message.")
if (configurationMessage.readReceipts != null) {
TextSecurePreferences.setReadReceiptsEnabled(context, configurationMessage.readReceipts!!)
SignalStore.settings.isReadReceiptsEnabled = configurationMessage.readReceipts!!
}
if (configurationMessage.unidentifiedDeliveryIndicators != null) {
TextSecurePreferences.setShowUnidentifiedDeliveryIndicatorsEnabled(context, configurationMessage.unidentifiedDeliveryIndicators!!)
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled = configurationMessage.unidentifiedDeliveryIndicators!!
}
if (configurationMessage.typingIndicators != null) {
TextSecurePreferences.setTypingIndicatorsEnabled(context, configurationMessage.typingIndicators!!)
SignalStore.settings.isTypingIndicatorsEnabled = configurationMessage.typingIndicators!!
}
if (configurationMessage.linkPreviews != null) {
@@ -150,8 +150,8 @@ public class LegacyMigrationJob extends MigrationJob {
}
if (lastSeenVersion < SCREENSHOTS) {
boolean screenSecurity = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(TextSecurePreferences.SCREEN_SECURITY_PREF, true);
TextSecurePreferences.setScreenSecurityEnabled(context, screenSecurity);
boolean screenSecurity = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("pref_screen_security", true);
SignalStore.settings().setScreenSecurityEnabled(screenSecurity);
}
if (lastSeenVersion < PERSISTENT_BLOBS) {
@@ -5,7 +5,6 @@ import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.TextSecurePreferences
/**
* Added as a way to initialize the story viewed receipts setting.
@@ -23,7 +22,7 @@ internal class StoryViewedReceiptsStateMigrationJob(
override fun performMigration() {
if (!SignalStore.story.isViewedReceiptsStateSet()) {
SignalStore.story.viewedReceiptsEnabled = TextSecurePreferences.isReadReceiptsEnabled(context)
SignalStore.story.viewedReceiptsEnabled = SignalStore.settings.isReadReceiptsEnabled
if (SignalStore.account.isRegistered) {
recipients.markNeedsSync(Recipient.self().id)
StorageSyncHelper.scheduleSyncForDataChange()
@@ -32,7 +32,6 @@ import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.util.AvatarUtil
import org.thoughtcrime.securesms.util.BubbleUtil
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import java.util.Optional
import androidx.core.app.Person as PersonCompat
import org.signal.core.ui.R as CoreUiR
@@ -177,7 +176,7 @@ sealed class NotificationBuilder(protected val context: Context) {
if (ledColor != "none") {
var blinkPattern = SignalStore.settings.messageLedBlinkPattern
if (blinkPattern == "custom") {
blinkPattern = TextSecurePreferences.getNotificationLedPatternCustom(context)
blinkPattern = SignalStore.settings.messageLedBlinkPatternCustom
}
val (onTime: Int, offTime: Int) = blinkPattern.parseBlinkPattern()
setLights(Color.parseColor(ledColor), onTime, offTime)
@@ -36,7 +36,6 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stories.my.MyStoriesActivity
import org.thoughtcrime.securesms.util.BubbleUtil
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import org.signal.core.ui.R as CoreUiR
@@ -260,7 +259,7 @@ object NotificationFactory {
setOnlyAlertOnce(!shouldAlert)
setSilent(!shouldAlert)
addMessages(conversation)
setPriority(TextSecurePreferences.getNotificationPriority(context))
setPriority(SignalStore.settings.messageNotificationPriority)
setLights()
setAlarms(conversation.recipient)
setTicker(conversation.mostRecentNotification.getStyledPrimaryText(context, true))
@@ -304,7 +303,7 @@ object NotificationFactory {
addMessages(state)
setOnlyAlertOnce(!hasNewNotifications)
setSilent(!hasNewNotifications)
setPriority(TextSecurePreferences.getNotificationPriority(context))
setPriority(SignalStore.settings.messageNotificationPriority)
setLights()
setAlarms(state.mostRecentSender)
setTicker(state.mostRecentNotification?.getStyledPrimaryText(context, true))
@@ -304,7 +304,7 @@ public class BackupsPreferenceFragment extends Fragment {
int minute = timePickerFragment.getMinute();
SignalStore.settings().setBackupSchedule(hour, minute);
updateTimeLabel();
TextSecurePreferences.setNextBackupTime(requireContext(), 0);
SignalStore.settings().setLocalBackupNextTime(0);
LocalBackupListener.schedule(requireContext());
});
timePickerFragment.show(getChildFragmentManager(), "TIME_PICKER");
@@ -422,7 +422,7 @@ object RegistrationRepository {
Log.v(TAG, "registerAccount()")
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, registrationData.e164, SignalServiceAddress.DEFAULT_DEVICE_ID, registrationData.password).registrationApi
val universalUnidentifiedAccess: Boolean = TextSecurePreferences.isUniversalUnidentifiedAccess(context)
val universalUnidentifiedAccess: Boolean = SignalStore.settings.isUniversalUnidentifiedAccess
val unidentifiedAccessKey: ByteArray = UnidentifiedAccess.deriveAccessKeyFrom(registrationData.profileKey)
val masterKey: MasterKey?
@@ -85,7 +85,6 @@ import org.thoughtcrime.securesms.registration.ui.restore.StorageServiceRestore
import org.thoughtcrime.securesms.registration.util.RegistrationUtil
import org.thoughtcrime.securesms.registration.viewmodel.SvrAuthCredentialSet
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.dualsim.MccMncProducer
import org.whispersystems.signalservice.api.SvrNoDataException
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage
@@ -1165,7 +1164,7 @@ class RegistrationViewModel : ViewModel() {
)
if (message.readReceipts != null) {
TextSecurePreferences.setReadReceiptsEnabled(context, message.readReceipts!!)
SignalStore.settings.isReadReceiptsEnabled = message.readReceipts!!
}
RegistrationRepository.registerAccountLocally(context, data)
@@ -83,6 +83,7 @@ import org.thoughtcrime.securesms.jobs.ReclaimUsernameAndLinkJob
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob
import org.thoughtcrime.securesms.jobs.RotateCertificateJob
import org.thoughtcrime.securesms.keyvalue.Completed
import org.thoughtcrime.securesms.keyvalue.LegacySharedPrefs
import org.thoughtcrime.securesms.keyvalue.NewAccount
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
import org.thoughtcrime.securesms.keyvalue.SignalStore
@@ -161,7 +162,7 @@ class AppRegistrationStorageController(private val context: Context) : StorageCo
servicePassword = servicePassword,
aep = aep,
registrationLockEnabled = SignalStore.svr.isRegistrationLockEnabled,
unrestrictedUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context),
unrestrictedUnidentifiedAccess = SignalStore.settings.isUniversalUnidentifiedAccess,
aciIdentityKeyPair = aciIdentityKeyPair,
pniIdentityKeyPair = pniIdentityKeyPair
)
@@ -371,6 +372,8 @@ class AppRegistrationStorageController(private val context: Context) : StorageCo
// Reset it so the state we read below reflects the restored values rather than stale pre-restore ones.
SignalStore.onPostBackupRestore()
restoreLegacySettingsFromSharedPrefs()
// A post-registration restore clobbers parts of SignalStore.account with the backup's values -- V1 backups
// carry the identity keys and AEP. Re-apply the frozen account data to heal the committed registration.
val committedAccountData = inProgressData.accountData
@@ -858,7 +861,7 @@ class AppRegistrationStorageController(private val context: Context) : StorageCo
RotateSignedPreKeyListener.schedule(context)
}
accountData.linkedDeviceData?.readReceipts?.let { TextSecurePreferences.setReadReceiptsEnabled(context, it) }
accountData.linkedDeviceData?.readReceipts?.let { SignalStore.settings.isReadReceiptsEnabled = it }
}
private fun getOrCreateProfileKey(aci: ACI?): ProfileKey {
@@ -913,6 +916,27 @@ class AppRegistrationStorageController(private val context: Context) : StorageCo
}
}
/**
* Restores shared prefs from v1 backups that would otherwise get lost.
*/
private fun restoreLegacySettingsFromSharedPrefs() {
if (LegacySharedPrefs.contains(context, "pref_read_receipts")) {
SignalStore.settings.isReadReceiptsEnabled = LegacySharedPrefs.getBoolean(context, "pref_read_receipts", false)
}
if (LegacySharedPrefs.contains(context, "pref_typing_indicators")) {
SignalStore.settings.isTypingIndicatorsEnabled = LegacySharedPrefs.getBoolean(context, "pref_typing_indicators", false)
}
if (LegacySharedPrefs.contains(context, "pref_turn_only")) {
SignalStore.settings.isTurnOnly = LegacySharedPrefs.getBoolean(context, "pref_turn_only", false)
}
if (LegacySharedPrefs.contains(context, "pref_incognito_keyboard")) {
SignalStore.settings.isIncognitoKeyboardEnabled = LegacySharedPrefs.getBoolean(context, "pref_incognito_keyboard", false)
}
}
private fun readRestoredLocalBackupState(includePreRegistrationKeys: Boolean = false): LocalBackupRestoreProgress.Complete {
val restoredPin = SignalStore.svr.pin?.takeIf { it.isNotBlank() }
val restoredProfileKey = SignalStore.account.aci
@@ -67,7 +67,6 @@ import org.thoughtcrime.securesms.scribbles.stickers.FeatureSticker;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.SaveAttachmentUtil;
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
@@ -361,7 +360,7 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
TextEntryDialogFragment.Companion.show(
getChildFragmentManager(),
textElement,
TextSecurePreferences.isIncognitoKeyboardEnabled(requireContext()),
SignalStore.settings().isIncognitoKeyboardEnabled(),
selectAll,
imageEditorHud.getColorIndex()
);
@@ -8,7 +8,6 @@ import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.JavaTimeExtensionsKt;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.time.LocalDateTime;
import java.util.Random;
@@ -25,7 +24,7 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
@Override
protected long getNextScheduledExecutionTime(Context context) {
return TextSecurePreferences.getNextBackupTime(context);
return SignalStore.settings().getLocalBackupNextTime();
}
@Override
@@ -55,7 +54,7 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
long nextTime = JavaTimeExtensionsKt.toMillis(next);
TextSecurePreferences.setNextBackupTime(context, nextTime);
SignalStore.settings().setLocalBackupNextTime(nextTime);
return nextTime;
}
@@ -74,7 +74,6 @@ import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkManager;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.RecipientAccessList;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.rx.RxStore;
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
@@ -1199,7 +1198,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
process((s, p) -> {
RemotePeer activePeer = s.getCallInfoState().getActivePeer();
if (activePeer != null && activePeer.getCallId().equals(remotePeer.getCallId())) {
return p.handleTurnServerUpdate(s, servers, TextSecurePreferences.isTurnOnly(context));
return p.handleTurnServerUpdate(s, servers, SignalStore.settings().isTurnOnly());
}
Log.w(TAG, "Ignoring received turn servers for incorrect call id. requesting_call_id: " + remotePeer.getCallId() + " current_call_id: " + (activePeer != null ? activePeer.getCallId() : "null"));
@@ -34,7 +34,6 @@ import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileId
import org.thoughtcrime.securesms.payments.Entropy
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.Recipient.Companion.self
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.push.UsernameLinkComponents
import org.whispersystems.signalservice.api.storage.SignalAccountRecord
import org.whispersystems.signalservice.api.storage.SignalContactRecord
@@ -167,9 +166,9 @@ object StorageSyncHelper {
avatarUrlPath = self.profileAvatar ?: ""
noteToSelfArchived = selfRecord != null && selfRecord.syncExtras.isArchived
noteToSelfMarkedUnread = selfRecord != null && selfRecord.syncExtras.isForcedUnread
typingIndicators = TextSecurePreferences.isTypingIndicatorsEnabled(context)
readReceipts = TextSecurePreferences.isReadReceiptsEnabled(context)
sealedSenderIndicators = TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context)
typingIndicators = SignalStore.settings.isTypingIndicatorsEnabled
readReceipts = SignalStore.settings.isReadReceiptsEnabled
sealedSenderIndicators = SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled
linkPreviews = SignalStore.settings.isLinkPreviewsEnabled
unlistedPhoneNumber = SignalStore.phoneNumberPrivacy.phoneNumberDiscoverabilityMode == PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE
phoneNumberSharingMode = StorageSyncModels.localToRemotePhoneNumberSharingMode(SignalStore.phoneNumberPrivacy.phoneNumberSharingMode)
@@ -269,9 +268,9 @@ object StorageSyncHelper {
fun applyAccountStorageSyncUpdates(context: Context, self: Recipient, update: StorageRecordUpdate<SignalAccountRecord>, fetchProfile: Boolean) {
SignalDatabase.recipients.applyStorageSyncAccountUpdate(update)
TextSecurePreferences.setReadReceiptsEnabled(context, update.new.proto.readReceipts)
TextSecurePreferences.setTypingIndicatorsEnabled(context, update.new.proto.typingIndicators)
TextSecurePreferences.setShowUnidentifiedDeliveryIndicatorsEnabled(context, update.new.proto.sealedSenderIndicators)
SignalStore.settings.isReadReceiptsEnabled = update.new.proto.readReceipts
SignalStore.settings.isTypingIndicatorsEnabled = update.new.proto.typingIndicators
SignalStore.settings.isShowUnidentifiedDeliveryIndicatorsEnabled = update.new.proto.sealedSenderIndicators
SignalStore.settings.isLinkPreviewsEnabled = update.new.proto.linkPreviews
SignalStore.phoneNumberPrivacy.phoneNumberDiscoverabilityMode = if (update.new.proto.unlistedPhoneNumber) PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE else PhoneNumberDiscoverabilityMode.DISCOVERABLE
SignalStore.phoneNumberPrivacy.phoneNumberSharingMode = StorageSyncModels.remoteToLocalPhoneNumberSharingMode(update.new.proto.phoneNumberSharingMode)
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase.Companion.threads
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.jobmanager.impl.NotInCallConstraint
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob.Companion.enqueueAttachmentDelete
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream
@@ -167,9 +168,9 @@ object AttachmentUtil {
private fun getAllowedAutoDownloadTypes(context: Context): Set<String> {
return when {
NetworkUtil.isConnectedWifi(context) -> TextSecurePreferences.getWifiMediaDownloadAllowed(context)
NetworkUtil.isConnectedRoaming(context) -> TextSecurePreferences.getRoamingMediaDownloadAllowed(context)
NetworkUtil.isConnectedMobile(context) -> TextSecurePreferences.getMobileMediaDownloadAllowed(context)
NetworkUtil.isConnectedWifi(context) -> SignalStore.settings.wifiMediaDownloadAllowed
NetworkUtil.isConnectedRoaming(context) -> SignalStore.settings.roamingMediaDownloadAllowed
NetworkUtil.isConnectedMobile(context) -> SignalStore.settings.mobileMediaDownloadAllowed
else -> emptySet()
}
}
@@ -6,10 +6,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;
import androidx.annotation.ArrayRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
@@ -17,90 +14,43 @@ import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.PendingIntentFlags;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.backup.proto.SharedPreference;
import org.thoughtcrime.securesms.backup.v2.BackupRepository;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.keyvalue.SettingsValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.NotificationIds;
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.registration.ui.RegistrationActivity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TextSecurePreferences {
private static final String TAG = Log.tag(TextSecurePreferences.class);
public static final String THEME_PREF = "pref_theme";
public static final String LANGUAGE_PREF = "pref_language";
public static final String ENABLE_MANUAL_MMS_PREF = "pref_enable_manual_mms";
public static final String RINGTONE_PREF = "pref_key_ringtone";
public static final String VIBRATE_PREF = "pref_key_vibrate";
private static final String NOTIFICATION_PREF = "pref_key_enable_notifications";
public static final String LED_COLOR_PREF = "pref_led_color";
public static final String LED_BLINK_PREF = "pref_led_blink";
private static final String LED_BLINK_PREF_CUSTOM = "pref_led_blink_custom";
public static final String SCREEN_SECURITY_PREF = "pref_screen_security";
private static final String ENTER_SENDS_PREF = "pref_enter_sends";
private static final String SMS_DELIVERY_REPORT_PREF = "pref_delivery_report_sms";
private static final String PROMPTED_PUSH_REGISTRATION_PREF = "pref_prompted_push_registration";
private static final String PROMPTED_OPTIMIZE_DOZE_PREF = "pref_prompted_optimize_doze";
private static final String DIRECTORY_FRESH_TIME_PREF = "pref_directory_refresh_time";
private static final String UPDATE_APK_REFRESH_TIME_PREF = "pref_update_apk_refresh_time";
private static final String SIGNED_PREKEY_ROTATION_TIME_PREF = "pref_signed_pre_key_rotation_time";
private static final String IN_THREAD_NOTIFICATION_PREF = "pref_key_inthread_notifications";
private static final String SHOW_INVITE_REMINDER_PREF = "pref_show_invite_reminder";
public static final String MESSAGE_BODY_TEXT_SIZE_PREF = "pref_message_body_text_size";
private static final String WIFI_SMS_PREF = "pref_wifi_sms";
private static final String RATING_LATER_PREF = "pref_rating_later";
private static final String RATING_ENABLED_PREF = "pref_rating_enabled";
public static final String REPEAT_ALERTS_PREF = "pref_repeat_alerts";
public static final String NOTIFICATION_PRIVACY_PREF = "pref_notification_privacy";
public static final String NOTIFICATION_PRIORITY_PREF = "pref_notification_priority";
public static final String NEW_CONTACTS_NOTIFICATIONS = "pref_enable_new_contacts_notifications";
public static final String MEDIA_DOWNLOAD_MOBILE_PREF = "pref_media_download_mobile";
public static final String MEDIA_DOWNLOAD_WIFI_PREF = "pref_media_download_wifi";
public static final String MEDIA_DOWNLOAD_ROAMING_PREF = "pref_media_download_roaming";
public static final String SYSTEM_EMOJI_PREF = "pref_system_emoji";
private static final String MULTI_DEVICE_PROVISIONED_PREF = "pref_multi_device";
public static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
public static final String READ_RECEIPTS_PREF = "pref_read_receipts";
public static final String INCOGNITO_KEYBOARD_PREF = "pref_incognito_keyboard";
public static final String UNAUTHORIZED_RECEIVED = "pref_unauthorized_received";
private static final String SUCCESSFUL_DIRECTORY_PREF = "pref_successful_directory";
public static final String CALL_NOTIFICATIONS_PREF = "pref_call_notifications";
public static final String CALL_RINGTONE_PREF = "pref_call_ringtone";
public static final String CALL_VIBRATE_PREF = "pref_call_vibrate";
public static final String BACKUP = "pref_backup";
public static final String BACKUP_ENABLED = "pref_backup_enabled";
private static final String BACKUP_PASSPHRASE = "pref_backup_passphrase";
private static final String ENCRYPTED_BACKUP_PASSPHRASE = "pref_encrypted_backup_passphrase";
private static final String BACKUP_TIME = "pref_backup_next_time";
@Deprecated
public static final String REGISTRATION_LOCK_PREF_V1 = "pref_registration_lock";
@@ -124,17 +74,13 @@ public class TextSecurePreferences {
private static final String NEEDS_MESSAGE_PULL = "pref_needs_message_pull";
public static final String UNIVERSAL_UNIDENTIFIED_ACCESS = "pref_universal_unidentified_access";
public static final String SHOW_UNIDENTIFIED_DELIVERY_INDICATORS = "pref_show_unidentifed_delivery_indicators";
private static final String UNIDENTIFIED_ACCESS_CERTIFICATE_ROTATION_TIME_PREF = "pref_unidentified_access_certificate_rotation_time";
private static final String UNIDENTIFIED_DELIVERY_ENABLED = "pref_unidentified_delivery_enabled";
public static final String TYPING_INDICATORS = "pref_typing_indicators";
public static final String LINK_PREVIEWS = "pref_link_previews";
private static final String SEEN_STICKER_INTRO_TOOLTIP = "pref_seen_sticker_intro_tooltip";
private static final String MEDIA_KEYBOARD_MODE = "pref_media_keyboard_mode";
public static final String RECENT_STORAGE_KEY = "pref_recent_emoji2";
private static final String JOB_MANAGER_VERSION = "pref_job_manager_version";
@@ -145,101 +91,8 @@ public class TextSecurePreferences {
private static final String HAS_SEEN_VIDEO_RECORDING_TOOLTIP = "camerax.fragment.has.dismissed.video.recording.tooltip";
private static final String[] booleanPreferencesToBackup = {SCREEN_SECURITY_PREF,
INCOGNITO_KEYBOARD_PREF,
ALWAYS_RELAY_CALLS_PREF,
READ_RECEIPTS_PREF,
TYPING_INDICATORS,
SHOW_UNIDENTIFIED_DELIVERY_INDICATORS,
UNIVERSAL_UNIDENTIFIED_ACCESS,
NOTIFICATION_PREF,
VIBRATE_PREF,
IN_THREAD_NOTIFICATION_PREF,
CALL_NOTIFICATIONS_PREF,
CALL_VIBRATE_PREF,
NEW_CONTACTS_NOTIFICATIONS,
SHOW_INVITE_REMINDER_PREF,
SYSTEM_EMOJI_PREF,
ENTER_SENDS_PREF};
private static final String[] stringPreferencesToBackup = {LED_COLOR_PREF,
LED_BLINK_PREF,
REPEAT_ALERTS_PREF,
NOTIFICATION_PRIVACY_PREF,
THEME_PREF,
LANGUAGE_PREF,
MESSAGE_BODY_TEXT_SIZE_PREF};
private static final String[] stringSetPreferencesToBackup = {MEDIA_DOWNLOAD_MOBILE_PREF,
MEDIA_DOWNLOAD_WIFI_PREF,
MEDIA_DOWNLOAD_ROAMING_PREF};
private static volatile SharedPreferences preferences = null;
public static long getPreferencesToSaveToBackupCount(@NonNull Context context) {
SharedPreferences preferences = getSharedPreferences(context);
long count = 0;
for (String booleanPreference : booleanPreferencesToBackup) {
if (preferences.contains(booleanPreference)) {
count++;
}
}
for (String stringPreference : stringPreferencesToBackup) {
if (preferences.contains(stringPreference)) {
count++;
}
}
for (String stringSetPreference : stringSetPreferencesToBackup) {
if (preferences.contains(stringSetPreference)) {
count++;
}
}
return count;
}
public static List<SharedPreference> getPreferencesToSaveToBackup(@NonNull Context context) {
SharedPreferences preferences = getSharedPreferences(context);
List<SharedPreference> backupProtos = new ArrayList<>();
String defaultFile = context.getPackageName() + "_preferences";
for (String booleanPreference : booleanPreferencesToBackup) {
if (preferences.contains(booleanPreference)) {
backupProtos.add(new SharedPreference.Builder()
.file_(defaultFile)
.key(booleanPreference)
.booleanValue(preferences.getBoolean(booleanPreference, false))
.build());
}
}
for (String stringPreference : stringPreferencesToBackup) {
if (preferences.contains(stringPreference)) {
backupProtos.add(new SharedPreference.Builder()
.file_(defaultFile)
.key(stringPreference)
.value_(preferences.getString(stringPreference, null))
.build());
}
}
for (String stringSetPreference : stringSetPreferencesToBackup) {
if (preferences.contains(stringSetPreference)) {
backupProtos.add(new SharedPreference.Builder()
.file_(defaultFile)
.key(stringSetPreference)
.isStringSetValue(true)
.stringSetValue(new ArrayList<>(preferences.getStringSet(stringSetPreference, Collections.emptySet())))
.build());
}
}
return backupProtos;
}
public static void onPostBackupRestore(@NonNull Context context) {
if (NotificationChannels.supported()) {
NotificationChannels.getInstance().updateMessageVibrate(SignalStore.settings().isMessageVibrateEnabled());
@@ -313,19 +166,6 @@ public class TextSecurePreferences {
return getStringPreference(context, ENCRYPTED_BACKUP_PASSPHRASE, null);
}
@Deprecated
public static boolean isBackupEnabled(@NonNull Context context) {
return getBooleanPreference(context, BACKUP_ENABLED, false);
}
public static void setNextBackupTime(@NonNull Context context, long time) {
setLongPreference(context, BACKUP_TIME, time);
}
public static long getNextBackupTime(@NonNull Context context) {
return getLongPreference(context, BACKUP_TIME, -1);
}
public static void setHasSuccessfullyRetrievedDirectory(Context context, boolean value) {
setBooleanPreference(context, SUCCESSFUL_DIRECTORY_PREF, value);
}
@@ -353,55 +193,6 @@ public class TextSecurePreferences {
return getBooleanPreference(context, UNAUTHORIZED_RECEIVED, false);
}
public static boolean isIncognitoKeyboardEnabled(Context context) {
return getBooleanPreference(context, INCOGNITO_KEYBOARD_PREF, false);
}
public static boolean isReadReceiptsEnabled(Context context) {
return getBooleanPreference(context, READ_RECEIPTS_PREF, false);
}
public static void setReadReceiptsEnabled(Context context, boolean enabled) {
setBooleanPreference(context, READ_RECEIPTS_PREF, enabled);
}
public static boolean isTypingIndicatorsEnabled(Context context) {
return getBooleanPreference(context, TYPING_INDICATORS, false);
}
public static void setTypingIndicatorsEnabled(Context context, boolean enabled) {
setBooleanPreference(context, TYPING_INDICATORS, enabled);
}
public static int getNotificationPriority(Context context) {
try {
return Integer.parseInt(getStringPreference(context, NOTIFICATION_PRIORITY_PREF, String.valueOf(NotificationCompat.PRIORITY_HIGH)));
} catch (ClassCastException e) {
return getIntegerPreference(context, NOTIFICATION_PRIORITY_PREF, NotificationCompat.PRIORITY_HIGH);
}
}
/**
* @deprecated Use {@link SettingsValues#getMessageFontSize()} via {@link org.thoughtcrime.securesms.keyvalue.SignalStore} instead.
*/
@Deprecated
public static int getMessageBodyTextSize(Context context) {
return Integer.parseInt(getStringPreference(context, MESSAGE_BODY_TEXT_SIZE_PREF, "16"));
}
public static boolean isTurnOnly(Context context) {
return getBooleanPreference(context, ALWAYS_RELAY_CALLS_PREF, false);
}
@Deprecated
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
}
public static boolean isNewContactsNotificationEnabled(Context context) {
return getBooleanPreference(context, NEW_CONTACTS_NOTIFICATIONS, false);
}
public static long getRatingLaterTimestamp(Context context) {
return getLongPreference(context, RATING_LATER_PREF, 0);
}
@@ -418,40 +209,12 @@ public class TextSecurePreferences {
setBooleanPreference(context, RATING_ENABLED_PREF, enabled);
}
@Deprecated
public static boolean isWifiSmsEnabled(Context context) {
return getBooleanPreference(context, WIFI_SMS_PREF, false);
public static long getUnidentifiedAccessCertificateRotationTime(Context context) {
return getLongPreference(context, UNIDENTIFIED_ACCESS_CERTIFICATE_ROTATION_TIME_PREF, 0L);
}
@Deprecated
public static int getRepeatAlertsCount(Context context) {
try {
return Integer.parseInt(getStringPreference(context, REPEAT_ALERTS_PREF, "0"));
} catch (NumberFormatException e) {
Log.w(TAG, e);
return 0;
}
}
@Deprecated
public static boolean isInThreadNotifications(Context context) {
return getBooleanPreference(context, IN_THREAD_NOTIFICATION_PREF, true);
}
public static boolean isUniversalUnidentifiedAccess(Context context) {
return getBooleanPreference(context, UNIVERSAL_UNIDENTIFIED_ACCESS, false);
}
public static void setIsUniversalUnidentifiedAccess(Context context, boolean enabled) {
setBooleanPreference(context, UNIVERSAL_UNIDENTIFIED_ACCESS, enabled);
}
public static void setShowUnidentifiedDeliveryIndicatorsEnabled(Context context, boolean enabled) {
setBooleanPreference(context, SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, enabled);
}
public static boolean isShowUnidentifiedDeliveryIndicatorsEnabled(Context context) {
return getBooleanPreference(context, SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, false);
public static void setUnidentifiedAccessCertificateRotationTime(Context context, long value) {
setLongPreference(context, UNIDENTIFIED_ACCESS_CERTIFICATE_ROTATION_TIME_PREF, value);
}
public static void setIsUnidentifiedDeliveryEnabled(Context context, boolean enabled) {
@@ -482,36 +245,10 @@ public class TextSecurePreferences {
setLongPreference(context, UPDATE_APK_REFRESH_TIME_PREF, value);
}
@Deprecated
public static boolean isEnterSendsEnabled(Context context) {
return getBooleanPreference(context, ENTER_SENDS_PREF, false);
}
public static void setScreenSecurityEnabled(Context context, boolean value) {
setBooleanPreference(context, SCREEN_SECURITY_PREF, value);
}
public static boolean isScreenSecurityEnabled(Context context) {
return getBooleanPreference(context, SCREEN_SECURITY_PREF, false);
}
public static boolean isLegacyUseLocalApnsEnabled(Context context) {
return getBooleanPreference(context, ENABLE_MANUAL_MMS_PREF, false);
}
/**
* @deprecated Use {@link SettingsValues#getTheme()} via {@link org.thoughtcrime.securesms.keyvalue.SignalStore} instead.
*/
@Deprecated
public static String getTheme(Context context) {
return getStringPreference(context, THEME_PREF, DynamicTheme.systemThemeAvailable() ? "system" : "light");
}
@Deprecated
public static boolean isSmsDeliveryReportsEnabled(Context context) {
return getBooleanPreference(context, SMS_DELIVERY_REPORT_PREF, false);
}
public static boolean hasPromptedPushRegistration(Context context) {
return getBooleanPreference(context, PROMPTED_PUSH_REGISTRATION_PREF, false);
}
@@ -528,91 +265,6 @@ public class TextSecurePreferences {
return getBooleanPreference(context, PROMPTED_OPTIMIZE_DOZE_PREF, false);
}
@Deprecated
public static boolean isNotificationsEnabled(Context context) {
return getBooleanPreference(context, NOTIFICATION_PREF, true);
}
@Deprecated
public static boolean isCallNotificationsEnabled(Context context) {
return getBooleanPreference(context, CALL_NOTIFICATIONS_PREF, true);
}
@Deprecated
public static @NonNull Uri getNotificationRingtone(Context context) {
String result = getStringPreference(context, RINGTONE_PREF, Settings.System.DEFAULT_NOTIFICATION_URI.toString());
if (result != null && result.startsWith("file:")) {
result = Settings.System.DEFAULT_NOTIFICATION_URI.toString();
}
return Uri.parse(result);
}
@Deprecated
public static @NonNull Uri getCallNotificationRingtone(Context context) {
String result = getStringPreference(context, CALL_RINGTONE_PREF, Settings.System.DEFAULT_RINGTONE_URI.toString());
if (result != null && result.startsWith("file:")) {
result = Settings.System.DEFAULT_RINGTONE_URI.toString();
}
return Uri.parse(result);
}
@Deprecated
public static boolean isNotificationVibrateEnabled(Context context) {
return getBooleanPreference(context, VIBRATE_PREF, true);
}
@Deprecated
public static boolean isCallNotificationVibrateEnabled(Context context) {
boolean defaultValue = (Settings.System.getInt(context.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 1) == 1);
return getBooleanPreference(context, CALL_VIBRATE_PREF, defaultValue);
}
@Deprecated
public static String getNotificationLedColor(Context context) {
return getStringPreference(context, LED_COLOR_PREF, "blue");
}
@Deprecated
public static String getNotificationLedPattern(Context context) {
return getStringPreference(context, LED_BLINK_PREF, "500,2000");
}
public static String getNotificationLedPatternCustom(Context context) {
return getStringPreference(context, LED_BLINK_PREF_CUSTOM, "500,2000");
}
public static void setNotificationLedPatternCustom(Context context, String pattern) {
setStringPreference(context, LED_BLINK_PREF_CUSTOM, pattern);
}
@Deprecated
public static boolean isSystemEmojiPreferred(Context context) {
return getBooleanPreference(context, SYSTEM_EMOJI_PREF, false);
}
public static @NonNull Set<String> getMobileMediaDownloadAllowed(Context context) {
return getMediaDownloadAllowed(context, MEDIA_DOWNLOAD_MOBILE_PREF, R.array.pref_media_download_mobile_data_default);
}
public static @NonNull Set<String> getWifiMediaDownloadAllowed(Context context) {
return getMediaDownloadAllowed(context, MEDIA_DOWNLOAD_WIFI_PREF, R.array.pref_media_download_wifi_default);
}
public static @NonNull Set<String> getRoamingMediaDownloadAllowed(Context context) {
return getMediaDownloadAllowed(context, MEDIA_DOWNLOAD_ROAMING_PREF, R.array.pref_media_download_roaming_default);
}
private static @NonNull Set<String> getMediaDownloadAllowed(Context context, String key, @ArrayRes int defaultValuesRes) {
return getStringSetPreference(context,
key,
new HashSet<>(Arrays.asList(context.getResources().getStringArray(defaultValuesRes))));
}
public static void setLastOutageCheckTime(Context context, long timestamp) {
setLongPreference(context, LAST_OUTAGE_CHECK_TIME, timestamp);
}
@@ -693,15 +345,6 @@ public class TextSecurePreferences {
setBooleanPreference(context, SEEN_STICKER_INTRO_TOOLTIP, seenStickerTooltip);
}
public static void setMediaKeyboardMode(Context context, MediaKeyboardMode mode) {
setStringPreference(context, MEDIA_KEYBOARD_MODE, mode.name());
}
public static MediaKeyboardMode getMediaKeyboardMode(Context context) {
String name = getStringPreference(context, MEDIA_KEYBOARD_MODE, MediaKeyboardMode.EMOJI.name());
return MediaKeyboardMode.valueOf(name);
}
public static void setJobManagerVersion(Context context, int version) {
setIntegerPrefrence(context, JOB_MANAGER_VERSION, version);
}
@@ -770,15 +413,6 @@ public class TextSecurePreferences {
getSharedPreferences(context).edit().remove(key).apply();
}
private static Set<String> getStringSetPreference(Context context, String key, Set<String> defaultValues) {
final SharedPreferences prefs = getSharedPreferences(context);
if (prefs.contains(key)) {
return prefs.getStringSet(key, Collections.<String>emptySet());
} else {
return defaultValues;
}
}
private static void clearLocalCredentials(Context context) {
ProfileKey newProfileKey = ProfileKeyUtil.createNew();
Recipient self = Recipient.self();
@@ -818,7 +452,4 @@ public class TextSecurePreferences {
}
// NEVER rename these -- they're persisted by name
public enum MediaKeyboardMode {
EMOJI, STICKER, GIF
}
}
@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.notifications
import android.app.Application
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import org.junit.After
import org.junit.Assert
@@ -23,10 +22,10 @@ import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.JobManager
import org.thoughtcrime.securesms.jobmanager.JsonJobData
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.testutil.MockAppDependenciesRule
import org.thoughtcrime.securesms.util.TextSecurePreferences
import java.util.LinkedList
@RunWith(RobolectricTestRunner::class)
@@ -46,8 +45,8 @@ class MarkReadReceiverTest {
mockkObject(Recipient)
every { Recipient.self() } returns Recipient()
mockkStatic(TextSecurePreferences::class)
every { TextSecurePreferences.isReadReceiptsEnabled(any()) } returns true
mockkObject(SignalStore)
every { SignalStore.settings.isReadReceiptsEnabled } returns true
}
@After
@@ -213,7 +213,7 @@ class AppRegistrationStorageControllerTest {
assertThat(SignalStore.account.restoredAccountEntropyPool).isFalse()
assertThat(SignalStore.account.restoredAccountEntropyPoolFromPrimary).isTrue()
assertThat(SignalStore.backup.mediaRootBackupKey.value).isEqualTo(mediaRootBackupKey)
assertThat(TextSecurePreferences.isReadReceiptsEnabled(context)).isTrue()
assertThat(SignalStore.settings.isReadReceiptsEnabled).isTrue()
assertThat(SignalStore.svr.pin).isNull()
assertThat(SignalStore.svr.hasOptedOut()).isFalse()
@@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.jobmanager.impl.NotInCallConstraint
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stickers.StickerLocator
@@ -49,7 +50,7 @@ class AttachmentUtilTest {
mockkStatic(NotInCallConstraint::class)
mockkStatic(NetworkUtil::class)
mockkStatic(TextSecurePreferences::class)
mockkObject(SignalStore)
mockkObject(MultiDeviceDeleteSyncJob.Companion)
every { MultiDeviceDeleteSyncJob.enqueueAttachmentDelete(any(), any()) } just Runs
@@ -57,9 +58,9 @@ class AttachmentUtilTest {
every { NetworkUtil.isConnectedWifi(context) } returns true
every { NetworkUtil.isConnectedRoaming(context) } returns false
every { NetworkUtil.isConnectedMobile(context) } returns false
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns emptySet()
every { TextSecurePreferences.getRoamingMediaDownloadAllowed(context) } returns emptySet()
every { TextSecurePreferences.getMobileMediaDownloadAllowed(context) } returns emptySet()
every { SignalStore.settings.wifiMediaDownloadAllowed } returns emptySet()
every { SignalStore.settings.roamingMediaDownloadAllowed } returns emptySet()
every { SignalStore.settings.mobileMediaDownloadAllowed } returns emptySet()
every { messageTable.getMessageRecord(any()) } returns messageRecord
every { messageRecord.fromRecipient } returns fromRecipient
@@ -104,7 +105,7 @@ class AttachmentUtilTest {
every { toRecipient.isGroup } returns true
every { toRecipient.isProfileSharing } returns true
every { fromRecipient.isSystemContact } returns false
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment()))
}
@@ -125,7 +126,7 @@ class AttachmentUtilTest {
@Test
fun `null toRecipient falls to individual trust`() {
every { threadTable.getRecipientForThreadId(any()) } returns null
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment()))
}
@@ -134,7 +135,7 @@ class AttachmentUtilTest {
fun `profile sharing from recipient is trusted`() {
every { fromRecipient.isSystemContact } returns false
every { fromRecipient.isProfileSharing } returns true
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment()))
}
@@ -142,7 +143,7 @@ class AttachmentUtilTest {
@Test
fun `video gif blocked when in call`() {
val attachment = attachment(videoGif = true, contentType = "video/mp4")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
every { NotInCallConstraint.isNotInConnectedCall() } returns false
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
@@ -151,7 +152,7 @@ class AttachmentUtilTest {
@Test
fun `document blocked when in call`() {
val attachment = attachment(contentType = "application/pdf", fileName = "doc.pdf")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("documents")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("documents")
every { NotInCallConstraint.isNotInConnectedCall() } returns false
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@@ -163,7 +164,7 @@ class AttachmentUtilTest {
every { fromRecipient.isSystemContact } returns false
every { fromRecipient.isProfileSharing } returns false
every { messageRecord.isOutgoing } returns true
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment()))
}
@@ -172,7 +173,7 @@ class AttachmentUtilTest {
fun `outgoing message is trusted`() {
every { fromRecipient.isSystemContact } returns false
every { messageRecord.isOutgoing } returns true
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment()))
}
@@ -181,7 +182,7 @@ class AttachmentUtilTest {
fun `self recipient is trusted`() {
every { fromRecipient.isSystemContact } returns false
every { fromRecipient.isSelf } returns true
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment()))
}
@@ -190,21 +191,21 @@ class AttachmentUtilTest {
fun `release notes recipient is trusted`() {
every { fromRecipient.isSystemContact } returns false
every { fromRecipient.isReleaseNotes } returns true
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment()))
}
@Test
fun `zero size rejects`() {
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment(size = 0L, contentType = "image/jpeg")))
}
@Test
fun `ciphertext over 200MB rejects`() {
val huge = attachment(size = 250L * 1024 * 1024, contentType = "image/jpeg")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, huge))
}
@@ -232,7 +233,7 @@ class AttachmentUtilTest {
@Test
fun `large sticker requires image allowed type`() {
val attachment = attachment(size = 500L * 1024, isSticker = true, contentType = "image/webp")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@@ -240,7 +241,7 @@ class AttachmentUtilTest {
@Test
fun `large sticker blocked when in call`() {
val attachment = attachment(size = 500L * 1024, isSticker = true, contentType = "image/webp")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
every { NotInCallConstraint.isNotInConnectedCall() } returns false
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
@@ -249,7 +250,7 @@ class AttachmentUtilTest {
@Test
fun `large sticker blocked when image type not allowed`() {
val attachment = attachment(size = 500L * 1024, isSticker = true, contentType = "image/webp")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("audio")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("audio")
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@@ -263,27 +264,27 @@ class AttachmentUtilTest {
@Test
fun `unnamed audio without voice note flag uses audio setting`() {
val attachment = attachment(size = 10L * 1024, voiceNote = false, contentType = "audio/aac", fileName = null)
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("audio")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("audio")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns emptySet()
every { SignalStore.settings.wifiMediaDownloadAllowed } returns emptySet()
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@Test
fun `named audio uses audio setting`() {
val attachment = attachment(size = 10L * 1024, voiceNote = false, contentType = "audio/mpeg", fileName = "song.mp3")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("audio")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("audio")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns emptySet()
every { SignalStore.settings.wifiMediaDownloadAllowed } returns emptySet()
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@Test
fun `large voice note requires audio allowed type`() {
val attachment = attachment(size = 500L * 1024, voiceNote = true, contentType = "audio/aac", fileName = null)
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("audio")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("audio")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@@ -291,7 +292,7 @@ class AttachmentUtilTest {
@Test
fun `large voice note blocked when audio not allowed`() {
val attachment = attachment(size = 500L * 1024, voiceNote = true, contentType = "audio/aac", fileName = null)
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@@ -299,7 +300,7 @@ class AttachmentUtilTest {
@Test
fun `large voice note blocked when in call`() {
val attachment = attachment(size = 500L * 1024, voiceNote = true, contentType = "audio/aac", fileName = null)
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("audio")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("audio")
every { NotInCallConstraint.isNotInConnectedCall() } returns false
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
@@ -308,51 +309,51 @@ class AttachmentUtilTest {
@Test
fun `video gif requires image allowed type`() {
val attachment = attachment(videoGif = true, contentType = "video/mp4")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns emptySet()
every { SignalStore.settings.wifiMediaDownloadAllowed } returns emptySet()
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@Test
fun `image content type uses image setting`() {
val attachment = attachment(contentType = "image/jpeg")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns emptySet()
every { SignalStore.settings.wifiMediaDownloadAllowed } returns emptySet()
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@Test
fun `video content type uses video setting`() {
val attachment = attachment(contentType = "video/mp4")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("video")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("video")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@Test
fun `document content type uses documents setting`() {
val attachment = attachment(contentType = "application/pdf", fileName = "doc.pdf")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("documents")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("documents")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns emptySet()
every { SignalStore.settings.wifiMediaDownloadAllowed } returns emptySet()
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@Test
fun `null content type falls to documents setting`() {
val attachment = attachment(contentType = null, fileName = "file")
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("documents")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("documents")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment))
}
@Test
fun `in-call blocks non-sticker paths`() {
every { NotInCallConstraint.isNotInConnectedCall() } returns false
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image", "video", "audio", "documents")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image", "video", "audio", "documents")
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment(contentType = "image/jpeg")))
assertFalse(AttachmentUtil.isAutoDownloadPermitted(context, attachment(contentType = "application/pdf", fileName = "a.pdf")))
@@ -362,7 +363,7 @@ class AttachmentUtilTest {
fun `roaming network uses roaming allowed set`() {
every { NetworkUtil.isConnectedWifi(context) } returns false
every { NetworkUtil.isConnectedRoaming(context) } returns true
every { TextSecurePreferences.getRoamingMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.roamingMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment(contentType = "image/jpeg")))
}
@@ -372,7 +373,7 @@ class AttachmentUtilTest {
every { NetworkUtil.isConnectedWifi(context) } returns false
every { NetworkUtil.isConnectedRoaming(context) } returns false
every { NetworkUtil.isConnectedMobile(context) } returns true
every { TextSecurePreferences.getMobileMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.mobileMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isAutoDownloadPermitted(context, attachment(contentType = "image/jpeg")))
}
@@ -433,20 +434,20 @@ class AttachmentUtilTest {
@Test
fun `restore image permitted when allowed and not in call`() {
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
assertTrue(AttachmentUtil.isRestoreOnOpenPermitted(context, attachment(contentType = "image/jpeg")))
}
@Test
fun `restore image blocked when in call`() {
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns setOf("image")
every { SignalStore.settings.wifiMediaDownloadAllowed } returns setOf("image")
every { NotInCallConstraint.isNotInConnectedCall() } returns false
assertFalse(AttachmentUtil.isRestoreOnOpenPermitted(context, attachment(contentType = "image/jpeg")))
}
@Test
fun `restore image blocked when type not allowed`() {
every { TextSecurePreferences.getWifiMediaDownloadAllowed(context) } returns emptySet()
every { SignalStore.settings.wifiMediaDownloadAllowed } returns emptySet()
assertFalse(AttachmentUtil.isRestoreOnOpenPermitted(context, attachment(contentType = "image/jpeg")))
}
@@ -6,6 +6,7 @@
package org.signal.core.ui
import android.app.Application
import androidx.annotation.VisibleForTesting
object CoreUiDependencies {
@@ -21,6 +22,15 @@ object CoreUiDependencies {
_provider = provider
}
/**
* Replaces any existing provider, unlike [init]. Only for use in tests.
*/
@VisibleForTesting
fun testInject(application: Application, provider: Provider) {
_application = application
_provider = provider
}
val application: Application
get() = _application
@@ -17,7 +17,7 @@ class CoreUiDependenciesRule(
private val isIncognitoKeyboardEnabled: Boolean = false
) : ExternalResource() {
override fun before() {
CoreUiDependencies.init(application, Provider(isIncognitoKeyboardEnabled))
CoreUiDependencies.testInject(application, Provider(isIncognitoKeyboardEnabled))
}
private class Provider(