diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/quality/CallQuality.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/quality/CallQuality.kt index fa3dff2669..157dba0c1a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/quality/CallQuality.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/quality/CallQuality.kt @@ -10,6 +10,7 @@ import org.signal.ringrtc.CallSummary import org.signal.ringrtc.GroupCall import org.signal.storageservice.protos.calls.quality.SubmitCallQualitySurveyRequest import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.util.LocaleRemoteConfig import org.thoughtcrime.securesms.util.RemoteConfig import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.milliseconds @@ -71,10 +72,19 @@ object CallQuality { } } + /** + * Consumes any pending request. We will automatically filter out requests if they're over five minutes old. + */ fun consumeQualityRequest(): SubmitCallQualitySurveyRequest? { - val request = SignalStore.callQuality.surveyRequest + val request = SignalStore.callQuality.surveyRequest ?: return null SignalStore.callQuality.surveyRequest = null - return if (isFeatureEnabled()) request else null + + val fiveMinutesAgo = System.currentTimeMillis().milliseconds - 5.minutes + return if (!isFeatureEnabled() || request.end_timestamp.milliseconds < fiveMinutesAgo) { + null + } else { + request + } } private fun isCallQualitySurveyRequired(callSummary: CallSummary): Boolean { @@ -109,8 +119,8 @@ object CallQuality { return true } - val chance = RemoteConfig.callQualitySurveyPercent - val roll = (0 until 100).random() + val chance = LocaleRemoteConfig.getCallQualitySurveyPartsPerMillion() + val roll = (0 until 1_000_000).random() if (roll < chance) { return true diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/LocaleRemoteConfig.java b/app/src/main/java/org/thoughtcrime/securesms/util/LocaleRemoteConfig.java index 725e983c65..f834ff0ca0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/LocaleRemoteConfig.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/LocaleRemoteConfig.java @@ -82,6 +82,10 @@ public final class LocaleRemoteConfig { return isEnabledPartsPerMillion(RemoteConfig.DEVICE_SPECIFIC_NOTIFICATION_CONFIG, DeviceSpecificNotificationConfig.getCurrentConfig().getLocalePercent()); } + public static long getCallQualitySurveyPartsPerMillion() { + return getPartsPerMillion(RemoteConfig.callQualitySurveyPPM()); + } + /** * Parses a comma-separated list of country codes and area codes to check if self's e164 starts with * one of them. For example, "33,1555" will return turn for e164's that start with 33 or look like 1-555-xxx-xxx. @@ -104,6 +108,17 @@ public final class LocaleRemoteConfig { return countryAndAreaCodes.stream().anyMatch(e164Numbers::startsWith); } + private static long getPartsPerMillion(@NonNull String serialized) { + Map countryCodeValues = parseCountryValues(serialized, 0); + Recipient self = Recipient.self(); + + if (countryCodeValues.isEmpty() || !self.getE164().isPresent() || !self.getServiceId().isPresent()) { + return 0L; + } + + return getCountryValue(countryCodeValues, self.getE164().orElse(""), 0); + } + /** * Parses a comma-separated list of country codes colon-separated from how many buckets out of 1 million * should be enabled to see this megaphone in that country code. At the end of the list, an optional @@ -112,15 +127,9 @@ public final class LocaleRemoteConfig { * the world should see the megaphone. */ private static boolean isEnabledPartsPerMillion(@NonNull String flag, @NonNull String serialized) { - Map countryCodeValues = parseCountryValues(serialized, 0); - Recipient self = Recipient.self(); - - if (countryCodeValues.isEmpty() || !self.getE164().isPresent() || !self.getServiceId().isPresent()) { - return false; - } - - long countEnabled = getCountryValue(countryCodeValues, self.getE164().orElse(""), 0); - long currentUserBucket = BucketingUtil.bucket(flag, self.requireAci().getRawUuid(), 1_000_000); + Recipient self = Recipient.self(); + long countEnabled = getPartsPerMillion(serialized); + long currentUserBucket = BucketingUtil.bucket(flag, self.requireAci().getRawUuid(), 1_000_000); return countEnabled > currentUserBucket; } 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 5410604922..a12e6b9779 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt @@ -1226,16 +1226,16 @@ object RemoteConfig { @JvmStatic @get:JvmName("callQualitySurvey") val callQualitySurvey: Boolean by remoteBoolean( - key = "android.callQualitySurvey.3", + key = "android.callQualitySurvey.4", defaultValue = false, hotSwappable = true ) @JvmStatic - @get:JvmName("callQualitySurveyPercent") - val callQualitySurveyPercent: Int by remoteInt( - key = "android.callQualitySurveyPercent", - defaultValue = 1, + @get:JvmName("callQualitySurveyPPM") + val callQualitySurveyPPM: String by remoteString( + key = "android.callQualitySurveyPPM", + defaultValue = "*:10000", hotSwappable = true ) // endregion diff --git a/app/src/test/java/org/thoughtcrime/securesms/util/LocaleRemoteConfigTest_getCountryValue.java b/app/src/test/java/org/thoughtcrime/securesms/util/LocaleRemoteConfigTest_getCountryValue.java index e82a3f2eb6..8965927435 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/util/LocaleRemoteConfigTest_getCountryValue.java +++ b/app/src/test/java/org/thoughtcrime/securesms/util/LocaleRemoteConfigTest_getCountryValue.java @@ -79,5 +79,4 @@ public class LocaleRemoteConfigTest_getCountryValue { public void determineCountEnabled() { assertEquals(output, LocaleRemoteConfig.getCountryValue(countryCounts, phoneNumber, 0)); } - }