mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-25 11:20:47 +01:00
Handle safety number changes in a group call context.
This commit is contained in:
committed by
Greyson Parrelli
parent
112782ccaf
commit
42d61518b3
@@ -1410,7 +1410,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendAnywayAfterSafetyNumberChange() {
|
||||
public void onSendAnywayAfterSafetyNumberChange(@NonNull List<RecipientId> changedRecipients) {
|
||||
initializeIdentityRecords().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.telecom.Call;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -13,6 +12,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LiveData;
|
||||
@@ -30,16 +30,18 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public final class SafetyNumberChangeDialog extends DialogFragment implements SafetyNumberChangeAdapter.Callbacks {
|
||||
|
||||
public static final String SAFETY_NUMBER_DIALOG = "SAFETY_NUMBER";
|
||||
|
||||
private static final String RECIPIENT_IDS_EXTRA = "recipient_ids";
|
||||
private static final String MESSAGE_ID_EXTRA = "message_id";
|
||||
private static final String MESSAGE_TYPE_EXTRA = "message_type";
|
||||
private static final String IS_CALL_EXTRA = "is_call";
|
||||
private static final String RECIPIENT_IDS_EXTRA = "recipient_ids";
|
||||
private static final String MESSAGE_ID_EXTRA = "message_id";
|
||||
private static final String MESSAGE_TYPE_EXTRA = "message_type";
|
||||
private static final String CONTINUE_TEXT_RESOURCE_EXTRA = "continue_text_resource";
|
||||
private static final String CANCEL_TEXT_RESOURCE_EXTRA = "cancel_text_resource";
|
||||
|
||||
private SafetyNumberChangeViewModel viewModel;
|
||||
private SafetyNumberChangeAdapter adapter;
|
||||
@@ -54,6 +56,7 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
|
||||
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);
|
||||
@@ -69,6 +72,7 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
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(fragmentActivity.getSupportFragmentManager(), SAFETY_NUMBER_DIALOG);
|
||||
@@ -77,7 +81,43 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
public static void showForCall(@NonNull FragmentManager fragmentManager, @NonNull RecipientId recipientId) {
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putStringArray(RECIPIENT_IDS_EXTRA, new String[] { recipientId.serialize() });
|
||||
arguments.putBoolean(IS_CALL_EXTRA, true);
|
||||
arguments.putInt(CONTINUE_TEXT_RESOURCE_EXTRA, R.string.safety_number_change_dialog__call_anyway);
|
||||
SafetyNumberChangeDialog fragment = new SafetyNumberChangeDialog();
|
||||
fragment.setArguments(arguments);
|
||||
fragment.show(fragmentManager, SAFETY_NUMBER_DIALOG);
|
||||
}
|
||||
|
||||
public static void showForGroupCall(@NonNull FragmentManager fragmentManager, @NonNull List<IdentityDatabase.IdentityRecord> identityRecords) {
|
||||
List<String> ids = Stream.of(identityRecords)
|
||||
.filterNot(IdentityDatabase.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__join_call);
|
||||
SafetyNumberChangeDialog fragment = new SafetyNumberChangeDialog();
|
||||
fragment.setArguments(arguments);
|
||||
fragment.show(fragmentManager, SAFETY_NUMBER_DIALOG);
|
||||
}
|
||||
|
||||
public static void showForDuringGroupCall(@NonNull FragmentManager fragmentManager, @NonNull Collection<RecipientId> recipientIds) {
|
||||
Fragment previous = fragmentManager.findFragmentByTag(SAFETY_NUMBER_DIALOG);
|
||||
if (previous != null) {
|
||||
((SafetyNumberChangeDialog) previous).updateRecipients(recipientIds);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> ids = Stream.of(recipientIds)
|
||||
.map(RecipientId::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__continue_call);
|
||||
arguments.putInt(CANCEL_TEXT_RESOURCE_EXTRA, R.string.safety_number_change_dialog__leave_call);
|
||||
SafetyNumberChangeDialog fragment = new SafetyNumberChangeDialog();
|
||||
fragment.setArguments(arguments);
|
||||
fragment.show(fragmentManager, SAFETY_NUMBER_DIALOG);
|
||||
@@ -105,7 +145,8 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
|
||||
@Override
|
||||
public @NonNull Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
boolean isCall = requireArguments().getBoolean(IS_CALL_EXTRA, false);
|
||||
int continueText = requireArguments().getInt(CONTINUE_TEXT_RESOURCE_EXTRA, android.R.string.ok);
|
||||
int cancelText = requireArguments().getInt(CANCEL_TEXT_RESOURCE_EXTRA, android.R.string.cancel);
|
||||
|
||||
dialogView = LayoutInflater.from(requireActivity()).inflate(R.layout.safety_number_change_dialog, null);
|
||||
|
||||
@@ -115,13 +156,17 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
|
||||
builder.setTitle(R.string.safety_number_change_dialog__safety_number_changes)
|
||||
.setView(dialogView)
|
||||
.setPositiveButton(isCall ? R.string.safety_number_change_dialog__call_anyway : R.string.safety_number_change_dialog__send_anyway, this::handleSendAnyway)
|
||||
.setNegativeButton(android.R.string.cancel, this::handleCancel);
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(continueText, this::handleSendAnyway)
|
||||
.setNegativeButton(cancelText, this::handleCancel);
|
||||
|
||||
setCancelable(false);
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
@Override public void onDestroyView() {
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
dialogView = null;
|
||||
super.onDestroyView();
|
||||
}
|
||||
@@ -134,6 +179,10 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
list.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||
}
|
||||
|
||||
private void updateRecipients(Collection<RecipientId> recipientIds) {
|
||||
viewModel.updateRecipients(recipientIds);
|
||||
}
|
||||
|
||||
private void handleSendAnyway(DialogInterface dialogInterface, int which) {
|
||||
Activity activity = getActivity();
|
||||
Callback callback;
|
||||
@@ -149,9 +198,9 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
@Override
|
||||
public void onChanged(TrustAndVerifyResult result) {
|
||||
if (callback != null) {
|
||||
switch (result) {
|
||||
switch (result.getResult()) {
|
||||
case TRUST_AND_VERIFY:
|
||||
callback.onSendAnywayAfterSafetyNumberChange();
|
||||
callback.onSendAnywayAfterSafetyNumberChange(result.getChangedRecipients());
|
||||
break;
|
||||
case TRUST_VERIFY_AND_RESEND:
|
||||
callback.onMessageResentAfterSafetyNumberChange();
|
||||
@@ -177,7 +226,7 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onSendAnywayAfterSafetyNumberChange();
|
||||
void onSendAnywayAfterSafetyNumberChange(@NonNull List<RecipientId> changedRecipients);
|
||||
void onMessageResentAfterSafetyNumberChange();
|
||||
void onCanceled();
|
||||
}
|
||||
|
||||
@@ -11,15 +11,12 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||
import org.thoughtcrime.securesms.database.Database;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@@ -29,6 +26,7 @@ import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
||||
@@ -43,12 +41,6 @@ final class SafetyNumberChangeRepository {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@NonNull LiveData<SafetyNumberChangeState> getSafetyNumberChangeState(@NonNull List<RecipientId> recipientIds, @Nullable Long messageId, @Nullable String messageType) {
|
||||
MutableLiveData<SafetyNumberChangeState> liveData = new MutableLiveData<>();
|
||||
SignalExecutors.BOUNDED.execute(() -> liveData.postValue(getSafetyNumberChangeStateInternal(recipientIds, messageId, messageType)));
|
||||
return liveData;
|
||||
}
|
||||
|
||||
@NonNull LiveData<TrustAndVerifyResult> trustOrVerifyChangedRecipients(@NonNull List<ChangedRecipient> changedRecipients) {
|
||||
MutableLiveData<TrustAndVerifyResult> liveData = new MutableLiveData<>();
|
||||
SignalExecutors.BOUNDED.execute(() -> liveData.postValue(trustOrVerifyChangedRecipientsInternal(changedRecipients)));
|
||||
@@ -62,7 +54,7 @@ final class SafetyNumberChangeRepository {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private @NonNull SafetyNumberChangeState getSafetyNumberChangeStateInternal(@NonNull List<RecipientId> recipientIds, @Nullable Long messageId, @Nullable String messageType) {
|
||||
public @NonNull SafetyNumberChangeState getSafetyNumberChangeState(@NonNull Collection<RecipientId> recipientIds, @Nullable Long messageId, @Nullable String messageType) {
|
||||
MessageRecord messageRecord = null;
|
||||
if (messageId != null && messageType != null) {
|
||||
messageRecord = getMessageRecord(messageId, messageType);
|
||||
@@ -112,7 +104,7 @@ final class SafetyNumberChangeRepository {
|
||||
}
|
||||
}
|
||||
|
||||
return TrustAndVerifyResult.TRUST_AND_VERIFY;
|
||||
return TrustAndVerifyResult.trustAndVerify(changedRecipients);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -130,7 +122,7 @@ final class SafetyNumberChangeRepository {
|
||||
processOutgoingMessageRecord(changedRecipients, messageRecord);
|
||||
}
|
||||
|
||||
return TrustAndVerifyResult.TRUST_VERIFY_AND_RESEND;
|
||||
return TrustAndVerifyResult.trustVerifyAndResend(changedRecipients, messageRecord);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.conversation.ui.error;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
@@ -10,22 +11,26 @@ import androidx.lifecycle.ViewModelProvider;
|
||||
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeRepository.SafetyNumberChangeState;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class SafetyNumberChangeViewModel extends ViewModel {
|
||||
|
||||
private final SafetyNumberChangeRepository safetyNumberChangeRepository;
|
||||
private final LiveData<SafetyNumberChangeState> safetyNumberChangeState;
|
||||
private final SafetyNumberChangeRepository safetyNumberChangeRepository;
|
||||
private final MutableLiveData<Collection<RecipientId>> recipientIds;
|
||||
private final LiveData<SafetyNumberChangeState> safetyNumberChangeState;
|
||||
|
||||
private SafetyNumberChangeViewModel(@NonNull List<RecipientId> recipientIds,
|
||||
@Nullable Long messageId,
|
||||
@Nullable String messageType,
|
||||
SafetyNumberChangeRepository safetyNumberChangeRepository)
|
||||
@NonNull SafetyNumberChangeRepository safetyNumberChangeRepository)
|
||||
{
|
||||
this.safetyNumberChangeRepository = safetyNumberChangeRepository;
|
||||
safetyNumberChangeState = this.safetyNumberChangeRepository.getSafetyNumberChangeState(recipientIds, messageId, messageType);
|
||||
this.recipientIds = new MutableLiveData<>(recipientIds);
|
||||
this.safetyNumberChangeState = LiveDataUtil.mapAsync(this.recipientIds, ids -> this.safetyNumberChangeRepository.getSafetyNumberChangeState(ids, messageId, messageType));
|
||||
}
|
||||
|
||||
@NonNull LiveData<List<ChangedRecipient>> getChangedRecipients() {
|
||||
@@ -41,6 +46,10 @@ public final class SafetyNumberChangeViewModel extends ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
void updateRecipients(Collection<RecipientId> recipientIds) {
|
||||
this.recipientIds.setValue(recipientIds);
|
||||
}
|
||||
|
||||
public static final class Factory implements ViewModelProvider.Factory {
|
||||
private final List<RecipientId> recipientIds;
|
||||
private final Long messageId;
|
||||
|
||||
@@ -1,7 +1,53 @@
|
||||
package org.thoughtcrime.securesms.conversation.ui.error;
|
||||
|
||||
public enum TrustAndVerifyResult {
|
||||
TRUST_AND_VERIFY,
|
||||
TRUST_VERIFY_AND_RESEND,
|
||||
UNKNOWN
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Result of trust/verify after safety number change.
|
||||
*/
|
||||
public class TrustAndVerifyResult {
|
||||
|
||||
private final List<RecipientId> changedRecipients;
|
||||
private final MessageRecord messageRecord;
|
||||
private final Result result;
|
||||
|
||||
static TrustAndVerifyResult trustAndVerify(@NonNull List<ChangedRecipient> changedRecipients) {
|
||||
return new TrustAndVerifyResult(changedRecipients, null, Result.TRUST_AND_VERIFY);
|
||||
}
|
||||
|
||||
static TrustAndVerifyResult trustVerifyAndResend(@NonNull List<ChangedRecipient> changedRecipients, @NonNull MessageRecord messageRecord) {
|
||||
return new TrustAndVerifyResult(changedRecipients, messageRecord, Result.TRUST_VERIFY_AND_RESEND);
|
||||
}
|
||||
|
||||
TrustAndVerifyResult(@NonNull List<ChangedRecipient> changedRecipients, @Nullable MessageRecord messageRecord, @NonNull Result result) {
|
||||
this.changedRecipients = Stream.of(changedRecipients).map(changedRecipient -> changedRecipient.getRecipient().getId()).toList();
|
||||
this.messageRecord = messageRecord;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientId> getChangedRecipients() {
|
||||
return changedRecipients;
|
||||
}
|
||||
|
||||
public @Nullable MessageRecord getMessageRecord() {
|
||||
return messageRecord;
|
||||
}
|
||||
|
||||
public @NonNull Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum Result {
|
||||
TRUST_AND_VERIFY,
|
||||
TRUST_VERIFY_AND_RESEND,
|
||||
UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user