Always perform CDSI lookups when starting new chats.

This commit is contained in:
Greyson Parrelli
2024-03-06 12:11:52 -05:00
committed by Alex Hart
parent 184c1b67cc
commit 2e4ac7ede1
15 changed files with 264 additions and 126 deletions

View File

@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientRepository;
import org.thoughtcrime.securesms.recipients.ui.findby.FindByActivity;
import org.thoughtcrime.securesms.recipients.ui.findby.FindByMode;
import org.thoughtcrime.securesms.util.CommunicationActions;
@@ -132,33 +133,19 @@ public class NewConversationActivity extends ContactSelectionActivity
AlertDialog progress = SimpleProgressDialog.show(this);
SimpleTask.run(getLifecycle(), () -> {
Recipient resolved = Recipient.external(this, number);
if (!resolved.isRegistered() || !resolved.hasServiceId()) {
Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.");
try {
ContactDiscovery.refresh(this, resolved, false, TimeUnit.SECONDS.toMillis(10));
resolved = Recipient.resolved(resolved.getId());
} catch (IOException e) {
Log.w(TAG, "[onContactSelected] Failed to refresh directory for new contact.");
return null;
}
}
return resolved;
}, resolved -> {
SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(this, number), result -> {
progress.dismiss();
if (resolved != null) {
if (result instanceof RecipientRepository.LookupResult.Success) {
Recipient resolved = Recipient.resolved(((RecipientRepository.LookupResult.Success) result).getRecipientId());
if (smsSupported || resolved.isRegistered() && resolved.hasServiceId()) {
launch(resolved);
} else {
new MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, resolved.getDisplayName(this)))
.setPositiveButton(android.R.string.ok, null)
.show();
}
} else if (result instanceof RecipientRepository.LookupResult.NotFound || result instanceof RecipientRepository.LookupResult.InvalidEntry) {
new MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number))
.setPositiveButton(android.R.string.ok, null)
.show();
} else {
new MaterialAlertDialogBuilder(this)
.setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again)

View File

@@ -16,16 +16,14 @@ import org.thoughtcrime.securesms.ContactSelectionListFragment
import org.thoughtcrime.securesms.InviteActivity
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.contacts.ContactSelectionDisplayMode
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery.refresh
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.recipients.RecipientRepository
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog
import java.io.IOException
import java.util.Optional
import java.util.function.Consumer
import kotlin.time.Duration.Companion.seconds
class NewCallActivity : ContactSelectionActivity(), ContactSelectionListFragment.NewCallCallback {
@@ -46,38 +44,36 @@ class NewCallActivity : ContactSelectionActivity(), ContactSelectionListFragment
Log.i(TAG, "[onContactSelected] Maybe creating a new recipient.")
if (SignalStore.account().isRegistered) {
Log.i(TAG, "[onContactSelected] Doing contact refresh.")
val progress = SimpleProgressDialog.show(this)
SimpleTask.run<Recipient>(lifecycle, {
var resolved = Recipient.external(this, number!!)
if (!resolved.isRegistered || !resolved.hasServiceId()) {
Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.")
resolved = try {
refresh(this, resolved, false, 10.seconds.inWholeMilliseconds)
Recipient.resolved(resolved.id)
} catch (e: IOException) {
Log.w(TAG, "[onContactSelected] Failed to refresh directory for new contact.")
return@run null
}
}
resolved
}) { resolved: Recipient? ->
SimpleTask.run(lifecycle, { RecipientRepository.lookupNewE164(this, number!!) }, { result ->
progress.dismiss()
if (resolved != null) {
if (resolved.isRegistered && resolved.hasServiceId()) {
launch(resolved)
} else {
when (result) {
is RecipientRepository.LookupResult.Success -> {
val resolved = Recipient.resolved(result.recipientId)
if (resolved.isRegistered && resolved.hasServiceId()) {
launch(resolved)
}
}
is RecipientRepository.LookupResult.NotFound,
is RecipientRepository.LookupResult.InvalidEntry -> {
MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, resolved.getDisplayName(this)))
.setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number))
.setPositiveButton(android.R.string.ok, null)
.show()
}
else -> {
MaterialAlertDialogBuilder(this)
.setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again)
.setPositiveButton(android.R.string.ok, null)
.show()
}
} else {
MaterialAlertDialogBuilder(this)
.setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again)
.setPositiveButton(android.R.string.ok, null)
.show()
}
}
})
}
}
callback.accept(true)

View File

@@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.registration.RegistrationUtil
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.util.UuidUtil
import java.io.IOException
@@ -112,6 +113,19 @@ object ContactDiscovery {
}
}
/**
* Looks up the PNI/ACI for an E164. Only creates a recipient if the number is in the CDS directory.
* Use sparingly! This will always use up the user's CDS quota. Always prefer other syncing methods for bulk lookups.
*
* Returns a [LookupResult] if the E164 is in the CDS directory, or null if it is not.
* Important: Just because a user is not in the directory does not mean they are not registered. They could have discoverability off.
*/
@Throws(IOException::class)
@WorkerThread
fun lookupE164(e164: String): LookupResult? {
return ContactDiscoveryRefreshV2.lookupE164(e164)
}
@JvmStatic
@WorkerThread
fun syncRecipientInfoWithSystemContacts(context: Context) {
@@ -278,7 +292,7 @@ object ContactDiscovery {
/**
* Whether or not a session exists with the provided recipient.
*/
fun hasSession(id: RecipientId): Boolean {
private fun hasSession(id: RecipientId): Boolean {
val recipient = Recipient.resolved(id)
if (!recipient.hasServiceId()) {
@@ -295,4 +309,10 @@ object ContactDiscovery {
val registeredIds: Set<RecipientId>,
val rewrites: Map<String, String>
)
data class LookupResult(
val recipientId: RecipientId,
val pni: ServiceId.PNI,
val aci: ServiceId.ACI?
)
}

View File

@@ -86,6 +86,42 @@ object ContactDiscoveryRefreshV2 {
}
}
@Throws(IOException::class)
@WorkerThread
@Synchronized
fun lookupE164(e164: String): ContactDiscovery.LookupResult? {
val response: CdsiV2Service.Response = try {
ApplicationDependencies.getSignalServiceAccountManager().getRegisteredUsersWithCdsi(
emptySet(),
setOf(e164),
SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(),
Optional.empty(),
BuildConfig.CDSI_MRENCLAVE,
10_000,
if (FeatureFlags.useLibsignalNetForCdsiLookup()) BuildConfig.LIBSIGNAL_NET_ENV else null
) {
Log.i(TAG, "Ignoring token for one-off lookup.")
}
} catch (e: CdsiResourceExhaustedException) {
Log.w(TAG, "CDS resource exhausted! Can try again in ${e.retryAfterSeconds} seconds.")
SignalStore.misc().cdsBlockedUtil = System.currentTimeMillis() + e.retryAfterSeconds.seconds.inWholeMilliseconds
throw e
} catch (e: CdsiInvalidTokenException) {
Log.w(TAG, "We did not provide a token, but still got a token error! Unexpected, but ignoring.")
throw e
}
return response.results[e164]?.let { item ->
val id = SignalDatabase.recipients.processIndividualCdsLookup(e164 = e164, aci = item.aci.orElse(null), pni = item.pni)
ContactDiscovery.LookupResult(
recipientId = id,
pni = item.pni,
aci = item.aci?.orElse(null)
)
}
}
@Throws(IOException::class)
private fun refreshInternal(
recipientE164s: Set<String>,

View File

@@ -2867,11 +2867,8 @@ class ConversationFragment :
}
override fun onInviteToSignalClicked() {
val recipient = viewModel.recipientSnapshot ?: return
InviteActions.inviteUserToSignal(
requireContext(),
recipient,
binding.conversationInputPanel.embeddedTextEditor::appendInvite,
this@ConversationFragment::startActivity
)
}
@@ -3328,8 +3325,6 @@ class ConversationFragment :
InviteActions.inviteUserToSignal(
context = requireContext(),
recipient = recipient,
appendInviteToComposer = composeText::appendInvite,
launchIntent = this@ConversationFragment::startActivity
)
}
@@ -3742,8 +3737,6 @@ class ConversationFragment :
override fun onInviteToSignal(recipient: Recipient) {
InviteActions.inviteUserToSignal(
context = requireContext(),
recipient = recipient,
appendInviteToComposer = null,
launchIntent = this@ConversationFragment::startActivity
)
}

View File

@@ -433,6 +433,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
return readableDatabase.exists(TABLE_NAME).where("$ACI_COLUMN = ? AND $PNI_COLUMN = ?", serviceId.toString(), pni.toString()).run()
}
fun getByE164IfRegisteredAndDiscoverable(e164: String): RecipientId? {
return readableDatabase
.select(ID)
.from(TABLE_NAME)
.where("$E164 = ? AND $REGISTERED = ${RegisteredState.REGISTERED.id} AND $PHONE_NUMBER_DISCOVERABLE = ${PhoneNumberDiscoverableState.DISCOVERABLE.id} AND ($PNI_COLUMN NOT NULL OR $ACI_COLUMN NOT NULL)", e164)
.run()
.readToSingleObject { RecipientId.from(it.requireLong(ID)) }
}
@JvmOverloads
fun getAndPossiblyMerge(serviceId: ServiceId?, e164: String?, changeSelf: Boolean = false): RecipientId {
require(serviceId != null || e164 != null) { "Must provide an ACI or E164!" }
@@ -2267,6 +2276,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
getAndPossiblyMerge(null, record.pni, record.e164)
}
fun processIndividualCdsLookup(aci: ACI?, pni: PNI, e164: String): RecipientId {
return getAndPossiblyMerge(aci = aci, pni = pni, e164 = e164)
}
/**
* Processes CDSv2 results, merging recipients as necessary. Does not mark users as
* registered.

View File

@@ -8,11 +8,13 @@ import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.DimensionUnit;
import org.signal.core.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.ContactSelectionActivity;
import org.thoughtcrime.securesms.ContactSelectionListFragment;
import org.thoughtcrime.securesms.PushContactSelectionActivity;
@@ -21,9 +23,11 @@ import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.SelectionLimits;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientRepository;
import org.thoughtcrime.securesms.recipients.ui.findby.FindByActivity;
import org.thoughtcrime.securesms.recipients.ui.findby.FindByMode;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import java.util.ArrayList;
import java.util.Collections;
@@ -104,9 +108,34 @@ public class AddMembersActivity extends PushContactSelectionActivity implements
getContactFilterView().clear();
}
enableDone();
if (recipientId.isPresent()) {
callback.accept(true);
enableDone();
return;
}
callback.accept(true);
AlertDialog progress = SimpleProgressDialog.show(this);
SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(this, number), result -> {
progress.dismiss();
if (result instanceof RecipientRepository.LookupResult.Success) {
enableDone();
callback.accept(true);
} else if (result instanceof RecipientRepository.LookupResult.NotFound || result instanceof RecipientRepository.LookupResult.InvalidEntry) {
new MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number))
.setPositiveButton(android.R.string.ok, null)
.show();
callback.accept(false);
} else {
new MaterialAlertDialogBuilder(this)
.setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again)
.setPositiveButton(android.R.string.ok, null)
.show();
callback.accept(false);
}
});
}
@Override

View File

@@ -8,17 +8,21 @@ import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import com.annimon.stream.Stream;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.ContactSelectionActivity;
import org.thoughtcrime.securesms.ContactSelectionListFragment;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.ContactSelectionDisplayMode;
import org.thoughtcrime.securesms.groups.ui.addtogroup.AddToGroupViewModel.Event;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientRepository;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import java.util.ArrayList;
import java.util.Collections;

View File

@@ -9,6 +9,7 @@ import android.view.View;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
@@ -27,6 +28,7 @@ import org.thoughtcrime.securesms.groups.ui.creategroup.details.AddGroupDetailsA
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientRepository;
import org.thoughtcrime.securesms.recipients.ui.findby.FindByActivity;
import org.thoughtcrime.securesms.recipients.ui.findby.FindByMode;
import org.thoughtcrime.securesms.util.FeatureFlags;
@@ -117,7 +119,32 @@ public class CreateGroupActivity extends ContactSelectionActivity implements Con
shrinkSkip();
callback.accept(true);
if (recipientId.isPresent()) {
callback.accept(true);
return;
}
AlertDialog progress = SimpleProgressDialog.show(this);
SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(this, number), result -> {
progress.dismiss();
if (result instanceof RecipientRepository.LookupResult.Success) {
callback.accept(true);
} else if (result instanceof RecipientRepository.LookupResult.NotFound || result instanceof RecipientRepository.LookupResult.InvalidEntry) {
new MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, number))
.setPositiveButton(android.R.string.ok, null)
.show();
callback.accept(false);
} else {
new MaterialAlertDialogBuilder(this)
.setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again)
.setPositiveButton(android.R.string.ok, null)
.show();
callback.accept(false);
}
});
}
@Override

View File

@@ -5,10 +5,7 @@ import android.content.Intent
import android.widget.Toast
import androidx.annotation.MainThread
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.Util
/**
* Handles 'invite to signal' actions.
@@ -25,29 +22,18 @@ object InviteActions {
@MainThread
fun inviteUserToSignal(
context: Context,
recipient: Recipient,
appendInviteToComposer: ((String) -> Unit)?,
launchIntent: (Intent) -> Unit
) {
val inviteText = context.getString(
R.string.ConversationActivity_lets_switch_to_signal,
context.getString(R.string.install_url)
)
val intent = CommunicationActions.createIntentToShareTextViaShareSheet(inviteText)
if (appendInviteToComposer != null && Util.isDefaultSmsProvider(context) && SignalStore.misc().smsExportPhase.isSmsSupported()) {
appendInviteToComposer(inviteText)
} else if (recipient.hasSmsAddress()) {
launchIntent(
CommunicationActions.createIntentToComposeSmsThroughDefaultApp(recipient, inviteText)
)
if (intent.resolveActivity(context.packageManager) != null) {
launchIntent(Intent.createChooser(intent, context.getString(R.string.InviteActivity_invite_to_signal)))
} else {
val intent = CommunicationActions.createIntentToShareTextViaShareSheet(inviteText)
if (intent.resolveActivity(context.packageManager) != null) {
launchIntent(Intent.createChooser(intent, context.getString(R.string.InviteActivity_invite_to_signal)))
} else {
Toast.makeText(context, R.string.InviteActivity_no_app_to_share_to, Toast.LENGTH_LONG).show()
}
Toast.makeText(context, R.string.InviteActivity_no_app_to_share_to, Toast.LENGTH_LONG).show()
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.recipients
import android.content.Context
import androidx.annotation.WorkerThread
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.phonenumbers.NumberUtil
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import java.io.IOException
/**
* We operate on recipients many places, but sometimes we find ourselves performing the same recipient-related operations in several locations.
* This is meant to be a place to put those common operations.
*/
object RecipientRepository {
private val TAG = Log.tag(RecipientRepository::class.java)
/**
* Attempts to lookup a potentially-new recipient by their e164.
* We will check locally first for a potential match, but may end up hitting the network.
* This will not create a new recipient if we could not find it in the CDSI directory.
*/
@WorkerThread
@JvmStatic
fun lookupNewE164(context: Context, inputE164: String): LookupResult {
val e164 = PhoneNumberFormatter.get(context).format(inputE164)
if (!NumberUtil.isVisuallyValidNumber(e164)) {
return LookupResult.InvalidEntry
}
val matchingFullRecipientId = SignalDatabase.recipients.getByE164IfRegisteredAndDiscoverable(e164)
if (matchingFullRecipientId != null) {
Log.i(TAG, "Already have a full, discoverable recipient for $e164. $matchingFullRecipientId")
return LookupResult.Success(matchingFullRecipientId)
}
Log.i(TAG, "Need to lookup up $e164 with CDSI.")
return try {
val result = ContactDiscovery.lookupE164(e164)
if (result == null) {
LookupResult.NotFound()
} else {
LookupResult.Success(result.recipientId)
}
} catch (e: IOException) {
return LookupResult.NetworkError
}
}
sealed interface LookupResult {
data class Success(val recipientId: RecipientId) : LookupResult
object InvalidEntry : LookupResult
data class NotFound(val recipientId: RecipientId = RecipientId.UNKNOWN) : LookupResult
object NetworkError : LookupResult
}
}

View File

@@ -84,7 +84,6 @@ import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.Use
import org.thoughtcrime.securesms.invites.InviteActions
import org.thoughtcrime.securesms.permissions.compose.Permissions
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberVisualTransformation
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.registration.util.CountryPrefix
import org.thoughtcrime.securesms.util.viewModel
@@ -161,6 +160,7 @@ class FindByActivity : PassphraseRequiredActivity() {
FindByResult.InvalidEntry -> navController.navigate("invalid-entry")
is FindByResult.NotFound -> navController.navigate("not-found/${result.recipientId.toLong()}")
is FindByResult.NetworkError -> navController.navigate("network-error")
}
}
},
@@ -220,6 +220,16 @@ class FindByActivity : PassphraseRequiredActivity() {
)
}
dialog(
route = "network-error"
) {
Dialogs.SimpleMessageDialog(
message = getString(R.string.FindByActivity__network_error_dialog),
dismiss = getString(android.R.string.ok),
onDismiss = { navController.popBackStack() }
)
}
dialog(
route = "not-found/{recipientId}",
arguments = listOf(navArgument("recipientId") { type = NavType.LongType })
@@ -260,15 +270,10 @@ class FindByActivity : PassphraseRequiredActivity() {
dismiss = dismiss,
onConfirm = {
if (state.mode == FindByMode.PHONE_NUMBER) {
val recipientId = navBackStackEntry.arguments?.getLong("recipientId")?.takeIf { it > 0 }?.let { RecipientId.from(it) } ?: RecipientId.UNKNOWN
if (recipientId != RecipientId.UNKNOWN) {
InviteActions.inviteUserToSignal(
context,
Recipient.resolved(recipientId),
null,
this@FindByActivity::startActivity
)
}
InviteActions.inviteUserToSignal(
context,
this@FindByActivity::startActivity
)
}
},
onDismiss = { navController.popBackStack() }
@@ -429,6 +434,10 @@ private fun Content(
}
}
if (state.isLookupInProgress) {
Dialogs.IndeterminateProgressDialog()
}
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}

View File

@@ -11,4 +11,5 @@ sealed interface FindByResult {
data class Success(val recipientId: RecipientId) : FindByResult
object InvalidEntry : FindByResult
data class NotFound(val recipientId: RecipientId = RecipientId.UNKNOWN) : FindByResult
object NetworkError : FindByResult
}

View File

@@ -14,14 +14,11 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import org.signal.core.util.concurrent.safeBlockingGet
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery
import org.thoughtcrime.securesms.phonenumbers.NumberUtil
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientRepository
import org.thoughtcrime.securesms.registration.util.CountryPrefix
import org.thoughtcrime.securesms.util.UsernameUtil
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter
import java.util.concurrent.TimeUnit
class FindByViewModel(
mode: FindByMode
@@ -86,40 +83,13 @@ class FindByViewModel(
val countryCode = stateSnapshot.selectedCountryPrefix.digits
val nationalNumber = stateSnapshot.userEntry.removePrefix(countryCode.toString())
val e164 = "$countryCode$nationalNumber"
val e164 = "+$countryCode$nationalNumber"
if (!NumberUtil.isVisuallyValidNumber(e164)) {
return FindByResult.InvalidEntry
}
val recipient = try {
Recipient.external(context, e164)
} catch (e: Exception) {
return FindByResult.InvalidEntry
}
return if (!recipient.isRegistered || !recipient.hasServiceId()) {
try {
ContactDiscovery.refresh(context, recipient, false, TimeUnit.SECONDS.toMillis(10))
val resolved = Recipient.resolved(recipient.id)
if (!resolved.isRegistered) {
if (PhoneNumberFormatter.isValidNumber(nationalNumber, countryCode.toString())) {
FindByResult.NotFound(recipient.id)
} else {
FindByResult.InvalidEntry
}
} else {
FindByResult.Success(recipient.id)
}
} catch (e: Exception) {
if (PhoneNumberFormatter.isValidNumber(nationalNumber, countryCode.toString())) {
FindByResult.NotFound(recipient.id)
} else {
FindByResult.InvalidEntry
}
}
} else {
FindByResult.Success(recipient.id)
return when (val result = RecipientRepository.lookupNewE164(context, e164)) {
RecipientRepository.LookupResult.InvalidEntry -> FindByResult.InvalidEntry
RecipientRepository.LookupResult.NetworkError -> FindByResult.NetworkError
is RecipientRepository.LookupResult.NotFound -> FindByResult.NotFound(result.recipientId)
is RecipientRepository.LookupResult.Success -> FindByResult.Success(result.recipientId)
}
}
}