From 9c9620c9174cb447fdf545189a7b52e8eda056fd Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Tue, 4 Feb 2025 16:11:28 -0500 Subject: [PATCH] Do not connect to web socket until restore decision made. --- .../banner/banners/MediaRestoreProgressBanner.kt | 2 +- .../thoughtcrime/securesms/keyvalue/AccountValues.kt | 4 ++-- .../thoughtcrime/securesms/keyvalue/BackupValues.kt | 2 +- .../securesms/keyvalue/RegistrationValues.kt | 5 ++++- .../securesms/keyvalue/SignalStoreValueDelegates.kt | 12 +++++++----- .../securesms/messages/IncomingMessageObserver.kt | 10 +++++++--- .../org/thoughtcrime/securesms/util/RemoteConfig.kt | 2 +- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/banner/banners/MediaRestoreProgressBanner.kt b/app/src/main/java/org/thoughtcrime/securesms/banner/banners/MediaRestoreProgressBanner.kt index db1c78d0e1..09a934da1d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/banner/banners/MediaRestoreProgressBanner.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/banner/banners/MediaRestoreProgressBanner.kt @@ -42,7 +42,7 @@ class MediaRestoreProgressBanner(private val listener: RestoreProgressBannerList private var totalRestoredSize: Long = 0 override val enabled: Boolean - get() = SignalStore.backup.isRestoreInProgress || totalRestoredSize > 0 + get() = SignalStore.backup.isMediaRestoreInProgress || totalRestoredSize > 0 override val dataFlow: Flow by lazy { SignalStore diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt index 7e5911be53..72ba52955c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt @@ -408,7 +408,7 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context) putBoolean(KEY_IS_REGISTERED, registered) - AppDependencies.incomingMessageObserver.notifyRegistrationChanged() + AppDependencies.incomingMessageObserver.notifyRegistrationStateChanged() if (previous != registered) { Recipient.self().live().refresh() @@ -426,7 +426,7 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context) fun clearRegistrationButKeepCredentials() { putBoolean(KEY_IS_REGISTERED, false) - AppDependencies.incomingMessageObserver.notifyRegistrationChanged() + AppDependencies.incomingMessageObserver.notifyRegistrationStateChanged() Recipient.self().live().refresh() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt index 58d26ab470..e242816de8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/BackupValues.kt @@ -249,7 +249,7 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) { val totalRestorableAttachmentSizeFlow: Flow get() = totalRestorableAttachmentSizeValue.toFlow() - val isRestoreInProgress: Boolean + val isMediaRestoreInProgress: Boolean get() = totalRestorableAttachmentSize > 0 /** Store that lets you interact with message ZK credentials. */ diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/RegistrationValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/RegistrationValues.kt index 726a2ecce2..3148d6dc95 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/RegistrationValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/RegistrationValues.kt @@ -4,6 +4,7 @@ import androidx.annotation.CheckResult import androidx.annotation.VisibleForTesting import org.thoughtcrime.securesms.database.model.databaseprotos.LocalRegistrationMetadata import org.thoughtcrime.securesms.database.model.databaseprotos.RestoreDecisionState +import org.thoughtcrime.securesms.dependencies.AppDependencies class RegistrationValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) { @@ -71,5 +72,7 @@ class RegistrationValues internal constructor(store: KeyValueStore) : SignalStor @get:JvmName("isRestoringOnNewDevice") var restoringOnNewDevice: Boolean by booleanValue(RESTORING_ON_NEW_DEVICE, false) - var restoreDecisionState: RestoreDecisionState by protoValue(RESTORE_DECISION_STATE, RestoreDecisionState.Skipped, RestoreDecisionState.ADAPTER) + var restoreDecisionState: RestoreDecisionState by protoValue(RESTORE_DECISION_STATE, RestoreDecisionState.Skipped, RestoreDecisionState.ADAPTER) { newValue -> + AppDependencies.incomingMessageObserver.notifyRegistrationStateChanged() + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValueDelegates.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValueDelegates.kt index 225222fc20..1a152f97a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValueDelegates.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValueDelegates.kt @@ -42,8 +42,8 @@ internal fun SignalStoreValues.protoValue(key: String, adapter: ProtoAdapter return KeyValueProtoValue(key, adapter, this.store) } -internal fun SignalStoreValues.protoValue(key: String, default: M, adapter: ProtoAdapter): SignalStoreValueDelegate { - return KeyValueProtoWithDefaultValue(key, default, adapter, this.store) +internal fun SignalStoreValues.protoValue(key: String, default: M, adapter: ProtoAdapter, onSet: ((M) -> Unit)? = null): SignalStoreValueDelegate { + return KeyValueProtoWithDefaultValue(key, default, adapter, this.store, onSet) } internal fun SignalStoreValueDelegate.withPrecondition(precondition: () -> Boolean): SignalStoreValueDelegate { @@ -64,7 +64,7 @@ internal fun SignalStoreValueDelegate.map(transform: (T) -> T): SignalSto * Kotlin delegate that serves as a base for all other value types. This allows us to only expose this sealed * class to callers and protect the individual implementations as private behind the various extension functions. */ -sealed class SignalStoreValueDelegate(val store: KeyValueStore, open val default: T) { +sealed class SignalStoreValueDelegate(val store: KeyValueStore, open val default: T, private val onSet: ((T) -> Unit)? = null) { private var flow: Lazy> = lazy { MutableStateFlow(getValue(store)) } @@ -74,6 +74,7 @@ sealed class SignalStoreValueDelegate(val store: KeyValueStore, open val defa operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { setValue(store, value) + onSet?.invoke(value) if (flow.isInitialized()) { flow.value.tryEmit(value) } @@ -162,8 +163,9 @@ private class KeyValueProtoWithDefaultValue( private val key: String, default: M, private val adapter: ProtoAdapter, - store: KeyValueStore -) : SignalStoreValueDelegate(store, default) { + store: KeyValueStore, + onSet: ((M) -> Unit)? = null +) : SignalStoreValueDelegate(store, default, onSet) { override fun getValue(values: KeyValueStore): M { return if (values.containsKey(key)) { adapter.decode(values.getBlob(key, null)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt index 01d6962ea1..0e7eacd5b1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt @@ -23,12 +23,14 @@ import org.thoughtcrime.securesms.jobs.PushProcessMessageErrorJob import org.thoughtcrime.securesms.jobs.PushProcessMessageJob import org.thoughtcrime.securesms.jobs.UnableToStartException import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.keyvalue.isDecisionPending import org.thoughtcrime.securesms.messages.MessageDecryptor.FollowUpOperation import org.thoughtcrime.securesms.messages.protocol.BufferedProtocolStore import org.thoughtcrime.securesms.notifications.NotificationChannels import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.AlarmSleepTimer import org.thoughtcrime.securesms.util.AppForegroundObserver +import org.thoughtcrime.securesms.util.RemoteConfig import org.thoughtcrime.securesms.util.SignalLocalMetrics import org.thoughtcrime.securesms.util.asChain import org.whispersystems.signalservice.api.SignalWebSocket @@ -145,7 +147,7 @@ class IncomingMessageObserver(private val context: Application, private val sign networkConnectionListener.register() } - fun notifyRegistrationChanged() { + fun notifyRegistrationStateChanged() { connectionNecessarySemaphore.release() } @@ -202,15 +204,17 @@ class IncomingMessageObserver(private val context: Application, private val sign val hasNetwork = NetworkConstraint.isMet(context) val hasProxy = SignalStore.proxy.isProxyEnabled val forceWebsocket = SignalStore.internal.isWebsocketModeForced + val isRestoreDecisionPending = RemoteConfig.restoreAfterRegistration && SignalStore.registration.restoreDecisionState.isDecisionPending val lastInteractionString = if (appVisibleSnapshot) "N/A" else timeIdle.toString() + " ms (" + (if (timeIdle < maxBackgroundTime) "within limit" else "over limit") + ")" val conclusion = registered && (appVisibleSnapshot || timeIdle < maxBackgroundTime || !fcmEnabled || keepAliveEntries.isNotEmpty()) && - hasNetwork + hasNetwork && + !isRestoreDecisionPending val needsConnectionString = if (conclusion) "Needs Connection" else "Does Not Need Connection" - Log.d(TAG, "[$needsConnectionString] Network: $hasNetwork, Foreground: $appVisibleSnapshot, Time Since Last Interaction: $lastInteractionString, FCM: $fcmEnabled, Stay open requests: $keepAliveEntries, Registered: $registered, Proxy: $hasProxy, Force websocket: $forceWebsocket") + Log.d(TAG, "[$needsConnectionString] Network: $hasNetwork, Foreground: $appVisibleSnapshot, Time Since Last Interaction: $lastInteractionString, FCM: $fcmEnabled, Stay open requests: $keepAliveEntries, Registered: $registered, Proxy: $hasProxy, Force websocket: $forceWebsocket, Pending restore: $isRestoreDecisionPending") return conclusion } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt index 2a4cefc319..700e3b0848 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt @@ -1083,7 +1083,7 @@ object RemoteConfig { /** JSON object representing some details about how we might want to warn the user around connectivity issues. */ val connectivityWarningConfig: String by remoteString( key = "android.connectivityWarningConfig", - defaultValue = "", + defaultValue = "{}", hotSwappable = true )