mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-25 04:06:14 +00:00
Always perform CDSI lookups when starting new chats.
This commit is contained in:
committed by
Alex Hart
parent
184c1b67cc
commit
2e4ac7ede1
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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?
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user