mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-07-01 03:26:01 +01:00
Improve handling of devices without Play Services.
This commit is contained in:
committed by
Michelle Tang
parent
0beda1e615
commit
baa4dd3c86
@@ -91,6 +91,7 @@ import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
|
||||
import org.thoughtcrime.securesms.logging.PersistentLogger;
|
||||
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity;
|
||||
import org.thoughtcrime.securesms.messageprocessingalarm.RoutineMessageFetchReceiver;
|
||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
|
||||
import org.thoughtcrime.securesms.mms.SignalGlideModule;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
@@ -454,22 +455,27 @@ public class ApplicationContext extends Application implements AppForegroundObse
|
||||
PlayServicesUtil.PlayServicesStatus playServicesStatus = PlayServicesUtil.getPlayServicesStatus(this);
|
||||
|
||||
if (playServicesStatus == PlayServicesUtil.PlayServicesStatus.SUCCESS && !SignalStore.account().isFcmEnabled()) {
|
||||
Log.i(TAG, "Play Services are newly-available. Enabling FCM and updating server.");
|
||||
Log.w(TAG, "Play Services are newly-available. Enabling FCM and updating server.");
|
||||
SignalStore.account().setFcmEnabled(true);
|
||||
AppDependencies.getJobManager().startChain(new FcmRefreshJob())
|
||||
.then(new RefreshAttributesJob())
|
||||
.enqueue();
|
||||
AppDependencies.resetNetwork();
|
||||
AppDependencies.startNetwork();
|
||||
IncomingMessageObserver.stopForegroundService(this);
|
||||
} else if (playServicesStatus == PlayServicesUtil.PlayServicesStatus.MISSING && SignalStore.account().isFcmEnabled()) {
|
||||
Log.w(TAG, "Play Services are no longer available. Disabling FCM and updating server.");
|
||||
SignalStore.account().setFcmEnabled(false);
|
||||
SignalStore.account().setFcmToken(null);
|
||||
AppDependencies.getJobManager().add(new RefreshAttributesJob());
|
||||
Log.w(TAG, "Play Services are no longer available. Attempting to get an FCM token anyway.");
|
||||
AppDependencies.getJobManager().add(new FcmRefreshJob());
|
||||
} else if (playServicesStatus == PlayServicesUtil.PlayServicesStatus.MISSING && (System.currentTimeMillis() - SignalStore.misc().getLastMissingPlayServicesFcmVerificationTime()) > TimeUnit.DAYS.toMillis(3)) {
|
||||
Log.i(TAG, "Play Services are unavailable, but it's been long enough that we should check and see if we can get an FCM token anyway.");
|
||||
AppDependencies.getJobManager().add(new FcmRefreshJob());
|
||||
} else if (SignalStore.account().isFcmEnabled()) {
|
||||
long lastSetTime = SignalStore.account().getFcmTokenLastSetTime();
|
||||
long nextSetTime = lastSetTime + TimeUnit.HOURS.toMillis(6);
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (SignalStore.account().getFcmToken() == null || nextSetTime <= now || lastSetTime > now) {
|
||||
Log.i(TAG, "Time for routine FCM token refresh.");
|
||||
AppDependencies.getJobManager().add(new FcmRefreshJob());
|
||||
}
|
||||
} else {
|
||||
|
||||
+44
-1
@@ -17,6 +17,7 @@ import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.signal.core.ui.compose.ComposeFragment
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Dialogs
|
||||
import org.signal.core.ui.compose.Dividers
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.Rows
|
||||
@@ -90,6 +91,18 @@ class DataAndStorageSettingsFragment : ComposeFragment() {
|
||||
override fun onRoamingDataAutoDownloadSelectionChanged(selection: Array<String>) {
|
||||
viewModel.setRoamingAutoDownloadValues(selection.toSet())
|
||||
}
|
||||
|
||||
override fun onForceWebsocketModeChanged(enabled: Boolean) {
|
||||
viewModel.onForceWebsocketModeToggled(enabled)
|
||||
}
|
||||
|
||||
override fun onConfirmStayConnectedInBackground() {
|
||||
viewModel.confirmStayConnectedInBackground()
|
||||
}
|
||||
|
||||
override fun onDismissStayConnectedInBackgroundDialog() {
|
||||
viewModel.dismissStayConnectedInBackgroundDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +115,9 @@ private interface DataAndStorageSettingsCallbacks {
|
||||
fun onMobileDataAutoDownloadSelectionChanged(selection: Array<String>) = Unit
|
||||
fun onWifiDataAutoDownloadSelectionChanged(selection: Array<String>) = Unit
|
||||
fun onRoamingDataAutoDownloadSelectionChanged(selection: Array<String>) = Unit
|
||||
fun onForceWebsocketModeChanged(enabled: Boolean) = Unit
|
||||
fun onConfirmStayConnectedInBackground() = Unit
|
||||
fun onDismissStayConnectedInBackgroundDialog() = Unit
|
||||
|
||||
object Empty : DataAndStorageSettingsCallbacks
|
||||
}
|
||||
@@ -252,6 +268,19 @@ private fun DataAndStorageSettingsScreen(
|
||||
Dividers.Default()
|
||||
}
|
||||
|
||||
item {
|
||||
Rows.ToggleRow(
|
||||
checked = state.forceWebsocketMode || !state.playServicesAvailable,
|
||||
text = stringResource(R.string.DataAndStorageSettingsFragment__stay_connected_in_background),
|
||||
enabled = state.playServicesAvailable,
|
||||
onCheckChanged = callbacks::onForceWebsocketModeChanged
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Dividers.Default()
|
||||
}
|
||||
|
||||
item {
|
||||
Texts.SectionHeader(stringResource(R.string.preferences_proxy))
|
||||
}
|
||||
@@ -264,6 +293,17 @@ private fun DataAndStorageSettingsScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.showStayConnectedDialog) {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = "",
|
||||
body = stringResource(R.string.DataAndStorageSettingsFragment__staying_connected_while_in_the_background_will_likely_result_in_increased_battery_usage),
|
||||
confirm = stringResource(R.string.DataAndStorageSettingsFragment__enable),
|
||||
dismiss = stringResource(android.R.string.cancel),
|
||||
onConfirm = callbacks::onConfirmStayConnectedInBackground,
|
||||
onDismiss = callbacks::onDismissStayConnectedInBackgroundDialog
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +319,10 @@ private fun DataAndStorageSettingsScreenPreview() {
|
||||
roamingAutoDownloadValues = setOf(),
|
||||
callDataMode = CallDataMode.HIGH_ALWAYS,
|
||||
isProxyEnabled = false,
|
||||
sentMediaQuality = SentMediaQuality.STANDARD
|
||||
sentMediaQuality = SentMediaQuality.STANDARD,
|
||||
forceWebsocketMode = false,
|
||||
playServicesAvailable = true,
|
||||
showStayConnectedDialog = false
|
||||
),
|
||||
callbacks = DataAndStorageSettingsCallbacks.Empty
|
||||
)
|
||||
|
||||
+4
-1
@@ -10,5 +10,8 @@ data class DataAndStorageSettingsState(
|
||||
val roamingAutoDownloadValues: Set<String>,
|
||||
val callDataMode: CallDataMode,
|
||||
val isProxyEnabled: Boolean,
|
||||
val sentMediaQuality: SentMediaQuality
|
||||
val sentMediaQuality: SentMediaQuality,
|
||||
val forceWebsocketMode: Boolean,
|
||||
val playServicesAvailable: Boolean,
|
||||
val showStayConnectedDialog: Boolean
|
||||
)
|
||||
|
||||
+35
-3
@@ -7,8 +7,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SettingsValues.ForceWebsocketMode
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver
|
||||
import org.thoughtcrime.securesms.mms.SentMediaQuality
|
||||
import org.thoughtcrime.securesms.util.PlayServicesUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.webrtc.CallDataMode
|
||||
|
||||
@@ -23,7 +26,7 @@ class DataAndStorageSettingsViewModel(
|
||||
|
||||
fun refresh() {
|
||||
repository.getTotalStorageUse { totalStorageUse ->
|
||||
store.update { getState().copy(totalStorageUse = totalStorageUse) }
|
||||
store.update { getState().copy(totalStorageUse = totalStorageUse, showStayConnectedDialog = it.showStayConnectedDialog) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +56,34 @@ class DataAndStorageSettingsViewModel(
|
||||
getStateAndCopyStorageUsage()
|
||||
}
|
||||
|
||||
fun onForceWebsocketModeToggled(enabled: Boolean) {
|
||||
if (enabled) {
|
||||
store.update { it.copy(showStayConnectedDialog = true) }
|
||||
} else {
|
||||
applyForceWebsocketMode(false)
|
||||
}
|
||||
}
|
||||
|
||||
fun confirmStayConnectedInBackground() {
|
||||
applyForceWebsocketMode(true)
|
||||
}
|
||||
|
||||
fun dismissStayConnectedInBackgroundDialog() {
|
||||
store.update { it.copy(showStayConnectedDialog = false) }
|
||||
}
|
||||
|
||||
private fun applyForceWebsocketMode(enabled: Boolean) {
|
||||
SignalStore.settings.forceWebsocketMode = if (enabled) ForceWebsocketMode.ENABLED_BY_USER else ForceWebsocketMode.DISABLED
|
||||
if (!enabled) {
|
||||
IncomingMessageObserver.stopForegroundService(AppDependencies.application)
|
||||
}
|
||||
AppDependencies.resetNetwork()
|
||||
AppDependencies.startNetwork()
|
||||
getStateAndCopyStorageUsage()
|
||||
}
|
||||
|
||||
private fun getStateAndCopyStorageUsage() {
|
||||
store.update { getState().copy(totalStorageUse = it.totalStorageUse) }
|
||||
store.update { getState().copy(totalStorageUse = it.totalStorageUse, showStayConnectedDialog = it.showStayConnectedDialog) }
|
||||
}
|
||||
|
||||
private fun getState() = DataAndStorageSettingsState(
|
||||
@@ -70,7 +99,10 @@ class DataAndStorageSettingsViewModel(
|
||||
),
|
||||
callDataMode = SignalStore.settings.callDataMode,
|
||||
isProxyEnabled = SignalStore.proxy.isProxyEnabled,
|
||||
sentMediaQuality = SignalStore.settings.sentMediaQuality
|
||||
sentMediaQuality = SignalStore.settings.sentMediaQuality,
|
||||
forceWebsocketMode = SignalStore.settings.forceWebsocketMode.isEnabled,
|
||||
playServicesAvailable = PlayServicesUtil.getPlayServicesStatus(AppDependencies.application) == PlayServicesUtil.PlayServicesStatus.SUCCESS,
|
||||
showStayConnectedDialog = false
|
||||
)
|
||||
|
||||
class Factory(
|
||||
|
||||
-20
@@ -83,7 +83,6 @@ import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.max
|
||||
import kotlin.random.Random
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__internal_preferences) {
|
||||
|
||||
@@ -511,25 +510,6 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
|
||||
sectionHeaderPref(DSLSettingsText.from("Network"))
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from("Force websocket mode"),
|
||||
summary = DSLSettingsText.from("Pretend you have no Play Services. Ignores websocket messages and keeps the websocket open in a foreground service. You have to manually force-stop the app for changes to take effect."),
|
||||
isChecked = state.forceWebsocketMode,
|
||||
onClick = {
|
||||
viewModel.setForceWebsocketMode(!state.forceWebsocketMode)
|
||||
SimpleTask.run({
|
||||
val jobState = AppDependencies.jobManager.runSynchronously(RefreshAttributesJob(), 10.seconds.inWholeMilliseconds)
|
||||
return@run jobState.isPresent && jobState.get().isComplete
|
||||
}, { success ->
|
||||
if (success) {
|
||||
Toast.makeText(context, "Successfully refreshed attributes. Force-stop the app for changes to take effect.", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(context, "Failed to refresh attributes.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from("Allow censorship circumvention toggle"),
|
||||
summary = DSLSettingsText.from("Allow changing the censorship circumvention toggle regardless of network connectivity."),
|
||||
|
||||
-1
@@ -10,7 +10,6 @@ data class InternalSettingsState(
|
||||
val gv2forceInvites: Boolean,
|
||||
val gv2ignoreP2PChanges: Boolean,
|
||||
val allowCensorshipSetting: Boolean,
|
||||
val forceWebsocketMode: Boolean,
|
||||
val callingServer: String,
|
||||
val callingDataMode: CallManager.DataMode,
|
||||
val callingDisableTelecom: Boolean,
|
||||
|
||||
-6
@@ -70,11 +70,6 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setForceWebsocketMode(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.FORCE_WEBSOCKET_MODE, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun resetPnpInitializedState() {
|
||||
SignalStore.misc.hasPniInitializedDevices = false
|
||||
refresh()
|
||||
@@ -182,7 +177,6 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
|
||||
gv2forceInvites = SignalStore.internal.gv2ForceInvites,
|
||||
gv2ignoreP2PChanges = SignalStore.internal.gv2IgnoreP2PChanges,
|
||||
allowCensorshipSetting = SignalStore.internal.allowChangingCensorshipSetting,
|
||||
forceWebsocketMode = SignalStore.internal.isWebsocketModeForced,
|
||||
callingServer = SignalStore.internal.groupCallingServer,
|
||||
callingDataMode = SignalStore.internal.callingDataMode,
|
||||
callingDisableTelecom = SignalStore.internal.callingDisableTelecom,
|
||||
|
||||
+2
-2
@@ -380,7 +380,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
|
||||
|
||||
@Override
|
||||
public @NonNull SignalWebSocket.AuthenticatedWebSocket provideAuthWebSocket(@NonNull Supplier<SignalServiceConfiguration> signalServiceConfigurationSupplier, @NonNull Supplier<Network> libSignalNetworkSupplier) {
|
||||
SleepTimer sleepTimer = !SignalStore.account().isFcmEnabled() || SignalStore.internal().isWebsocketModeForced() ? new AlarmSleepTimer(context) : new UptimeSleepTimer();
|
||||
SleepTimer sleepTimer = !SignalStore.account().isFcmEnabled() || SignalStore.settings().getForceWebsocketMode().isEnabled() ? new AlarmSleepTimer(context) : new UptimeSleepTimer();
|
||||
SignalWebSocketHealthMonitor healthMonitor = new SignalWebSocketHealthMonitor(sleepTimer, true);
|
||||
|
||||
WebSocketFactory authFactory = () -> {
|
||||
@@ -413,7 +413,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
|
||||
|
||||
@Override
|
||||
public @NonNull SignalWebSocket.UnauthenticatedWebSocket provideUnauthWebSocket(@NonNull Supplier<SignalServiceConfiguration> signalServiceConfigurationSupplier, @NonNull Supplier<Network> libSignalNetworkSupplier) {
|
||||
SleepTimer sleepTimer = !SignalStore.account().isFcmEnabled() || SignalStore.internal().isWebsocketModeForced() ? new AlarmSleepTimer(context) : new UptimeSleepTimer();
|
||||
SleepTimer sleepTimer = !SignalStore.account().isFcmEnabled() || SignalStore.settings().getForceWebsocketMode().isEnabled() ? new AlarmSleepTimer(context) : new UptimeSleepTimer();
|
||||
SignalWebSocketHealthMonitor healthMonitor = new SignalWebSocketHealthMonitor(sleepTimer, false);
|
||||
|
||||
WebSocketFactory unauthFactory = () -> {
|
||||
|
||||
@@ -27,9 +27,12 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.gcm.FcmUtil;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.keyvalue.SettingsValues.ForceWebsocketMode;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.util.PlayServicesUtil;
|
||||
import org.whispersystems.signalservice.api.NetworkResultUtil;
|
||||
import org.signal.network.exceptions.NonSuccessfulResponseCodeException;
|
||||
|
||||
@@ -69,20 +72,20 @@ public class FcmRefreshJob extends BaseJob {
|
||||
|
||||
@Override
|
||||
public void onRun() throws Exception {
|
||||
if (!SignalStore.account().isFcmEnabled()) return;
|
||||
|
||||
Log.i(TAG, "Reregistering FCM...");
|
||||
|
||||
int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
|
||||
|
||||
if (result != ConnectionResult.SUCCESS) {
|
||||
Log.w(TAG, "Play Services are unavailable. Skipping FCM refresh.");
|
||||
return;
|
||||
boolean playServicesMissing = PlayServicesUtil.getPlayServicesStatus(context) == PlayServicesUtil.PlayServicesStatus.MISSING ;
|
||||
if (playServicesMissing) {
|
||||
Log.w(TAG, "Play Services are unavailable.");
|
||||
}
|
||||
|
||||
Optional<String> token = FcmUtil.getToken(context);
|
||||
|
||||
if (token.isPresent()) {
|
||||
if (playServicesMissing) {
|
||||
Log.w(TAG, "We were able to get a token despite Play Services being missing!");
|
||||
}
|
||||
|
||||
String oldToken = SignalStore.account().getFcmToken();
|
||||
|
||||
if (!token.get().equals(oldToken)) {
|
||||
@@ -94,6 +97,23 @@ public class FcmRefreshJob extends BaseJob {
|
||||
|
||||
NetworkResultUtil.toBasicLegacy(SignalNetwork.account().setFcmToken(token.get()));
|
||||
SignalStore.account().setFcmToken(token.get());
|
||||
|
||||
if (!SignalStore.account().isFcmEnabled()) {
|
||||
Log.w(TAG, "We had no Play Services, but were still able to get an FCM token! Re-enabling.");
|
||||
SignalStore.account().setFcmEnabled(true);
|
||||
AppDependencies.getJobManager().add(new RefreshAttributesJob());
|
||||
AppDependencies.resetNetwork();
|
||||
AppDependencies.startNetwork();
|
||||
IncomingMessageObserver.stopForegroundService(context);
|
||||
}
|
||||
|
||||
if (SignalStore.settings().getForceWebsocketMode() == ForceWebsocketMode.ENABLED_AUTOMATICALLY) {
|
||||
Log.i(TAG, "FCM succeeded while in auto-enabled websocket mode. Reverting to disabled.");
|
||||
SignalStore.settings().setForceWebsocketMode(ForceWebsocketMode.DISABLED);
|
||||
IncomingMessageObserver.stopForegroundService(context);
|
||||
AppDependencies.resetNetwork();
|
||||
AppDependencies.startNetwork();
|
||||
}
|
||||
} else {
|
||||
throw new RetryLaterException(new IOException("Failed to retrieve a token."));
|
||||
}
|
||||
@@ -102,6 +122,30 @@ public class FcmRefreshJob extends BaseJob {
|
||||
@Override
|
||||
public void onFailure() {
|
||||
Log.w(TAG, "FCM reregistration failed after retry attempt exhaustion!");
|
||||
|
||||
PlayServicesUtil.PlayServicesStatus status = PlayServicesUtil.getPlayServicesStatus(context);
|
||||
|
||||
if (status == PlayServicesUtil.PlayServicesStatus.MISSING) {
|
||||
Log.w(TAG, "This was a check where we tried to get a token despite having no Play Services. We failed. Marking down the time.");
|
||||
SignalStore.misc().setLastMissingPlayServicesFcmVerificationTime(System.currentTimeMillis());
|
||||
|
||||
if (SignalStore.account().isFcmEnabled()) {
|
||||
Log.w(TAG, "Play Services are no longer available, and we failed to fetch a token. Disabling FCM.");
|
||||
SignalStore.account().setFcmEnabled(false);
|
||||
SignalStore.account().setFcmToken(null);
|
||||
AppDependencies.getJobManager().add(new RefreshAttributesJob());
|
||||
AppDependencies.resetNetwork();
|
||||
AppDependencies.startNetwork();
|
||||
}
|
||||
} else if (status == PlayServicesUtil.PlayServicesStatus.SUCCESS &&
|
||||
SignalStore.settings().getForceWebsocketMode() == ForceWebsocketMode.DISABLED &&
|
||||
System.currentTimeMillis() - SignalStore.account().getFcmTokenLastSetTime() > TimeUnit.DAYS.toMillis(3))
|
||||
{
|
||||
Log.w(TAG, "FCM has been failing for over 3 days despite Play Services being available. Auto-enabling forced websocket mode so the user can still get messages.");
|
||||
SignalStore.settings().setForceWebsocketMode(ForceWebsocketMode.ENABLED_AUTOMATICALLY);
|
||||
AppDependencies.resetNetwork();
|
||||
AppDependencies.startNetwork();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -96,7 +96,7 @@ public class RefreshAttributesJob extends BaseJob {
|
||||
}
|
||||
|
||||
int registrationId = SignalStore.account().getRegistrationId();
|
||||
boolean fetchesMessages = !SignalStore.account().isFcmEnabled() || SignalStore.internal().isWebsocketModeForced();
|
||||
boolean fetchesMessages = !SignalStore.account().isFcmEnabled() || SignalStore.settings().getForceWebsocketMode().isEnabled();
|
||||
byte[] unidentifiedAccessKey = UnidentifiedAccess.deriveAccessKeyFrom(ProfileKeyUtil.getSelfProfileKey());
|
||||
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
|
||||
String registrationLockV2 = null;
|
||||
|
||||
@@ -26,7 +26,6 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
const val CALLING_USE_INPUT_VOICE_COMM: String = "internal.calling_use_input_voice_comm"
|
||||
const val SHAKE_TO_REPORT: String = "internal.shake_to_report"
|
||||
const val DISABLE_STORAGE_SERVICE: String = "internal.disable_storage_service"
|
||||
const val FORCE_WEBSOCKET_MODE: String = "internal.force_websocket_mode"
|
||||
const val LAST_SCROLL_POSITION: String = "internal.last_scroll_position"
|
||||
const val CONVERSATION_ITEM_V2_MEDIA: String = "internal.conversation_item_v2_media"
|
||||
const val WEB_SOCKET_SHADOWING_STATS: String = "internal.web_socket_shadowing_stats"
|
||||
@@ -170,11 +169,6 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
*/
|
||||
var callingUseInputVoiceComm by booleanValue(CALLING_USE_INPUT_VOICE_COMM, true).defaultForExternalUsers()
|
||||
|
||||
/**
|
||||
* Whether or not the system is forced to be in 'websocket mode', where FCM is ignored and we use a foreground service to keep the app alive.
|
||||
*/
|
||||
var isWebsocketModeForced: Boolean by booleanValue(FORCE_WEBSOCKET_MODE, false).defaultForExternalUsers()
|
||||
|
||||
var hevcEncoding by booleanValue(ENCODE_HEVC, false).defaultForExternalUsers()
|
||||
|
||||
var lastScrollPosition: Int by integerValue(LAST_SCROLL_POSITION, 0).defaultForExternalUsers()
|
||||
|
||||
@@ -53,6 +53,7 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
|
||||
private const val CALLING_ASSETS_VERSION = "misc.calling_assets_version"
|
||||
private const val LAST_SYNC_MESSAGE_SEEN_TIME_MS = "misc.last_sync_message_seen_time"
|
||||
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"
|
||||
}
|
||||
|
||||
public override fun onFirstEverAppLaunch() {
|
||||
@@ -348,4 +349,9 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
|
||||
* if new assets need to be fetched.
|
||||
*/
|
||||
var callingAssetsVersion: Int by integerValue(CALLING_ASSETS_VERSION, 0)
|
||||
|
||||
/**
|
||||
* The last time we tried to get an FCM token for a user reporting missing Play Services.
|
||||
*/
|
||||
var lastMissingPlayServicesFcmVerificationTime: Long by longValue(LAST_MISSING_PLAY_SERVICES_FCM_VERIFICATION_TIME, 0)
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ public final class SettingsValues extends SignalStoreValues {
|
||||
private static final String SCREEN_LOCK_ENABLED = "settings.screen.lock.enabled";
|
||||
private static final String SCREEN_LOCK_TIMEOUT = "settings.screen.lock.timeout";
|
||||
private static final String AUTOMATIC_VERIFICATION_ENABLED = "settings.automatic.verification.enabled";
|
||||
private static final String FORCE_WEBSOCKET_MODE = "settings.force.websocket.mode.2";
|
||||
|
||||
public static final int BACKUP_DEFAULT_HOUR = 2;
|
||||
public static final int BACKUP_DEFAULT_MINUTE = 0;
|
||||
@@ -570,6 +571,17 @@ public final class SettingsValues extends SignalStoreValues {
|
||||
putBoolean(AUTOMATIC_VERIFICATION_ENABLED, enabled);
|
||||
}
|
||||
|
||||
public @NonNull ForceWebsocketMode getForceWebsocketMode() {
|
||||
if (getStore().containsKey(FORCE_WEBSOCKET_MODE)) {
|
||||
return ForceWebsocketMode.deserialize(getInteger(FORCE_WEBSOCKET_MODE, ForceWebsocketMode.DISABLED.serialize()));
|
||||
}
|
||||
return getBoolean(FORCE_WEBSOCKET_MODE, false) ? ForceWebsocketMode.ENABLED_BY_USER : ForceWebsocketMode.DISABLED;
|
||||
}
|
||||
|
||||
public void setForceWebsocketMode(@NonNull ForceWebsocketMode mode) {
|
||||
putInteger(FORCE_WEBSOCKET_MODE, mode.serialize());
|
||||
}
|
||||
|
||||
private @Nullable Uri getUri(@NonNull String key) {
|
||||
String uri = getString(key, "");
|
||||
|
||||
@@ -607,6 +619,37 @@ public final class SettingsValues extends SignalStoreValues {
|
||||
}
|
||||
}
|
||||
|
||||
public enum ForceWebsocketMode {
|
||||
DISABLED(0), ENABLED_BY_USER(1), ENABLED_AUTOMATICALLY(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
ForceWebsocketMode(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this != DISABLED;
|
||||
}
|
||||
|
||||
public int serialize() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ForceWebsocketMode deserialize(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return DISABLED;
|
||||
case 1:
|
||||
return ENABLED_BY_USER;
|
||||
case 2:
|
||||
return ENABLED_AUTOMATICALLY;
|
||||
default:
|
||||
throw new IllegalArgumentException("Bad value: " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Theme {
|
||||
SYSTEM("system"), LIGHT("light"), DARK("dark");
|
||||
|
||||
|
||||
@@ -93,6 +93,14 @@ class IncomingMessageObserver(
|
||||
|
||||
private val censored: Boolean
|
||||
get() = AppDependencies.signalServiceNetworkAccess.isCensored()
|
||||
|
||||
/**
|
||||
* Stops the foreground service for websocket users.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun stopForegroundService(context: Context) {
|
||||
context.stopService(Intent(context, ForegroundService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
private val decryptionDrainedListeners: MutableList<Runnable> = CopyOnWriteArrayList()
|
||||
@@ -147,7 +155,7 @@ class IncomingMessageObserver(
|
||||
|
||||
MessageRetrievalThread().start()
|
||||
|
||||
if (!SignalStore.account.fcmEnabled || SignalStore.internal.isWebsocketModeForced) {
|
||||
if (!SignalStore.account.fcmEnabled || SignalStore.settings.forceWebsocketMode.isEnabled) {
|
||||
try {
|
||||
ForegroundServiceUtil.start(context, Intent(context, ForegroundService::class.java))
|
||||
} catch (e: UnableToStartException) {
|
||||
@@ -244,7 +252,7 @@ class IncomingMessageObserver(
|
||||
val fcmEnabled = SignalStore.account.fcmEnabled
|
||||
val hasNetwork = NetworkConstraint.isMet(context)
|
||||
val hasProxy = SignalStore.proxy.isProxyEnabled
|
||||
val forceWebsocket = SignalStore.internal.isWebsocketModeForced
|
||||
val forceWebsocket = SignalStore.settings.forceWebsocketMode.isEnabled
|
||||
val websocketAlreadyOpen = isConnectionAvailable()
|
||||
|
||||
val lastInteractionString = if (appVisibleSnapshot) "N/A" else timeIdle.toString() + " ms (" + (if (timeIdle < maxBackgroundTime) "within limit" else "over limit") + ")"
|
||||
@@ -431,7 +439,7 @@ class IncomingMessageObserver(
|
||||
Log.i(TAG, "Initializing! (${this.hashCode()})")
|
||||
uncaughtExceptionHandler = this
|
||||
|
||||
sleepTimer = if (!SignalStore.account.fcmEnabled || SignalStore.internal.isWebsocketModeForced) AlarmSleepTimer(context) else UptimeSleepTimer()
|
||||
sleepTimer = if (!SignalStore.account.fcmEnabled || SignalStore.settings.forceWebsocketMode.isEnabled) AlarmSleepTimer(context) else UptimeSleepTimer()
|
||||
|
||||
canProcessMessages = !SignalStore.registration.restoreDecisionState.isDecisionPending
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user