diff --git a/src/org/thoughtcrime/securesms/database/Address.java b/src/org/thoughtcrime/securesms/database/Address.java
index 9934b0ec4..a60028c7a 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 be6ec02e4..c8f794a3b 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");
}
-
}