Use SIM country code when registered number is unavailable

Convert directory operations to Addresses

Fixes #6845
// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-08-02 12:51:46 -07:00
parent 4838fade6c
commit 7f46e99f9c
11 changed files with 155 additions and 152 deletions

View File

@ -1023,8 +1023,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
capabilities.getVideoCapability() == Capability.UNKNOWN)
{
try {
capabilities = DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients,
TextSecurePreferences.getLocalNumber(context));
capabilities = DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients);
} catch (IOException e) {
Log.w(TAG, e);
}

View File

@ -24,7 +24,6 @@ import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.i18n.phonenumbers.AsYouTypeFormatter;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
@ -32,6 +31,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
/**
@ -147,26 +147,17 @@ public class RegistrationActivity extends BaseActionBarActivity {
}
private void initializeNumber() {
PhoneNumberUtil numberUtil = PhoneNumberUtil.getInstance();
String localNumber = Util.getDeviceE164Number(this);
Optional<Phonenumber.PhoneNumber> localNumber = Util.getDeviceNumber(this);
try {
if (!TextUtils.isEmpty(localNumber)) {
Phonenumber.PhoneNumber localNumberObject = numberUtil.parse(localNumber, null);
if (localNumber.isPresent()) {
this.countryCode.setText(String.valueOf(localNumber.get().getCountryCode()));
this.number.setText(String.valueOf(localNumber.get().getNationalNumber()));
} else {
Optional<String> simCountryIso = Util.getSimCountryIso(this);
if (localNumberObject != null) {
this.countryCode.setText(String.valueOf(localNumberObject.getCountryCode()));
this.number.setText(String.valueOf(localNumberObject.getNationalNumber()));
}
} else {
String simCountryIso = Util.getSimCountryIso(this);
if (!TextUtils.isEmpty(simCountryIso)) {
this.countryCode.setText(numberUtil.getCountryCodeForRegion(simCountryIso)+"");
}
if (simCountryIso.isPresent() && !TextUtils.isEmpty(simCountryIso.get())) {
this.countryCode.setText(PhoneNumberUtil.getInstance().getCountryCodeForRegion(simCountryIso.get())+"");
}
} catch (NumberParseException npe) {
Log.w(TAG, npe);
}
}

View File

@ -35,6 +35,7 @@ import android.util.Log;
import android.util.Pair;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
@ -76,29 +77,28 @@ public class ContactsDatabase {
this.context = context;
}
public synchronized @NonNull List<String> setRegisteredUsers(@NonNull Account account,
@NonNull String localNumber,
@NonNull List<ContactTokenDetails> registeredContacts,
boolean remove)
public synchronized @NonNull List<Address> setRegisteredUsers(@NonNull Account account,
@NonNull List<ContactTokenDetails> registeredContacts,
boolean remove)
throws RemoteException, OperationApplicationException
{
Map<String, ContactTokenDetails> registeredNumbers = new HashMap<>();
List<String> addedNumbers = new LinkedList<>();
ArrayList<ContentProviderOperation> operations = new ArrayList<>();
Map<String, SignalContact> currentContacts = getSignalRawContacts(account, localNumber);
Map<Address, ContactTokenDetails> registeredAddresses = new HashMap<>();
List<Address> addedAddresses = new LinkedList<>();
ArrayList<ContentProviderOperation> operations = new ArrayList<>();
Map<Address, SignalContact> currentContacts = getSignalRawContacts(account);
for (ContactTokenDetails registeredContact : registeredContacts) {
String registeredNumber = registeredContact.getNumber();
Address registeredAddress = Address.fromSerialized(registeredContact.getNumber());
registeredNumbers.put(registeredNumber, registeredContact);
registeredAddresses.put(registeredAddress, registeredContact);
if (!currentContacts.containsKey(registeredNumber)) {
Optional<SystemContactInfo> systemContactInfo = getSystemContactInfo(registeredNumber, localNumber);
if (!currentContacts.containsKey(registeredAddress)) {
Optional<SystemContactInfo> systemContactInfo = getSystemContactInfo(registeredAddress);
if (systemContactInfo.isPresent()) {
Log.w(TAG, "Adding number: " + registeredNumber);
addedNumbers.add(registeredNumber);
Log.w(TAG, "Adding number: " + registeredAddress);
addedAddresses.add(registeredAddress);
addTextSecureRawContact(operations, account, systemContactInfo.get().number,
systemContactInfo.get().name, systemContactInfo.get().id,
true);
@ -106,8 +106,8 @@ public class ContactsDatabase {
}
}
for (Map.Entry<String, SignalContact> currentContactEntry : currentContacts.entrySet()) {
ContactTokenDetails tokenDetails = registeredNumbers.get(currentContactEntry.getKey());
for (Map.Entry<Address, SignalContact> currentContactEntry : currentContacts.entrySet()) {
ContactTokenDetails tokenDetails = registeredAddresses.get(currentContactEntry.getKey());
if (tokenDetails == null) {
if (remove) {
@ -129,7 +129,7 @@ public class ContactsDatabase {
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operations);
}
return addedNumbers;
return addedAddresses;
}
@NonNull Cursor querySystemContacts(String filter) {
@ -220,7 +220,7 @@ public class ContactsDatabase {
}
private void addContactVoiceSupport(List<ContentProviderOperation> operations,
@NonNull String e164number, long rawContactId)
@NonNull Address address, long rawContactId)
{
operations.add(ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
.withSelection(RawContacts._ID + " = ?", new String[] {String.valueOf(rawContactId)})
@ -230,9 +230,9 @@ public class ContactsDatabase {
operations.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build())
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
.withValue(ContactsContract.Data.MIMETYPE, CALL_MIMETYPE)
.withValue(ContactsContract.Data.DATA1, e164number)
.withValue(ContactsContract.Data.DATA1, address.toPhoneString())
.withValue(ContactsContract.Data.DATA2, context.getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, context.getString(R.string.ContactsDatabase_signal_call_s, e164number))
.withValue(ContactsContract.Data.DATA3, context.getString(R.string.ContactsDatabase_signal_call_s, address.toPhoneString()))
.withYieldAllowed(true)
.build());
}
@ -346,15 +346,13 @@ public class ContactsDatabase {
.build());
}
private @NonNull Map<String, SignalContact> getSignalRawContacts(@NonNull Account account,
@NonNull String localNumber)
{
private @NonNull Map<Address, SignalContact> getSignalRawContacts(@NonNull Account account) {
Uri currentContactsUri = RawContacts.CONTENT_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type).build();
Map<String, SignalContact> signalContacts = new HashMap<>();
Cursor cursor = null;
Map<Address, SignalContact> signalContacts = new HashMap<>();
Cursor cursor = null;
try {
String[] projection;
@ -368,21 +366,13 @@ public class ContactsDatabase {
cursor = context.getContentResolver().query(currentContactsUri, projection, null, null, null);
while (cursor != null && cursor.moveToNext()) {
String currentNumber;
try {
currentNumber = PhoneNumberFormatter.formatNumber(cursor.getString(1), localNumber);
} catch (InvalidNumberException e) {
Log.w(TAG, e);
currentNumber = cursor.getString(1);
}
long rawContactId = cursor.getLong(0);
long contactId = cursor.getLong(3);
String supportsVoice = cursor.getString(2);
String rawContactDisplayName = null;
String aggregateDisplayName = null;
int rawContactDisplayNameSource = 0;
Address currentAddress = Address.fromExternal(context, cursor.getString(1));
long rawContactId = cursor.getLong(0);
long contactId = cursor.getLong(3);
String supportsVoice = cursor.getString(2);
String rawContactDisplayName = null;
String aggregateDisplayName = null;
int rawContactDisplayNameSource = 0;
if (Build.VERSION.SDK_INT >= 11) {
rawContactDisplayName = cursor.getString(4);
@ -390,7 +380,7 @@ public class ContactsDatabase {
aggregateDisplayName = getDisplayName(contactId);
}
signalContacts.put(currentNumber, new SignalContact(rawContactId, supportsVoice, rawContactDisplayName, aggregateDisplayName, rawContactDisplayNameSource));
signalContacts.put(currentAddress, new SignalContact(rawContactId, supportsVoice, rawContactDisplayName, aggregateDisplayName, rawContactDisplayNameSource));
}
} finally {
if (cursor != null)
@ -400,10 +390,11 @@ public class ContactsDatabase {
return signalContacts;
}
private Optional<SystemContactInfo> getSystemContactInfo(@NonNull String e164number,
@NonNull String localNumber)
private Optional<SystemContactInfo> getSystemContactInfo(@NonNull Address address)
{
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(e164number));
if (!address.isPhone()) return Optional.absent();
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address.toPhoneString()));
String[] projection = {ContactsContract.PhoneLookup.NUMBER,
ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.DISPLAY_NAME};
@ -414,25 +405,21 @@ public class ContactsDatabase {
numberCursor = context.getContentResolver().query(uri, projection, null, null, null);
while (numberCursor != null && numberCursor.moveToNext()) {
try {
String systemNumber = numberCursor.getString(0);
String canonicalizedSystemNumber = PhoneNumberFormatter.formatNumber(systemNumber, localNumber);
String systemNumber = numberCursor.getString(0);
Address systemAddress = Address.fromExternal(context, systemNumber);
if (canonicalizedSystemNumber.equals(e164number)) {
idCursor = context.getContentResolver().query(RawContacts.CONTENT_URI,
new String[] {RawContacts._ID},
RawContacts.CONTACT_ID + " = ? ",
new String[] {String.valueOf(numberCursor.getLong(1))},
null);
if (systemAddress.equals(address)) {
idCursor = context.getContentResolver().query(RawContacts.CONTENT_URI,
new String[] {RawContacts._ID},
RawContacts.CONTACT_ID + " = ? ",
new String[] {String.valueOf(numberCursor.getLong(1))},
null);
if (idCursor != null && idCursor.moveToNext()) {
return Optional.of(new SystemContactInfo(numberCursor.getString(2),
numberCursor.getString(0),
idCursor.getLong(0)));
}
if (idCursor != null && idCursor.moveToNext()) {
return Optional.of(new SystemContactInfo(numberCursor.getString(2),
numberCursor.getString(0),
idCursor.getLong(0)));
}
} catch (InvalidNumberException e) {
Log.w(TAG, e);
}
}
} finally {

View File

@ -7,6 +7,7 @@ import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
import com.google.i18n.phonenumbers.NumberParseException;
@ -20,7 +21,6 @@ import org.thoughtcrime.securesms.util.NumberUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
@ -60,7 +60,17 @@ public class Address implements Parcelable, Comparable<Address> {
}
public static Address fromExternal(@NonNull Context context, @Nullable String external) {
return new Address(new ExternalAddressFormatter(TextSecurePreferences.getLocalNumber(context)).format(external));
String localNumber = TextSecurePreferences.getLocalNumber(context);
ExternalAddressFormatter formatter;
if (!TextUtils.isEmpty(localNumber)) {
formatter = new ExternalAddressFormatter(localNumber);
} else {
formatter = new ExternalAddressFormatter(Util.getSimCountryIso(context).or("US"), true);
}
return new Address(formatter.format(external));
}
public static @NonNull List<Address> fromSerializedList(@NonNull String serialized, char delimiter) {
@ -171,23 +181,28 @@ public class Address implements Parcelable, Comparable<Address> {
add("AC");
}};
private final Phonenumber.PhoneNumber localNumber;
private final String localNumberString;
private final String localCountryCode;
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) {
ExternalAddressFormatter(@NonNull String localNumberString) {
try {
this.localNumberString = localNumber;
this.localNumber = phoneNumberUtil.parse(localNumber, null);
this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(this.localNumber);
Phonenumber.PhoneNumber localNumber = phoneNumberUtil.parse(localNumberString, null);
this.localNumberString = localNumberString;
this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(localNumber);
} catch (NumberParseException e) {
throw new AssertionError(e);
}
}
ExternalAddressFormatter(@NonNull String localCountryCode, boolean countryCode) {
this.localNumberString = "";
this.localCountryCode = localCountryCode;
}
public String format(@Nullable String number) {
if (number == null) return "Unknown";
if (number.startsWith("__textsecure_group__!")) return number;

View File

@ -8,11 +8,10 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.util.ArrayList;
import java.util.Collection;
@ -173,7 +172,7 @@ public class TextSecureDirectory {
db.replace(TABLE_NAME, null, values);
}
public void setNumbers(List<ContactTokenDetails> activeTokens, Collection<String> inactiveTokens) {
public void setNumbers(List<ContactTokenDetails> activeTokens, Collection<Address> inactiveAddresses) {
long timestamp = System.currentTimeMillis();
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.beginTransaction();
@ -191,9 +190,9 @@ public class TextSecureDirectory {
db.replace(TABLE_NAME, null, values);
}
for (String token : inactiveTokens) {
for (Address address : inactiveAddresses) {
ContentValues values = new ContentValues();
values.put(NUMBER, token);
values.put(NUMBER, address.serialize());
values.put(REGISTERED, 0);
values.put(TIMESTAMP, timestamp);
db.replace(TABLE_NAME, null, values);
@ -205,23 +204,18 @@ public class TextSecureDirectory {
}
}
public Set<String> getPushEligibleContactNumbers(String localNumber) {
final Uri uri = Phone.CONTENT_URI;
final Set<String> results = new HashSet<>();
Cursor cursor = null;
public Set<Address> getPushEligibleContactNumbers() {
final Uri uri = Phone.CONTENT_URI;
final Set<Address> results = new HashSet<>();
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, new String[] {Phone.NUMBER}, null, null, null);
while (cursor != null && cursor.moveToNext()) {
final String rawNumber = cursor.getString(0);
if (rawNumber != null) {
try {
final String e164Number = PhoneNumberFormatter.formatNumber(rawNumber, localNumber);
results.add(e164Number);
} catch (InvalidNumberException e) {
Log.w("Directory", "Invalid number: " + rawNumber);
}
if (!TextUtils.isEmpty(rawNumber)) {
results.add(Address.fromExternal(context, rawNumber));
}
}
@ -234,7 +228,7 @@ public class TextSecureDirectory {
null, null, null, null, null);
while (cursor != null && cursor.moveToNext()) {
results.add(cursor.getString(0));
results.add(Address.fromSerialized(cursor.getString(0)));
}
}

View File

@ -54,7 +54,7 @@ public class DirectoryRefreshJob extends ContextJob {
if (recipients == null) {
DirectoryHelper.refreshDirectory(context, KeyCachingService.getMasterSecret(context));
} else {
DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients, TextSecurePreferences.getLocalNumber(context));
DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients);
}
SecurityEvent.broadcastSecurityUpdateEvent(context);
} finally {

View File

@ -206,6 +206,7 @@ public class RegistrationService extends Service {
String challenge = waitForChallenge();
accountManager.verifyAccountWithCode(challenge, signalingKey, registrationId, !supportsGcm);
TextSecurePreferences.setLocalNumber(this, number);
handleCommonRegistration(accountManager, number, password, signalingKey, supportsGcm);
markAsVerified(number, password, signalingKey);
@ -257,7 +258,7 @@ public class RegistrationService extends Service {
TextSecurePreferences.setWebsocketRegistered(this, true);
DatabaseFactory.getIdentityDatabase(this).saveIdentity(self, identityKey.getPublicKey(), IdentityDatabase.VerifiedStatus.VERIFIED, true, System.currentTimeMillis(), true);
DirectoryHelper.refreshDirectory(this, accountManager, number);
DirectoryHelper.refreshDirectory(this, accountManager);
DirectoryRefreshListener.schedule(this);
RotateSignedPreKeyListener.schedule(this);

View File

@ -9,6 +9,7 @@ import android.os.RemoteException;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import org.thoughtcrime.securesms.ApplicationContext;
@ -32,6 +33,7 @@ import org.whispersystems.signalservice.api.push.ContactTokenDetails;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@ -75,9 +77,9 @@ public class DirectoryHelper {
public static void refreshDirectory(@NonNull Context context, @Nullable MasterSecret masterSecret)
throws IOException
{
RefreshResult result = refreshDirectory(context,
AccountManagerFactory.createManager(context),
TextSecurePreferences.getLocalNumber(context));
if (TextUtils.isEmpty(TextSecurePreferences.getLocalNumber(context))) return;
RefreshResult result = refreshDirectory(context, AccountManagerFactory.createManager(context));
if (!result.getNewUsers().isEmpty() && TextSecurePreferences.isMultiDevice(context)) {
ApplicationContext.getInstance(context)
@ -90,32 +92,38 @@ public class DirectoryHelper {
}
}
public static @NonNull RefreshResult refreshDirectory(@NonNull Context context,
@NonNull SignalServiceAccountManager accountManager,
@NonNull String localNumber)
public static @NonNull RefreshResult refreshDirectory(@NonNull Context context, @NonNull SignalServiceAccountManager accountManager)
throws IOException
{
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
Set<String> eligibleContactNumbers = directory.getPushEligibleContactNumbers(localNumber);
List<ContactTokenDetails> activeTokens = accountManager.getContacts(eligibleContactNumbers);
if (TextUtils.isEmpty(TextSecurePreferences.getLocalNumber(context))) {
return new RefreshResult(new LinkedList<Address>(), false);
}
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
Set<Address> eligibleContactNumbers = directory.getPushEligibleContactNumbers();
Set<String> serializedAddresses = new HashSet<>();
for (Address address : eligibleContactNumbers) {
serializedAddresses.add(address.serialize());
}
List<ContactTokenDetails> activeTokens = accountManager.getContacts(serializedAddresses);
if (activeTokens != null) {
for (ContactTokenDetails activeToken : activeTokens) {
eligibleContactNumbers.remove(activeToken.getNumber());
activeToken.setNumber(activeToken.getNumber());
eligibleContactNumbers.remove(Address.fromSerialized(activeToken.getNumber()));
}
directory.setNumbers(activeTokens, eligibleContactNumbers);
return updateContactsDatabase(context, localNumber, activeTokens, true);
return updateContactsDatabase(context, activeTokens, true);
}
return new RefreshResult(new LinkedList<String>(), false);
return new RefreshResult(new LinkedList<Address>(), false);
}
public static UserCapabilities refreshDirectoryFor(@NonNull Context context,
@Nullable MasterSecret masterSecret,
@NonNull Recipients recipients,
@NonNull String localNumber)
@NonNull Recipients recipients)
throws IOException
{
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
@ -126,7 +134,7 @@ public class DirectoryHelper {
if (details.isPresent()) {
directory.setNumber(details.get(), true);
RefreshResult result = updateContactsDatabase(context, localNumber, details.get());
RefreshResult result = updateContactsDatabase(context, details.get());
if (!result.getNewUsers().isEmpty() && TextSecurePreferences.isMultiDevice(context)) {
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceContactUpdateJob(context));
@ -181,16 +189,12 @@ public class DirectoryHelper {
}
private static @NonNull RefreshResult updateContactsDatabase(@NonNull Context context,
@NonNull String localNumber,
@NonNull final ContactTokenDetails activeToken)
{
return updateContactsDatabase(context, localNumber,
new LinkedList<ContactTokenDetails>() {{add(activeToken);}},
false);
return updateContactsDatabase(context, new LinkedList<ContactTokenDetails>() {{add(activeToken);}}, false);
}
private static @NonNull RefreshResult updateContactsDatabase(@NonNull Context context,
@NonNull String localNumber,
@NonNull List<ContactTokenDetails> activeTokens,
boolean removeMissing)
{
@ -198,8 +202,8 @@ public class DirectoryHelper {
if (account.isPresent()) {
try {
List<String> newUsers = DatabaseFactory.getContactsDatabase(context)
.setRegisteredUsers(account.get().getAccount(), localNumber, activeTokens, removeMissing);
List<Address> newUsers = DatabaseFactory.getContactsDatabase(context)
.setRegisteredUsers(account.get().getAccount(), activeTokens, removeMissing);
return new RefreshResult(newUsers, account.get().isFresh());
} catch (RemoteException | OperationApplicationException e) {
@ -207,18 +211,16 @@ public class DirectoryHelper {
}
}
return new RefreshResult(new LinkedList<String>(), false);
return new RefreshResult(new LinkedList<Address>(), false);
}
private static void notifyNewUsers(@NonNull Context context,
@Nullable MasterSecret masterSecret,
@NonNull List<String> newUsers)
@NonNull List<Address> newUsers)
{
if (!TextSecurePreferences.isNewContactsNotificationEnabled(context)) return;
for (String newUserString : newUsers) {
Address newUser = Address.fromSerialized(newUserString);
for (Address newUser: newUsers) {
if (!SessionUtil.hasSession(context, masterSecret, newUser) && !Util.isOwnNumber(context, newUser)) {
IncomingJoinedMessage message = new IncomingJoinedMessage(newUser);
Optional<InsertResult> insertResult = DatabaseFactory.getSmsDatabase(context).insertMessageInbox(message);
@ -287,15 +289,15 @@ public class DirectoryHelper {
private static class RefreshResult {
private final List<String> newUsers;
private final boolean fresh;
private final List<Address> newUsers;
private final boolean fresh;
private RefreshResult(List<String> newUsers, boolean fresh) {
private RefreshResult(List<Address> newUsers, boolean fresh) {
this.newUsers = newUsers;
this.fresh = fresh;
}
public List<String> getNewUsers() {
public List<Address> getNewUsers() {
return newUsers;
}

View File

@ -304,7 +304,7 @@ public class TextSecurePreferences {
}
public static String getLocalNumber(Context context) {
return getStringPreference(context, LOCAL_NUMBER_PREF, "No Stored Number");
return getStringPreference(context, LOCAL_NUMBER_PREF, null);
}
public static void setLocalNumber(Context context, String localNumber) {

View File

@ -42,11 +42,14 @@ import android.widget.EditText;
import com.google.android.mms.pdu_alt.CharacterSets;
import com.google.android.mms.pdu_alt.EncodedStringValue;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.mms.OutgoingLegacyMmsConnection;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.io.ByteArrayOutputStream;
@ -234,22 +237,24 @@ public class Util {
return total;
}
public static @Nullable String getDeviceE164Number(Context context) {
final String localNumber = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number();
final String countryIso = getSimCountryIso(context);
final Integer countryCode = PhoneNumberUtil.getInstance().getCountryCodeForRegion(countryIso);
public static Optional<Phonenumber.PhoneNumber> getDeviceNumber(Context context) {
try {
final String localNumber = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number();
final Optional<String> countryIso = getSimCountryIso(context);
if (TextUtils.isEmpty(localNumber)) return null;
if (TextUtils.isEmpty(localNumber)) return Optional.absent();
if (!countryIso.isPresent()) return Optional.absent();
if (localNumber.startsWith("+")) return localNumber;
else if (!TextUtils.isEmpty(countryIso)) return PhoneNumberFormatter.formatE164(String.valueOf(countryCode), localNumber);
else if (localNumber.length() == 10) return "+1" + localNumber;
else return "+" + localNumber;
return Optional.fromNullable(PhoneNumberUtil.getInstance().parse(localNumber, countryIso.get()));
} catch (NumberParseException e) {
Log.w(TAG, e);
return Optional.absent();
}
}
public static @Nullable String getSimCountryIso(Context context) {
public static Optional<String> getSimCountryIso(Context context) {
String simCountryIso = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getSimCountryIso();
return simCountryIso != null ? simCountryIso.toUpperCase() : null;
return Optional.fromNullable(simCountryIso != null ? simCountryIso.toUpperCase() : null);
}
public static <T> List<List<T>> partition(List<T> list, int partitionSize) {

View File

@ -39,6 +39,9 @@ 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");
formatter = new Address.ExternalAddressFormatter("+442079460010");
assertEquals(formatter.format("(020) 7946 0018"), "+442079460018");
}
@Test
@ -47,4 +50,10 @@ public class AddressTest {
assertEquals(formatter.format("__textsecure_group__!foobar"), "__textsecure_group__!foobar");
}
@Test
public void testLostLocalNumber() throws Exception {
Address.ExternalAddressFormatter formatter = new Address.ExternalAddressFormatter("US", true);
assertEquals(formatter.format("(415) 111-1122"), "+14151111122");
}
}