diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/LocaleFeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/LocaleFeatureFlags.java index 07a2387af0..091504a74c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/LocaleFeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/LocaleFeatureFlags.java @@ -10,9 +10,12 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.mms.PushMediaConstraints; import org.thoughtcrime.securesms.recipients.Recipient; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; /** * Provide access to locale specific values within feature flags following the locale CSV-Colon format. @@ -30,7 +33,7 @@ public final class LocaleFeatureFlags { * In donate megaphone group for given country code */ public static boolean isInDonateMegaphone() { - return isEnabled(FeatureFlags.DONATE_MEGAPHONE, FeatureFlags.donateMegaphone()); + return isEnabledPartsPerMillion(FeatureFlags.DONATE_MEGAPHONE, FeatureFlags.donateMegaphone()); } public static @NonNull Optional getMediaQualityLevel() { @@ -41,44 +44,66 @@ public final class LocaleFeatureFlags { } public static boolean shouldShowReleaseNote(@NonNull String releaseNoteUuid, @NonNull String countries) { - return isEnabled(releaseNoteUuid, countries); + return isEnabledPartsPerMillion(releaseNoteUuid, countries); } /** * @return Whether Google Pay is disabled in this region */ public static boolean isGooglePayDisabled() { - return isEnabled(FeatureFlags.GOOGLE_PAY_DISABLED_REGIONS, FeatureFlags.googlePayDisabledRegions()); + return isEnabledE164Start(FeatureFlags.googlePayDisabledRegions()); } /** * @return Whether credit cards are disabled in this region */ public static boolean isCreditCardDisabled() { - return isEnabled(FeatureFlags.CREDIT_CARD_DISABLED_REGIONS, FeatureFlags.creditCardDisabledRegions()); + return isEnabledE164Start(FeatureFlags.creditCardDisabledRegions()); } /** * @return Whether PayPal is disabled in this region */ public static boolean isPayPalDisabled() { - return isEnabled(FeatureFlags.PAYPAL_DISABLED_REGIONS, FeatureFlags.paypalDisabledRegions()); + return isEnabledE164Start(FeatureFlags.paypalDisabledRegions()); } public static boolean isIdealEnabled() { - return isEnabled(FeatureFlags.IDEAL_ENABLED_REGIONS, FeatureFlags.idealEnabledRegions()); + return isEnabledE164Start(FeatureFlags.idealEnabledRegions()); } public static boolean isSepaEnabled() { - return isEnabled(FeatureFlags.SEPA_ENABLED_REGIONS, FeatureFlags.sepaEnabledRegions()); + return isEnabledE164Start(FeatureFlags.sepaEnabledRegions()); } public static boolean isDelayedNotificationPromptEnabled() { - return FeatureFlags.internalUser() || isEnabled(FeatureFlags.PROMPT_FOR_NOTIFICATION_LOGS, FeatureFlags.promptForDelayedNotificationLogs()); + return FeatureFlags.internalUser() || isEnabledPartsPerMillion(FeatureFlags.PROMPT_FOR_NOTIFICATION_LOGS, FeatureFlags.promptForDelayedNotificationLogs()); } public static boolean isBatterySaverPromptEnabled() { - return FeatureFlags.internalUser() || isEnabled(FeatureFlags.PROMPT_BATTERY_SAVER, FeatureFlags.promptBatterySaver()); + return FeatureFlags.internalUser() || isEnabledPartsPerMillion(FeatureFlags.PROMPT_BATTERY_SAVER, FeatureFlags.promptBatterySaver()); + } + + /** + * 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. + */ + private static boolean isEnabledE164Start(@NonNull String serialized) { + Recipient self = Recipient.self(); + + if (self.getE164().isEmpty()) { + return false; + } + + return isEnabledE164Start(serialized, self.getE164().get()); + } + + @VisibleForTesting + static boolean isEnabledE164Start(@NonNull String serialized, @NonNull String e164) { + List countryAndAreaCodes = Arrays.stream(serialized.split(",")).map(s -> s.trim().replaceAll("\\s", "")).collect(Collectors.toList()); + String e164Numbers = e164.replaceAll("\\D", ""); + + return countryAndAreaCodes.stream().anyMatch(e164Numbers::startsWith); } /** @@ -88,7 +113,7 @@ public final class LocaleFeatureFlags { * in the list. For example, "1:20000,*:40000" would mean 2% of the NANPA phone numbers and 4% of the rest of * the world should see the megaphone. */ - private static boolean isEnabled(@NonNull String flag, @NonNull String serialized) { + private static boolean isEnabledPartsPerMillion(@NonNull String flag, @NonNull String serialized) { Map countryCodeValues = parseCountryValues(serialized, 0); Recipient self = Recipient.self(); diff --git a/app/src/test/java/org/thoughtcrime/securesms/util/LocaleFeatureFlags_isEnabled.kt b/app/src/test/java/org/thoughtcrime/securesms/util/LocaleFeatureFlags_isEnabled.kt new file mode 100644 index 0000000000..d84aaffb97 --- /dev/null +++ b/app/src/test/java/org/thoughtcrime/securesms/util/LocaleFeatureFlags_isEnabled.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.util + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.thoughtcrime.securesms.assertIs + +@RunWith(Parameterized::class) +class LocaleFeatureFlags_isEnabled(private val serializedList: String, private val e164: List, private val output: Boolean) { + + @Test + fun isLegal() { + e164.forEach { + LocaleFeatureFlags.isEnabledE164Start(serializedList, it) assertIs output + } + } + + companion object { + @Parameterized.Parameters + @JvmStatic + fun data(): Collection> { + return listOf( + arrayOf("1,2,3", listOf("+15555555555", "+25552555555", "+35555555555"), true), + arrayOf("1 123,2,33 1231", listOf("+112355555555", "+25552555555", "+331231555555"), true), + arrayOf("1,2,3", listOf("+1 5 5 5 5 55 5555", "+255525 55 555", "+355 55 555555"), true), + arrayOf("1 123,2,33 1231", listOf("+1 1 2 3 55 555 555", "+ 255-52 5 5 5555", "+3 31 2 3 1 5-5 5 5 5 5"), true), + + arrayOf("5,7,8", listOf("+15555555555", "+25552555555", "+35555555555"), false), + arrayOf("5 123,5,31 1231", listOf("+112355555555", "+25552555555", "+331231555555"), false), + arrayOf("5,7,8", listOf("+1 5 5 5 5 55 5555", "+255525 55 555", "+355 55 555555"), false), + arrayOf("1 125,5,33 5231", listOf("+1 1 2 3 55 555 555", "+ 255 52 5 5 5555", "+3 31 2 3 1 5 5 5-5-5 5"), false) + ) + } + } +}