Remove TextSecurePreferences.

This commit is contained in:
Greyson Parrelli
2026-09-30 13:34:01 -03:00
committed by Alex Hart
parent e6632ff8e0
commit d57b928c6f
123 changed files with 658 additions and 1247 deletions
@@ -44,7 +44,7 @@ class InstrumentationApplicationDependencyProvider(val application: Application,
private var archiveService: ArchiveService = mockk(relaxed = true)
init {
recipientCache = LiveRecipientCache(application) { r -> r.run() }
recipientCache = LiveRecipientCache { r -> r.run() }
}
override fun provideBillingApi(): BillingApi = billingApi
@@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.JobManager
import org.thoughtcrime.securesms.jobmanager.JobMigrator
import org.thoughtcrime.securesms.jobmanager.JobTracker
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.keyvalue.SignalStore
import java.util.concurrent.CountDownLatch
import kotlin.random.Random
@@ -90,7 +90,7 @@ class JobManagerPerformanceTests {
.setConstraintFactories(JobManagerFactories.getConstraintFactories(context))
.setConstraintObservers(JobManagerFactories.getConstraintObservers(context))
.setJobStorage(FastJobStorage(getInstance(context)))
.setJobMigrator(JobMigrator(TextSecurePreferences.getJobManagerVersion(context), JobManager.CURRENT_VERSION, JobManagerFactories.getJobMigrations(context)))
.setJobMigrator(JobMigrator(SignalStore.misc.jobManagerVersion, JobManager.CURRENT_VERSION, JobManagerFactories.getJobMigrations(context)))
.build()
return JobManager(context, config)
@@ -34,7 +34,6 @@ import org.thoughtcrime.securesms.registration.data.LocalRegistrationMetadataUti
import org.thoughtcrime.securesms.registration.data.RegistrationData
import org.thoughtcrime.securesms.registration.data.RegistrationRepository
import org.thoughtcrime.securesms.registration.util.RegistrationUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import java.util.UUID
@@ -88,8 +87,8 @@ object TestUsers {
SignalStore.registration.restoreDecisionState = RestoreDecisionState.Skipped
RegistrationUtil.maybeMarkRegistrationComplete()
SignalDatabase.recipients.setProfileName(Recipient.self().id, ProfileName.fromParts("Tester", "McTesterson"))
TextSecurePreferences.setPromptedOptimizeDoze(application, true)
TextSecurePreferences.setRatingEnabled(application, false)
SignalStore.uiHints.setHasPromptedOptimizeDoze(true)
SignalStore.misc.ratingEnabled = false
PreKeyUtil.generateAndStoreSignedPreKey(AppDependencies.protocolStore.aci(), SignalStore.account.aciPreKeys)
PreKeyUtil.generateAndStoreOneTimeEcPreKeys(AppDependencies.protocolStore.aci(), SignalStore.account.aciPreKeys)
@@ -16,9 +16,9 @@ import org.thoughtcrime.securesms.keyvalue.PlainTextKeyValueStore;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.migrations.QuoteThumbnailBackfillMigrationJob;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.stickers.BlessedPacks;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.signal.core.util.Util;
/**
@@ -36,9 +36,9 @@ public final class AppInitialization {
Log.i(TAG, "onFirstEverAppLaunch()");
PlainTextKeyValueStore.setAppMigrationVersion(ApplicationMigrations.CURRENT_VERSION);
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
SignalStore.misc().setJobManagerVersion(JobManager.CURRENT_VERSION);
PlainTextKeyValueStore.setLastVersionCode(BuildConfig.VERSION_CODE);
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
SignalStore.tooltips().markStickerIntroTooltipSeen();
SignalStore.settings().setPassphraseDisabled(true);
SignalStore.settings().setReadReceiptsEnabled(true);
SignalStore.settings().setTypingIndicatorsEnabled(true);
@@ -56,7 +56,9 @@ public final class AppInitialization {
SignalStore.onboarding().clearAll();
SignalStore.settings().setPassphraseDisabled(true);
SignalStore.notificationProfile().setHasSeenTooltip(true);
TextSecurePreferences.onPostBackupRestore(context);
if (NotificationChannels.supported()) {
NotificationChannels.getInstance().updateMessageVibrate(SignalStore.settings().isMessageVibrateEnabled());
}
SignalStore.settings().setPassphraseDisabled(true);
AppDependencies.getJobManager().addAll(BlessedPacks.getFirstInstallJobs());
EmojiSearchIndexDownloadJob.scheduleImmediately();
@@ -82,9 +84,9 @@ public final class AppInitialization {
Log.w(TAG, "onRepairFirstEverAppLaunch()");
PlainTextKeyValueStore.setAppMigrationVersion(ApplicationMigrations.CURRENT_VERSION);
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
SignalStore.misc().setJobManagerVersion(JobManager.CURRENT_VERSION);
PlainTextKeyValueStore.setLastVersionCode(BuildConfig.VERSION_CODE);
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
SignalStore.tooltips().markStickerIntroTooltipSeen();
SignalStore.settings().setPassphraseDisabled(true);
AppDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onFirstEverAppLaunch();
@@ -132,7 +132,6 @@ import org.thoughtcrime.securesms.util.RemoteConfig;
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
import org.thoughtcrime.securesms.util.SignalUncaughtExceptionHandler;
import org.thoughtcrime.securesms.util.SqlCipherLogTarget;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.VersionTracker;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import org.whispersystems.signalservice.api.websocket.SignalWebSocket;
@@ -459,14 +458,14 @@ public class ApplicationContext extends Application implements AppForegroundObse
}
private void initializeFirstEverAppLaunch() {
if (TextSecurePreferences.getFirstInstallVersion(this) == -1) {
if (SignalStore.misc().getFirstInstallVersion() == -1) {
if (!SignalDatabase.databaseFileExists(this) || VersionTracker.getDaysSinceFirstInstalled(this) < 365) {
Log.i(TAG, "First ever app launch!");
AppInitialization.onFirstEverAppLaunch(this);
}
Log.i(TAG, "Setting first install version to " + BuildConfig.CANONICAL_VERSION_CODE);
TextSecurePreferences.setFirstInstallVersion(this, BuildConfig.CANONICAL_VERSION_CODE);
SignalStore.misc().setFirstInstallVersion(BuildConfig.CANONICAL_VERSION_CODE);
} else if (!SignalStore.settings().getPassphraseDisabled() && VersionTracker.getDaysSinceFirstInstalled(this) < 90) {
Log.i(TAG, "Detected a new install that doesn't have passphrases disabled -- assuming bad initialization.");
AppInitialization.onRepairFirstEverAppLaunch(this);
@@ -586,7 +585,7 @@ public class ApplicationContext extends Application implements AppForegroundObse
}
private void executePendingContactSync() {
if (TextSecurePreferences.needsFullContactSync(this)) {
if (SignalStore.misc().getNeedsFullContactSync()) {
AppDependencies.getJobManager().add(new MultiDeviceContactUpdateJob(true));
}
}
@@ -81,7 +81,6 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.search.SearchRepository;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter;
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModelList;
@@ -222,7 +221,7 @@ public final class ContactSelectionListFragment extends LoggingFragment {
public void onStart() {
super.onStart();
if (hasContactsPermissions(requireContext()) && !TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
if (hasContactsPermissions(requireContext()) && !SignalStore.misc().getHasSuccessfullyRetrievedDirectory()) {
handleContactPermissionGranted();
} else {
requireActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
@@ -441,7 +440,7 @@ public final class ContactSelectionListFragment extends LoggingFragment {
.ifNecessary()
.onAllGranted(() -> {
contactSearchView.setAlpha(0.5f);
if (!TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
if (!SignalStore.misc().getHasSuccessfullyRetrievedDirectory()) {
handleContactPermissionGranted();
} else {
contactSearchViewModel.refresh();
@@ -38,7 +38,6 @@ import org.thoughtcrime.securesms.restore.RestoreActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.AppStartup;
import org.thoughtcrime.securesms.util.Environment;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Locale;
@@ -175,7 +174,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
return STATE_PROMPT_PASSPHRASE;
} else if (ApplicationMigrations.isUpdate(this) && ApplicationMigrations.isUiBlockingMigrationRunning()) {
return STATE_UI_BLOCKING_UPGRADE;
} else if (!TextSecurePreferences.hasPromptedPushRegistration(this)) {
} else if (!SignalStore.registration().getHasPromptedPushRegistration()) {
return STATE_WELCOME_PUSH_SCREEN;
} else if (shouldResumeLinkingRegistration()) {
return STATE_RESUME_LINKING_REG;
@@ -251,7 +250,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
private Intent getUiBlockingUpgradeIntent() {
return getRoutedIntent(ApplicationMigrationActivity.class,
TextSecurePreferences.hasPromptedPushRegistration(this)
SignalStore.registration().getHasPromptedPushRegistration()
? getConversationListIntent()
: getPushRegistrationIntent());
}
@@ -12,9 +12,9 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobs.ApkUpdateJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.service.PersistentAlarmManagerListener;
import org.thoughtcrime.securesms.util.Environment;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.concurrent.TimeUnit;
@@ -26,7 +26,7 @@ public class ApkUpdateRefreshListener extends PersistentAlarmManagerListener {
@Override
protected long getNextScheduledExecutionTime(Context context) {
return TextSecurePreferences.getUpdateApkRefreshTime(context);
return SignalStore.apkUpdate().getRefreshTime();
}
@Override
@@ -39,7 +39,7 @@ public class ApkUpdateRefreshListener extends PersistentAlarmManagerListener {
}
long newTime = System.currentTimeMillis() + INTERVAL;
TextSecurePreferences.setUpdateApkRefreshTime(context, newTime);
SignalStore.apkUpdate().setRefreshTime(newTime);
return newTime;
}
@@ -72,7 +72,7 @@ public class BackupDialog {
.takePersistableUriPermission(backupDirectoryUri, takeFlags);
}
BackupPassphrase.set(context, Util.join(password, " "));
SignalStore.backup().setV1BackupPassphrase(Util.join(password, " "));
SignalStore.settings().setLocalBackupNextTime(0);
SignalStore.settings().setBackupEnabled(true);
LocalBackupListener.schedule(context);
@@ -177,7 +177,7 @@ public class BackupDialog {
positiveButton.setOnClickListener(v -> {
String passphrase = prompt.getText().toString();
if (passphrase.equals(BackupPassphrase.get(context))) {
if (passphrase.equals(SignalStore.backup().getV1BackupPassphrase())) {
Toast.makeText(context, R.string.BackupDialog_you_successfully_entered_your_backup_passphrase, Toast.LENGTH_SHORT).show();
dialog.dismiss();
} else {
@@ -1,55 +0,0 @@
package org.thoughtcrime.securesms.backup;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.core.util.crypto.KeyStoreHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
/**
* Allows the getting and setting of the backup passphrase, which is stored encrypted on API >= 23.
*/
public final class BackupPassphrase {
private BackupPassphrase() {
}
private static final String TAG = Log.tag(BackupPassphrase.class);
public static @Nullable String get(@NonNull Context context) {
String passphrase = TextSecurePreferences.getBackupPassphrase(context);
String encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context);
if (passphrase == null && encryptedPassphrase == null) {
return null;
}
if (encryptedPassphrase == null) {
Log.i(TAG, "Migrating to encrypted passphrase.");
set(context, passphrase);
encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context);
if (encryptedPassphrase == null) throw new AssertionError("Passphrase migration failed");
}
KeyStoreHelper.SealedData data = KeyStoreHelper.SealedData.fromString(encryptedPassphrase);
return stripSpaces(new String(KeyStoreHelper.unseal(data)));
}
public static void set(@NonNull Context context, @Nullable String passphrase) {
if (passphrase == null) {
TextSecurePreferences.setBackupPassphrase(context, null);
TextSecurePreferences.setEncryptedBackupPassphrase(context, null);
} else {
KeyStoreHelper.SealedData encryptedPassphrase = KeyStoreHelper.seal(passphrase.getBytes());
TextSecurePreferences.setEncryptedBackupPassphrase(context, encryptedPassphrase.serialize());
TextSecurePreferences.setBackupPassphrase(context, null);
}
}
private static String stripSpaces(@Nullable String passphrase) {
return passphrase != null ? passphrase.replace(" ", "") : null;
}
}
@@ -21,7 +21,6 @@ import org.signal.core.util.Stopwatch;
import org.signal.core.util.logging.Log;
import org.signal.core.models.database.AttachmentId;
import org.thoughtcrime.securesms.backup.proto.KeyValue;
import org.thoughtcrime.securesms.backup.proto.SharedPreference;
import org.thoughtcrime.securesms.backup.proto.SqlStatement;
import org.signal.core.util.crypto.AttachmentSecret;
import org.signal.core.util.crypto.ClassicDecryptingPartInputStream;
@@ -151,7 +151,6 @@ import org.thoughtcrime.securesms.service.BackupMediaRestoreService
import org.thoughtcrime.securesms.service.BackupProgressService
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.toMillis
import org.whispersystems.signalservice.api.link.TransferArchiveResponse
import org.whispersystems.signalservice.api.messages.AttachmentTransferProgress
@@ -485,7 +484,7 @@ object BackupRepository {
return false
}
val isRegistered = SignalStore.account.isRegistered && !TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application)
val isRegistered = SignalStore.account.isRegistered && !SignalStore.account.isUnauthorizedReceived
if (!isRegistered) {
Log.d(TAG, "[shouldDisplayCouldNotCompleteBackupSheet] Not displaying sheet for unregistered user.")
return false
@@ -60,8 +60,6 @@ object AccountDataArchiveProcessor {
private val TAG = Log.tag(AccountDataArchiveProcessor::class)
fun export(db: SignalDatabase, signalStore: SignalStore, exportState: ExportState, emitter: BackupFrameEmitter) {
val context = AppDependencies.application
val selfId = db.recipientTable.getByAci(signalStore.accountValues.aci!!).get()
val selfRecord = db.recipientTable.getRecordForSync(selfId)!!
@@ -25,12 +25,11 @@ import org.thoughtcrime.securesms.banner.ui.compose.Action
import org.thoughtcrime.securesms.banner.ui.compose.DefaultBanner
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.PowerManagerCompat
import org.thoughtcrime.securesms.util.TextSecurePreferences
class DozeBanner(private val context: Context) : Banner<Unit>() {
override val enabled: Boolean
get() = !SignalStore.account.fcmEnabled && !TextSecurePreferences.hasPromptedOptimizeDoze(context) && !ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.packageName)
get() = !SignalStore.account.fcmEnabled && !SignalStore.uiHints.hasPromptedOptimizeDoze() && !ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.packageName)
override val dataFlow: Flow<Unit>
get() = flowOf(Unit)
@@ -62,7 +61,7 @@ class DozeBanner(private val context: Context) : Banner<Unit>() {
}
private fun markAsPrompted() {
TextSecurePreferences.setPromptedOptimizeDoze(context, true)
SignalStore.uiHints.setHasPromptedOptimizeDoze(true)
enabledState.value = false
}
}
@@ -18,12 +18,12 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.banner.Banner
import org.thoughtcrime.securesms.banner.ui.compose.DefaultBanner
import org.thoughtcrime.securesms.banner.ui.compose.Importance
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.keyvalue.SignalStore
class ServiceOutageBanner(val context: Context) : Banner<Unit>() {
override val enabled: Boolean
get() = TextSecurePreferences.getServiceOutage(context)
get() = SignalStore.misc.serviceOutage
override val dataFlow: Flow<Unit> = flowOf(Unit)
@@ -27,7 +27,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.registration.ui.RegistrationActivity
import org.thoughtcrime.securesms.util.TextSecurePreferences
/**
* A banner displayed when the client is unauthorized (deregistered).
@@ -35,7 +34,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
class UnauthorizedBanner(val context: Context) : Banner<Unit>() {
override val enabled: Boolean
get() = TextSecurePreferences.isUnauthorizedReceived(context) || !SignalStore.account.isRegistered
get() = SignalStore.account.isUnauthorizedReceived || !SignalStore.account.isRegistered
override val dataFlow: Flow<Unit>
get() = flowOf(Unit)
@@ -1,260 +0,0 @@
package org.thoughtcrime.securesms.components;
import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceDialogFragmentCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.CustomPreferenceValidator;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.net.URI;
import java.net.URISyntaxException;
public class CustomDefaultPreference extends DialogPreference {
private static final String TAG = Log.tag(CustomDefaultPreference.class);
private final int inputType;
private final String customPreference;
private final String customToggle;
private CustomPreferenceValidator validator;
private String defaultValue;
public CustomDefaultPreference(Context context, AttributeSet attrs) {
super(context, attrs);
int[] attributeNames = new int[]{android.R.attr.inputType, R.attr.custom_pref_toggle};
TypedArray attributes = context.obtainStyledAttributes(attrs, attributeNames);
this.inputType = attributes.getInt(0, 0);
this.customPreference = getKey();
this.customToggle = attributes.getString(1);
this.validator = new CustomDefaultPreferenceDialogFragmentCompat.NullValidator();
attributes.recycle();
setPersistent(false);
setDialogLayoutResource(R.layout.custom_default_preference_dialog);
}
public CustomDefaultPreference setValidator(CustomPreferenceValidator validator) {
this.validator = validator;
return this;
}
public CustomDefaultPreference setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
this.setSummary(getSummary());
return this;
}
@Override
public String getSummary() {
if (isCustom()) {
return getContext().getString(R.string.CustomDefaultPreference_using_custom,
getPrettyPrintValue(getCustomValue()));
} else {
return getContext().getString(R.string.CustomDefaultPreference_using_default,
getPrettyPrintValue(getDefaultValue()));
}
}
private String getPrettyPrintValue(String value) {
if (TextUtils.isEmpty(value)) return getContext().getString(R.string.CustomDefaultPreference_none);
else return value;
}
private boolean isCustom() {
return TextSecurePreferences.getBooleanPreference(getContext(), customToggle, false);
}
private void setCustom(boolean custom) {
TextSecurePreferences.setBooleanPreference(getContext(), customToggle, custom);
}
private String getCustomValue() {
return TextSecurePreferences.getStringPreference(getContext(), customPreference, "");
}
private void setCustomValue(String value) {
TextSecurePreferences.setStringPreference(getContext(), customPreference, value);
}
private String getDefaultValue() {
return defaultValue;
}
public static class CustomDefaultPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
private static final String INPUT_TYPE = "input_type";
private Spinner spinner;
private EditText customText;
private TextView defaultLabel;
public static CustomDefaultPreferenceDialogFragmentCompat newInstance(String key) {
CustomDefaultPreferenceDialogFragmentCompat fragment = new CustomDefaultPreferenceDialogFragmentCompat();
Bundle b = new Bundle(1);
b.putString(PreferenceDialogFragmentCompat.ARG_KEY, key);
fragment.setArguments(b);
return fragment;
}
@Override
protected void onBindDialogView(@NonNull View view) {
Log.i(TAG, "onBindDialogView");
super.onBindDialogView(view);
CustomDefaultPreference preference = (CustomDefaultPreference)getPreference();
this.spinner = (Spinner) view.findViewById(R.id.default_or_custom);
this.defaultLabel = (TextView) view.findViewById(R.id.default_label);
this.customText = (EditText) view.findViewById(R.id.custom_edit);
this.customText.setInputType(preference.inputType);
this.customText.addTextChangedListener(new TextValidator());
this.customText.setText(preference.getCustomValue());
this.spinner.setOnItemSelectedListener(new SelectionLister());
this.defaultLabel.setText(preference.getPrettyPrintValue(preference.defaultValue));
}
@Override
public @NonNull Dialog onCreateDialog(Bundle instanceState) {
Dialog dialog = super.onCreateDialog(instanceState);
CustomDefaultPreference preference = (CustomDefaultPreference)getPreference();
if (preference.isCustom()) spinner.setSelection(1, true);
else spinner.setSelection(0, true);
return dialog;
}
@Override
public void onDialogClosed(boolean positiveResult) {
CustomDefaultPreference preference = (CustomDefaultPreference)getPreference();
if (positiveResult) {
if (spinner != null) preference.setCustom(spinner.getSelectedItemPosition() == 1);
if (customText != null) preference.setCustomValue(customText.getText().toString());
preference.setSummary(preference.getSummary());
}
}
interface CustomPreferenceValidator {
public boolean isValid(String value);
}
private static class NullValidator implements CustomPreferenceValidator {
@Override
public boolean isValid(String value) {
return true;
}
}
private class TextValidator implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
CustomDefaultPreference preference = (CustomDefaultPreference)getPreference();
if (spinner.getSelectedItemPosition() == 1) {
Button positiveButton = ((AlertDialog)getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
positiveButton.setEnabled(preference.validator.isValid(s.toString()));
}
}
}
public static class UriValidator implements CustomPreferenceValidator {
@Override
public boolean isValid(String value) {
if (TextUtils.isEmpty(value)) return true;
try {
new URI(value);
return true;
} catch (URISyntaxException mue) {
return false;
}
}
}
public static class HostnameValidator implements CustomPreferenceValidator {
@Override
public boolean isValid(String value) {
if (TextUtils.isEmpty(value)) return true;
try {
URI uri = new URI(null, value, null, null);
return true;
} catch (URISyntaxException mue) {
return false;
}
}
}
public static class PortValidator implements CustomPreferenceValidator {
@Override
public boolean isValid(String value) {
try {
Integer.parseInt(value);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
private class SelectionLister implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
CustomDefaultPreference preference = (CustomDefaultPreference)getPreference();
Button positiveButton = ((AlertDialog)getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
defaultLabel.setVisibility(position == 0 ? View.VISIBLE : View.GONE);
customText.setVisibility(position == 0 ? View.GONE : View.VISIBLE);
positiveButton.setEnabled(position == 0 || preference.validator.isValid(customText.getText().toString()));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
defaultLabel.setVisibility(View.VISIBLE);
customText.setVisibility(View.GONE);
}
}
}
}
@@ -8,8 +8,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.PlayStoreUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.VersionTracker;
import java.util.concurrent.TimeUnit;
@@ -22,10 +22,10 @@ public class RatingManager {
private static final String TAG = Log.tag(RatingManager.class);
public static void showRatingDialogIfNecessary(Context context) {
if (!TextSecurePreferences.isRatingEnabled(context) || BuildConfig.MANAGES_APP_UPDATES) return;
if (!SignalStore.misc().getRatingEnabled() || BuildConfig.MANAGES_APP_UPDATES) return;
long daysSinceInstall = VersionTracker.getDaysSinceFirstInstalled(context);
long laterTimestamp = TextSecurePreferences.getRatingLaterTimestamp(context);
long laterTimestamp = SignalStore.misc().getRatingLaterTimestamp();
if (daysSinceInstall >= DAYS_SINCE_INSTALL_THRESHOLD &&
System.currentTimeMillis() >= laterTimestamp)
@@ -41,21 +41,21 @@ public class RatingManager {
.setPositiveButton(R.string.RatingManager_rate_now, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
TextSecurePreferences.setRatingEnabled(context, false);
SignalStore.misc().setRatingEnabled(false);
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(context);
}
})
.setNegativeButton(R.string.RatingManager_no_thanks, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
TextSecurePreferences.setRatingEnabled(context, false);
SignalStore.misc().setRatingEnabled(false);
}
})
.setNeutralButton(R.string.RatingManager_later, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
long waitUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(DAYS_UNTIL_REPROMPT_THRESHOLD);
TextSecurePreferences.setRatingLaterTimestamp(context, waitUntil);
SignalStore.misc().setRatingLaterTimestamp(waitUntil);
}
})
.show();
@@ -32,6 +32,9 @@ public class RecentEmojiPageModel implements EmojiPageModel {
private static final int EMOJI_LRU_SIZE = 50;
public static final String KEY = "Recents";
/** The shared-prefs entry this model persists its LRU into. */
public static final String RECENT_STORAGE_KEY = "pref_recent_emoji2";
private final SharedPreferences prefs;
private final String preferenceName;
private final LinkedHashSet<String> recentlyUsed;
@@ -10,10 +10,8 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.InAppDona
import org.thoughtcrime.securesms.components.settings.app.subscription.RecurringInAppPaymentRepository
import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.livedata.Store
class AppSettingsViewModel : ViewModel() {
@@ -24,7 +22,7 @@ class AppSettingsViewModel : ViewModel() {
unreadPaymentsCount = 0,
hasExpiredGiftBadge = SignalStore.inAppPayments.getExpiredGiftBadge() != null,
allowUserToGoToDonationManagementScreen = SignalStore.inAppPayments.isLikelyASustainer() || InAppDonations.hasAtLeastOnePaymentMethodAvailable(),
userUnregistered = TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application) || !SignalStore.account.isRegistered,
userUnregistered = SignalStore.account.isUnauthorizedReceived || !SignalStore.account.isRegistered,
clientDeprecated = SignalStore.misc.isClientDeprecated
)
)
@@ -56,7 +54,7 @@ class AppSettingsViewModel : ViewModel() {
store.update {
it.copy(
clientDeprecated = SignalStore.misc.isClientDeprecated,
userUnregistered = TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application) || !SignalStore.account.isRegistered
userUnregistered = SignalStore.account.isUnauthorizedReceived || !SignalStore.account.isRegistered
)
}
}
@@ -12,11 +12,9 @@ import org.signal.core.util.concurrent.SignalDispatchers
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.components.settings.app.account.authenticator.TotpRepository
import org.thoughtcrime.securesms.components.settings.app.account.passkeys.AppPasskeysRepository
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
import org.thoughtcrime.securesms.pin.SvrRepository
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.kbs.PinHashUtil
import java.io.IOException
@@ -42,7 +40,7 @@ class AccountSettingsRepository {
fun isRegistrationLockEnabled(): Boolean = SignalStore.svr.isRegistrationLockEnabled
fun isUserUnregistered(): Boolean = TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application)
fun isUserUnregistered(): Boolean = SignalStore.account.isUnauthorizedReceived
fun isClientDeprecated(): Boolean = SignalStore.misc.isClientDeprecated
@@ -17,7 +17,6 @@ import kotlinx.coroutines.withContext
import org.signal.core.ui.util.StorageUtil
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.backup.BackupPassphrase
import org.thoughtcrime.securesms.backup.LocalExportProgress
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeyCredentialManagerHandler
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeySaveState
@@ -27,7 +26,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.keyvalue.protos.LocalBackupCreationProgress
import org.thoughtcrime.securesms.util.BackupUtil
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.formatHours
import java.time.LocalTime
import java.util.Locale
@@ -85,7 +83,7 @@ class LocalBackupsViewModel : ViewModel(), BackupKeyCredentialManagerHandler {
val context = AppDependencies.application
val backupTime = LocalTime.of(SignalStore.settings.backupHour, SignalStore.settings.backupMinute).formatHours(context)
val userUnregistered = TextSecurePreferences.isUnauthorizedReceived(context) || !SignalStore.account.isRegistered
val userUnregistered = SignalStore.account.isUnauthorizedReceived || !SignalStore.account.isRegistered
val clientDeprecated = SignalStore.misc.isClientDeprecated
val legacyLocalBackupsEnabled = SignalStore.settings.isBackupEnabled && BackupUtil.canUserAccessBackupDirectory(context)
val canTurnOn = legacyLocalBackupsEnabled || (!userUnregistered && !clientDeprecated)
@@ -143,7 +141,7 @@ class LocalBackupsViewModel : ViewModel(), BackupKeyCredentialManagerHandler {
SignalStore.backup.newLocalBackupsDirectory = SignalStore.settings.signalBackupDirectory?.toString()
BackupPassphrase.set(context, null)
SignalStore.backup.v1BackupPassphrase = null
SignalStore.settings.isBackupEnabled = false
BackupUtil.deleteAllBackups()
}
@@ -50,7 +50,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.keyvalue.protos.ArchiveUploadProgressState
import org.thoughtcrime.securesms.util.Environment
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
@@ -71,7 +70,7 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
backupState = BackupStateObserver.getNonIOBackupState(),
backupsEnabled = SignalStore.backup.areBackupsEnabled,
canBackupMessagesJobRun = BackupMessagesConstraint.isMet(AppDependencies.application),
canViewBackupKey = !TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application),
canViewBackupKey = !SignalStore.account.isUnauthorizedReceived,
lastBackupTimestamp = SignalStore.backup.lastBackupTime,
canBackUpUsingCellular = SignalStore.backup.backupWithCellular,
canRestoreUsingCellular = SignalStore.backup.restoreWithCellular,
@@ -17,7 +17,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.BackupUtil
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
class ChatsSettingsViewModel @JvmOverloads constructor(
private val repository: ChatsSettingsRepository = ChatsSettingsRepository()
@@ -34,7 +33,7 @@ class ChatsSettingsViewModel @JvmOverloads constructor(
enterKeySends = SignalStore.settings.isEnterKeySends,
localBackupsEnabled = SignalStore.settings.isBackupEnabled && BackupUtil.canUserAccessBackupDirectory(AppDependencies.application),
folderCount = 0,
userUnregistered = TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application) || !SignalStore.account.isRegistered,
userUnregistered = SignalStore.account.isUnauthorizedReceived || !SignalStore.account.isRegistered,
clientDeprecated = SignalStore.misc.isClientDeprecated,
isPlaintextExportEnabled = RemoteConfig.localPlaintextExport,
chatExportState = ChatExportState.None
@@ -57,7 +57,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.recipients.RecipientUtil
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import java.io.IOException
import kotlin.coroutines.resume
@@ -74,7 +73,7 @@ class ConversationSettingsRepository(
) {
fun isDeprecatedOrUnregistered(): Boolean {
return SignalStore.misc.isClientDeprecated || TextSecurePreferences.isUnauthorizedReceived(context)
return SignalStore.misc.isClientDeprecated || SignalStore.account.isUnauthorizedReceived
}
fun isInternalRecipientDetailsEnabled(): Boolean {
@@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.registration.util.RegistrationUtil
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.SignalE164Util
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import java.io.IOException
import java.util.Calendar
@@ -192,13 +191,13 @@ object ContactDiscovery {
)
stopwatch.split("contact-sync")
if (TextSecurePreferences.hasSuccessfullyRetrievedDirectory(context) && notifyOfNewUsers) {
if (SignalStore.misc.hasSuccessfullyRetrievedDirectory && notifyOfNewUsers) {
val systemContacts: Set<RecipientId> = SignalDatabase.recipients.getSystemContacts().toSet()
val newlyRegisteredSystemContacts: Set<RecipientId> = (result.registeredIds - preExistingRegisteredIds).intersect(systemContacts)
notifyNewUsers(context, newlyRegisteredSystemContacts)
} else {
TextSecurePreferences.setHasSuccessfullyRetrievedDirectory(context, true)
SignalStore.misc.hasSuccessfullyRetrievedDirectory = true
}
stopwatch.split("notify")
} else {
@@ -8,7 +8,6 @@ import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchRepository
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.adapter.mapping.AnyMappingModel
/**
@@ -18,7 +17,7 @@ import org.thoughtcrime.securesms.util.adapter.mapping.AnyMappingModel
*/
class InlineQueryViewModel(
private val emojiSearchRepository: EmojiSearchRepository = EmojiSearchRepository(AppDependencies.application),
private val recentEmojis: RecentEmojiPageModel = RecentEmojiPageModel(AppDependencies.application, TextSecurePreferences.RECENT_STORAGE_KEY)
private val recentEmojis: RecentEmojiPageModel = RecentEmojiPageModel(AppDependencies.application, RecentEmojiPageModel.RECENT_STORAGE_KEY)
) : ViewModel() {
private val querySubject: PublishSubject<InlineQuery> = PublishSubject.create()
@@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.conversation.v2.ConversationRecipientRepositor
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchRepository
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.adapter.mapping.AnyMappingModel
/**
@@ -24,7 +23,7 @@ class InlineQueryViewModelV2(
private val recipientRepository: ConversationRecipientRepository,
private val mentionsPickerRepository: MentionsPickerRepositoryV2 = MentionsPickerRepositoryV2(),
private val emojiSearchRepository: EmojiSearchRepository = EmojiSearchRepository(AppDependencies.application),
private val recentEmojis: RecentEmojiPageModel = RecentEmojiPageModel(AppDependencies.application, TextSecurePreferences.RECENT_STORAGE_KEY)
private val recentEmojis: RecentEmojiPageModel = RecentEmojiPageModel(AppDependencies.application, RecentEmojiPageModel.RECENT_STORAGE_KEY)
) : ViewModel() {
private val querySubject: PublishSubject<InlineQuery> = PublishSubject.create()
@@ -391,7 +391,6 @@ import org.thoughtcrime.securesms.util.PlayStoreUtil
import org.thoughtcrime.securesms.util.Projection
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.SignalLocalMetrics
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.UriUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.atMidnight
@@ -583,7 +582,7 @@ class ConversationFragment :
private val colorizer = ColorizerV2()
private val textDraftSaveDebouncer = Debouncer(500)
private val doubleTapToEditDebouncer = DoubleClickDebouncer(200)
private val recentEmojis: RecentEmojiPageModel by lazy { RecentEmojiPageModel(AppDependencies.application, TextSecurePreferences.RECENT_STORAGE_KEY) }
private val recentEmojis: RecentEmojiPageModel by lazy { RecentEmojiPageModel(AppDependencies.application, RecentEmojiPageModel.RECENT_STORAGE_KEY) }
private val nicknameEditActivityLauncher = registerForActivityResult(NicknameActivity.Contract()) {}
private val handler = Handler(Looper.getMainLooper())
@@ -1793,7 +1792,7 @@ class ConversationFragment :
}
}
if (TextSecurePreferences.getServiceOutage(context)) {
if (SignalStore.misc.serviceOutage) {
AppDependencies.jobManager.add(ServiceOutageDetectionJob())
}
@@ -2789,7 +2788,7 @@ class ConversationFragment :
}
private fun initializeMediaKeyboard() {
val stickerIntro: Boolean = !TextSecurePreferences.hasSeenStickerIntroTooltip(requireContext())
val stickerIntro: Boolean = !SignalStore.tooltips.hasSeenStickerIntroTooltip()
inputPanel.showMediaKeyboardToggle(true)
inputPanel.setMediaKeyboardToggleMode(preferredKeyboardPage())
@@ -3076,7 +3075,7 @@ class ConversationFragment :
}
private fun maybeShowSwipeToReplyTooltip() {
if (!TextSecurePreferences.hasSeenSwipeToReplyTooltip(requireContext())) {
if (!SignalStore.tooltips.hasSeenSwipeToReplyTooltip()) {
val tooltipText = if (ViewUtil.isLtr(requireContext())) {
R.string.ConversationFragment_you_can_swipe_to_the_right_reply
} else {
@@ -3085,7 +3084,7 @@ class ConversationFragment :
snackbar(tooltipText)
TextSecurePreferences.setHasSeenSwipeToReplyTooltip(requireContext(), true)
SignalStore.tooltips.markSwipeToReplyTooltipSeen()
}
}
@@ -5656,7 +5655,7 @@ class ConversationFragment :
return
}
if (!TextSecurePreferences.hasSeenStickerIntroTooltip(requireContext())) {
if (!SignalStore.tooltips.hasSeenStickerIntroTooltip()) {
return
}
@@ -8,8 +8,8 @@ import androidx.lifecycle.ViewModel
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.TooltipPopup
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.stickers.StickerPackInstallEvent
import org.thoughtcrime.securesms.util.TextSecurePreferences
/**
* Any and all tooltips that the conversation can display, and a light amount of related presentation logic.
@@ -30,7 +30,7 @@ class ConversationTooltips(fragment: Fragment) {
.setTextColor(ContextCompat.getColor(anchor.context, R.color.core_white))
.setText(R.string.ConversationActivity_new_say_it_with_stickers)
.setOnDismissListener {
TextSecurePreferences.setHasSeenStickerIntroTooltip(anchor.context, true)
SignalStore.tooltips.markStickerIntroTooltipSeen()
onDismiss()
}
.show(TooltipPopup.POSITION_ABOVE)
@@ -97,7 +97,6 @@ import org.thoughtcrime.securesms.sms.MessageSender
import org.thoughtcrime.securesms.util.BubbleUtil
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.NetworkUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.hasGiftBadge
import org.thoughtcrime.securesms.util.rx.RxStore
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
@@ -320,7 +319,7 @@ class ConversationViewModel(
messageRequestState = messageRequestRepository.getMessageRequestState(recipient, threadId),
groupRecord = groupRecord.orNull(),
isClientExpired = SignalStore.misc.isClientDeprecated,
isUnauthorized = TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application),
isUnauthorized = SignalStore.account.isUnauthorizedReceived,
threadContainsSms = !recipient.isRegistered && !recipient.isPushGroup && !recipient.isSelf && messageRequestRepository.threadContainsSms(threadId)
)
}.doOnNext {
@@ -168,7 +168,6 @@ import org.thoughtcrime.securesms.util.RemoteConfig;
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
import org.thoughtcrime.securesms.util.SignalProxyUtil;
import org.thoughtcrime.securesms.util.SnapToTopDataObserver;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.adapter.mapping.PagingMappingAdapter;
import org.thoughtcrime.securesms.verify.SelfVerificationFailureSheet;
@@ -453,7 +452,7 @@ public class ConversationListFragment extends MainFragment implements Conversati
if (SignalStore.account().isRegistered() &&
SignalStore.registration().isRegistrationComplete() &&
!TextSecurePreferences.isUnauthorizedReceived(requireContext()) &&
!SignalStore.account().isUnauthorizedReceived() &&
SignalStore.settings().getAutomaticVerificationEnabled() &&
SignalStore.misc().getHasKeyTransparencyFailure() &&
!SignalStore.misc().getHasSeenKeyTransparencyFailure()) {
@@ -16,7 +16,6 @@ import org.signal.libsignal.protocol.state.PreKeyRecord;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceAccountDataStore;
import org.whispersystems.signalservice.api.push.DistributionId;
@@ -2458,7 +2458,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
)
} ?: Recipient.live(recipientId).get()
} else {
RecipientCreator.forIndividual(context, recipientSettings)
RecipientCreator.forIndividual(recipientSettings)
}
val hasReadReceipt = SignalStore.settings.isReadReceiptsEnabled && cursor.requireBoolean(HAS_READ_RECEIPT)
@@ -120,7 +120,6 @@ import org.thoughtcrime.securesms.util.Environment;
import org.thoughtcrime.securesms.util.FrameRateTracker;
import org.thoughtcrime.securesms.util.PreKeyBatcher;
import org.thoughtcrime.securesms.util.RemoteConfig;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.video.exo.GiphyMp4Cache;
import org.thoughtcrime.securesms.video.exo.SimpleExoPlayerPool;
import org.thoughtcrime.securesms.webrtc.audio.AudioManagerCompat;
@@ -247,7 +246,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
@Override
public @NonNull LiveRecipientCache provideRecipientCache() {
return new LiveRecipientCache(context);
return new LiveRecipientCache();
}
@Override
@@ -262,7 +261,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
.setConstraintFactories(JobManagerFactories.getConstraintFactories(context))
.setConstraintObservers(JobManagerFactories.getConstraintObservers(context))
.setJobStorage(new FastJobStorage(JobDatabase.getInstance(context)))
.setJobMigrator(new JobMigrator(TextSecurePreferences.getJobManagerVersion(context), JobManager.CURRENT_VERSION, JobManagerFactories.getJobMigrations(context)))
.setJobMigrator(new JobMigrator(SignalStore.misc().getJobManagerVersion(), JobManager.CURRENT_VERSION, JobManagerFactories.getJobMigrations(context)))
.addReservedJobRunner(new FactoryJobPredicate(PushProcessMessageJob.KEY, MarkerJob.KEY))
.addReservedJobRunner(new FactoryJobPredicate(AttachmentUploadJob.KEY, AttachmentCompressionJob.KEY))
.addReservedJobRunner(new FactoryJobPredicate(
@@ -421,7 +420,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
};
SignalWebSocket.AuthenticatedWebSocket webSocket = new SignalWebSocket.AuthenticatedWebSocket(authFactory,
() -> !SignalStore.misc().isClientDeprecated() && SignalStore.account().isRegistered() && !TextSecurePreferences.isUnauthorizedReceived(context) && !DeviceTransferBlockingInterceptor.getInstance().isBlockingNetwork() && !Environment.IS_INSTRUMENTATION,
() -> !SignalStore.misc().isClientDeprecated() && SignalStore.account().isRegistered() && !SignalStore.account().isUnauthorizedReceived() && !DeviceTransferBlockingInterceptor.getInstance().isBlockingNetwork() && !Environment.IS_INSTRUMENTATION,
sleepTimer,
TimeUnit.SECONDS.toMillis(30));
if (AppForegroundObserver.isForegrounded()) {
@@ -15,7 +15,6 @@ import org.signal.devicetransfer.NewDeviceRestoreStatus;
import org.signal.devicetransfer.ServerTask;
import org.thoughtcrime.securesms.AppInitialization;
import org.thoughtcrime.securesms.backup.BackupEvent;
import org.thoughtcrime.securesms.backup.BackupPassphrase;
import org.thoughtcrime.securesms.backup.FullBackupImporter;
import org.thoughtcrime.securesms.crypto.AppAttachmentSecretStore;
import org.thoughtcrime.securesms.database.SignalDatabase;
@@ -50,7 +49,7 @@ public final class NewDeviceServerTask implements ServerTask {
String passphrase = SignalStore.account().getAccountEntropyPool().getValue();
BackupPassphrase.set(context, passphrase);
SignalStore.backup().setV1BackupPassphrase(passphrase);
FullBackupImporter.importFile(context,
AttachmentSecretProvider.getInstance(context, AppAttachmentSecretStore.INSTANCE).getOrCreateAttachmentSecret(),
database,
@@ -16,8 +16,8 @@ import org.thoughtcrime.securesms.jobmanager.impl.DefaultExecutorFactory;
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
import org.thoughtcrime.securesms.jobs.MinimalJobSpec;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.signal.core.util.Debouncer;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.signal.core.util.Util;
import org.signal.core.util.concurrent.FilteredExecutor;
@@ -87,7 +87,7 @@ public class JobManager implements ConstraintObserver.Notifier {
jobStorage.init();
int latestVersion = configuration.getJobMigrator().migrate(jobStorage);
TextSecurePreferences.setJobManagerVersion(application, latestVersion);
SignalStore.misc().setJobManagerVersion(latestVersion);
jobController.init();
@@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.SignalNetwork
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
/**
* Reserves backupIds for both text+media. The intention is that every registered user should be doing this, so it should happen post-registration
@@ -49,7 +48,7 @@ class ArchiveBackupIdReservationJob private constructor(parameters: Parameters)
return Result.success()
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account.isUnauthorizedReceived) {
Log.w(TAG, "Not authorized. Skipping.")
return Result.success()
}
@@ -56,7 +56,6 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.messages.AttachmentTransferProgress
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment
import org.whispersystems.signalservice.api.push.exceptions.ResumeLocationInvalidException
@@ -90,7 +89,7 @@ class BackupMessagesJob private constructor(
const val KEY = "BackupMessagesJob"
private fun isRegistered(): Boolean {
return SignalStore.account.isRegistered && !TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application)
return SignalStore.account.isRegistered && !SignalStore.account.isUnauthorizedReceived
}
private fun isBackupAllowed(): Boolean {
@@ -18,7 +18,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.SignalNetwork
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess
import kotlin.random.Random
import kotlin.time.Duration.Companion.days
@@ -93,7 +92,7 @@ class CheckKeyTransparencyJob private constructor(
} else if (!SignalStore.registration.isRegistrationComplete) {
Log.i(TAG, "Registration is not complete. Exiting.")
false
} else if (TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application)) {
} else if (SignalStore.account.isUnauthorizedReceived) {
Log.i(TAG, "Account is unauthorized. Exiting.")
false
} else if (!SignalStore.settings.automaticVerificationEnabled) {
@@ -190,7 +189,7 @@ class CheckKeyTransparencyJob private constructor(
* For others, it will only show once and only be cleared on the next successful verification.
*/
private fun markFailure() {
if (SignalStore.account.isRegistered && !TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application)) {
if (SignalStore.account.isRegistered && !SignalStore.account.isUnauthorizedReceived) {
SignalStore.misc.hasKeyTransparencyFailure = true
if (RemoteConfig.internalUser) {
SignalStore.misc.hasSeenKeyTransparencyFailure = false
@@ -7,7 +7,6 @@ import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
import org.whispersystems.signalservice.internal.util.StaticCredentialsProvider
import org.whispersystems.signalservice.internal.websocket.OkHttpWebSocketConnection
@@ -35,9 +34,8 @@ class CheckServiceReachabilityJob private constructor(params: Parameters) : Base
@JvmStatic
fun enqueueIfNecessary() {
val isCensored = AppDependencies.signalServiceNetworkAccess.isCensored()
val context = AppDependencies.application
val timeSinceLastCheck = System.currentTimeMillis() - SignalStore.misc.lastCensorshipServiceReachabilityCheckTime
if (SignalStore.account.isRegistered && !TextSecurePreferences.isUnauthorizedReceived(context) && isCensored && timeSinceLastCheck > TimeUnit.DAYS.toMillis(1)) {
if (SignalStore.account.isRegistered && !SignalStore.account.isUnauthorizedReceived && isCensored && timeSinceLastCheck > TimeUnit.DAYS.toMillis(1)) {
AppDependencies.jobManager.add(CheckServiceReachabilityJob())
}
}
@@ -58,7 +56,7 @@ class CheckServiceReachabilityJob private constructor(params: Parameters) : Base
return
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account.isUnauthorizedReceived) {
Log.w(TAG, "Unauthorized received, skipping.")
SignalStore.misc.lastCensorshipServiceReachabilityCheckTime = System.currentTimeMillis()
return
@@ -33,7 +33,6 @@ import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
import org.thoughtcrime.securesms.net.SignalNetwork;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.signal.core.util.PlayServicesUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.RequestResultUtil;
import org.signal.network.exceptions.NonSuccessfulResponseCodeException;
@@ -73,7 +72,7 @@ public class FcmRefreshJob extends BaseJob {
@Override
public void onRun() throws Exception {
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account().isUnauthorizedReceived()) {
Log.i(TAG, "No longer authorized. Ignoring.");
return;
}
@@ -19,7 +19,6 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.backup.BackupEvent;
import org.thoughtcrime.securesms.backup.BackupFileIOError;
import org.thoughtcrime.securesms.backup.BackupPassphrase;
import org.thoughtcrime.securesms.backup.BackupVerifier;
import org.thoughtcrime.securesms.backup.FullBackupExporter;
import org.thoughtcrime.securesms.crypto.AppAttachmentSecretStore;
@@ -27,6 +26,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.service.NotificationController;
@@ -124,7 +124,7 @@ public final class LocalBackupJob extends BaseJob {
EventBus.getDefault().register(updater);
notification.setIndeterminateProgress();
String backupPassword = BackupPassphrase.get(context);
String backupPassword = SignalStore.backup().getV1BackupPassphrase();
File backupDirectory = StorageUtil.getOrCreateBackupDirectory();
String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US).format(new Date());
String fileName = String.format("signal-%s.backup", timestamp);
@@ -20,7 +20,6 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.backup.BackupEvent;
import org.thoughtcrime.securesms.backup.BackupFileIOError;
import org.thoughtcrime.securesms.backup.BackupPassphrase;
import org.thoughtcrime.securesms.backup.BackupVerifier;
import org.thoughtcrime.securesms.backup.FullBackupExporter;
import org.thoughtcrime.securesms.crypto.AppAttachmentSecretStore;
@@ -102,7 +101,7 @@ public final class LocalBackupJobApi29 extends BaseJob {
notification.setIndeterminateProgress();
}
String backupPassword = BackupPassphrase.get(context);
String backupPassword = SignalStore.backup().getV1BackupPassphrase();
DocumentFile backupDirectory = DocumentFile.fromTreeUri(context, backupDirectoryUri);
String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US).format(new Date());
String fileName = String.format("signal-%s.backup", timestamp);
@@ -32,7 +32,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.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
@@ -196,18 +195,18 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
throws IOException, UntrustedIdentityException, NetworkException, NoSessionException
{
boolean isAppVisible = AppForegroundObserver.isForegrounded();
long timeSinceLastSync = System.currentTimeMillis() - TextSecurePreferences.getLastFullContactSyncTime(context);
long timeSinceLastSync = System.currentTimeMillis() - SignalStore.misc().getLastFullContactSyncTime();
Log.d(TAG, "Requesting a full contact sync. forced = " + forceSync + ", appVisible = " + isAppVisible + ", timeSinceLastSync = " + timeSinceLastSync + " ms");
if (!forceSync && !isAppVisible && timeSinceLastSync < FULL_SYNC_TIME) {
Log.i(TAG, "App is backgrounded and the last contact sync was too soon (" + timeSinceLastSync + " ms ago). Marking that we need a sync. Skipping multi-device contact update...");
TextSecurePreferences.setNeedsFullContactSync(context, true);
SignalStore.misc().setNeedsFullContactSync(true);
return;
}
TextSecurePreferences.setLastFullContactSyncTime(context, System.currentTimeMillis());
TextSecurePreferences.setNeedsFullContactSync(context, false);
SignalStore.misc().setLastFullContactSyncTime(System.currentTimeMillis());
SignalStore.misc().setNeedsFullContactSync(false);
WriteDetails writeDetails = createTempFile();
@@ -11,7 +11,6 @@ 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.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.signal.network.exceptions.PushNetworkException;
@@ -11,7 +11,6 @@ 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.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
@@ -11,7 +11,6 @@ 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.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.signal.network.exceptions.PushNetworkException;
@@ -20,7 +20,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.keyvalue.SvrValues;
import org.thoughtcrime.securesms.net.SignalNetwork;
import org.thoughtcrime.securesms.registration.data.RegistrationRepository;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.NetworkResultUtil;
import org.whispersystems.signalservice.api.RequestResultUtil;
import org.whispersystems.signalservice.api.account.AccountAttributes;
@@ -109,7 +108,7 @@ public class RefreshAttributesJob extends BaseJob {
return;
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account().isUnauthorizedReceived()) {
Log.i(TAG, "No longer authorized. Ignoring.");
return;
}
@@ -7,7 +7,6 @@ import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.pin.SvrRepository
import org.thoughtcrime.securesms.util.TextSecurePreferences
import java.io.IOException
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
@@ -25,7 +24,7 @@ class RefreshSvrCredentialsJob private constructor(parameters: Parameters) : Bas
@JvmStatic
fun enqueueIfNecessary() {
if (SignalStore.svr.hasPin() && SignalStore.account.isRegistered && !TextSecurePreferences.isUnauthorizedReceived(AppDependencies.application)) {
if (SignalStore.svr.hasPin() && SignalStore.account.isRegistered && !SignalStore.account.isUnauthorizedReceived) {
val lastTimestamp = SignalStore.svr.lastRefreshAuthTimestamp
if (lastTimestamp + FREQUENCY.inWholeMilliseconds < System.currentTimeMillis() || lastTimestamp > System.currentTimeMillis()) {
AppDependencies.jobManager.add(RefreshSvrCredentialsJob())
@@ -56,7 +55,7 @@ class RefreshSvrCredentialsJob private constructor(parameters: Parameters) : Bas
return
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account.isUnauthorizedReceived) {
Log.i(TAG, "No longer authorized. Ignoring.")
return
}
@@ -8,7 +8,6 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.SignalNetwork
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
import kotlin.time.Duration.Companion.days
@@ -45,7 +44,7 @@ class RemoteConfigRefreshJob private constructor(parameters: Parameters) : Job(p
return Result.success()
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account.isUnauthorizedReceived) {
Log.i(TAG, "No longer authorized. Ignoring.")
return Result.success()
}
@@ -101,7 +101,7 @@ class RetrieveProfileJob private constructor(parameters: Parameters, private val
val recipientsToFetch = SignalDatabase
.recipients
.getRecordsForProfileFetch(recipientIds, debounceThreshold)
.map { RecipientCreator.forRecord(context, it) }
.map { RecipientCreator.forRecord(it) }
stopwatch.split("resolve")
@@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.keyvalue.CertificateType;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.SignalNetwork;
import org.thoughtcrime.securesms.util.ExceptionHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.NetworkResultUtil;
import java.io.IOException;
@@ -60,7 +59,7 @@ public final class RotateCertificateJob extends BaseJob {
return;
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account().isUnauthorizedReceived()) {
Log.i(TAG, "No longer authorized. Ignoring.");
return;
}
@@ -7,8 +7,8 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -50,7 +50,7 @@ public class ServiceOutageDetectionJob extends BaseJob {
public void onRun() throws RetryLaterException {
Log.i(TAG, "onRun()");
long timeSinceLastCheck = System.currentTimeMillis() - TextSecurePreferences.getLastOutageCheckTime(context);
long timeSinceLastCheck = System.currentTimeMillis() - SignalStore.misc().getLastOutageCheckTime();
if (timeSinceLastCheck < CHECK_TIME) {
Log.w(TAG, "Skipping service outage check. Too soon.");
return;
@@ -62,16 +62,16 @@ public class ServiceOutageDetectionJob extends BaseJob {
if (IP_SUCCESS.equals(address.getHostAddress())) {
Log.i(TAG, "Service is available.");
TextSecurePreferences.setServiceOutage(context, false);
SignalStore.misc().setServiceOutage(false);
} else if (IP_FAILURE.equals(address.getHostAddress())) {
Log.w(TAG, "Service is down.");
TextSecurePreferences.setServiceOutage(context, true);
SignalStore.misc().setServiceOutage(true);
} else {
Log.w(TAG, "Service status check returned an unrecognized IP address. Could be a weird network state. Prompting retry.");
throw new RetryLaterException(new Exception("Unrecognized service outage IP address."));
}
TextSecurePreferences.setLastOutageCheckTime(context, System.currentTimeMillis());
SignalStore.misc().setLastOutageCheckTime(System.currentTimeMillis());
} catch (UnknownHostException e) {
throw new RetryLaterException(e);
}
@@ -85,8 +85,8 @@ public class ServiceOutageDetectionJob extends BaseJob {
@Override
public void onFailure() {
Log.i(TAG, "Service status check could not complete. Assuming success to avoid false positives due to bad network.");
TextSecurePreferences.setServiceOutage(context, false);
TextSecurePreferences.setLastOutageCheckTime(context, System.currentTimeMillis());
SignalStore.misc().setServiceOutage(false);
SignalStore.misc().setLastOutageCheckTime(System.currentTimeMillis());
}
public static final class Factory implements Job.Factory<ServiceOutageDetectionJob> {
@@ -112,7 +112,7 @@ class StorageAccountRestoreJob private constructor(parameters: Parameters) : Bas
Log.i(TAG, "Applying changes locally...")
SignalDatabase.writableDatabase.beginTransaction()
try {
StorageSyncHelper.applyAccountStorageSyncUpdates(context, self().fresh(), accountRecord, false)
StorageSyncHelper.applyAccountStorageSyncUpdates(self().fresh(), accountRecord, false)
SignalDatabase.writableDatabase.setTransactionSuccessful()
} finally {
SignalDatabase.writableDatabase.endTransaction()
@@ -95,7 +95,7 @@ class StorageForcePushJob private constructor(parameters: Parameters) : BaseJob(
.map { record -> StorageSyncModels.localToRemoteRecord(record, newContactStorageIds[record.id]!!.raw) }
.toMutableList()
val accountRecord = StorageSyncHelper.buildAccountRecord(context, Recipient.self().fresh())
val accountRecord = StorageSyncHelper.buildAccountRecord(Recipient.self().fresh())
val allNewStorageIds: MutableList<StorageId> = ArrayList(newContactStorageIds.values)
inserts.add(accountRecord)
@@ -39,7 +39,6 @@ import org.thoughtcrime.securesms.storage.StorageSyncValidations
import org.thoughtcrime.securesms.storage.StoryDistributionListRecordProcessor
import org.thoughtcrime.securesms.transport.RetryLaterException
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage
@@ -191,7 +190,7 @@ class StorageSyncJob private constructor(parameters: Parameters, private var loc
return
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account.isUnauthorizedReceived) {
Log.i(TAG, "No longer authorized. Ignoring.")
return
}
@@ -528,7 +527,7 @@ class StorageSyncJob private constructor(parameters: Parameters, private var loc
ContactRecordProcessor(identityConflictsPendingRepair).process(records.contacts, StorageSyncHelper.KEY_GENERATOR)
GroupV2RecordProcessor().process(records.gv2, StorageSyncHelper.KEY_GENERATOR)
NotificationProfileRecordProcessor().process(records.notificationProfileRecords, StorageSyncHelper.KEY_GENERATOR)
AccountRecordProcessor(context, freshSelf()).process(records.account, StorageSyncHelper.KEY_GENERATOR)
AccountRecordProcessor(freshSelf()).process(records.account, StorageSyncHelper.KEY_GENERATOR)
StoryDistributionListRecordProcessor().process(records.storyDistributionLists, StorageSyncHelper.KEY_GENERATOR)
CallLinkRecordProcessor().process(records.callLinkRecords, StorageSyncHelper.KEY_GENERATOR)
ChatFolderRecordProcessor().process(records.chatFolderRecords, StorageSyncHelper.KEY_GENERATOR)
@@ -575,7 +574,7 @@ class StorageSyncJob private constructor(parameters: Parameters, private var loc
if (!self.storageId.contentEquals(id.raw)) {
throw AssertionError("Local storage ID doesn't match self!")
}
records.add(StorageSyncHelper.buildAccountRecord(context, self))
records.add(StorageSyncHelper.buildAccountRecord(self))
}
ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST -> {
@@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.pin.Svr3Migration
import org.thoughtcrime.securesms.pin.SvrRepository
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.svr.SecureValueRecovery.BackupResponse
import org.whispersystems.signalservice.api.svr.SecureValueRecovery.PinChangeSession
import org.whispersystems.signalservice.api.svr.SecureValueRecoveryV2
@@ -61,7 +60,7 @@ class Svr2MirrorJob private constructor(parameters: Parameters, private var seri
return Result.success()
}
if (TextSecurePreferences.isUnauthorizedReceived(context)) {
if (SignalStore.account.isUnauthorizedReceived) {
Log.w(TAG, "Not authorized. Skipping.")
return Result.success()
}
@@ -5,14 +5,13 @@ import org.signal.core.util.concurrent.SignalExecutors
import org.signal.emoji.EmojiPageModel
import org.signal.emoji.EmojiSource.Companion.latest
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
import org.thoughtcrime.securesms.util.TextSecurePreferences
import java.util.function.Consumer
class EmojiKeyboardPageRepository(private val context: Context) {
fun getEmoji(consumer: Consumer<List<EmojiPageModel>>) {
SignalExecutors.BOUNDED.execute {
val list = mutableListOf<EmojiPageModel>()
list += RecentEmojiPageModel(context, TextSecurePreferences.RECENT_STORAGE_KEY)
list += RecentEmojiPageModel(context, RecentEmojiPageModel.RECENT_STORAGE_KEY)
list += latest.displayPages
consumer.accept(list)
}
@@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.Emoj
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.util.DefaultValueLiveData
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModelList
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
@@ -68,7 +67,7 @@ class EmojiKeyboardPageViewModel(private val repository: EmojiKeyboardPageReposi
companion object {
fun getStartingTab(): String {
return if (RecentEmojiPageModel.hasRecents(AppDependencies.application, TextSecurePreferences.RECENT_STORAGE_KEY)) {
return if (RecentEmojiPageModel.hasRecents(AppDependencies.application, RecentEmojiPageModel.RECENT_STORAGE_KEY)) {
RecentEmojiPageModel.KEY
} else {
EmojiCategory.PEOPLE.key
@@ -11,7 +11,6 @@ import org.signal.emoji.EmojiSource
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
import org.thoughtcrime.securesms.database.EmojiSearchTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.util.TextSecurePreferences
import java.util.function.Consumer
private const val MINIMUM_QUERY_THRESHOLD = 1
@@ -36,7 +35,7 @@ class EmojiSearchRepository(private val context: Context) {
fun submitQuery(query: String, includeRecents: Boolean, limit: Int = EMOJI_SEARCH_LIMIT, consumer: Consumer<EmojiPageModel>) {
if (query.length < MINIMUM_QUERY_THRESHOLD && includeRecents) {
consumer.accept(RecentEmojiPageModel(context, TextSecurePreferences.RECENT_STORAGE_KEY))
consumer.accept(RecentEmojiPageModel(context, RecentEmojiPageModel.RECENT_STORAGE_KEY))
} else {
SignalExecutors.SERIAL.execute {
val emoji: List<String> = emojiSearchTable.query(query, limit)
@@ -26,9 +26,9 @@ import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobmanager.impl.RegisteredConstraint
import org.thoughtcrime.securesms.jobs.PreKeysSyncJob
import org.thoughtcrime.securesms.notifications.UnregisteredNotifier
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.push.ServiceIds
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.push.UsernameLinkComponents
@@ -84,6 +84,7 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context)
private const val KEY_ACI = "account.aci"
private const val KEY_PNI = "account.pni"
private const val KEY_IS_REGISTERED = "account.is_registered"
private const val KEY_IS_UNAUTHORIZED_RECEIVED = "account.is_unauthorized_received"
private const val KEY_ACCOUNT_REGISTERED_AT = "account.registered_at"
private const val KEY_HAS_LINKED_DEVICES = "account.has_linked_devices"
@@ -113,6 +114,10 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context)
migrateFromSharedPrefsV3(context)
}
if (!store.containsKey(KEY_IS_UNAUTHORIZED_RECEIVED)) {
migrateFromSharedPrefsV4(context)
}
store.getString(KEY_PNI, null)?.let { pni ->
if (!pni.startsWith("PNI:")) {
store.beginWrite().putString(KEY_PNI, "PNI:$pni").commit()
@@ -516,6 +521,32 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context)
RegisteredConstraint.Observer.notifyListeners()
}
/**
* Whether the service has rejected our credentials on the authenticated websocket, i.e. we've been deregistered or unlinked remotely.
*
* This is distinct from [isRegistered], which tracks whether *we* believe this install completed registration. This flag is the service's verdict, and
* it is cleared automatically the next time we successfully authenticate. Note that setting it rotates the profile key, so it is not a free toggle.
*/
var isUnauthorizedReceived: Boolean
get() = getBoolean(KEY_IS_UNAUTHORIZED_RECEIVED, false)
set(value) {
val previous = isUnauthorizedReceived
putBoolean(KEY_IS_UNAUTHORIZED_RECEIVED, value)
if (previous != value) {
Recipient.self().live().refresh()
if (value) {
UnregisteredNotifier.notify(AppDependencies.application)
rotateProfileKey()
BackupRepository.haltBackupWritesForDeregistration()
} else {
UnregisteredNotifier.cancel(AppDependencies.application)
}
}
}
/**
* Milliseconds since epoch when account was registered or a negative value if not known.
*/
@@ -604,7 +635,14 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context)
private fun clearLocalCredentials() {
putString(KEY_SERVICE_PASSWORD, Util.getSecret(18))
rotateProfileKey()
}
/**
* Note that unlike [clearLocalCredentials] this leaves the service password alone, so we can still attempt to authenticate. Important for the
* [isUnauthorizedReceived] path, which needs to be able to recover on its own.
*/
private fun rotateProfileKey() {
val newProfileKey = ProfileKeyUtil.createNew()
val self = Recipient.self()
@@ -630,15 +668,15 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context)
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating account values from shared prefs.")
putString(KEY_ACI, TextSecurePreferences.getStringPreference(context, "pref_local_uuid", null))
putString(KEY_E164, TextSecurePreferences.getStringPreference(context, "pref_local_number", null))
putString(KEY_SERVICE_PASSWORD, TextSecurePreferences.getStringPreference(context, "pref_gcm_password", null))
putBoolean(KEY_IS_REGISTERED, TextSecurePreferences.getBooleanPreference(context, "pref_gcm_registered", false))
putInteger(KEY_REGISTRATION_ID, TextSecurePreferences.getIntegerPreference(context, "pref_local_registration_id", 0))
putBoolean(KEY_FCM_ENABLED, !TextSecurePreferences.getBooleanPreference(context, "pref_gcm_disabled", false))
putString(KEY_FCM_TOKEN, TextSecurePreferences.getStringPreference(context, "pref_gcm_registration_id", null))
putInteger(KEY_FCM_TOKEN_VERSION, TextSecurePreferences.getIntegerPreference(context, "pref_gcm_registration_id_version", 0))
putLong(KEY_FCM_TOKEN_LAST_SET_TIME, TextSecurePreferences.getLongPreference(context, "pref_gcm_registration_id_last_set_time", 0))
putString(KEY_ACI, LegacySharedPrefs.getStringOrNull(context, "pref_local_uuid"))
putString(KEY_E164, LegacySharedPrefs.getStringOrNull(context, "pref_local_number"))
putString(KEY_SERVICE_PASSWORD, LegacySharedPrefs.getStringOrNull(context, "pref_gcm_password"))
putBoolean(KEY_IS_REGISTERED, LegacySharedPrefs.getBoolean(context, "pref_gcm_registered", false))
putInteger(KEY_REGISTRATION_ID, LegacySharedPrefs.getInteger(context, "pref_local_registration_id", 0))
putBoolean(KEY_FCM_ENABLED, !LegacySharedPrefs.getBoolean(context, "pref_gcm_disabled", false))
putString(KEY_FCM_TOKEN, LegacySharedPrefs.getStringOrNull(context, "pref_gcm_registration_id"))
putInteger(KEY_FCM_TOKEN_VERSION, LegacySharedPrefs.getInteger(context, "pref_gcm_registration_id_version", 0))
putLong(KEY_FCM_TOKEN_LAST_SET_TIME, LegacySharedPrefs.getLong(context, "pref_gcm_registration_id_last_set_time", 0))
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
@@ -713,7 +751,14 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context)
private fun migrateFromSharedPrefsV3(context: Context) {
Log.i(TAG, "[V3] Migrating account values from shared prefs.")
putBoolean(KEY_HAS_LINKED_DEVICES, TextSecurePreferences.getBooleanPreference(context, "pref_multi_device", false))
putBoolean(KEY_HAS_LINKED_DEVICES, LegacySharedPrefs.getBoolean(context, "pref_multi_device", false))
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private fun migrateFromSharedPrefsV4(context: Context) {
Log.i(TAG, "[V4] Migrating account values from shared prefs.")
putBoolean(KEY_IS_UNAUTHORIZED_RECEIVED, LegacySharedPrefs.getBoolean(context, "pref_unauthorized_received", false))
}
private fun SharedPreferences.hasStringData(key: String): Boolean {
@@ -5,9 +5,10 @@
package org.thoughtcrime.securesms.keyvalue
import android.content.Context
import org.signal.core.util.logging.Log
class ApkUpdateValues(store: KeyValueStore) : SignalStoreValues(store) {
class ApkUpdateValues(store: KeyValueStore, context: Context) : SignalStoreValues(store) {
companion object {
private val TAG = Log.tag(ApkUpdateValues::class.java)
@@ -17,8 +18,25 @@ class ApkUpdateValues(store: KeyValueStore) : SignalStoreValues(store) {
private const val LAST_SUCCESSFUL_CHECK = "apk_update.last_successful_check"
private const val LAST_APK_UPLOAD_TIME = "apk_update.last_apk_upload_time"
private const val PENDING_APK_UPLOAD_TIME = "apk_update.pending_apk_upload_time"
private const val REFRESH_TIME = "apk_update.refresh_time"
}
init {
if (!store.containsKey(REFRESH_TIME)) {
migrateFromSharedPrefsV1(context)
}
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating apk update values from shared prefs.")
putLong(REFRESH_TIME, LegacySharedPrefs.getLong(context, "pref_update_apk_refresh_time", 0))
}
/** When the next APK update check is scheduled. See [lastSuccessfulCheck] for when one last succeeded. */
var refreshTime: Long by longValue(REFRESH_TIME, 0)
public override fun onFirstEverAppLaunch() = Unit
public override fun getKeysToIncludeInBackup(): List<String> = emptyList()
@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.keyvalue
import android.content.Context
import com.fasterxml.jackson.annotation.JsonProperty
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -7,6 +8,7 @@ import okio.withLock
import org.signal.core.models.backup.MediaRootBackupKey
import org.signal.core.models.backup.MessageBackupKey
import org.signal.core.util.LongSerializer
import org.signal.core.util.crypto.KeyStoreHelper
import org.signal.core.util.logging.Log
import org.signal.network.util.JsonUtil
import org.thoughtcrime.securesms.backup.DeletionState
@@ -29,7 +31,7 @@ import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.milliseconds
class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
class BackupValues(store: KeyValueStore, context: Context) : SignalStoreValues(store) {
companion object {
val TAG = Log.tag(BackupValues::class.java)
private const val KEY_MESSAGE_CREDENTIALS = "backup.messageCredentials"
@@ -68,6 +70,8 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
private const val KEY_MESSAGE_BACKUP_INITIALIZED = "backup.messageBackupInitialized"
private const val KEY_MEDIA_BACKUP_INITIALIZED = "backup.mediaBackupInitialized"
private const val KEY_IMPORTED_EMPTY_ANDROID_SETTINGS = "backup.importedEmptyAndroidSettings"
private const val KEY_V1_BACKUP_PASSPHRASE = "backup.v1BackupPassphrase"
private const val KEY_V1_BACKUP_PASSPHRASE_MIGRATED = "backup.v1BackupPassphraseMigrated"
const val KEY_ARCHIVE_UPLOAD_STATE = "backup.archiveUploadState"
@@ -124,11 +128,56 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
if (!store.containsKey(KEY_MESSAGE_BACKUP_INITIALIZED)) {
migrateSplitBackupsInitialized()
}
if (!store.getBoolean(KEY_V1_BACKUP_PASSPHRASE_MIGRATED, false)) {
migrateV1BackupPassphrase(context)
}
}
public override fun onFirstEverAppLaunch() = Unit
public override fun getKeysToIncludeInBackup(): List<String> = emptyList()
/**
* The passphrase for legacy (v1) local backups. This store is already encrypted, so unlike the shared-prefs home it used to
* have, there's no need to seal it with the keystore by hand.
*/
var v1BackupPassphrase: String?
get() = getString(KEY_V1_BACKUP_PASSPHRASE, null)?.stripSpaces()
set(value) {
putString(KEY_V1_BACKUP_PASSPHRASE, value)
}
/**
* Pulls the v1 backup passphrase out of shared prefs, where it lived as a hand-sealed blob because it predates this store.
*
* Do not alter. If you need to migrate more stuff, create a new method.
*/
private fun migrateV1BackupPassphrase(context: Context) {
Log.i(TAG, "[V1Passphrase] Migrating the legacy backup passphrase out of shared prefs.")
val sealed = LegacySharedPrefs.getStringOrNull(context, "pref_encrypted_backup_passphrase")
val passphrase = if (sealed != null) {
try {
String(KeyStoreHelper.unseal(KeyStoreHelper.SealedData.fromString(sealed)))
} catch (e: Exception) {
// Nothing we can do to recover it -- better to lose the passphrase than to fail to construct the store at all.
Log.w(TAG, "[V1Passphrase] Failed to unseal the legacy passphrase! The user will have to re-enter it.", e)
null
}
} else {
LegacySharedPrefs.getStringOrNull(context, "pref_backup_passphrase")
}
store
.beginWrite()
.putString(KEY_V1_BACKUP_PASSPHRASE, passphrase?.stripSpaces())
.putBoolean(KEY_V1_BACKUP_PASSPHRASE_MIGRATED, true)
.commit()
}
private fun String.stripSpaces(): String = this.replace(" ", "")
var cachedMediaCdnPath: String? by stringValue(KEY_CDN_MEDIA_PATH, null)
var lastBackupProtoSize: Long by longValue(KEY_BACKUP_LAST_PROTO_SIZE, 0L)
@@ -1,12 +1,10 @@
package org.thoughtcrime.securesms.keyvalue;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.preference.PreferenceManager;
import org.signal.core.util.logging.Log;
@@ -81,14 +79,9 @@ public final class CertificateValues extends SignalStoreValues {
private void migrateFromSharedPrefsV1(@NonNull Context context) {
Log.i(TAG, "[V1] Migrating certificate values from shared prefs.");
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
long legacyNextRotationTime = sharedPrefs.getLong("pref_unidentified_access_certificate_rotation_time", 0);
long legacyNextRotationTime = LegacySharedPrefs.INSTANCE.getLong(context, "pref_unidentified_access_certificate_rotation_time", 0);
putLong(LAST_ROTATION_TIME, legacyNextRotationTime > 0 ? legacyNextRotationTime - LEGACY_ROTATION_INTERVAL : NEVER_ROTATED);
sharedPrefs.edit()
.remove("pref_unidentified_access_certificate_rotation_time")
.apply();
}
}
@@ -34,6 +34,10 @@ object LegacySharedPrefs {
return prefs(context).getString(key, defaultValue) ?: defaultValue
}
fun getStringOrNull(context: Context, key: String): String? {
return prefs(context).getString(key, null)
}
/** Some values were stored as strings, but some installs ended up with ints. */
fun getIntegerFromString(context: Context, key: String, defaultValue: Int): Int {
return try {
@@ -1,5 +1,7 @@
package org.thoughtcrime.securesms.keyvalue
import android.content.Context
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.UsernameQrCodeColorScheme
import org.thoughtcrime.securesms.database.model.databaseprotos.PendingChangeNumberMetadata
import org.thoughtcrime.securesms.jobmanager.impl.ChangeNumberConstraintObserver
@@ -7,8 +9,10 @@ import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint
import org.thoughtcrime.securesms.jobs.DeprecatedNotificationJob
import org.thoughtcrime.securesms.keyvalue.protos.LeastActiveLinkedDevice
class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) {
class MiscellaneousValues internal constructor(store: KeyValueStore, context: Context) : SignalStoreValues(store) {
companion object {
private val TAG = Log.tag(MiscellaneousValues::class)
private const val LAST_PREKEY_REFRESH_TIME = "last_prekey_refresh_time"
private const val MESSAGE_REQUEST_ENABLE_TIME = "message_request_enable_time"
private const val LAST_PROFILE_REFRESH_TIME = "misc.last_profile_refresh_time"
@@ -58,8 +62,82 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
private const val LAST_APPLIED_PNI_CHANGE_SERVER_TIMESTAMP = "misc.last_applied_pni_change_server_timestamp"
private const val LAST_MISSING_PLAY_SERVICES_FCM_VERIFICATION_TIME = "misc.last_missing_play_services_fcm_verification_time"
private const val LAST_PROCESSED_SHARE_DATA_TIMESTAMP = "misc.last_processed_share_data_timestamp"
private const val DIRECTORY_REFRESH_TIME = "misc.directory_refresh_time"
private const val HAS_SUCCESSFULLY_RETRIEVED_DIRECTORY = "misc.has_successfully_retrieved_directory"
private const val LAST_FULL_CONTACT_SYNC_TIME = "misc.last_full_contact_sync_time"
private const val NEEDS_FULL_CONTACT_SYNC = "misc.needs_full_contact_sync"
private const val SERVICE_OUTAGE = "misc.service_outage"
private const val LAST_OUTAGE_CHECK_TIME = "misc.last_outage_check_time"
private const val SIGNED_PREKEY_ROTATION_TIME = "misc.signed_prekey_rotation_time"
private const val JOB_MANAGER_VERSION = "misc.job_manager_version"
private const val FIRST_INSTALL_VERSION = "misc.first_install_version"
private const val NOTIFICATION_CHANNEL_VERSION = "misc.notification_channel_version"
private const val NOTIFICATION_MESSAGES_CHANNEL_VERSION = "misc.notification_messages_channel_version"
private const val RATING_ENABLED = "misc.rating_enabled"
private const val RATING_LATER_TIMESTAMP = "misc.rating_later_timestamp"
}
init {
if (!store.containsKey(FIRST_INSTALL_VERSION)) {
migrateFromSharedPrefsV1(context)
}
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating misc values from shared prefs.")
store.beginWrite()
.putLong(DIRECTORY_REFRESH_TIME, LegacySharedPrefs.getLong(context, "pref_directory_refresh_time", 0))
.putBoolean(HAS_SUCCESSFULLY_RETRIEVED_DIRECTORY, LegacySharedPrefs.getBoolean(context, "pref_successful_directory", false))
.putLong(LAST_FULL_CONTACT_SYNC_TIME, LegacySharedPrefs.getLong(context, "pref_last_full_contact_sync_time", 0))
.putBoolean(NEEDS_FULL_CONTACT_SYNC, LegacySharedPrefs.getBoolean(context, "pref_needs_full_contact_sync", false))
.putBoolean(SERVICE_OUTAGE, LegacySharedPrefs.getBoolean(context, "pref_service_outage", false))
.putLong(LAST_OUTAGE_CHECK_TIME, LegacySharedPrefs.getLong(context, "pref_last_outage_check_time", 0))
.putLong(SIGNED_PREKEY_ROTATION_TIME, LegacySharedPrefs.getLong(context, "pref_signed_pre_key_rotation_time", 0))
.putInteger(JOB_MANAGER_VERSION, LegacySharedPrefs.getInteger(context, "pref_job_manager_version", 1))
.putInteger(NOTIFICATION_CHANNEL_VERSION, LegacySharedPrefs.getInteger(context, "pref_notification_channel_version", 1))
.putInteger(NOTIFICATION_MESSAGES_CHANNEL_VERSION, LegacySharedPrefs.getInteger(context, "pref_notification_messages_channel_version", 1))
.putBoolean(RATING_ENABLED, LegacySharedPrefs.getBoolean(context, "pref_rating_enabled", true))
.putLong(RATING_LATER_TIMESTAMP, LegacySharedPrefs.getLong(context, "pref_rating_later", -1))
// Written last so that it acts as the marker for this migration having run.
.putInteger(FIRST_INSTALL_VERSION, LegacySharedPrefs.getInteger(context, "pref_first_install_version", -1))
.commit()
}
/** When the next contact directory refresh is scheduled. */
var directoryRefreshTime: Long by longValue(DIRECTORY_REFRESH_TIME, 0)
/** Whether we've ever managed to pull down the contact directory. */
var hasSuccessfullyRetrievedDirectory: Boolean by booleanValue(HAS_SUCCESSFULLY_RETRIEVED_DIRECTORY, false)
var lastFullContactSyncTime: Long by longValue(LAST_FULL_CONTACT_SYNC_TIME, 0)
var needsFullContactSync: Boolean by booleanValue(NEEDS_FULL_CONTACT_SYNC, false)
/** Whether the service is currently reporting an outage. */
var serviceOutage: Boolean by booleanValue(SERVICE_OUTAGE, false)
var lastOutageCheckTime: Long by longValue(LAST_OUTAGE_CHECK_TIME, 0)
var signedPreKeyRotationTime: Long by longValue(SIGNED_PREKEY_ROTATION_TIME, 0)
/** The [org.thoughtcrime.securesms.jobmanager.JobManager] version the job database was last migrated to. */
var jobManagerVersion: Int by integerValue(JOB_MANAGER_VERSION, 1)
/** The canonical version code the app was first installed at, or -1 if we don't know. */
var firstInstallVersion: Int by integerValue(FIRST_INSTALL_VERSION, -1)
var notificationChannelVersion: Int by integerValue(NOTIFICATION_CHANNEL_VERSION, 1)
var notificationMessagesChannelVersion: Int by integerValue(NOTIFICATION_MESSAGES_CHANNEL_VERSION, 1)
/** Whether we're still allowed to ask the user to rate the app. */
var ratingEnabled: Boolean by booleanValue(RATING_ENABLED, true)
/** The earliest time we're allowed to ask the user to rate the app again. */
var ratingLaterTimestamp: Long by longValue(RATING_LATER_TIMESTAMP, -1)
public override fun onFirstEverAppLaunch() {
putLong(MESSAGE_REQUEST_ENABLE_TIME, 0)
putBoolean(NEEDS_USERNAME_RESTORE, true)
@@ -1,12 +1,13 @@
package org.thoughtcrime.securesms.keyvalue;
import android.content.Context;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
import org.thoughtcrime.securesms.lock.SignalPinReminders;
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Arrays;
import java.util.List;
@@ -22,10 +23,44 @@ public final class PinValues extends SignalStoreValues {
private static final String LAST_REMINDER_TIME = "pin.last_reminder_time";
private static final String NEXT_INTERVAL = "pin.interval_index";
private static final String KEYBOARD_TYPE = "kbs.keyboard_type";
private static final String MIGRATION_VERSION = "pin.migration_version";
public static final String PIN_REMINDERS_ENABLED = "pin.pin_reminders_enabled";
PinValues(KeyValueStore store) {
private static final int CURRENT_MIGRATION_VERSION = 1;
PinValues(KeyValueStore store, @NonNull Context context) {
super(store);
if (getLong(MIGRATION_VERSION, 0) < CURRENT_MIGRATION_VERSION) {
migrateFromSharedPrefsV1(context);
}
}
/**
* Unlike the other stores, we can't use one of the migrated keys as the "has this run?" marker: both {@link #NEXT_INTERVAL} and
* {@link #LAST_SUCCESSFUL_ENTRY} are keys released versions already write, so their presence says nothing about whether this
* migration ran. Hence the explicit {@link #MIGRATION_VERSION}.
*
* These values used to be read straight out of shared prefs as the *default* for the keys above, so only migrate the ones this
* store doesn't already have a value for.
*
* Do not alter. If you need to migrate more stuff, bump {@link #CURRENT_MIGRATION_VERSION} and add a new method.
*/
private void migrateFromSharedPrefsV1(@NonNull Context context) {
Log.i(TAG, "[V1] Migrating pin values from shared prefs.");
KeyValueStore.Writer writer = getStore().beginWrite();
if (!getStore().containsKey(LAST_SUCCESSFUL_ENTRY)) {
writer.putLong(LAST_SUCCESSFUL_ENTRY, LegacySharedPrefs.INSTANCE.getLong(context, "pref_registration_lock_last_reminder_time_post_kbs", 0));
}
if (!getStore().containsKey(NEXT_INTERVAL)) {
writer.putLong(NEXT_INTERVAL, LegacySharedPrefs.INSTANCE.getLong(context, "pref_registration_lock_next_reminder_interval", RegistrationLockReminders.INITIAL_INTERVAL));
}
writer.putLong(MIGRATION_VERSION, CURRENT_MIGRATION_VERSION)
.commit();
}
@Override
@@ -38,7 +73,7 @@ public final class PinValues extends SignalStoreValues {
}
public void onEntrySuccess(@NonNull String pin) {
long nextInterval = SignalPinReminders.getNextInterval(getCurrentInterval());
long nextInterval = SignalPinReminders.getNextInterval(getNextReminderInterval());
Log.i(TAG, "onEntrySuccess() nextInterval: " + nextInterval);
long now = System.currentTimeMillis();
@@ -53,7 +88,7 @@ public final class PinValues extends SignalStoreValues {
}
public void onEntrySuccessWithWrongGuess(@NonNull String pin) {
long nextInterval = SignalPinReminders.getPreviousInterval(getCurrentInterval());
long nextInterval = SignalPinReminders.getPreviousInterval(getNextReminderInterval());
Log.i(TAG, "onEntrySuccessWithWrongGuess() nextInterval: " + nextInterval);
long now = System.currentTimeMillis();
@@ -75,9 +110,9 @@ public final class PinValues extends SignalStoreValues {
long nextInterval;
if (includedFailure) {
nextInterval = SignalPinReminders.getPreviousInterval(getCurrentInterval());
nextInterval = SignalPinReminders.getPreviousInterval(getNextReminderInterval());
} else {
nextInterval = getCurrentInterval();
nextInterval = getNextReminderInterval();
}
Log.i(TAG, "onEntrySkip(includedFailure: " + includedFailure +") nextInterval: " + nextInterval);
@@ -101,12 +136,20 @@ public final class PinValues extends SignalStoreValues {
.apply();
}
public long getCurrentInterval() {
return getLong(NEXT_INTERVAL, TextSecurePreferences.getRegistrationLockNextReminderInterval(AppDependencies.getApplication()));
public long getNextReminderInterval() {
return getLong(NEXT_INTERVAL, RegistrationLockReminders.INITIAL_INTERVAL);
}
public void setNextReminderInterval(long interval) {
putLong(NEXT_INTERVAL, interval);
}
public long getLastSuccessfulEntryTime() {
return getLong(LAST_SUCCESSFUL_ENTRY, TextSecurePreferences.getRegistrationLockLastReminderTime(AppDependencies.getApplication()));
return getLong(LAST_SUCCESSFUL_ENTRY, 0);
}
public void setLastSuccessfulEntryTime(long time) {
putLong(LAST_SUCCESSFUL_ENTRY, time);
}
public long getLastReminderTime() {
@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.keyvalue
import android.content.Context
import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
import org.signal.core.util.logging.Log
@@ -7,7 +8,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.LocalRegistratio
import org.thoughtcrime.securesms.database.model.databaseprotos.RestoreDecisionState
import org.thoughtcrime.securesms.dependencies.AppDependencies
class RegistrationValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) {
class RegistrationValues internal constructor(store: KeyValueStore, context: Context) : SignalStoreValues(store) {
companion object {
private val TAG = Log.tag(RegistrationValues::class)
@@ -25,10 +26,28 @@ class RegistrationValues internal constructor(store: KeyValueStore) : SignalStor
private const val RESTORING_ON_NEW_DEVICE = "registration.restoring_on_new_device"
private const val IN_PROGRESS_DATA_BLOB_URI = "registration.in_progress_data_blob_uri"
private const val HAS_PROMPTED_PUSH_REGISTRATION = "registration.has_prompted_push_registration"
@VisibleForTesting
const val RESTORE_DECISION_STATE = "registration.restore_decision_state.2"
}
init {
if (!store.containsKey(HAS_PROMPTED_PUSH_REGISTRATION)) {
migrateFromSharedPrefsV1(context)
}
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating registration values from shared prefs.")
putBoolean(HAS_PROMPTED_PUSH_REGISTRATION, LegacySharedPrefs.getBoolean(context, "pref_prompted_push_registration", false))
}
/** Whether we've already walked the user through push registration. */
var hasPromptedPushRegistration: Boolean by booleanValue(HAS_PROMPTED_PUSH_REGISTRATION, false)
@Synchronized
public override fun onFirstEverAppLaunch() {
store
@@ -499,6 +499,39 @@ class SettingsValues internal constructor(store: KeyValueStore, private val cont
}
}
/**
* V1 backups made before these settings moved into this store carry them as shared prefs rather than key-values. The shared-prefs
* migration has already run by the time a restore happens, so the restored prefs need to be re-read afterwards or the user silently
* loses their privacy and security choices.
*/
fun restoreLegacySharedPrefsAfterBackupRestore() {
Log.i(TAG, "Restoring legacy privacy settings from shared prefs.")
val writer = store.beginWrite()
val booleanKeys = mapOf(
"pref_screen_security" to SCREEN_SECURITY_ENABLED,
"pref_incognito_keyboard" to INCOGNITO_KEYBOARD_ENABLED,
"pref_read_receipts" to READ_RECEIPTS_ENABLED,
"pref_typing_indicators" to TYPING_INDICATORS_ENABLED,
"pref_show_unidentifed_delivery_indicators" to SHOW_UNIDENTIFIED_DELIVERY_INDICATORS,
"pref_universal_unidentified_access" to UNIVERSAL_UNIDENTIFIED_ACCESS,
"pref_turn_only" to ALWAYS_RELAY_CALLS
)
for ((legacyKey, key) in booleanKeys) {
if (LegacySharedPrefs.contains(context, legacyKey)) {
writer.putBoolean(key, LegacySharedPrefs.getBoolean(context, legacyKey, false))
}
}
if (LegacySharedPrefs.contains(context, "pref_notification_privacy")) {
writer.putString(MESSAGE_NOTIFICATION_PRIVACY, LegacySharedPrefs.getString(context, "pref_notification_privacy", "all"))
}
writer.commit()
}
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating screen lock values from shared prefs.")
@@ -12,13 +12,13 @@ class SignalStore(context: Application, private val store: KeyValueStore) {
val accountValues = AccountValues(store, context)
val svrValues = SvrValues(store)
val registrationValues = RegistrationValues(store)
val pinValues = PinValues(store)
val registrationValues = RegistrationValues(store, context)
val pinValues = PinValues(store, context)
val remoteConfigValues = RemoteConfigValues(store)
val storageServiceValues = StorageServiceValues(store)
val uiHintValues = UiHintValues(store)
val tooltipValues = TooltipValues(store)
val miscValues = MiscellaneousValues(store)
val uiHintValues = UiHintValues(store, context)
val tooltipValues = TooltipValues(store, context)
val miscValues = MiscellaneousValues(store, context)
val internalValues = InternalValues(store)
val emojiValues = EmojiValues(store)
val settingsValues = SettingsValues(store, context)
@@ -35,8 +35,8 @@ class SignalStore(context: Application, private val store: KeyValueStore) {
val notificationProfileValues = NotificationProfileValues(store)
val releaseChannelValues = ReleaseChannelValues(store)
val storyValues = StoryValues(store)
val apkUpdateValues = ApkUpdateValues(store)
val backupValues = BackupValues(store)
val apkUpdateValues = ApkUpdateValues(store, context)
val backupValues = BackupValues(store, context)
val callQualityValues = CallQualityValues(store)
val labsValues = LabsValues(store)
@@ -145,6 +145,7 @@ class SignalStore(context: Application, private val store: KeyValueStore) {
@JvmStatic
fun onPostBackupRestore() {
instance!!.store.resetCache()
instance!!.settingsValues.restoreLegacySharedPrefsAfterBackupRestore()
}
@JvmStatic
@@ -270,6 +271,8 @@ class SignalStore(context: Application, private val store: KeyValueStore) {
val story: StoryValues
get() = instance!!.storyValues
@JvmStatic
@get:JvmName("apkUpdate")
val apkUpdate: ApkUpdateValues
get() = instance!!.apkUpdateValues
@@ -1,12 +1,18 @@
package org.thoughtcrime.securesms.keyvalue;
import android.content.Context;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import java.util.Collections;
import java.util.List;
public class TooltipValues extends SignalStoreValues {
private static final String TAG = Log.tag(TooltipValues.class);
private static final int GROUP_CALLING_MAX_TOOLTIP_DISPLAY_COUNT = 3;
private static final String BLUR_HUD_ICON = "tooltip.blur_hud_icon";
@@ -16,9 +22,41 @@ public class TooltipValues extends SignalStoreValues {
private static final String BUBBLE_OPT_OUT = "tooltip.bubble.opt.out";
private static final String PROFILE_SETTINGS_QR_CODE = "tooltip.profile_settings_qr_code";
private static final String CALLING_SWITCH_CAMERA = "tooltip.calling.switch_camera";
private static final String STICKER_INTRO = "tooltip.sticker_intro";
private static final String SWIPE_TO_REPLY = "tooltip.swipe_to_reply";
TooltipValues(@NonNull KeyValueStore store) {
TooltipValues(@NonNull KeyValueStore store, @NonNull Context context) {
super(store);
if (!store.containsKey(STICKER_INTRO)) {
migrateFromSharedPrefsV1(context);
}
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private void migrateFromSharedPrefsV1(@NonNull Context context) {
Log.i(TAG, "[V1] Migrating tooltip values from shared prefs.");
getStore().beginWrite()
.putBoolean(SWIPE_TO_REPLY, LegacySharedPrefs.INSTANCE.getBoolean(context, "pref_has_seen_swipe_to_reply", false))
.putBoolean(STICKER_INTRO, LegacySharedPrefs.INSTANCE.getBoolean(context, "pref_seen_sticker_intro_tooltip", false))
.commit();
}
public boolean hasSeenStickerIntroTooltip() {
return getBoolean(STICKER_INTRO, false);
}
public void markStickerIntroTooltipSeen() {
putBoolean(STICKER_INTRO, true);
}
public boolean hasSeenSwipeToReplyTooltip() {
return getBoolean(SWIPE_TO_REPLY, false);
}
public void markSwipeToReplyTooltipSeen() {
putBoolean(SWIPE_TO_REPLY, true);
}
@Override
@@ -1,12 +1,18 @@
package org.thoughtcrime.securesms.keyvalue;
import android.content.Context;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import java.util.Arrays;
import java.util.List;
public class UiHintValues extends SignalStoreValues {
private static final String TAG = Log.tag(UiHintValues.class);
private static final int NEVER_DISPLAY_PULL_TO_FILTER_TIP_THRESHOLD = 3;
private static final int HAS_SEEN_PINNED_MESSAGE_SHEET_THRESHOLD = 3;
@@ -34,9 +40,29 @@ public class UiHintValues extends SignalStoreValues {
private static final String HAS_DISMISSED_MEMBER_LABEL_ABOUT_OVERRIDE_WARNING = "uihints.has_dismissed_member_label_about_override_warning";
private static final String HAS_SEEN_ADMIN_DELETE_EDUCATION_DIALOG = "uihints.has_seen_admin_delete_education_dialog";
private static final String DISMISSED_SET_UP_USERNAME_BANNER = "uihints.dismissed_set_up_username_banner";
private static final String HAS_PROMPTED_OPTIMIZE_DOZE = "uihints.has_prompted_optimize_doze";
UiHintValues(@NonNull KeyValueStore store) {
UiHintValues(@NonNull KeyValueStore store, @NonNull Context context) {
super(store);
if (!store.containsKey(HAS_PROMPTED_OPTIMIZE_DOZE)) {
migrateFromSharedPrefsV1(context);
}
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private void migrateFromSharedPrefsV1(@NonNull Context context) {
Log.i(TAG, "[V1] Migrating ui hint values from shared prefs.");
putBoolean(HAS_PROMPTED_OPTIMIZE_DOZE, LegacySharedPrefs.INSTANCE.getBoolean(context, "pref_prompted_optimize_doze", false));
}
public boolean hasPromptedOptimizeDoze() {
return getBoolean(HAS_PROMPTED_OPTIMIZE_DOZE, false);
}
public void setHasPromptedOptimizeDoze(boolean value) {
putBoolean(HAS_PROMPTED_OPTIMIZE_DOZE, value);
}
@Override
@@ -5,7 +5,7 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import java.util.NavigableSet;
import java.util.TreeSet;
@@ -24,26 +24,26 @@ public class RegistrationLockReminders {
public static final long INITIAL_INTERVAL = INTERVALS.first();
public static boolean needsReminder(@NonNull Context context) {
long lastReminderTime = TextSecurePreferences.getRegistrationLockLastReminderTime(context);
long nextIntervalTime = TextSecurePreferences.getRegistrationLockNextReminderInterval(context);
long lastReminderTime = SignalStore.pin().getLastSuccessfulEntryTime();
long nextIntervalTime = SignalStore.pin().getNextReminderInterval();
return System.currentTimeMillis() > lastReminderTime + nextIntervalTime;
}
public static void scheduleReminder(@NonNull Context context, boolean success) {
if (success) {
long timeSinceLastReminder = System.currentTimeMillis() - TextSecurePreferences.getRegistrationLockLastReminderTime(context);
long timeSinceLastReminder = System.currentTimeMillis() - SignalStore.pin().getLastSuccessfulEntryTime();
Long nextReminderInterval = INTERVALS.higher(timeSinceLastReminder);
if (nextReminderInterval == null) {
nextReminderInterval = INTERVALS.last();
}
TextSecurePreferences.setRegistrationLockLastReminderTime(context, System.currentTimeMillis());
TextSecurePreferences.setRegistrationLockNextReminderInterval(context, nextReminderInterval);
SignalStore.pin().setLastSuccessfulEntryTime(System.currentTimeMillis());
SignalStore.pin().setNextReminderInterval(nextReminderInterval);
} else {
long timeSinceLastReminder = TextSecurePreferences.getRegistrationLockLastReminderTime(context) + TimeUnit.MINUTES.toMillis(5);
TextSecurePreferences.setRegistrationLockLastReminderTime(context, timeSinceLastReminder);
long timeSinceLastReminder = SignalStore.pin().getLastSuccessfulEntryTime() + TimeUnit.MINUTES.toMillis(5);
SignalStore.pin().setLastSuccessfulEntryTime(timeSinceLastReminder);
}
}
}
@@ -7,7 +7,6 @@ import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.keyvalue.KeepMessagesDuration;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.signal.core.util.Util;
final class LogSectionKeyPreferences implements LogSection {
@@ -27,7 +26,7 @@ final class LogSectionKeyPreferences implements LogSection {
.append("Media Quality : ").append(SignalStore.settings().getSentMediaQuality()).append("\n")
.append("Client Deprecated : ").append(SignalStore.misc().isClientDeprecated()).append("\n")
.append("Push Registered : ").append(SignalStore.account().isRegistered()).append("\n")
.append("Unauthorized Received : ").append(TextSecurePreferences.isUnauthorizedReceived(context)).append("\n")
.append("Unauthorized Received : ").append(SignalStore.account().isUnauthorizedReceived()).append("\n")
.append("self.isRegistered() : ").append(SignalStore.account().getAci() == null ? "false" : Recipient.self().isRegistered()).append("\n")
.append("Thread Trimming : ").append(getThreadTrimmingString()).append("\n")
.append("Censorship Setting : ").append(SignalStore.settings().getCensorshipCircumventionEnabled()).append("\n")
@@ -17,7 +17,7 @@ public class LogSectionPin implements LogSection {
public @NonNull CharSequence getContent(@NonNull Context context) {
return new StringBuilder().append("Last Successful Reminder Entry: ").append(SignalStore.pin().getLastSuccessfulEntryTime()).append("\n")
.append("Last Reminder Time: ").append(SignalStore.pin().getLastReminderTime()).append("\n")
.append("Next Reminder Interval: ").append(SignalStore.pin().getCurrentInterval()).append("\n")
.append("Next Reminder Interval: ").append(SignalStore.pin().getNextReminderInterval()).append("\n")
.append("Reglock: ").append(SignalStore.svr().isRegistrationLockEnabled()).append("\n")
.append("Signal PIN: ").append(SignalStore.svr().hasPin()).append("\n")
.append("Restored via AEP: ").append(SignalStore.account().restoredAccountEntropyPool()).append("\n")
@@ -30,7 +30,6 @@ import org.thoughtcrime.securesms.service.webrtc.AndroidTelecomUtil.telecomSuppo
import org.thoughtcrime.securesms.util.AppSignatureUtil
import org.thoughtcrime.securesms.util.NetworkUtil
import org.thoughtcrime.securesms.util.PowerManagerCompat
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.VersionTracker.getDaysSinceFirstInstalled
import java.util.Locale
import kotlin.math.roundToLong
@@ -71,7 +70,7 @@ class LogSectionSystemInfo : LogSection {
FCM : ${SignalStore.account.fcmEnabled}
Locale : ${Locale.getDefault()}
Linked Devices : ${SignalStore.account.isMultiDevice}
First Version : ${TextSecurePreferences.getFirstInstallVersion(context)}
First Version : ${SignalStore.misc.firstInstallVersion}
Days Installed : ${getDaysSinceFirstInstalled(context)}
Last Registration : ${getTimeRegistered()}
Build Variant : ${BuildConfig.BUILD_DISTRIBUTION_TYPE}${BuildConfig.BUILD_ENVIRONMENT_TYPE}${BuildConfig.BUILD_VARIANT_TYPE}
@@ -48,7 +48,6 @@ import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.Environment;
import org.thoughtcrime.securesms.util.RemoteConfig;
import org.signal.core.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.VersionTracker;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
@@ -131,7 +130,7 @@ public final class Megaphones {
// Specifically putting backup reminders here, above PIN reminders
put(Event.BACKUP_LOW_STORAGE_UPSELL, shouldShowBackupLowStorageUpsell(context) ? new BackupUpsellSchedule(records, TimeUnit.DAYS.toMillis(60), TimeUnit.DAYS.toMillis(120)) : NEVER);
put(Event.BACKUP_MEDIA_SIZE_UPSELL, shouldShowBackupMediaSizeUpsell() ? new BackupUpsellSchedule(records, TimeUnit.DAYS.toMillis(60), TimeUnit.DAYS.toMillis(120)) : NEVER);
put(Event.BACKUP_MESSAGE_COUNT_UPSELL, shouldShowBackupMessageCountUpsell(context) ? new BackupUpsellSchedule(records, TimeUnit.DAYS.toMillis(60)) : NEVER);
put(Event.BACKUP_MESSAGE_COUNT_UPSELL, shouldShowBackupMessageCountUpsell() ? new BackupUpsellSchedule(records, TimeUnit.DAYS.toMillis(60)) : NEVER);
put(Event.BACKUPS_GENERIC_UPSELL, shouldShowGenericBackupsMegaphone(context) ? new BackupUpsellSchedule(records, TimeUnit.DAYS.toMillis(60)) : NEVER);
put(Event.VERIFY_BACKUP_KEY, new VerifyBackupKeyReminderSchedule());
put(Event.USE_NEW_ON_DEVICE_BACKUPS, shouldShowUseNewOnDeviceBackupsMegaphone() ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(7)) : NEVER);
@@ -273,7 +272,7 @@ public final class Megaphones {
SignalStore.pin().onEntrySkip(includedFailure);
controller.onMegaphoneSnooze(Event.PIN_REMINDER);
controller.onMegaphoneToastRequested(controller.getMegaphoneActivity().getString(SignalPinReminders.getSkipReminderString(SignalStore.pin().getCurrentInterval())));
controller.onMegaphoneToastRequested(controller.getMegaphoneActivity().getString(SignalPinReminders.getSkipReminderString(SignalStore.pin().getNextReminderInterval())));
}
@Override
@@ -286,7 +285,7 @@ public final class Megaphones {
}
controller.onMegaphoneSnooze(Event.PIN_REMINDER);
controller.onMegaphoneToastRequested(controller.getMegaphoneActivity().getString(SignalPinReminders.getReminderString(SignalStore.pin().getCurrentInterval())));
controller.onMegaphoneToastRequested(controller.getMegaphoneActivity().getString(SignalPinReminders.getReminderString(SignalStore.pin().getNextReminderInterval())));
}
});
})
@@ -624,7 +623,7 @@ public final class Megaphones {
return false;
}
if (!SignalStore.account().isRegistered() || TextSecurePreferences.isUnauthorizedReceived(context) || SignalStore.account().isLinkedDevice()) {
if (!SignalStore.account().isRegistered() || SignalStore.account().isUnauthorizedReceived() || SignalStore.account().isLinkedDevice()) {
return false;
}
@@ -667,8 +666,8 @@ public final class Megaphones {
return System.currentTimeMillis() - lastSeenDonatePrompt;
}
private static boolean shouldShowBackupMessageCountUpsell(@NonNull Context context) {
if (!SignalStore.account().isRegistered() || TextSecurePreferences.isUnauthorizedReceived(context) || SignalStore.account().isLinkedDevice()) {
private static boolean shouldShowBackupMessageCountUpsell() {
if (!SignalStore.account().isRegistered() || SignalStore.account().isUnauthorizedReceived() || SignalStore.account().isLinkedDevice()) {
return false;
}
@@ -692,7 +691,7 @@ public final class Megaphones {
}
private static boolean shouldShowBackupLowStorageUpsell(@NonNull Context context) {
if (!SignalStore.account().isRegistered() || TextSecurePreferences.isUnauthorizedReceived(context) || SignalStore.account().isLinkedDevice() || !Environment.Backups.supportsGooglePlayBilling()) {
if (!SignalStore.account().isRegistered() || SignalStore.account().isUnauthorizedReceived() || SignalStore.account().isLinkedDevice() || !Environment.Backups.supportsGooglePlayBilling()) {
return false;
}
@@ -31,7 +31,7 @@ final class SignalPinReminderSchedule implements MegaphoneSchedule {
}
long lastReminderTime = SignalStore.pin().getLastReminderTime();
long interval = SignalStore.pin().getCurrentInterval();
long interval = SignalStore.pin().getNextReminderInterval();
return currentTime - lastReminderTime >= interval;
}
@@ -860,7 +860,7 @@ object DataMessageProcessor {
val giftBadge: DataMessage.GiftBadge = message.giftBadge!!
check(giftBadge.receiptCredentialPresentation != null)
notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipientId, metadata.sourceDeviceId)
notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipientId, metadata.sourceDeviceId)
val token = ReceiptCredentialPresentation(giftBadge.receiptCredentialPresentation!!.toByteArray()).serialize()
val dbGiftBadge = GiftBadge.Builder()
@@ -911,7 +911,7 @@ object DataMessageProcessor {
): InsertResult? {
log(envelope.clientTimestamp!!, "Media message.")
notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId)
notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipient.id, metadata.sourceDeviceId)
val insertResult: InsertResult?
@@ -1018,7 +1018,7 @@ object DataMessageProcessor {
handlePossibleExpirationUpdate(envelope, metadata, senderRecipient, threadRecipient, groupId, message.expireTimerDuration, message.expireTimerVersion, receivedTime)
notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId)
notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipient.id, metadata.sourceDeviceId)
val textMessage = IncomingMessage(
type = MessageType.NORMAL,
@@ -1479,7 +1479,7 @@ object DataMessageProcessor {
}
}
fun notifyTypingStoppedFromIncomingMessage(context: Context, senderRecipient: Recipient, threadRecipientId: RecipientId, device: Int) {
fun notifyTypingStoppedFromIncomingMessage(senderRecipient: Recipient, threadRecipientId: RecipientId, device: Int) {
val threadId = SignalDatabase.threads.getThreadIdIfExistsFor(threadRecipientId)
if (threadId > 0 && SignalStore.settings.isTypingIndicatorsEnabled) {
@@ -85,7 +85,7 @@ object EditMessageProcessor {
return
}
DataMessageProcessor.notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId)
DataMessageProcessor.notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipient.id, metadata.sourceDeviceId)
targetMessage = targetMessage.withAttachments(SignalDatabase.attachments.getAttachmentsForMessage(targetMessage.id))
@@ -49,7 +49,6 @@ import org.thoughtcrime.securesms.util.AlarmSleepTimer
import org.thoughtcrime.securesms.util.Environment
import org.thoughtcrime.securesms.util.SignalLocalMetrics
import org.thoughtcrime.securesms.util.SignalTrace
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.asChain
import org.whispersystems.signalservice.api.messages.EnvelopeResponse
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
@@ -176,7 +175,7 @@ class IncomingMessageObserver(
MessageRetrievalThread().start()
val registered = SignalStore.account.isRegistered && !TextSecurePreferences.isUnauthorizedReceived(context)
val registered = SignalStore.account.isRegistered && !SignalStore.account.isUnauthorizedReceived
if (registered && (!SignalStore.account.fcmEnabled || SignalStore.settings.forceWebsocketMode.isEnabled)) {
SignalExecutors.UNBOUNDED.execute {
if (!SafeForegroundService.start(context, ForegroundService::class.java)) {
@@ -251,7 +250,7 @@ class IncomingMessageObserver(
val timeIdle = if (isForeground) 0 else System.currentTimeMillis() - lastInteractionTime
val registered = SignalStore.account.isRegistered
val unauthorizedReceived = TextSecurePreferences.isUnauthorizedReceived(context)
val unauthorizedReceived = SignalStore.account.isUnauthorizedReceived
val fcmEnabled = SignalStore.account.fcmEnabled
val hasNetwork = NetworkConstraint.isMet(context)
val hasProxy = SignalStore.proxy.isProxyEnabled
@@ -278,7 +277,7 @@ class IncomingMessageObserver(
}
private fun isConnectionAvailable(): Boolean {
return !TextSecurePreferences.isUnauthorizedReceived(context) && SignalStore.account.isRegistered && (authWebSocket.stateSnapshot == WebSocketConnectionState.CONNECTED || (authWebSocket.shouldSendKeepAlives() && NetworkConstraint.isMet(context)))
return !SignalStore.account.isUnauthorizedReceived && SignalStore.account.isRegistered && (authWebSocket.stateSnapshot == WebSocketConnectionState.CONNECTED || (authWebSocket.shouldSendKeepAlives() && NetworkConstraint.isMet(context)))
}
/** Conditions are evaluated outside of [connectionLock] so notifiers never block on them. We only park if nothing signaled since the version we evaluated against. */
@@ -518,7 +518,6 @@ open class MessageContentProcessor(private val context: Context) {
content.receiptMessage != null -> {
ReceiptMessageProcessor.process(
context,
senderRecipient,
envelope,
content,
@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.messages
import android.annotation.SuppressLint
import android.content.Context
import org.signal.core.util.Stopwatch
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.AppDependencies
@@ -22,13 +21,13 @@ object ReceiptMessageProcessor {
private const val VERBOSE = false
fun process(context: Context, senderRecipient: Recipient, envelope: Envelope, content: Content, metadata: EnvelopeMetadata, earlyMessageCacheEntry: EarlyMessageCacheEntry?, batchCache: BatchCache) {
fun process(senderRecipient: Recipient, envelope: Envelope, content: Content, metadata: EnvelopeMetadata, earlyMessageCacheEntry: EarlyMessageCacheEntry?, batchCache: BatchCache) {
val receiptMessage = content.receiptMessage!!
when (receiptMessage.type) {
ReceiptMessage.Type.DELIVERY -> handleDeliveryReceipt(envelope, metadata, receiptMessage, senderRecipient.id, batchCache)
ReceiptMessage.Type.READ -> handleReadReceipt(context, senderRecipient.id, envelope, metadata, receiptMessage, earlyMessageCacheEntry, batchCache)
ReceiptMessage.Type.VIEWED -> handleViewedReceipt(context, envelope, metadata, receiptMessage, senderRecipient.id, earlyMessageCacheEntry, batchCache)
ReceiptMessage.Type.READ -> handleReadReceipt(senderRecipient.id, envelope, metadata, receiptMessage, earlyMessageCacheEntry, batchCache)
ReceiptMessage.Type.VIEWED -> handleViewedReceipt(envelope, metadata, receiptMessage, senderRecipient.id, earlyMessageCacheEntry, batchCache)
else -> warn(envelope.clientTimestamp!!, "Unknown recipient message type ${receiptMessage.type}")
}
}
@@ -68,7 +67,6 @@ object ReceiptMessageProcessor {
@SuppressLint("DefaultLocale")
private fun handleReadReceipt(
context: Context,
senderRecipientId: RecipientId,
envelope: Envelope,
metadata: EnvelopeMetadata,
@@ -104,7 +102,6 @@ object ReceiptMessageProcessor {
}
private fun handleViewedReceipt(
context: Context,
envelope: Envelope,
metadata: EnvelopeMetadata,
viewedReceipt: ReceiptMessage,
@@ -174,13 +174,13 @@ object SyncMessageProcessor {
when {
syncMessage.sent != null -> handleSynchronizeSentMessage(context, envelope, content, metadata, syncMessage.sent!!, senderRecipient, threadRecipient, earlyMessageCacheEntry, batchCache)
syncMessage.request != null -> handleSynchronizeRequestMessage(context, syncMessage.request!!, envelope.clientTimestamp!!)
syncMessage.request != null -> handleSynchronizeRequestMessage(syncMessage.request!!, envelope.clientTimestamp!!)
syncMessage.read.isNotEmpty() -> handleSynchronizeReadMessage(context, syncMessage.read, envelope.clientTimestamp!!, earlyMessageCacheEntry, batchCache)
syncMessage.viewed.isNotEmpty() -> handleSynchronizeViewedMessage(context, syncMessage.viewed, envelope.clientTimestamp!!)
syncMessage.viewOnceOpen != null -> handleSynchronizeViewOnceOpenMessage(context, syncMessage.viewOnceOpen!!, envelope.clientTimestamp!!, earlyMessageCacheEntry, batchCache)
syncMessage.verified != null -> handleSynchronizeVerifiedMessage(context, syncMessage.verified!!)
syncMessage.stickerPackOperation.isNotEmpty() -> handleSynchronizeStickerPackOperation(syncMessage.stickerPackOperation, envelope.clientTimestamp!!)
syncMessage.configuration != null -> handleSynchronizeConfigurationMessage(context, syncMessage.configuration!!, envelope.clientTimestamp!!)
syncMessage.configuration != null -> handleSynchronizeConfigurationMessage(syncMessage.configuration!!, envelope.clientTimestamp!!)
syncMessage.blocked != null -> handleSynchronizeBlockedListMessage(syncMessage.blocked!!, envelope.clientTimestamp!!)
syncMessage.fetchLatest?.type != null -> handleSynchronizeFetchMessage(syncMessage.fetchLatest!!.type!!, envelope.clientTimestamp!!)
syncMessage.messageRequestResponse != null -> handleSynchronizeMessageRequestResponse(syncMessage.messageRequestResponse!!, envelope.clientTimestamp!!)
@@ -978,7 +978,7 @@ object SyncMessageProcessor {
return threadId
}
private fun handleSynchronizeRequestMessage(context: Context, message: Request, envelopeTimestamp: Long) {
private fun handleSynchronizeRequestMessage(message: Request, envelopeTimestamp: Long) {
if (SignalStore.account.isPrimaryDevice) {
log(envelopeTimestamp, "Synchronize request message.")
} else {
@@ -1135,7 +1135,7 @@ object SyncMessageProcessor {
}
}
private fun handleSynchronizeConfigurationMessage(context: Context, configurationMessage: Configuration, envelopeTimestamp: Long) {
private fun handleSynchronizeConfigurationMessage(configurationMessage: Configuration, envelopeTimestamp: Long) {
log(envelopeTimestamp, "Synchronize configuration message.")
if (configurationMessage.readReceipts != null) {
@@ -73,7 +73,7 @@ public class ApplyUnknownFieldsToSelfMigrationJob extends MigrationJob {
SignalAccountRecord signalAccountRecord = new SignalAccountRecord(storageId, accountRecord);
Log.d(TAG, "Applying potentially now known unknowns");
StorageSyncHelper.applyAccountStorageSyncUpdates(context, self, signalAccountRecord, false);
StorageSyncHelper.applyAccountStorageSyncUpdates(self, signalAccountRecord, false);
} catch (IOException e) {
Log.w(TAG, e);
}
@@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.FileUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.VersionTracker;
import java.io.File;
@@ -166,7 +165,7 @@ public class LegacyMigrationJob extends MigrationJob {
if (lastSeenVersion < INTERNALIZE_CONTACTS) {
if (SignalStore.account().isRegistered()) {
TextSecurePreferences.setHasSuccessfullyRetrievedDirectory(context, true);
SignalStore.misc().setHasSuccessfullyRetrievedDirectory(true);
}
}
@@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
import org.thoughtcrime.securesms.jobs.StorageForcePushJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
/**
* This does a couple things:
@@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceStorageSyncRequestJob;
import org.thoughtcrime.securesms.jobs.StorageSyncJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
/**
* Just runs a storage sync. Useful if you've started syncing a new field to storage service.
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.MainActivity;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.NotificationIds;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.List;
import java.util.Set;
@@ -73,7 +72,7 @@ public class UserNotificationMigrationJob extends MigrationJob {
return;
}
if (TextSecurePreferences.getFirstInstallVersion(context) < 759) {
if (SignalStore.misc().getFirstInstallVersion() < 759) {
Log.w(TAG, "Install is older than v5.0.8. Skipping.");
return;
}
@@ -17,9 +17,7 @@ import org.signal.core.util.AppForegroundObserver
import org.signal.core.util.SleepTimer
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.clockskew.ClockSkewDetector
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.websocket.HealthMonitor
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
@@ -91,13 +89,13 @@ class SignalWebSocketHealthMonitor(
}
WebSocketConnectionState.CONNECTED -> {
if (webSocket is SignalWebSocket.AuthenticatedWebSocket) {
TextSecurePreferences.setUnauthorizedReceived(AppDependencies.application, false)
SignalStore.account.isUnauthorizedReceived = false
}
failedInConnecting = false
}
WebSocketConnectionState.AUTHENTICATION_FAILED -> {
if (webSocket is SignalWebSocket.AuthenticatedWebSocket) {
TextSecurePreferences.setUnauthorizedReceived(AppDependencies.application, true)
SignalStore.account.isUnauthorizedReceived = true
}
}
WebSocketConnectionState.REMOTE_DEPRECATED -> {
@@ -37,7 +37,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.ConversationUtil;
import org.signal.core.util.ServiceUtil;
import org.thoughtcrime.securesms.util.RemoteConfig;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.ArrayList;
import java.util.Arrays;
@@ -113,10 +112,10 @@ public class NotificationChannels {
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
int oldVersion = TextSecurePreferences.getNotificationChannelVersion(context);
int oldVersion = SignalStore.misc().getNotificationChannelVersion();
if (oldVersion != VERSION) {
onUpgrade(notificationManager, oldVersion, VERSION);
TextSecurePreferences.setNotificationChannelVersion(context, VERSION);
SignalStore.misc().setNotificationChannelVersion(VERSION);
}
onCreate(notificationManager);
@@ -214,7 +213,7 @@ public class NotificationChannels {
* @return The channel ID for the default messages channel.
*/
public synchronized @NonNull String getMessagesChannel() {
return getMessagesChannelId(TextSecurePreferences.getNotificationMessagesChannelVersion(context));
return getMessagesChannelId(SignalStore.misc().getNotificationMessagesChannelVersion());
}
/**
@@ -709,7 +708,7 @@ public class NotificationChannels {
if (oldVersion < Version.AUDIO_ATTRIBUTE_CHANGE) {
Context context = AppDependencies.getApplication();
int existingMessageChannelVersion = TextSecurePreferences.getNotificationMessagesChannelVersion(context);
int existingMessageChannelVersion = SignalStore.misc().getNotificationMessagesChannelVersion();
int newMessageChannelVersion = existingMessageChannelVersion + 1;
String existingChannelId = "messages_" + existingMessageChannelVersion;
String newChannelId = "messages_" + newMessageChannelVersion;
@@ -734,7 +733,7 @@ public class NotificationChannels {
notificationManager.createNotificationChannel(newChannel);
TextSecurePreferences.setNotificationMessagesChannelVersion(context, newMessageChannelVersion);
SignalStore.misc().setNotificationMessagesChannelVersion(newMessageChannelVersion);
}
}
}
@@ -803,12 +802,12 @@ public class NotificationChannels {
@TargetApi(26)
private void updateMessageChannel(@NonNull ChannelUpdater updater) {
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
int existingVersion = TextSecurePreferences.getNotificationMessagesChannelVersion(context);
int existingVersion = SignalStore.misc().getNotificationMessagesChannelVersion();
int newVersion = existingVersion + 1;
Log.i(TAG, "Updating message channel from version " + existingVersion + " to " + newVersion);
if (updateExistingChannel(notificationManager, getMessagesChannelId(existingVersion), getMessagesChannelId(newVersion), updater)) {
TextSecurePreferences.setNotificationMessagesChannelVersion(context, newVersion);
SignalStore.misc().setNotificationMessagesChannelVersion(newVersion);
} else {
onCreate(notificationManager);
}
@@ -0,0 +1,61 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.notifications
import android.Manifest
import android.app.PendingIntent
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.signal.core.util.PendingIntentFlags
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.registration.ui.RegistrationActivity
/**
* Notification shown when the service tells us our credentials are no longer valid, prompting the user to re-register or re-link.
*/
object UnregisteredNotifier {
private val TAG = Log.tag(UnregisteredNotifier::class)
fun notify(context: Context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Notification permission is not granted.")
return
}
val registrationIntent = if (SignalStore.account.isLinkedDevice) {
RegistrationActivity.newIntentForReLinkDevice(context)
} else {
RegistrationActivity.newIntentForReRegistration(context)
}
val reRegistrationIntent = PendingIntent.getActivity(
context,
0,
registrationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentFlags.immutable()
)
val notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_signal_logo_large)
.setContentText(context.getString(R.string.LoggedOutNotification_you_have_been_logged_out))
.setContentIntent(reRegistrationIntent)
.setOnlyAlertOnce(true)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(context).notify(NotificationIds.UNREGISTERED_NOTIFICATION_ID, notification)
}
fun cancel(context: Context) {
NotificationManagerCompat.from(context).cancel(NotificationIds.UNREGISTERED_NOTIFICATION_ID)
}
}
@@ -19,7 +19,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.notifications.DeviceSpecificNotificationConfig.ShowCondition
import org.thoughtcrime.securesms.util.ConnectivityWarning
import org.thoughtcrime.securesms.util.NetworkUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
import java.util.concurrent.TimeUnit
import kotlin.time.Duration.Companion.days
@@ -79,7 +78,7 @@ class VitalsViewModel(private val context: Application) : AndroidViewModel(conte
val timeSinceLastConnection = System.currentTimeMillis() - SignalStore.misc.lastWebSocketConnectTime
val timeSinceLastConnectionWarning = System.currentTimeMillis() - SignalStore.misc.lastConnectivityWarningTime
val connectedToWebSocket = AppDependencies.webSocketObserver.value == WebSocketConnectionState.CONNECTED
val isRegistered = SignalStore.account.isRegistered && !TextSecurePreferences.isUnauthorizedReceived(context)
val isRegistered = SignalStore.account.isRegistered && !SignalStore.account.isUnauthorizedReceived
if (ConnectivityWarning.isEnabled && timeSinceLastConnection > ConnectivityWarning.threshold && timeSinceLastConnectionWarning > 14.days.inWholeMilliseconds && NetworkUtil.isConnected(context) && isRegistered && !connectedToWebSocket) {
return@fromCallable if (ConnectivityWarning.isDebugPromptEnabled) {
@@ -46,7 +46,6 @@ import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.util.BackupUtil;
import org.thoughtcrime.securesms.util.Environment;
import org.thoughtcrime.securesms.util.JavaTimeExtensionsKt;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.text.NumberFormat;
import java.time.LocalTime;
@@ -330,7 +329,7 @@ public class BackupsPreferenceFragment extends Fragment {
}
private void updateToggle() {
boolean userUnregistered = TextSecurePreferences.isUnauthorizedReceived(AppDependencies.getApplication()) || !SignalStore.account().isRegistered();
boolean userUnregistered = SignalStore.account().isUnauthorizedReceived() || !SignalStore.account().isRegistered();
boolean clientDeprecated = SignalStore.misc().isClientDeprecated();
boolean legacyLocalBackupsEnabled = SignalStore.settings().isBackupEnabled() && BackupUtil.canUserAccessBackupDirectory(AppDependencies.getApplication());
@@ -1,82 +0,0 @@
package org.thoughtcrime.securesms.preferences;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.DialogFragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroupAdapter;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.CustomDefaultPreference;
public abstract class CorrectedPreferenceFragment extends PreferenceFragmentCompat {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View lv = getView().findViewById(android.R.id.list);
if (lv != null) lv.setPadding(0, 0, 0, 0);
}
@Override
public void onDisplayPreferenceDialog(Preference preference) {
DialogFragment dialogFragment = null;
if (preference instanceof CustomDefaultPreference) {
dialogFragment = CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.newInstance(preference.getKey());
}
if (dialogFragment != null) {
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG");
} else {
super.onDisplayPreferenceDialog(preference);
}
}
@Override
@SuppressLint("RestrictedApi")
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new PreferenceGroupAdapter(preferenceScreen) {
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
Preference preference = getItem(position);
if (preference instanceof PreferenceCategory) {
setZeroPaddingToLayoutChildren(holder.itemView);
} else {
View iconFrame = holder.itemView.findViewById(androidx.preference.R.id.icon_frame);
if (iconFrame != null) {
iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE);
}
}
}
};
}
private void setZeroPaddingToLayoutChildren(View view) {
if (!(view instanceof ViewGroup)) return;
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i));
ViewCompat.setPaddingRelative(viewGroup, 0, viewGroup.getPaddingTop(), ViewCompat.getPaddingEnd(viewGroup), viewGroup.getPaddingBottom());
}
}
}
@@ -1,29 +0,0 @@
package org.thoughtcrime.securesms.preferences;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.R;
import java.util.Arrays;
public abstract class ListSummaryPreferenceFragment extends CorrectedPreferenceFragment {
protected class ListSummaryListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
ListPreference listPref = (ListPreference) preference;
int entryIndex = Arrays.asList(listPref.getEntryValues()).indexOf(value);
listPref.setSummary(entryIndex >= 0 && entryIndex < listPref.getEntries().length
? listPref.getEntries()[entryIndex]
: getString(R.string.preferences__led_color_unknown));
return true;
}
}
protected void initializeListSummary(ListPreference pref) {
pref.setSummary(pref.getEntry());
}
}
@@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.signalservice.api.util.StreamDetails;
@@ -107,7 +106,7 @@ class EditProfileViewModel extends ViewModel {
}
public boolean isRegisteredAndUpToDate() {
return !TextSecurePreferences.isUnauthorizedReceived(AppDependencies.getApplication()) && SignalStore.account().isRegistered() && !SignalStore.misc().isClientDeprecated();
return !SignalStore.account().isUnauthorizedReceived() && SignalStore.account().isRegistered() && !SignalStore.misc().isClientDeprecated();
}
public boolean isDeprecated() {
@@ -117,7 +117,7 @@ class AvatarProvider : BaseContentProvider() {
if (uriMatcher.match(uri) == AVATAR) {
if (VERBOSE) Log.i(TAG, "Loading avatar.")
try {
val recipient = getRecipientId(uri)?.let { RecipientCreator.forRecord(application, SignalDatabase.recipients.getRecord(it)) } ?: return null
val recipient = getRecipientId(uri)?.let { RecipientCreator.forRecord(SignalDatabase.recipients.getRecord(it)) } ?: return null
return getParcelFileDescriptorForAvatar(recipient)
} catch (ioe: IOException) {
Log.w(TAG, ioe)
@@ -39,7 +39,7 @@ import org.thoughtcrime.securesms.keyboard.emoji.KeyboardPageSearchView;
import org.thoughtcrime.securesms.reactions.ReactionsRepository;
import org.thoughtcrime.securesms.reactions.edit.EditReactionsActivity;
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel;
@@ -52,7 +52,7 @@ public final class ReactWithAnyEmojiBottomSheetDialogFragment extends FixedRound
{
public static final String REACTION_STORAGE_KEY = "reactions_recent_emoji";
private static final String ABOUT_STORAGE_KEY = TextSecurePreferences.RECENT_STORAGE_KEY;
private static final String ABOUT_STORAGE_KEY = RecentEmojiPageModel.RECENT_STORAGE_KEY;
private static final String ARG_MESSAGE_ID = "arg_message_id";
private static final String ARG_IS_MMS = "arg_is_mms";

Some files were not shown because too many files have changed in this diff Show More