mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-26 03:40:56 +01:00
Implement new Safety Number Changes bottom sheeet.
This commit is contained in:
@@ -158,6 +158,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceMessageActivity;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
|
||||
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
@@ -1874,7 +1875,8 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
||||
|
||||
@Override
|
||||
public void onIncomingIdentityMismatchClicked(@NonNull RecipientId recipientId) {
|
||||
SafetyNumberChangeDialog.show(getParentFragmentManager(), recipientId);
|
||||
SafetyNumberBottomSheet.forRecipientId(recipientId)
|
||||
.show(getParentFragmentManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -152,6 +152,7 @@ import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNotePlayerView;
|
||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey;
|
||||
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.contactshare.ContactShareEditActivity;
|
||||
@@ -161,7 +162,6 @@ import org.thoughtcrime.securesms.conversation.ConversationGroupViewModel.GroupA
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
|
||||
import org.thoughtcrime.securesms.conversation.drafts.DraftRepository;
|
||||
import org.thoughtcrime.securesms.conversation.drafts.DraftViewModel;
|
||||
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog;
|
||||
import org.thoughtcrime.securesms.conversation.ui.groupcall.GroupCallViewModel;
|
||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel;
|
||||
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
|
||||
@@ -263,6 +263,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.recipients.ui.disappearingmessages.RecipientDisappearingMessagesActivity;
|
||||
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
|
||||
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet;
|
||||
import org.thoughtcrime.securesms.search.MessageResult;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
@@ -348,7 +349,7 @@ public class ConversationParentFragment extends Fragment
|
||||
AttachmentKeyboard.Callback,
|
||||
ConversationReactionOverlay.OnReactionSelectedListener,
|
||||
ReactWithAnyEmojiBottomSheetDialogFragment.Callback,
|
||||
SafetyNumberChangeDialog.Callback,
|
||||
SafetyNumberBottomSheet.Callbacks,
|
||||
ReactionsBottomSheetDialogFragment.Callback,
|
||||
MediaKeyboard.MediaKeyboardListener,
|
||||
EmojiEventListener,
|
||||
@@ -1594,22 +1595,16 @@ public class ConversationParentFragment extends Fragment
|
||||
private void handleRecentSafetyNumberChange() {
|
||||
List<IdentityRecord> records = identityRecords.getUnverifiedRecords();
|
||||
records.addAll(identityRecords.getUntrustedRecords());
|
||||
SafetyNumberChangeDialog.show(getChildFragmentManager(), records);
|
||||
SafetyNumberBottomSheet
|
||||
.forIdentityRecordsAndDestination(
|
||||
records,
|
||||
new ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.getId())
|
||||
)
|
||||
.show(getChildFragmentManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendAnywayAfterSafetyNumberChange(@NonNull List<RecipientId> changedRecipients) {
|
||||
Log.d(TAG, "onSendAnywayAfterSafetyNumberChange");
|
||||
initializeIdentityRecords().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
sendMessage(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageResentAfterSafetyNumberChange() {
|
||||
public void onMessageResentAfterSafetyNumberChangeInBottomSheet() {
|
||||
Log.d(TAG, "onMessageResentAfterSafetyNumberChange");
|
||||
initializeIdentityRecords().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
@@ -3629,6 +3624,17 @@ public class ConversationParentFragment extends Fragment
|
||||
material3OnScrollHelper.setColorImmediate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAnywayAfterSafetyNumberChangedInBottomSheet(@NonNull List<? extends ContactSearchKey.RecipientSearchKey> destinations) {
|
||||
Log.d(TAG, "onSendAnywayAfterSafetyNumberChange");
|
||||
initializeIdentityRecords().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
sendMessage(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Listeners
|
||||
|
||||
private final class DeleteCanceledVoiceNoteListener implements ListenableFuture.Listener<VoiceNoteDraft> {
|
||||
@@ -3888,7 +3894,9 @@ public class ConversationParentFragment extends Fragment
|
||||
@Override
|
||||
public void onMessageWithErrorClicked(@NonNull MessageRecord messageRecord) {
|
||||
if (messageRecord.isIdentityMismatchFailure()) {
|
||||
SafetyNumberChangeDialog.show(requireContext(), getChildFragmentManager(), messageRecord);
|
||||
SafetyNumberBottomSheet
|
||||
.forMessageRecord(requireContext(), messageRecord)
|
||||
.show(getChildFragmentManager());
|
||||
} else if (messageRecord.hasFailedWithNetworkFailures()) {
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setMessage(R.string.conversation_activity__message_could_not_be_sent)
|
||||
|
||||
@@ -34,12 +34,12 @@ import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchMediator
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchState
|
||||
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog
|
||||
import org.thoughtcrime.securesms.database.model.IdentityRecord
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseGroupStoryBottomSheet
|
||||
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
|
||||
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
||||
import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter
|
||||
import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel
|
||||
@@ -74,7 +74,7 @@ import org.thoughtcrime.securesms.util.visible
|
||||
*/
|
||||
class MultiselectForwardFragment :
|
||||
Fragment(R.layout.multiselect_forward_fragment),
|
||||
SafetyNumberChangeDialog.Callback,
|
||||
SafetyNumberBottomSheet.Callbacks,
|
||||
ChooseStoryTypeBottomSheet.Callback,
|
||||
WrapperDialogFragment.WrapperDialogFragmentCallback,
|
||||
ChooseInitialMyStoryMembershipBottomSheetDialogFragment.Callback {
|
||||
@@ -204,7 +204,7 @@ class MultiselectForwardFragment :
|
||||
when (it.stage) {
|
||||
MultiselectForwardState.Stage.Selection -> {}
|
||||
MultiselectForwardState.Stage.FirstConfirmation -> displayFirstSendConfirmation()
|
||||
is MultiselectForwardState.Stage.SafetyConfirmation -> displaySafetyNumberConfirmation(it.stage.identities)
|
||||
is MultiselectForwardState.Stage.SafetyConfirmation -> displaySafetyNumberConfirmation(it.stage.identities, it.stage.selectedContacts)
|
||||
MultiselectForwardState.Stage.LoadingIdentities -> {}
|
||||
MultiselectForwardState.Stage.SendPending -> {
|
||||
handler?.removeCallbacksAndMessages(null)
|
||||
@@ -288,8 +288,10 @@ class MultiselectForwardFragment :
|
||||
viewModel.send(addMessage.text.toString(), contactSearchMediator.getSelectedContacts())
|
||||
}
|
||||
|
||||
private fun displaySafetyNumberConfirmation(identityRecords: List<IdentityRecord>) {
|
||||
SafetyNumberChangeDialog.show(childFragmentManager, identityRecords)
|
||||
private fun displaySafetyNumberConfirmation(identityRecords: List<IdentityRecord>, selectedContacts: List<ContactSearchKey>) {
|
||||
SafetyNumberBottomSheet
|
||||
.forIdentityRecordsAndDestinations(identityRecords, selectedContacts)
|
||||
.show(childFragmentManager)
|
||||
}
|
||||
|
||||
private fun dismissWithSuccess(@PluralsRes toastTextResId: Int) {
|
||||
@@ -332,11 +334,11 @@ class MultiselectForwardFragment :
|
||||
callback.exitFlow()
|
||||
}
|
||||
|
||||
override fun onSendAnywayAfterSafetyNumberChange(changedRecipients: MutableList<RecipientId>) {
|
||||
viewModel.confirmSafetySend(addMessage.text.toString(), contactSearchMediator.getSelectedContacts())
|
||||
override fun sendAnywayAfterSafetyNumberChangedInBottomSheet(destinations: List<ContactSearchKey.RecipientSearchKey>) {
|
||||
viewModel.confirmSafetySend(addMessage.text.toString(), destinations.toSet())
|
||||
}
|
||||
|
||||
override fun onMessageResentAfterSafetyNumberChange() {
|
||||
override fun onMessageResentAfterSafetyNumberChangeInBottomSheet() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ data class MultiselectForwardState(
|
||||
object Selection : Stage()
|
||||
object FirstConfirmation : Stage()
|
||||
object LoadingIdentities : Stage()
|
||||
data class SafetyConfirmation(val identities: List<IdentityRecord>) : Stage()
|
||||
data class SafetyConfirmation(val identities: List<IdentityRecord>, val selectedContacts: List<ContactSearchKey>) : Stage()
|
||||
object SendPending : Stage()
|
||||
object SomeFailed : Stage()
|
||||
object AllFailed : Stage()
|
||||
|
||||
@@ -44,7 +44,14 @@ class MultiselectForwardViewModel(
|
||||
if (identityRecords.isEmpty()) {
|
||||
performSend(additionalMessage, selectedContacts)
|
||||
} else {
|
||||
store.update { it.copy(stage = MultiselectForwardState.Stage.SafetyConfirmation(identityRecords)) }
|
||||
store.update { state ->
|
||||
state.copy(
|
||||
stage = MultiselectForwardState.Stage.SafetyConfirmation(
|
||||
identityRecords,
|
||||
selectedContacts.filterIsInstance<ContactSearchKey.RecipientSearchKey>()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.conversation.ui.error;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -28,9 +27,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.IdentityRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity;
|
||||
|
||||
@@ -64,37 +61,6 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
fragment.show(fragmentManager, SAFETY_NUMBER_DIALOG);
|
||||
}
|
||||
|
||||
public static void show(@NonNull FragmentManager fragmentManager, @NonNull List<IdentityRecord> identityRecords) {
|
||||
List<String> ids = Stream.of(identityRecords)
|
||||
.filterNot(IdentityRecord::isFirstUse)
|
||||
.map(record -> record.getRecipientId().serialize())
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putStringArray(RECIPIENT_IDS_EXTRA, ids.toArray(new String[0]));
|
||||
arguments.putInt(CONTINUE_TEXT_RESOURCE_EXTRA, R.string.safety_number_change_dialog__send_anyway);
|
||||
SafetyNumberChangeDialog fragment = new SafetyNumberChangeDialog();
|
||||
fragment.setArguments(arguments);
|
||||
fragment.show(fragmentManager, SAFETY_NUMBER_DIALOG);
|
||||
}
|
||||
|
||||
public static void show(@NonNull Context context, @NonNull FragmentManager fragmentManager, @NonNull MessageRecord messageRecord) {
|
||||
List<String> ids = Stream.of(messageRecord.getIdentityKeyMismatches())
|
||||
.map(mismatch -> mismatch.getRecipientId(context).serialize())
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putStringArray(RECIPIENT_IDS_EXTRA, ids.toArray(new String[0]));
|
||||
arguments.putLong(MESSAGE_ID_EXTRA, messageRecord.getId());
|
||||
arguments.putString(MESSAGE_TYPE_EXTRA, messageRecord.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
|
||||
arguments.putInt(CONTINUE_TEXT_RESOURCE_EXTRA, R.string.safety_number_change_dialog__send_anyway);
|
||||
SafetyNumberChangeDialog fragment = new SafetyNumberChangeDialog();
|
||||
fragment.setArguments(arguments);
|
||||
fragment.show(fragmentManager, SAFETY_NUMBER_DIALOG);
|
||||
}
|
||||
|
||||
public static void showForCall(@NonNull FragmentManager fragmentManager, @NonNull RecipientId recipientId) {
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putStringArray(RECIPIENT_IDS_EXTRA, new String[] { recipientId.serialize() });
|
||||
@@ -140,7 +106,7 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
fragment.show(fragmentManager, SAFETY_NUMBER_DIALOG);
|
||||
}
|
||||
|
||||
private SafetyNumberChangeDialog() { }
|
||||
private SafetyNumberChangeDialog() {}
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
|
||||
@@ -22,10 +22,12 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.IdentityRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.safety.SafetyNumberRecipient;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||
@@ -35,17 +37,39 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
final class SafetyNumberChangeRepository {
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public final class SafetyNumberChangeRepository {
|
||||
|
||||
private static final String TAG = Log.tag(SafetyNumberChangeRepository.class);
|
||||
|
||||
private final Context context;
|
||||
|
||||
SafetyNumberChangeRepository(Context context) {
|
||||
public SafetyNumberChangeRepository(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Single<TrustAndVerifyResult> trustOrVerifyChangedRecipientsRx(@NonNull List<SafetyNumberRecipient> safetyNumberRecipients) {
|
||||
Log.d(TAG, "Trust or verify changed recipients for: " + Util.join(safetyNumberRecipients, ","));
|
||||
return Single.fromCallable(() -> trustOrVerifyChangedRecipientsInternal(fromSafetyNumberRecipients(safetyNumberRecipients)))
|
||||
.subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Single<TrustAndVerifyResult> trustOrVerifyChangedRecipientsAndResendRx(@NonNull List<SafetyNumberRecipient> safetyNumberRecipients, @NonNull MessageId messageId) {
|
||||
Log.d(TAG, "Trust or verify changed recipients and resend message: " + messageId + " for: " + Util.join(safetyNumberRecipients, ","));
|
||||
return Single.fromCallable(() -> {
|
||||
MessageRecord messageRecord = messageId.isMms() ? SignalDatabase.mms().getMessageRecord(messageId.getId())
|
||||
: SignalDatabase.sms().getMessageRecord(messageId.getId());
|
||||
|
||||
return trustOrVerifyChangedRecipientsAndResendInternal(fromSafetyNumberRecipients(safetyNumberRecipients), messageRecord);
|
||||
}).subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
@NonNull LiveData<TrustAndVerifyResult> trustOrVerifyChangedRecipients(@NonNull List<ChangedRecipient> changedRecipients) {
|
||||
Log.d(TAG, "Trust or verify changed recipients for: " + Util.join(changedRecipients, ","));
|
||||
MutableLiveData<TrustAndVerifyResult> liveData = new MutableLiveData<>();
|
||||
@@ -78,6 +102,14 @@ final class SafetyNumberChangeRepository {
|
||||
return new SafetyNumberChangeState(changedRecipients, messageRecord);
|
||||
}
|
||||
|
||||
private @NonNull List<ChangedRecipient> fromSafetyNumberRecipients(@NonNull List<SafetyNumberRecipient> safetyNumberRecipients) {
|
||||
return safetyNumberRecipients.stream().map(this::fromSafetyNumberRecipient).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private @NonNull ChangedRecipient fromSafetyNumberRecipient(@NonNull SafetyNumberRecipient safetyNumberRecipient) {
|
||||
return new ChangedRecipient(safetyNumberRecipient.getRecipient(), safetyNumberRecipient.getIdentityRecord());
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private @Nullable MessageRecord getMessageRecord(Long messageId, String messageType) {
|
||||
try {
|
||||
@@ -99,7 +131,7 @@ final class SafetyNumberChangeRepository {
|
||||
private TrustAndVerifyResult trustOrVerifyChangedRecipientsInternal(@NonNull List<ChangedRecipient> changedRecipients) {
|
||||
SignalIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
|
||||
|
||||
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||
for (ChangedRecipient changedRecipient : changedRecipients) {
|
||||
IdentityRecord identityRecord = changedRecipient.getIdentityRecord();
|
||||
|
||||
@@ -126,7 +158,7 @@ final class SafetyNumberChangeRepository {
|
||||
Log.d(TAG, "No changed recipients to process, will still process message record");
|
||||
}
|
||||
|
||||
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
||||
for (ChangedRecipient changedRecipient : changedRecipients) {
|
||||
SignalProtocolAddress mismatchAddress = changedRecipient.getRecipient().requireServiceId().toProtocolAddress(SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user