Improve network reliability.

This commit is contained in:
Greyson Parrelli
2022-02-28 18:35:54 -05:00
parent 1314b04994
commit 01e75120a7
11 changed files with 484 additions and 370 deletions

View File

@@ -198,11 +198,11 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
sectionHeaderPref(R.string.preferences__internal_network)
switchPref(
title = DSLSettingsText.from(R.string.preferences__internal_force_censorship),
summary = DSLSettingsText.from(R.string.preferences__internal_force_censorship_description),
isChecked = state.forceCensorship,
title = DSLSettingsText.from(R.string.preferences__internal_allow_censorship_toggle),
summary = DSLSettingsText.from(R.string.preferences__internal_allow_censorship_toggle_description),
isChecked = state.allowCensorshipSetting,
onClick = {
viewModel.setForceCensorship(!state.forceCensorship)
viewModel.setAllowCensorshipSetting(!state.allowCensorshipSetting)
}
)

View File

@@ -12,7 +12,7 @@ data class InternalSettingsState(
val gv2ignoreP2PChanges: Boolean,
val disableAutoMigrationInitiation: Boolean,
val disableAutoMigrationNotification: Boolean,
val forceCensorship: Boolean,
val allowCensorshipSetting: Boolean,
val callingServer: String,
val audioProcessingMethod: CallManager.AudioProcessingMethod,
val useBuiltInEmojiSet: Boolean,

View File

@@ -66,8 +66,8 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
refresh()
}
fun setForceCensorship(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.FORCE_CENSORSHIP, enabled)
fun setAllowCensorshipSetting(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.ALLOW_CENSORSHIP_SETTING, enabled)
refresh()
}
@@ -109,7 +109,7 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
gv2ignoreP2PChanges = SignalStore.internalValues().gv2IgnoreP2PChanges(),
disableAutoMigrationInitiation = SignalStore.internalValues().disableGv1AutoMigrateInitiation(),
disableAutoMigrationNotification = SignalStore.internalValues().disableGv1AutoMigrateNotification(),
forceCensorship = SignalStore.internalValues().forcedCensorship(),
allowCensorshipSetting = SignalStore.internalValues().allowChangingCensorshipSetting(),
callingServer = SignalStore.internalValues().groupCallingServer(),
audioProcessingMethod = SignalStore.internalValues().audioProcessingMethod(),
useBuiltInEmojiSet = SignalStore.internalValues().forceBuiltInEmoji(),

View File

@@ -138,6 +138,28 @@ class AdvancedPrivacySettingsFragment : DSLSettingsFragment(R.string.preferences
dividerPref()
sectionHeaderPref(R.string.preferences_communication__category_censorship_circumvention)
val censorshipSummaryResId: Int = when (state.censorshipCircumventionState) {
CensorshipCircumventionState.AVAILABLE -> R.string.preferences_communication__censorship_circumvention_if_enabled_signal_will_attempt_to_circumvent_censorship
CensorshipCircumventionState.AVAILABLE_MANUALLY_DISABLED -> R.string.preferences_communication__censorship_circumvention_you_have_manually_disabled
CensorshipCircumventionState.AVAILABLE_AUTOMATICALLY_ENABLED -> R.string.preferences_communication__censorship_circumvention_has_been_activated_based_on_your_accounts_phone_number
CensorshipCircumventionState.UNAVAILABLE_CONNECTED -> R.string.preferences_communication__censorship_circumvention_is_not_necessary_you_are_already_connected
CensorshipCircumventionState.UNAVAILABLE_NO_INTERNET -> R.string.preferences_communication__censorship_circumvention_can_only_be_activated_when_connected_to_the_internet
}
switchPref(
title = DSLSettingsText.from(R.string.preferences_communication__censorship_circumvention),
summary = DSLSettingsText.from(censorshipSummaryResId),
isChecked = state.censorshipCircumventionEnabled,
isEnabled = state.censorshipCircumventionState.available,
onClick = {
viewModel.setCensorshipCircumventionEnabled(!state.censorshipCircumventionEnabled)
}
)
dividerPref()
sectionHeaderPref(R.string.preferences_communication__category_sealed_sender)
switchPref(

View File

@@ -3,7 +3,26 @@ package org.thoughtcrime.securesms.components.settings.app.privacy.advanced
data class AdvancedPrivacySettingsState(
val isPushEnabled: Boolean,
val alwaysRelayCalls: Boolean,
val censorshipCircumventionState: CensorshipCircumventionState,
val censorshipCircumventionEnabled: Boolean,
val showSealedSenderStatusIcon: Boolean,
val allowSealedSenderFromAnyone: Boolean,
val showProgressSpinner: Boolean
)
enum class CensorshipCircumventionState(val available: Boolean) {
/** The setting is unavailable because you're connected to the websocket */
UNAVAILABLE_CONNECTED(false),
/** The setting is unavailable because you have no network access at all */
UNAVAILABLE_NO_INTERNET(false),
/** The setting is available, and the user manually disabled it even though we thought they were censored */
AVAILABLE_MANUALLY_DISABLED(true),
/** The setting is available, and it's on because we think the user is censored */
AVAILABLE_AUTOMATICALLY_ENABLED(true),
/** The setting is generically available */
AVAILABLE(true),
}

View File

@@ -4,23 +4,40 @@ import android.content.SharedPreferences
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob
import org.thoughtcrime.securesms.keyvalue.SettingsValues
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import org.thoughtcrime.securesms.util.SingleLiveEvent
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.livedata.Store
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
class AdvancedPrivacySettingsViewModel(
private val sharedPreferences: SharedPreferences,
private val repository: AdvancedPrivacySettingsRepository
) : ViewModel() {
) : ViewModel(), NetworkConstraintObserver.NetworkListener {
private val store = Store(getState())
private val singleEvents = SingleLiveEvent<Event>()
val state: LiveData<AdvancedPrivacySettingsState> = store.stateLiveData
val events: LiveData<Event> = singleEvents
val disposables: CompositeDisposable = CompositeDisposable()
init {
NetworkConstraintObserver.getInstance(ApplicationDependencies.getApplication()).addListener(this)
disposables.add(
ApplicationDependencies.getSignalWebSocket().webSocketState
.observeOn(AndroidSchedulers.mainThread())
.subscribe { refresh() }
)
}
fun disablePushMessages() {
store.update { getState().copy(showProgressSpinner = true) }
@@ -58,21 +75,87 @@ class AdvancedPrivacySettingsViewModel(
refresh()
}
fun setCensorshipCircumventionEnabled(enabled: Boolean) {
SignalStore.settings().setCensorshipCircumventionEnabled(enabled)
ApplicationDependencies.resetNetworkConnectionsAfterProxyChange()
refresh()
}
fun refresh() {
store.update { getState().copy(showProgressSpinner = it.showProgressSpinner) }
}
private fun getState() = AdvancedPrivacySettingsState(
isPushEnabled = SignalStore.account().isRegistered,
alwaysRelayCalls = TextSecurePreferences.isTurnOnly(ApplicationDependencies.getApplication()),
showSealedSenderStatusIcon = TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(
ApplicationDependencies.getApplication()
),
allowSealedSenderFromAnyone = TextSecurePreferences.isUniversalUnidentifiedAccess(
ApplicationDependencies.getApplication()
),
false
)
override fun onNetworkChanged() {
refresh()
}
override fun onCleared() {
NetworkConstraintObserver.getInstance(ApplicationDependencies.getApplication()).removeListener(this)
disposables.dispose()
}
private fun getState(): AdvancedPrivacySettingsState {
val censorshipCircumventionState = getCensorshipCircumventionState()
return AdvancedPrivacySettingsState(
isPushEnabled = SignalStore.account().isRegistered,
alwaysRelayCalls = TextSecurePreferences.isTurnOnly(ApplicationDependencies.getApplication()),
censorshipCircumventionState = censorshipCircumventionState,
censorshipCircumventionEnabled = getCensorshipCircumventionEnabled(censorshipCircumventionState),
showSealedSenderStatusIcon = TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(
ApplicationDependencies.getApplication()
),
allowSealedSenderFromAnyone = TextSecurePreferences.isUniversalUnidentifiedAccess(
ApplicationDependencies.getApplication()
),
false
)
}
private fun getCensorshipCircumventionState(): CensorshipCircumventionState {
val countryCode: Int = PhoneNumberFormatter.getLocalCountryCode()
val isCountryCodeCensoredByDefault: Boolean = ApplicationDependencies.getSignalServiceNetworkAccess().isCountryCodeCensoredByDefault(countryCode)
val enabledState: SettingsValues.CensorshipCircumventionEnabled = SignalStore.settings().censorshipCircumventionEnabled
val hasInternet: Boolean = NetworkConstraint.isMet(ApplicationDependencies.getApplication())
val websocketConnected: Boolean = ApplicationDependencies.getSignalWebSocket().webSocketState.firstOrError().blockingGet() == WebSocketConnectionState.CONNECTED
return when {
SignalStore.internalValues().allowChangingCensorshipSetting() -> {
CensorshipCircumventionState.AVAILABLE
}
isCountryCodeCensoredByDefault && enabledState == SettingsValues.CensorshipCircumventionEnabled.DISABLED -> {
CensorshipCircumventionState.AVAILABLE_MANUALLY_DISABLED
}
isCountryCodeCensoredByDefault -> {
CensorshipCircumventionState.AVAILABLE_AUTOMATICALLY_ENABLED
}
!hasInternet && enabledState != SettingsValues.CensorshipCircumventionEnabled.ENABLED -> {
CensorshipCircumventionState.UNAVAILABLE_NO_INTERNET
}
websocketConnected && enabledState != SettingsValues.CensorshipCircumventionEnabled.ENABLED -> {
CensorshipCircumventionState.UNAVAILABLE_CONNECTED
}
else -> {
CensorshipCircumventionState.AVAILABLE
}
}
}
private fun getCensorshipCircumventionEnabled(state: CensorshipCircumventionState): Boolean {
return when (state) {
CensorshipCircumventionState.UNAVAILABLE_CONNECTED,
CensorshipCircumventionState.UNAVAILABLE_NO_INTERNET,
CensorshipCircumventionState.AVAILABLE_MANUALLY_DISABLED -> {
false
}
CensorshipCircumventionState.AVAILABLE_AUTOMATICALLY_ENABLED -> {
true
}
else -> {
SignalStore.settings().censorshipCircumventionEnabled == SettingsValues.CensorshipCircumventionEnabled.ENABLED
}
}
}
enum class Event {
DISABLE_PUSH_FAILED