Do not connect to web socket until restore decision made.

This commit is contained in:
Cody Henthorne
2025-02-04 16:11:28 -05:00
committed by Greyson Parrelli
parent d028fcff8b
commit 9c9620c917
7 changed files with 23 additions and 14 deletions

View File

@@ -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<BackupStatusData> by lazy {
SignalStore

View File

@@ -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()
}

View File

@@ -249,7 +249,7 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
val totalRestorableAttachmentSizeFlow: Flow<Long>
get() = totalRestorableAttachmentSizeValue.toFlow()
val isRestoreInProgress: Boolean
val isMediaRestoreInProgress: Boolean
get() = totalRestorableAttachmentSize > 0
/** Store that lets you interact with message ZK credentials. */

View File

@@ -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()
}
}

View File

@@ -42,8 +42,8 @@ internal fun <M> SignalStoreValues.protoValue(key: String, adapter: ProtoAdapter
return KeyValueProtoValue(key, adapter, this.store)
}
internal fun <M> SignalStoreValues.protoValue(key: String, default: M, adapter: ProtoAdapter<M>): SignalStoreValueDelegate<M> {
return KeyValueProtoWithDefaultValue(key, default, adapter, this.store)
internal fun <M> SignalStoreValues.protoValue(key: String, default: M, adapter: ProtoAdapter<M>, onSet: ((M) -> Unit)? = null): SignalStoreValueDelegate<M> {
return KeyValueProtoWithDefaultValue(key, default, adapter, this.store, onSet)
}
internal fun <T> SignalStoreValueDelegate<T>.withPrecondition(precondition: () -> Boolean): SignalStoreValueDelegate<T> {
@@ -64,7 +64,7 @@ internal fun <T> SignalStoreValueDelegate<T>.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<T>(val store: KeyValueStore, open val default: T) {
sealed class SignalStoreValueDelegate<T>(val store: KeyValueStore, open val default: T, private val onSet: ((T) -> Unit)? = null) {
private var flow: Lazy<MutableStateFlow<T>> = lazy { MutableStateFlow(getValue(store)) }
@@ -74,6 +74,7 @@ sealed class SignalStoreValueDelegate<T>(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<M>(
private val key: String,
default: M,
private val adapter: ProtoAdapter<M>,
store: KeyValueStore
) : SignalStoreValueDelegate<M>(store, default) {
store: KeyValueStore,
onSet: ((M) -> Unit)? = null
) : SignalStoreValueDelegate<M>(store, default, onSet) {
override fun getValue(values: KeyValueStore): M {
return if (values.containsKey(key)) {
adapter.decode(values.getBlob(key, null))

View File

@@ -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
}

View File

@@ -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
)