package org.thoughtcrime.securesms.database; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.Log; import com.google.i18n.phonenumbers.NumberParseException; import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.google.i18n.phonenumbers.Phonenumber; import com.google.i18n.phonenumbers.ShortNumberInfo; 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 java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.regex.Pattern; public class Address implements Parcelable, Comparable
{ public static final Parcelable.Creator
CREATOR = new Parcelable.Creator
() { public Address createFromParcel(Parcel in) { return new Address(in); } public Address[] newArray(int size) { return new Address[size]; } }; public static final Address UNKNOWN = new Address("Unknown"); private static final String TAG = Address.class.getSimpleName(); private final String address; private Address(@NonNull String address) { if (address == null) throw new AssertionError(address); this.address = address; } public Address(Parcel in) { this(in.readString()); } public static Address fromSerialized(@NonNull String serialized) { return new Address(serialized); } public static List
fromSerializedList(@NonNull String serialized, @NonNull String delimiter) { List elements = Util.split(serialized, delimiter); List
addresses = new LinkedList<>(); for (String element : elements) { addresses.add(Address.fromSerialized(element)); } return addresses; } public static Address fromExternal(@NonNull Context context, @Nullable String external) { return new Address(new ExternalAddressFormatter(TextSecurePreferences.getLocalNumber(context)).format(external)); } public static Address[] fromParcelable(Parcelable[] parcelables) { Address[] addresses = new Address[parcelables.length]; for (int i=0;i SHORT_COUNTRIES = new HashSet() {{ add("NU"); add("TK"); add("NC"); add("AC"); }}; private final Phonenumber.PhoneNumber localNumber; private final String localNumberString; private final String localCountryCode; private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]"); public ExternalAddressFormatter(String localNumber) { try { this.localNumberString = localNumber; this.localNumber = phoneNumberUtil.parse(localNumber, null); this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(this.localNumber); } catch (NumberParseException e) { throw new AssertionError(e); } } public String format(@Nullable String number) { if (number == null) return "Unknown"; if (number.startsWith("__textsecure_group__!")) return number; if (ALPHA_PATTERN.matcher(number).matches()) return number.trim(); String bareNumber = number.replaceAll("[^0-9+]", ""); if (bareNumber.length() == 0) { if (number.trim().length() == 0) return "Unknown"; else return number.trim(); } // libphonenumber doesn't seem to be correct for Germany and Finland if (bareNumber.length() <= 6 && ("DE".equals(localCountryCode) || "FI".equals(localCountryCode) || "SK".equals(localCountryCode))) { return bareNumber; } // libphonenumber seems incorrect for Russia and a few other countries with 4 digit short codes. if (bareNumber.length() <= 4 && !SHORT_COUNTRIES.contains(localCountryCode)) { return bareNumber; } try { Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(bareNumber, localCountryCode); if (ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(parsedNumber, localCountryCode)) { return bareNumber; } return phoneNumberUtil.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164); } catch (NumberParseException e) { Log.w(TAG, e); if (bareNumber.charAt(0) == '+') return bareNumber; String localNumberImprecise = localNumberString; if (localNumberImprecise.charAt(0) == '+') localNumberImprecise = localNumberImprecise.substring(1); if (localNumberImprecise.length() == bareNumber.length() || bareNumber.length() > localNumberImprecise.length()) return "+" + number; int difference = localNumberImprecise.length() - bareNumber.length(); return "+" + localNumberImprecise.substring(0, difference) + bareNumber; } } } }