From 1502b0ae3ed0664ebbf68c2204e3dfbaa0bfdff5 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Wed, 9 Jan 2019 17:12:33 -0800 Subject: [PATCH] Add processing rules for partial US and BR phone numbers. --- .../securesms/database/Address.java | 103 +++++++++++++++--- .../securesms/database/AddressTest.java | 35 +++++- 2 files changed, 122 insertions(+), 16 deletions(-) diff --git a/src/org/thoughtcrime/securesms/database/Address.java b/src/org/thoughtcrime/securesms/database/Address.java index 9934b0ec41..a60028c7a6 100644 --- a/src/org/thoughtcrime/securesms/database/Address.java +++ b/src/org/thoughtcrime/securesms/database/Address.java @@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.NumberUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libsignal.util.guava.Optional; import java.util.Collections; import java.util.HashSet; @@ -28,6 +29,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; import java.util.regex.Pattern; public class Address implements Parcelable, Comparable
{ @@ -186,26 +188,30 @@ public class Address implements Parcelable, Comparable
{ add("AC"); }}; - private final String localNumberString; - private final String localCountryCode; + private static final Pattern US_NO_AREACODE = Pattern.compile("^(\\d{7})$"); + private static final Pattern BR_NO_AREACODE = Pattern.compile("^(9?\\d{8})$"); + + private final Optional localNumber; + private final String localCountryCode; private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]"); ExternalAddressFormatter(@NonNull String localNumberString) { try { - Phonenumber.PhoneNumber localNumber = phoneNumberUtil.parse(localNumberString, null); + Phonenumber.PhoneNumber libNumber = phoneNumberUtil.parse(localNumberString, null); + int countryCode = libNumber.getCountryCode(); - this.localNumberString = localNumberString; - this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(localNumber); + this.localNumber = Optional.of(new PhoneNumber(localNumberString, countryCode, parseAreaCode(localNumberString, countryCode))); + this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(libNumber); } catch (NumberParseException e) { throw new AssertionError(e); } } ExternalAddressFormatter(@NonNull String localCountryCode, boolean countryCode) { - this.localNumberString = ""; - this.localCountryCode = localCountryCode; + this.localNumber = Optional.absent(); + this.localCountryCode = localCountryCode; } public String format(@Nullable String number) { @@ -230,20 +236,21 @@ public class Address implements Parcelable, Comparable
{ return bareNumber; } + if (isShortCode(bareNumber, localCountryCode)) { + return bareNumber; + } + + String processedNumber = applyAreaCodeRules(localNumber, bareNumber); + try { - Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(bareNumber, localCountryCode); - - if (ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(parsedNumber, localCountryCode)) { - return bareNumber; - } - + Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(processedNumber, localCountryCode); return phoneNumberUtil.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164); } catch (NumberParseException e) { Log.w(TAG, e); if (bareNumber.charAt(0) == '+') return bareNumber; - String localNumberImprecise = localNumberString; + String localNumberImprecise = localNumber.isPresent() ? localNumber.get().getE164Number() : ""; if (localNumberImprecise.charAt(0) == '+') localNumberImprecise = localNumberImprecise.substring(1); @@ -256,6 +263,72 @@ public class Address implements Parcelable, Comparable
{ return "+" + localNumberImprecise.substring(0, difference) + bareNumber; } } - } + private boolean isShortCode(@NonNull String bareNumber, String localCountryCode) { + try { + Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(bareNumber, localCountryCode); + return ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(parsedNumber, localCountryCode); + } catch (NumberParseException e) { + return false; + } + } + + private @Nullable String parseAreaCode(@NonNull String e164Number, int countryCode) { + switch (countryCode) { + case 1: + return e164Number.substring(2, 5); + case 55: + return e164Number.substring(3, 5); + } + return null; + } + + + private @NonNull String applyAreaCodeRules(@NonNull Optional localNumber, @NonNull String testNumber) { + if (!localNumber.isPresent() || !localNumber.get().getAreaCode().isPresent()) { + return testNumber; + } + + Matcher matcher; + switch (localNumber.get().getCountryCode()) { + case 1: + matcher = US_NO_AREACODE.matcher(testNumber); + if (matcher.matches()) { + return localNumber.get().getAreaCode() + matcher.group(); + } + break; + + case 55: + matcher = BR_NO_AREACODE.matcher(testNumber); + if (matcher.matches()) { + return localNumber.get().getAreaCode() + matcher.group(); + } + } + return testNumber; + } + + private static class PhoneNumber { + private final String e164Number; + private final int countryCode; + private final Optional areaCode; + + PhoneNumber(String e164Number, int countryCode, @Nullable String areaCode) { + this.e164Number = e164Number; + this.countryCode = countryCode; + this.areaCode = Optional.fromNullable(areaCode); + } + + String getE164Number() { + return e164Number; + } + + int getCountryCode() { + return countryCode; + } + + Optional getAreaCode() { + return areaCode; + } + } + } } diff --git a/test/unitTest/java/org/thoughtcrime/securesms/database/AddressTest.java b/test/unitTest/java/org/thoughtcrime/securesms/database/AddressTest.java index be6ec02e41..c8f794a3b9 100644 --- a/test/unitTest/java/org/thoughtcrime/securesms/database/AddressTest.java +++ b/test/unitTest/java/org/thoughtcrime/securesms/database/AddressTest.java @@ -39,11 +39,45 @@ public class AddressTest { assertEquals(formatter.format("+1 415.111.1126"), "+14151111126"); assertEquals(formatter.format("+1 415 111 1127"), "+14151111127"); assertEquals(formatter.format("+1 (415) 111 1128"), "+14151111128"); + assertEquals(formatter.format("911"), "911"); + assertEquals(formatter.format("+456-7890"), "+4567890"); formatter = new Address.ExternalAddressFormatter("+442079460010"); assertEquals(formatter.format("(020) 7946 0018"), "+442079460018"); } + @Test + public void testUsNumbers() { + Address.ExternalAddressFormatter formatter = new Address.ExternalAddressFormatter("+16105880522"); + + assertEquals("+551234567890", formatter.format("+551234567890")); + assertEquals("+11234567890", formatter.format("(123) 456-7890")); + assertEquals("+11234567890", formatter.format("1234567890")); + assertEquals("+16104567890", formatter.format("456-7890")); + assertEquals("+16104567890", formatter.format("4567890")); + assertEquals("+11234567890", formatter.format("011 1 123 456 7890")); + assertEquals("+5511912345678", formatter.format("0115511912345678")); + assertEquals("+16105880522", formatter.format("+16105880522")); + } + + @Test + public void testBrNumbers() { + Address.ExternalAddressFormatter formatter = new Address.ExternalAddressFormatter("+5521912345678"); + + assertEquals("+16105880522", formatter.format("+16105880522")); + assertEquals("+552187654321", formatter.format("8765 4321")); + assertEquals("+5521987654321", formatter.format("9 8765 4321")); + assertEquals("+552287654321", formatter.format("22 8765 4321")); + assertEquals("+5522987654321", formatter.format("22 9 8765 4321")); + assertEquals("+551234567890", formatter.format("+55 (123) 456-7890")); + assertEquals("+14085048577", formatter.format("002214085048577")); + assertEquals("+5511912345678", formatter.format("011912345678")); + assertEquals("+5511912345678", formatter.format("02111912345678")); + assertEquals("+551234567", formatter.format("1234567")); + assertEquals("+5521912345678", formatter.format("+5521912345678")); + assertEquals("+552112345678", formatter.format("+552112345678")); + } + @Test public void testGroup() throws Exception { Address.ExternalAddressFormatter formatter = new Address.ExternalAddressFormatter("+14152222222"); @@ -55,5 +89,4 @@ public class AddressTest { Address.ExternalAddressFormatter formatter = new Address.ExternalAddressFormatter("US", true); assertEquals(formatter.format("(415) 111-1122"), "+14151111122"); } - }