parent
233cc7ecce
commit
0e2d52026e
|
@ -223,7 +223,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
|
|||
.setConstraintFactories(JobManagerFactories.getConstraintFactories(this))
|
||||
.setConstraintObservers(JobManagerFactories.getConstraintObservers(this))
|
||||
.setJobStorage(new FastJobStorage(DatabaseFactory.getJobDatabase(this)))
|
||||
.setJobMigrator(new JobMigrator(TextSecurePreferences.getJobManagerVersion(this), 1, JobManagerFactories.getJobMigrations()))
|
||||
.setJobMigrator(new JobMigrator(TextSecurePreferences.getJobManagerVersion(this), 2, JobManagerFactories.getJobMigrations(this)))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
@ -338,7 +338,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
|
|||
|
||||
private void executePendingContactSync() {
|
||||
if (TextSecurePreferences.needsFullContactSync(this)) {
|
||||
ApplicationContext.getInstance(this).getJobManager().add(new MultiDeviceContactUpdateJob(this, true));
|
||||
ApplicationContext.getInstance(this).getJobManager().add(new MultiDeviceContactUpdateJob(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
|||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
|
@ -36,7 +37,7 @@ public interface BindableConversationItem extends Unbindable {
|
|||
interface EventListener {
|
||||
void onQuoteClicked(MmsMessageRecord messageRecord);
|
||||
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
|
||||
void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms);
|
||||
void onMoreTextClicked(@NonNull RecipientId conversationRecipientId, long messageId, boolean isMms);
|
||||
void onStickerClicked(@NonNull StickerLocator stickerLocator);
|
||||
void onViewOnceMessageClicked(@NonNull MmsMessageRecord messageRecord);
|
||||
void onSharedContactDetailsClicked(@NonNull Contact contact, @NonNull View avatarTransitionView);
|
||||
|
|
|
@ -17,12 +17,14 @@ import android.view.ViewGroup;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.loaders.BlockedContactsLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.preferences.BlockedContactListItem;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
|
||||
|
@ -78,6 +80,12 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
|
|||
getLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getLoaderManager().restartLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle bundle) {
|
||||
super.onActivityCreated(bundle);
|
||||
|
@ -107,7 +115,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
|
|||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
Recipient recipient = ((BlockedContactListItem)view).getRecipient();
|
||||
Intent intent = new Intent(getActivity(), RecipientPreferenceActivity.class);
|
||||
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENT_ID, recipient.getId());
|
||||
|
||||
startActivity(intent);
|
||||
}
|
||||
|
@ -129,8 +137,8 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
String address = cursor.getString(1);
|
||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(address), true);
|
||||
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RecipientDatabase.ID)));
|
||||
LiveRecipient recipient = Recipient.live(recipientId);
|
||||
|
||||
((BlockedContactListItem) view).set(glideRequests, recipient);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import android.text.method.LinkMovementMethod;
|
|||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
|
@ -22,6 +21,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
|||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.jobs.PushDecryptJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.VerifySpan;
|
||||
|
@ -46,7 +46,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||
{
|
||||
super(context);
|
||||
|
||||
Recipient recipient = Recipient.from(context, mismatch.getAddress(), false);
|
||||
Recipient recipient = Recipient.resolved(mismatch.getRecipientId(context));
|
||||
String name = recipient.toShortString();
|
||||
String introduction = context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed, name, name);
|
||||
SpannableString spannableString = new SpannableString(introduction + " " +
|
||||
|
@ -59,7 +59,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||
setTitle(name);
|
||||
setMessage(spannableString);
|
||||
|
||||
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(messageRecord, mismatch, recipient.getAddress()));
|
||||
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(messageRecord, mismatch, recipient.getId()));
|
||||
setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), new CancelListener());
|
||||
}
|
||||
|
||||
|
@ -78,12 +78,12 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||
|
||||
private final MessageRecord messageRecord;
|
||||
private final IdentityKeyMismatch mismatch;
|
||||
private final Address address;
|
||||
private final RecipientId recipientId;
|
||||
|
||||
private AcceptListener(MessageRecord messageRecord, IdentityKeyMismatch mismatch, Address address) {
|
||||
private AcceptListener(MessageRecord messageRecord, IdentityKeyMismatch mismatch, RecipientId recipientId) {
|
||||
this.messageRecord = messageRecord;
|
||||
this.mismatch = mismatch;
|
||||
this.address = address;
|
||||
this.recipientId = recipientId;
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
|
@ -94,7 +94,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(address.toPhoneString(), 1);
|
||||
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireAddress().toPhoneString(), 1);
|
||||
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
|
||||
|
||||
identityKeyStore.saveIdentity(mismatchAddress, mismatch.getIdentityKey(), true);
|
||||
|
@ -137,17 +137,17 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||
|
||||
if (messageRecord.isMms()) {
|
||||
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
||||
mismatch.getAddress(),
|
||||
mismatch.getRecipientId(getContext()),
|
||||
mismatch.getIdentityKey());
|
||||
|
||||
if (messageRecord.getRecipient().isPushGroupRecipient()) {
|
||||
MessageSender.resendGroupMessage(getContext(), messageRecord, mismatch.getAddress());
|
||||
if (messageRecord.getRecipient().isPushGroup()) {
|
||||
MessageSender.resendGroupMessage(getContext(), messageRecord, Recipient.resolved(mismatch.getRecipientId(getContext())).getId());
|
||||
} else {
|
||||
MessageSender.resend(getContext(), messageRecord);
|
||||
}
|
||||
} else {
|
||||
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
||||
mismatch.getAddress(),
|
||||
mismatch.getRecipientId(getContext()),
|
||||
mismatch.getIdentityKey());
|
||||
|
||||
MessageSender.resend(getContext(), messageRecord);
|
||||
|
@ -160,13 +160,13 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
|
||||
|
||||
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
||||
mismatch.getAddress(),
|
||||
mismatch.getRecipientId(getContext()),
|
||||
mismatch.getIdentityKey());
|
||||
|
||||
boolean legacy = !messageRecord.isContentBundleKeyExchange();
|
||||
|
||||
SignalServiceEnvelope envelope = new SignalServiceEnvelope(SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE,
|
||||
messageRecord.getIndividualRecipient().getAddress().toPhoneString(),
|
||||
messageRecord.getIndividualRecipient().requireAddress().toPhoneString(),
|
||||
messageRecord.getRecipientDeviceId(),
|
||||
messageRecord.getDateSent(),
|
||||
legacy ? Base64.decode(messageRecord.getBody()) : null,
|
||||
|
|
|
@ -45,7 +45,6 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
|||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
|
||||
|
@ -112,9 +111,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||
dynamicTheme.onResume(this);
|
||||
dynamicLanguage.onResume(this);
|
||||
|
||||
SimpleTask.run(getLifecycle(), () -> {
|
||||
return Recipient.from(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)), false);
|
||||
}, this::initializeProfileIcon);
|
||||
SimpleTask.run(getLifecycle(), Recipient::self, this::initializeProfileIcon);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -191,7 +188,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||
Drawable fallback = new GeneratedContactPhoto(name, R.drawable.ic_profile_default).asDrawable(this, fallbackColor.toAvatarColor(this));
|
||||
|
||||
GlideApp.with(this)
|
||||
.load(new ProfileContactPhoto(recipient.getAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this))))
|
||||
.load(new ProfileContactPhoto(recipient.requireAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this))))
|
||||
.error(fallback)
|
||||
.circleCrop()
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
|
@ -225,7 +222,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||
searchToolbar.clearFocus();
|
||||
|
||||
Intent intent = new Intent(this, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis());
|
||||
|
|
|
@ -76,7 +76,7 @@ class ConversationListAdapter extends CursorRecyclerViewAdapter<ConversationList
|
|||
public long getItemId(@NonNull Cursor cursor) {
|
||||
ThreadRecord record = getThreadRecord(cursor);
|
||||
|
||||
return Conversions.byteArrayToLong(digest.digest(record.getRecipient().getAddress().serialize().getBytes()));
|
||||
return Conversions.byteArrayToLong(digest.digest(record.getRecipient().getId().serialize().getBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ConversationListArchiveActivity extends PassphraseRequiredActionBar
|
|||
@Override
|
||||
public void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeenTime) {
|
||||
Intent intent = new Intent(this, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.putExtra(ConversationActivity.IS_ARCHIVED_EXTRA, true);
|
||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||
|
|
|
@ -39,13 +39,13 @@ import org.thoughtcrime.securesms.components.ThumbnailView;
|
|||
import org.thoughtcrime.securesms.components.TypingIndicatorView;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.search.model.MessageResult;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.SearchUtil;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -53,7 +53,7 @@ import java.util.Locale;
|
|||
import java.util.Set;
|
||||
|
||||
public class ConversationListItem extends RelativeLayout
|
||||
implements RecipientModifiedListener,
|
||||
implements RecipientForeverObserver,
|
||||
BindableConversationListItem, Unbindable
|
||||
{
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -65,7 +65,7 @@ public class ConversationListItem extends RelativeLayout
|
|||
private static final int MAX_SNIPPET_LENGTH = 500;
|
||||
|
||||
private Set<Long> selectedThreads;
|
||||
private Recipient recipient;
|
||||
private LiveRecipient recipient;
|
||||
private long threadId;
|
||||
private GlideRequests glideRequests;
|
||||
private View subjectContainer;
|
||||
|
@ -132,21 +132,23 @@ public class ConversationListItem extends RelativeLayout
|
|||
boolean batchMode,
|
||||
@Nullable String highlightSubstring)
|
||||
{
|
||||
if (this.recipient != null) this.recipient.removeForeverObserver(this);
|
||||
|
||||
this.selectedThreads = selectedThreads;
|
||||
this.recipient = thread.getRecipient();
|
||||
this.recipient = thread.getRecipient().live();
|
||||
this.threadId = thread.getThreadId();
|
||||
this.glideRequests = glideRequests;
|
||||
this.unreadCount = thread.getUnreadCount();
|
||||
this.distributionType = thread.getDistributionType();
|
||||
this.lastSeen = thread.getLastSeen();
|
||||
|
||||
this.recipient.addListener(this);
|
||||
this.recipient.observeForever(this);
|
||||
if (highlightSubstring != null) {
|
||||
String name = recipient.isLocalNumber() ? getContext().getString(R.string.note_to_self) : recipient.getName();
|
||||
String name = recipient.get().isLocalNumber() ? getContext().getString(R.string.note_to_self) : recipient.get().getName();
|
||||
|
||||
this.fromView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), name, highlightSubstring));
|
||||
} else {
|
||||
this.fromView.setText(recipient, unreadCount == 0);
|
||||
this.fromView.setText(recipient.get(), unreadCount == 0);
|
||||
}
|
||||
|
||||
if (typingThreads.contains(threadId)) {
|
||||
|
@ -182,9 +184,9 @@ public class ConversationListItem extends RelativeLayout
|
|||
setStatusIcons(thread);
|
||||
setThumbnailSnippet(thread);
|
||||
setBatchState(batchMode);
|
||||
setRippleColor(recipient);
|
||||
setRippleColor(recipient.get());
|
||||
setUnreadIndicator(thread);
|
||||
this.contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
this.contactPhotoImage.setAvatar(glideRequests, recipient.get(), true);
|
||||
}
|
||||
|
||||
public void bind(@NonNull Recipient contact,
|
||||
|
@ -192,16 +194,18 @@ public class ConversationListItem extends RelativeLayout
|
|||
@NonNull Locale locale,
|
||||
@Nullable String highlightSubstring)
|
||||
{
|
||||
if (this.recipient != null) this.recipient.removeForeverObserver(this);
|
||||
|
||||
this.selectedThreads = Collections.emptySet();
|
||||
this.recipient = contact;
|
||||
this.recipient = contact.live();
|
||||
this.glideRequests = glideRequests;
|
||||
|
||||
this.recipient.addListener(this);
|
||||
this.recipient.observeForever(this);
|
||||
|
||||
String name = recipient.isLocalNumber() ? getContext().getString(R.string.note_to_self) : recipient.getName();
|
||||
String name = recipient.get().isLocalNumber() ? getContext().getString(R.string.note_to_self) : recipient.get().getName();
|
||||
|
||||
fromView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), name, highlightSubstring));
|
||||
subjectView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), contact.getAddress().toString(), highlightSubstring));
|
||||
subjectView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), contact.requireAddress().toString(), highlightSubstring));
|
||||
dateView.setText("");
|
||||
archivedView.setVisibility(GONE);
|
||||
unreadIndicator.setVisibility(GONE);
|
||||
|
@ -211,7 +215,7 @@ public class ConversationListItem extends RelativeLayout
|
|||
|
||||
setBatchState(false);
|
||||
setRippleColor(contact);
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient.get(), true);
|
||||
}
|
||||
|
||||
public void bind(@NonNull MessageResult messageResult,
|
||||
|
@ -219,13 +223,15 @@ public class ConversationListItem extends RelativeLayout
|
|||
@NonNull Locale locale,
|
||||
@Nullable String highlightSubstring)
|
||||
{
|
||||
if (this.recipient != null) this.recipient.removeForeverObserver(this);
|
||||
|
||||
this.selectedThreads = Collections.emptySet();
|
||||
this.recipient = messageResult.conversationRecipient;
|
||||
this.recipient = messageResult.conversationRecipient.live();
|
||||
this.glideRequests = glideRequests;
|
||||
|
||||
this.recipient.addListener(this);
|
||||
this.recipient.observeForever(this);
|
||||
|
||||
fromView.setText(recipient, true);
|
||||
fromView.setText(recipient.get(), true);
|
||||
subjectView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), messageResult.bodySnippet, highlightSubstring));
|
||||
dateView.setText(DateUtils.getBriefRelativeTimeSpanString(getContext(), locale, messageResult.receivedTimestampMs));
|
||||
archivedView.setVisibility(GONE);
|
||||
|
@ -235,14 +241,14 @@ public class ConversationListItem extends RelativeLayout
|
|||
thumbnailView.setVisibility(GONE);
|
||||
|
||||
setBatchState(false);
|
||||
setRippleColor(recipient);
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
setRippleColor(recipient.get());
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient.get(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (this.recipient != null) {
|
||||
this.recipient.removeListener(this);
|
||||
this.recipient.removeForeverObserver(this);
|
||||
this.recipient = null;
|
||||
contactPhotoImage.setAvatar(glideRequests, null, true);
|
||||
}
|
||||
|
@ -253,7 +259,7 @@ public class ConversationListItem extends RelativeLayout
|
|||
}
|
||||
|
||||
public Recipient getRecipient() {
|
||||
return recipient;
|
||||
return recipient.get();
|
||||
}
|
||||
|
||||
public long getThreadId() {
|
||||
|
@ -339,14 +345,10 @@ public class ConversationListItem extends RelativeLayout
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(() -> {
|
||||
if (this.recipient == recipient) {
|
||||
fromView.setText(recipient, unreadCount == 0);
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
setRippleColor(recipient);
|
||||
}
|
||||
});
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
fromView.setText(recipient, unreadCount == 0);
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
setRippleColor(recipient);
|
||||
}
|
||||
|
||||
private static class ThumbnailPositioner implements Runnable {
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.groups.GroupManager;
|
|||
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
|
@ -260,7 +261,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||
Intent intent = new Intent(this, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
@ -286,9 +287,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||
List<String> selected = data.getStringArrayListExtra("contacts");
|
||||
|
||||
for (String contact : selected) {
|
||||
Address address = Address.fromExternal(this, contact);
|
||||
Recipient recipient = Recipient.from(this, address, false);
|
||||
|
||||
Recipient recipient = Recipient.external(this, contact);
|
||||
addSelectedContacts(recipient);
|
||||
}
|
||||
break;
|
||||
|
@ -338,16 +337,17 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
@Override
|
||||
protected GroupActionResult doInBackground(Void... avoid) {
|
||||
List<Address> memberAddresses = new LinkedList<>();
|
||||
List<RecipientId> memberAddresses = new LinkedList<>();
|
||||
|
||||
for (Recipient recipient : members) {
|
||||
memberAddresses.add(recipient.getAddress());
|
||||
memberAddresses.add(recipient.getId());
|
||||
}
|
||||
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(activity)));
|
||||
memberAddresses.add(Recipient.self().getId());
|
||||
|
||||
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true);
|
||||
Recipient groupRecipient = Recipient.from(activity, Address.fromSerialized(groupId), true);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true);
|
||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(activity).getOrInsertFromGroupId(groupId);
|
||||
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
|
||||
return new GroupActionResult(groupRecipient, threadId);
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||
if (!activity.isFinishing()) {
|
||||
Intent intent = activity.getIntent();
|
||||
intent.putExtra(GROUP_THREAD_EXTRA, result.get().getThreadId());
|
||||
intent.putExtra(GROUP_ADDRESS_EXTRA, result.get().getGroupRecipient().getAddress());
|
||||
intent.putExtra(GROUP_ADDRESS_EXTRA, result.get().getGroupRecipient().requireAddress());
|
||||
activity.setResult(RESULT_OK, intent);
|
||||
activity.finish();
|
||||
}
|
||||
|
@ -493,7 +493,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||
if (failIfNotPush && !isPush) {
|
||||
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_cannot_add_non_push_to_existing_group,
|
||||
recipient.toShortString())));
|
||||
} else if (TextUtils.equals(TextSecurePreferences.getLocalNumber(activity), recipient.getAddress().serialize())) {
|
||||
} else if (TextUtils.equals(TextSecurePreferences.getLocalNumber(activity), recipient.requireAddress().serialize())) {
|
||||
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_youre_already_in_the_group)));
|
||||
} else {
|
||||
results.add(new Result(recipient, isPush, null));
|
||||
|
|
|
@ -32,7 +32,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
|
|||
|
||||
@Override
|
||||
protected List<Recipient> doInBackground(Void... params) {
|
||||
return DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), true);
|
||||
return DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.requireAddress().toGroupString(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,7 +66,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
|
|||
|
||||
if (recipient.getContactUri() != null) {
|
||||
Intent intent = new Intent(context, RecipientPreferenceActivity.class);
|
||||
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENT_ID, recipient.getId());
|
||||
|
||||
context.startActivity(intent);
|
||||
} else {
|
||||
|
@ -123,7 +123,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
|
|||
}
|
||||
|
||||
private boolean isLocalNumber(Recipient recipient) {
|
||||
return Util.isOwnNumber(context, recipient.getAddress());
|
||||
return Util.isOwnNumber(context, recipient.requireAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,11 +75,10 @@ public class IncomingMessageProcessor {
|
|||
|
||||
public void processEnvelope(@NonNull SignalServiceEnvelope envelope) {
|
||||
if (envelope.hasSource()) {
|
||||
Address source = Address.fromExternal(context, envelope.getSource());
|
||||
Recipient recipient = Recipient.from(context, source, false);
|
||||
Recipient recipient = Recipient.external(context, envelope.getSource());
|
||||
|
||||
if (!isActiveNumber(recipient)) {
|
||||
recipientDatabase.setRegistered(recipient, RecipientDatabase.RegisteredState.REGISTERED);
|
||||
recipientDatabase.setRegistered(recipient.getId(), RecipientDatabase.RegisteredState.REGISTERED);
|
||||
jobManager.add(new DirectoryRefreshJob(recipient, false));
|
||||
}
|
||||
}
|
||||
|
@ -101,9 +100,8 @@ public class IncomingMessageProcessor {
|
|||
|
||||
private void processReceipt(@NonNull SignalServiceEnvelope envelope) {
|
||||
Log.i(TAG, String.format(Locale.ENGLISH, "Received receipt: (XXXXX, %d)", envelope.getTimestamp()));
|
||||
mmsSmsDatabase.incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()),
|
||||
envelope.getTimestamp()),
|
||||
System.currentTimeMillis());
|
||||
mmsSmsDatabase.incrementDeliveryReceiptCount(new SyncMessageId(Recipient.external(context, envelope.getSource()).getId(), envelope.getTimestamp()),
|
||||
System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private boolean isActiveNumber(@NonNull Recipient recipient) {
|
||||
|
|
|
@ -217,13 +217,13 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
|||
if (context == null) return null;
|
||||
|
||||
for (String number : numbers) {
|
||||
Recipient recipient = Recipient.from(context, Address.fromExternal(context, number), false);
|
||||
Recipient recipient = Recipient.external(context, number);
|
||||
int subscriptionId = recipient.getDefaultSubscriptionId().or(-1);
|
||||
|
||||
MessageSender.send(context, new OutgoingTextMessage(recipient, message, subscriptionId), -1L, true, null);
|
||||
|
||||
if (recipient.getContactUri() != null) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setSeenInviteReminder(recipient, true);
|
||||
DatabaseFactory.getRecipientDatabase(context).setSeenInviteReminder(recipient.getId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ import android.widget.Toast;
|
|||
|
||||
import com.codewaves.stickyheadergrid.StickyHeaderGridLayoutManager;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader;
|
||||
|
@ -59,14 +58,15 @@ import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.Buc
|
|||
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
|
||||
|
@ -83,15 +83,15 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
@SuppressWarnings("unused")
|
||||
private final static String TAG = MediaOverviewActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
public static final String RECIPIENT_EXTRA = "recipient_id";
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
||||
private Toolbar toolbar;
|
||||
private TabLayout tabLayout;
|
||||
private ViewPager viewPager;
|
||||
private Recipient recipient;
|
||||
private Toolbar toolbar;
|
||||
private TabLayout tabLayout;
|
||||
private ViewPager viewPager;
|
||||
private LiveRecipient recipient;
|
||||
|
||||
@Override
|
||||
protected void onPreCreate() {
|
||||
|
@ -129,21 +129,19 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
}
|
||||
|
||||
private void initializeResources() {
|
||||
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
|
||||
RecipientId recipientId = getIntent().getParcelableExtra(RECIPIENT_EXTRA);
|
||||
|
||||
this.viewPager = ViewUtil.findById(this, R.id.pager);
|
||||
this.toolbar = ViewUtil.findById(this, R.id.toolbar);
|
||||
this.tabLayout = ViewUtil.findById(this, R.id.tab_layout);
|
||||
this.recipient = Recipient.from(this, address, true);
|
||||
this.recipient = Recipient.live(recipientId);
|
||||
}
|
||||
|
||||
private void initializeToolbar() {
|
||||
setSupportActionBar(this.toolbar);
|
||||
getSupportActionBar().setTitle(recipient.toShortString());
|
||||
getSupportActionBar().setTitle(recipient.get().toShortString());
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
this.recipient.addListener(recipient -> {
|
||||
Util.runOnMain(() -> getSupportActionBar().setTitle(recipient.toShortString()));
|
||||
});
|
||||
this.recipient.observe(this, recipient -> getSupportActionBar().setTitle(recipient.toShortString()));
|
||||
}
|
||||
|
||||
public void onEnterMultiSelect() {
|
||||
|
@ -171,7 +169,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
else throw new AssertionError();
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putString(MediaOverviewGalleryFragment.ADDRESS_EXTRA, recipient.getAddress().serialize());
|
||||
args.putParcelable(MediaOverviewGalleryFragment.RECIPIENT_EXTRA, recipient.getId());
|
||||
args.putSerializable(MediaOverviewGalleryFragment.LOCALE_EXTRA, dynamicLanguage.getCurrentLocale());
|
||||
|
||||
fragment.setArguments(args);
|
||||
|
@ -194,8 +192,8 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
|
||||
public static abstract class MediaOverviewFragment<T> extends Fragment implements LoaderManager.LoaderCallbacks<T> {
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
public static final String LOCALE_EXTRA = "locale_extra";
|
||||
public static final String RECIPIENT_EXTRA = "recipient_id";
|
||||
public static final String LOCALE_EXTRA = "locale_extra";
|
||||
|
||||
protected TextView noMedia;
|
||||
protected Recipient recipient;
|
||||
|
@ -206,13 +204,13 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
|
||||
String address = getArguments().getString(ADDRESS_EXTRA);
|
||||
Locale locale = (Locale)getArguments().getSerializable(LOCALE_EXTRA);
|
||||
RecipientId recipientId = getArguments().getParcelable(RECIPIENT_EXTRA);
|
||||
Locale locale = (Locale)getArguments().getSerializable(LOCALE_EXTRA);
|
||||
|
||||
if (address == null) throw new AssertionError();
|
||||
if (recipientId == null) throw new AssertionError();
|
||||
if (locale == null) throw new AssertionError();
|
||||
|
||||
this.recipient = Recipient.from(getContext(), Address.fromSerialized(address), true);
|
||||
this.recipient = Recipient.live(recipientId).get();
|
||||
this.locale = locale;
|
||||
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
|
@ -258,7 +256,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
|
||||
@Override
|
||||
public @NonNull Loader<BucketedThreadMedia> onCreateLoader(int i, Bundle bundle) {
|
||||
return new BucketedThreadMediaLoader(getContext(), recipient.getAddress());
|
||||
return new BucketedThreadMediaLoader(getContext(), recipient.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -308,7 +306,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, mediaRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, true);
|
||||
|
||||
|
@ -497,13 +495,13 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
|
||||
@Override
|
||||
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return new ThreadMediaLoader(getContext(), recipient.getAddress(), false);
|
||||
return new ThreadMediaLoader(requireContext(), recipient.getId(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
|
||||
((CursorRecyclerViewAdapter)this.recyclerView.getAdapter()).changeCursor(data);
|
||||
getActivity().invalidateOptionsMenu();
|
||||
requireActivity().invalidateOptionsMenu();
|
||||
|
||||
this.noMedia.setVisibility(data.getCount() > 0 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
|
|
@ -63,12 +63,11 @@ import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
|
|||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
@ -78,15 +77,14 @@ import java.util.Map;
|
|||
* Activity for displaying media attachments in-app
|
||||
*/
|
||||
public final class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
implements RecipientModifiedListener,
|
||||
LoaderManager.LoaderCallbacks<Pair<Cursor, Integer>>,
|
||||
implements LoaderManager.LoaderCallbacks<Pair<Cursor, Integer>>,
|
||||
MediaRailAdapter.RailItemListener,
|
||||
MediaPreviewFragment.Events
|
||||
{
|
||||
|
||||
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
public static final String RECIPIENT_EXTRA = "recipient_id";
|
||||
public static final String DATE_EXTRA = "date";
|
||||
public static final String SIZE_EXTRA = "size";
|
||||
public static final String CAPTION_EXTRA = "caption";
|
||||
|
@ -138,11 +136,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
|
|||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
Util.runOnMain(this::initializeActionBar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRailItemClicked(int distanceFromActive) {
|
||||
mediaPager.setCurrentItem(mediaPager.getCurrentItem() + distanceFromActive);
|
||||
|
@ -223,7 +216,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
|
|||
}
|
||||
|
||||
private void initializeResources() {
|
||||
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
|
||||
RecipientId recipientId = getIntent().getParcelableExtra(RECIPIENT_EXTRA);
|
||||
|
||||
initialMediaUri = getIntent().getData();
|
||||
initialMediaType = getIntent().getType();
|
||||
|
@ -232,8 +225,8 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
|
|||
leftIsRecent = getIntent().getBooleanExtra(LEFT_IS_RECENT_EXTRA, false);
|
||||
restartItem = -1;
|
||||
|
||||
if (address != null) {
|
||||
conversationRecipient = Recipient.from(this, address, true);
|
||||
if (recipientId != null) {
|
||||
conversationRecipient = Recipient.live(recipientId).get();
|
||||
} else {
|
||||
conversationRecipient = null;
|
||||
}
|
||||
|
@ -305,7 +298,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
|
|||
|
||||
private void showOverview() {
|
||||
Intent intent = new Intent(this, MediaOverviewActivity.class);
|
||||
intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
|
||||
intent.putExtra(MediaOverviewActivity.RECIPIENT_EXTRA, conversationRecipient.getId());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
|
@ -491,7 +484,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
|
|||
|
||||
if (adapter != null) {
|
||||
MediaItem item = adapter.getMediaItemFor(position);
|
||||
if (item.recipient != null) item.recipient.addListener(MediaPreviewActivity.this);
|
||||
if (item.recipient != null) item.recipient.live().observe(MediaPreviewActivity.this, r -> initializeActionBar());
|
||||
viewModel.setActiveAlbumRailItem(MediaPreviewActivity.this, position);
|
||||
initializeActionBar();
|
||||
}
|
||||
|
@ -504,7 +497,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
|
|||
|
||||
if (adapter != null) {
|
||||
MediaItem item = adapter.getMediaItemFor(position);
|
||||
if (item.recipient != null) item.recipient.removeListener(MediaPreviewActivity.this);
|
||||
if (item.recipient != null) item.recipient.live().removeObservers(MediaPreviewActivity.this);
|
||||
|
||||
adapter.pause(position);
|
||||
}
|
||||
|
@ -682,11 +675,11 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
|
|||
public MediaItem getMediaItemFor(int position) {
|
||||
cursor.moveToPosition(getCursorPosition(position));
|
||||
MediaRecord mediaRecord = MediaRecord.from(context, cursor);
|
||||
Address address = mediaRecord.getAddress();
|
||||
RecipientId recipientId = mediaRecord.getRecipientId();
|
||||
|
||||
if (mediaRecord.getAttachment().getDataUri() == null) throw new AssertionError();
|
||||
|
||||
return new MediaItem(address != null ? Recipient.from(context, address,true) : null,
|
||||
return new MediaItem(Recipient.live(recipientId).get(),
|
||||
mediaRecord.getAttachment(),
|
||||
mediaRecord.getAttachment().getDataUri(),
|
||||
mediaRecord.getContentType(),
|
||||
|
|
|
@ -52,8 +52,8 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
|
@ -73,14 +73,14 @@ import java.util.Locale;
|
|||
/**
|
||||
* @author Jake McGinty
|
||||
*/
|
||||
public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks<Cursor>, RecipientModifiedListener {
|
||||
public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks<Cursor> {
|
||||
private final static String TAG = MessageDetailsActivity.class.getSimpleName();
|
||||
|
||||
public final static String MESSAGE_ID_EXTRA = "message_id";
|
||||
public final static String THREAD_ID_EXTRA = "thread_id";
|
||||
public final static String IS_PUSH_GROUP_EXTRA = "is_push_group";
|
||||
public final static String TYPE_EXTRA = "type";
|
||||
public final static String ADDRESS_EXTRA = "address";
|
||||
public static final String MESSAGE_ID_EXTRA = "message_id";
|
||||
public static final String THREAD_ID_EXTRA = "thread_id";
|
||||
public static final String IS_PUSH_GROUP_EXTRA = "is_push_group";
|
||||
public static final String TYPE_EXTRA = "type";
|
||||
public static final String RECIPIENT_EXTRA = "recipient_id";
|
||||
|
||||
private GlideRequests glideRequests;
|
||||
private long threadId;
|
||||
|
@ -149,10 +149,10 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
assert getSupportActionBar() != null;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
Recipient recipient = Recipient.from(this, getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
|
||||
recipient.addListener(this);
|
||||
LiveRecipient recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
|
||||
recipient.observe(this, r -> setActionBarColor(r.getColor()));
|
||||
|
||||
setActionBarColor(recipient.getColor());
|
||||
setActionBarColor(recipient.get().getColor());
|
||||
}
|
||||
|
||||
private void setActionBarColor(MaterialColor color) {
|
||||
|
@ -164,11 +164,6 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(() -> setActionBarColor(recipient.getColor()));
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
inflater = LayoutInflater.from(this);
|
||||
View header = inflater.inflate(R.layout.message_details_header, recipientsList, false);
|
||||
|
@ -366,20 +361,20 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
List<RecipientDeliveryStatus> recipients = new LinkedList<>();
|
||||
|
||||
if (!messageRecord.getRecipient().isGroupRecipient()) {
|
||||
if (!messageRecord.getRecipient().isGroup()) {
|
||||
recipients.add(new RecipientDeliveryStatus(messageRecord.getRecipient(), getStatusFor(messageRecord.getDeliveryReceiptCount(), messageRecord.getReadReceiptCount(), messageRecord.isPending()), messageRecord.isUnidentified(), -1));
|
||||
} else {
|
||||
List<GroupReceiptInfo> receiptInfoList = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageRecord.getId());
|
||||
|
||||
if (receiptInfoList.isEmpty()) {
|
||||
List<Recipient> group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().getAddress().toGroupString(), false);
|
||||
List<Recipient> group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().requireAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient recipient : group) {
|
||||
recipients.add(new RecipientDeliveryStatus(recipient, RecipientDeliveryStatus.Status.UNKNOWN, false, -1));
|
||||
}
|
||||
} else {
|
||||
for (GroupReceiptInfo info : receiptInfoList) {
|
||||
recipients.add(new RecipientDeliveryStatus(Recipient.from(context, info.getAddress(), true),
|
||||
recipients.add(new RecipientDeliveryStatus(Recipient.resolved(info.getRecipientId()),
|
||||
getStatusFor(info.getStatus(), messageRecord.isPending(), messageRecord.isFailed()),
|
||||
info.isUnidentified(),
|
||||
info.getTimestamp()));
|
||||
|
|
|
@ -49,7 +49,7 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.
|
|||
@Override
|
||||
public long getItemId(int position) {
|
||||
try {
|
||||
return Conversions.byteArrayToLong(MessageDigest.getInstance("SHA1").digest(members.get(position).recipient.getAddress().serialize().getBytes()));
|
||||
return Conversions.byteArrayToLong(MessageDigest.getInstance("SHA1").digest(members.get(position).recipient.requireAddress().serialize().getBytes()));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import android.widget.ImageView;
|
|||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.DeliveryStatusView;
|
||||
|
@ -34,9 +36,8 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
|||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
/**
|
||||
* A simple view to show the recipients of a message
|
||||
|
@ -44,7 +45,7 @@ import org.thoughtcrime.securesms.util.Util;
|
|||
* @author Jake McGinty
|
||||
*/
|
||||
public class MessageRecipientListItem extends RelativeLayout
|
||||
implements RecipientModifiedListener
|
||||
implements RecipientForeverObserver
|
||||
{
|
||||
@SuppressWarnings("unused")
|
||||
private final static String TAG = MessageRecipientListItem.class.getSimpleName();
|
||||
|
@ -84,10 +85,12 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
final RecipientDeliveryStatus member,
|
||||
final boolean isPushGroup)
|
||||
{
|
||||
if (this.member != null) this.member.getRecipient().live().removeForeverObserver(this);
|
||||
|
||||
this.glideRequests = glideRequests;
|
||||
this.member = member;
|
||||
|
||||
member.getRecipient().addListener(this);
|
||||
member.getRecipient().live().observeForever(this);
|
||||
fromView.setText(member.getRecipient());
|
||||
contactPhotoImage.setAvatar(glideRequests, member.getRecipient(), false);
|
||||
setIssueIndicators(record, isPushGroup);
|
||||
|
@ -138,7 +141,7 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
private NetworkFailure getNetworkFailure(final MessageRecord record) {
|
||||
if (record.hasNetworkFailures()) {
|
||||
for (final NetworkFailure failure : record.getNetworkFailures()) {
|
||||
if (failure.getAddress().equals(member.getRecipient().getAddress())) {
|
||||
if (failure.getRecipientId(getContext()).equals(member.getRecipient().getId())) {
|
||||
return failure;
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +152,7 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
private IdentityKeyMismatch getKeyMismatch(final MessageRecord record) {
|
||||
if (record.isIdentityMismatchFailure()) {
|
||||
for (final IdentityKeyMismatch mismatch : record.getIdentityKeyMismatches()) {
|
||||
if (mismatch.getAddress().equals(member.getRecipient().getAddress())) {
|
||||
if (mismatch.getRecipientId(getContext()).equals(member.getRecipient().getId())) {
|
||||
return mismatch;
|
||||
}
|
||||
}
|
||||
|
@ -158,14 +161,12 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
}
|
||||
|
||||
public void unbind() {
|
||||
if (this.member != null && this.member.getRecipient() != null) this.member.getRecipient().removeListener(this);
|
||||
if (this.member != null && this.member.getRecipient() != null) this.member.getRecipient().live().removeForeverObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(() -> {
|
||||
fromView.setText(recipient);
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, false);
|
||||
});
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
fromView.setText(recipient);
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,10 +51,10 @@ public class NewConversationActivity extends ContactSelectionActivity
|
|||
|
||||
@Override
|
||||
public void onContactSelected(String number) {
|
||||
Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true);
|
||||
Recipient recipient = Recipient.external(this, number);
|
||||
|
||||
Intent intent = new Intent(this, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA));
|
||||
intent.setDataAndType(getIntent().getData(), getIntent().getType());
|
||||
|
||||
|
|
|
@ -67,8 +67,9 @@ import org.thoughtcrime.securesms.permissions.Permissions;
|
|||
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.ContactPreference;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.Dialogs;
|
||||
|
@ -78,7 +79,6 @@ import org.thoughtcrime.securesms.util.DynamicTheme;
|
|||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -86,11 +86,11 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener, LoaderManager.LoaderCallbacks<Cursor>
|
||||
public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor>
|
||||
{
|
||||
private static final String TAG = RecipientPreferenceActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "recipient_address";
|
||||
public static final String RECIPIENT_ID = "recipient_address";
|
||||
public static final String CAN_HAVE_SAFETY_NUMBER_EXTRA = "can_have_safety_number";
|
||||
|
||||
private static final String PREFERENCE_MUTED = "pref_key_recipient_mute";
|
||||
|
@ -109,7 +109,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
|
||||
private ImageView avatar;
|
||||
private GlideRequests glideRequests;
|
||||
private Address address;
|
||||
private RecipientId recipientId;
|
||||
private TextView threadPhotoRailLabel;
|
||||
private ThreadPhotoRailView threadPhotoRailView;
|
||||
private CollapsingToolbarLayout toolbarLayout;
|
||||
|
@ -124,13 +124,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
public void onCreate(Bundle instanceState, boolean ready) {
|
||||
setContentView(R.layout.recipient_preference_activity);
|
||||
this.glideRequests = GlideApp.with(this);
|
||||
this.address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
|
||||
this.recipientId = getIntent().getParcelableExtra(RECIPIENT_ID);
|
||||
|
||||
Recipient recipient = Recipient.from(this, address, true);
|
||||
LiveRecipient recipient = Recipient.live(recipientId);
|
||||
|
||||
initializeToolbar();
|
||||
setHeader(recipient);
|
||||
recipient.addListener(this);
|
||||
setHeader(recipient.get());
|
||||
recipient.observe(this, this::setHeader);
|
||||
|
||||
getSupportLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
|
||||
this.threadPhotoRailView.setListener(mediaRecord -> {
|
||||
Intent intent = new Intent(RecipientPreferenceActivity.this, MediaPreviewActivity.class);
|
||||
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, address);
|
||||
intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipientId);
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, mediaRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
||||
|
@ -190,7 +190,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
|
||||
this.threadPhotoRailLabel.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(this, MediaOverviewActivity.class);
|
||||
intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, address);
|
||||
intent.putExtra(MediaOverviewActivity.RECIPIENT_EXTRA, recipientId);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
|
@ -206,7 +206,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
}
|
||||
|
||||
private void setHeader(@NonNull Recipient recipient) {
|
||||
ContactPhoto contactPhoto = recipient.isLocalNumber() ? new ProfileContactPhoto(recipient.getAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this)))
|
||||
ContactPhoto contactPhoto = recipient.isLocalNumber() ? new ProfileContactPhoto(recipient.requireAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this)))
|
||||
: recipient.getContactPhoto();
|
||||
FallbackContactPhoto fallbackPhoto = recipient.isLocalNumber() ? new ResourceContactPhoto(R.drawable.ic_profile_default, R.drawable.ic_person_large)
|
||||
: recipient.getFallbackContactPhoto();
|
||||
|
@ -225,14 +225,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
this.toolbarLayout.setContentScrimColor(recipient.getColor().toActionBarColor(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(() -> setHeader(recipient));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return new ThreadMediaLoader(this, address, true);
|
||||
return new ThreadMediaLoader(this, recipientId, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -248,7 +243,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
this.threadPhotoRailView.setCursor(glideRequests, data);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(ADDRESS_EXTRA, address);
|
||||
bundle.putParcelable(RECIPIENT_ID, recipientId);
|
||||
initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), null, bundle);
|
||||
}
|
||||
|
||||
|
@ -257,12 +252,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
this.threadPhotoRailView.setCursor(glideRequests, null);
|
||||
}
|
||||
|
||||
public static class RecipientPreferenceFragment
|
||||
extends CorrectedPreferenceFragment
|
||||
implements RecipientModifiedListener
|
||||
{
|
||||
private Recipient recipient;
|
||||
private boolean canHaveSafetyNumber;
|
||||
public static class RecipientPreferenceFragment extends CorrectedPreferenceFragment {
|
||||
private LiveRecipient recipient;
|
||||
private boolean canHaveSafetyNumber;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
|
@ -277,20 +269,20 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
Preference customNotificationsPref = this.findPreference(PREFERENCE_CUSTOM_NOTIFICATIONS);
|
||||
|
||||
if (NotificationChannels.supported()) {
|
||||
((SwitchPreferenceCompat) customNotificationsPref).setChecked(recipient.getNotificationChannel() != null);
|
||||
((SwitchPreferenceCompat) customNotificationsPref).setChecked(recipient.get().getNotificationChannel() != null);
|
||||
customNotificationsPref.setOnPreferenceChangeListener(new CustomNotificationsChangedListener());
|
||||
|
||||
this.findPreference(PREFERENCE_MESSAGE_TONE).setDependency(PREFERENCE_CUSTOM_NOTIFICATIONS);
|
||||
this.findPreference(PREFERENCE_MESSAGE_VIBRATE).setDependency(PREFERENCE_CUSTOM_NOTIFICATIONS);
|
||||
|
||||
if (recipient.getNotificationChannel() != null) {
|
||||
final Context context = getContext();
|
||||
if (recipient.get().getNotificationChannel() != null) {
|
||||
final Context context = requireContext();
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(getContext());
|
||||
db.setMessageRingtone(recipient, NotificationChannels.getMessageRingtone(context, recipient));
|
||||
db.setMessageVibrate(recipient, NotificationChannels.getMessageVibrate(context, recipient) ? VibrateState.ENABLED : VibrateState.DISABLED);
|
||||
db.setMessageRingtone(recipient.getId(), NotificationChannels.getMessageRingtone(context, recipient.get()));
|
||||
db.setMessageVibrate(recipient.getId(), NotificationChannels.getMessageVibrate(context, recipient.get()) ? VibrateState.ENABLED : VibrateState.DISABLED);
|
||||
NotificationChannels.ensureCustomChannelConsistency(context);
|
||||
return null;
|
||||
}
|
||||
|
@ -336,13 +328,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setSummaries(recipient);
|
||||
setSummaries(recipient.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
this.recipient.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -359,8 +350,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
}
|
||||
|
||||
private void initializeRecipients() {
|
||||
this.recipient = Recipient.from(getActivity(), getArguments().getParcelable(ADDRESS_EXTRA), true);
|
||||
this.recipient.addListener(this);
|
||||
this.recipient = Recipient.live(getArguments().getParcelable(RECIPIENT_ID));
|
||||
this.recipient.observe(this, this::setSummaries);
|
||||
}
|
||||
|
||||
private void setSummaries(Recipient recipient) {
|
||||
|
@ -406,7 +397,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
if (privacyCategory != null) privacyCategory.setVisible(false);
|
||||
if (divider != null) divider.setVisible(false);
|
||||
if (callCategory != null) callCategory.setVisible(false);
|
||||
} if (recipient.isGroupRecipient()) {
|
||||
} if (recipient.isGroup()) {
|
||||
if (colorPreference != null) colorPreference.setVisible(false);
|
||||
if (identityPreference != null) identityPreference.setVisible(false);
|
||||
if (callCategory != null) callCategory.setVisible(false);
|
||||
|
@ -417,7 +408,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
colorPreference.setColors(MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(getActivity()));
|
||||
colorPreference.setColor(recipient.getColor().toActionBarColor(getActivity()));
|
||||
|
||||
aboutPreference.setTitle(formatAddress(recipient.getAddress()));
|
||||
aboutPreference.setTitle(formatAddress(recipient.requireAddress()));
|
||||
aboutPreference.setSummary(recipient.getCustomLabel());
|
||||
aboutPreference.setSecure(recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED);
|
||||
|
||||
|
@ -478,15 +469,6 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(() -> {
|
||||
if (getContext() != null && getActivity() != null && !getActivity().isFinishing()) {
|
||||
setSummaries(recipient);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class RingtoneChangeListener implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private final boolean calls;
|
||||
|
@ -514,10 +496,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
@Override
|
||||
protected Void doInBackground(Uri... params) {
|
||||
if (calls) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setCallRingtone(recipient, params[0]);
|
||||
DatabaseFactory.getRecipientDatabase(context).setCallRingtone(recipient.getId(), params[0]);
|
||||
} else {
|
||||
DatabaseFactory.getRecipientDatabase(context).setMessageRingtone(recipient, params[0]);
|
||||
NotificationChannels.updateMessageRingtone(context, recipient, params[0]);
|
||||
DatabaseFactory.getRecipientDatabase(context).setMessageRingtone(recipient.getId(), params[0]);
|
||||
NotificationChannels.updateMessageRingtone(context, recipient.get(), params[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -541,10 +523,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
Uri defaultUri;
|
||||
|
||||
if (calls) {
|
||||
current = recipient.getCallRingtone();
|
||||
current = recipient.get().getCallRingtone();
|
||||
defaultUri = TextSecurePreferences.getCallNotificationRingtone(getContext());
|
||||
} else {
|
||||
current = recipient.getMessageRingtone();
|
||||
current = recipient.get().getMessageRingtone();
|
||||
defaultUri = TextSecurePreferences.getNotificationRingtone(getContext());
|
||||
}
|
||||
|
||||
|
@ -582,11 +564,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (call) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setCallVibrate(recipient, vibrateState);
|
||||
DatabaseFactory.getRecipientDatabase(context).setCallVibrate(recipient.getId(), vibrateState);
|
||||
}
|
||||
else {
|
||||
DatabaseFactory.getRecipientDatabase(context).setMessageVibrate(recipient, vibrateState);
|
||||
NotificationChannels.updateMessageVibrate(context, recipient, vibrateState);
|
||||
DatabaseFactory.getRecipientDatabase(context).setMessageVibrate(recipient.getId(), vibrateState);
|
||||
NotificationChannels.updateMessageVibrate(context, recipient.get(), vibrateState);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -605,7 +587,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
|
||||
final int value = (Integer) newValue;
|
||||
final MaterialColor selectedColor = MaterialColors.CONVERSATION_PALETTE.getByColor(context, value);
|
||||
final MaterialColor currentColor = recipient.getColor();
|
||||
final MaterialColor currentColor = recipient.get().getColor();
|
||||
|
||||
if (selectedColor == null) return true;
|
||||
|
||||
|
@ -613,12 +595,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setColor(recipient, selectedColor);
|
||||
DatabaseFactory.getRecipientDatabase(context).setColor(recipient.getId(), selectedColor);
|
||||
|
||||
if (recipient.resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
if (recipient.get().resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceContactUpdateJob(context, recipient.getAddress()));
|
||||
.add(new MultiDeviceContactUpdateJob(recipient.getId()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -632,30 +614,28 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (recipient.isMuted()) handleUnmute(preference.getContext());
|
||||
else handleMute(preference.getContext());
|
||||
if (recipient.get().isMuted()) handleUnmute(preference.getContext());
|
||||
else handleMute(preference.getContext());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleMute(@NonNull Context context) {
|
||||
MuteDialog.show(context, until -> setMuted(context, recipient, until));
|
||||
MuteDialog.show(context, until -> setMuted(context, recipient.get(), until));
|
||||
|
||||
setSummaries(recipient);
|
||||
setSummaries(recipient.get());
|
||||
}
|
||||
|
||||
private void handleUnmute(@NonNull Context context) {
|
||||
setMuted(context, recipient, 0);
|
||||
setMuted(context, recipient.get(), 0);
|
||||
}
|
||||
|
||||
private void setMuted(@NonNull final Context context, final Recipient recipient, final long until) {
|
||||
recipient.setMuted(until);
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(context)
|
||||
.setMuted(recipient, until);
|
||||
.setMuted(recipient.getId(), until);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
@ -674,7 +654,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
Intent verifyIdentityIntent = new Intent(preference.getContext(), VerifyIdentityActivity.class);
|
||||
verifyIdentityIntent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
verifyIdentityIntent.putExtra(VerifyIdentityActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
verifyIdentityIntent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(identityKey.getIdentityKey()));
|
||||
verifyIdentityIntent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, identityKey.getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
|
||||
startActivity(verifyIdentityIntent);
|
||||
|
@ -686,8 +666,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
private class BlockClickedListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (recipient.isBlocked()) handleUnblock(preference.getContext());
|
||||
else handleBlock(preference.getContext());
|
||||
if (recipient.get().isBlocked()) handleUnblock(preference.getContext());
|
||||
else handleBlock(preference.getContext());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -700,10 +680,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
int titleRes = R.string.RecipientPreferenceActivity_block_this_contact_question;
|
||||
int bodyRes = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact;
|
||||
|
||||
if (recipient.isGroupRecipient()) {
|
||||
if (recipient.get().isGroup()) {
|
||||
bodyRes = R.string.RecipientPreferenceActivity_block_and_leave_group_description;
|
||||
|
||||
if (recipient.isGroupRecipient() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.getAddress().toGroupString())) {
|
||||
if (recipient.get().isGroup() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.get().requireAddress().toGroupString())) {
|
||||
titleRes = R.string.RecipientPreferenceActivity_block_and_leave_group;
|
||||
} else {
|
||||
titleRes = R.string.RecipientPreferenceActivity_block_group;
|
||||
|
@ -721,7 +701,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
.setCancelable(true)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.RecipientPreferenceActivity_block, (dialog, which) -> {
|
||||
setBlocked(context, recipient, true);
|
||||
setBlocked(context, recipient.get(), true);
|
||||
}).show();
|
||||
}
|
||||
}.execute();
|
||||
|
@ -731,7 +711,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
int titleRes = R.string.RecipientPreferenceActivity_unblock_this_contact_question;
|
||||
int bodyRes = R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact;
|
||||
|
||||
if (recipient.isGroupRecipient()) {
|
||||
if (recipient.resolve().isGroup()) {
|
||||
titleRes = R.string.RecipientPreferenceActivity_unblock_this_group_question;
|
||||
bodyRes = R.string.RecipientPreferenceActivity_unblock_this_group_description;
|
||||
}
|
||||
|
@ -741,7 +721,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
.setMessage(bodyRes)
|
||||
.setCancelable(true)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock, (dialog, which) -> setBlocked(context, recipient, false)).show();
|
||||
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock, (dialog, which) -> setBlocked(context, recipient.get(), false)).show();
|
||||
}
|
||||
|
||||
private void setBlocked(@NonNull final Context context, final Recipient recipient, final boolean blocked) {
|
||||
|
@ -749,9 +729,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(context)
|
||||
.setBlocked(recipient, blocked);
|
||||
.setBlocked(recipient.getId(), blocked);
|
||||
|
||||
if (recipient.isGroupRecipient() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.getAddress().toGroupString())) {
|
||||
if (recipient.isGroup() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.requireAddress().toGroupString())) {
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, recipient);
|
||||
|
||||
|
@ -759,9 +739,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
MessageSender.send(context, leaveMessage.get(), threadId, false, null);
|
||||
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
String groupId = recipient.getAddress().toGroupString();
|
||||
String groupId = recipient.requireAddress().toGroupString();
|
||||
groupDatabase.setActive(groupId, false);
|
||||
groupDatabase.remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
||||
groupDatabase.remove(groupId, Recipient.self().getId());
|
||||
} else {
|
||||
Log.w(TAG, "Failed to leave group. Can't block.");
|
||||
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
||||
|
@ -787,19 +767,19 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
|
||||
@Override
|
||||
public void onMessageClicked() {
|
||||
CommunicationActions.startConversation(getContext(), recipient, null);
|
||||
CommunicationActions.startConversation(getContext(), recipient.get(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecureCallClicked() {
|
||||
CommunicationActions.startVoiceCall(getActivity(), recipient);
|
||||
CommunicationActions.startVoiceCall(getActivity(), recipient.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInSecureCallClicked() {
|
||||
try {
|
||||
Intent dialIntent = new Intent(Intent.ACTION_DIAL,
|
||||
Uri.parse("tel:" + recipient.getAddress().serialize()));
|
||||
Uri.parse("tel:" + recipient.get().requireAddress().serialize()));
|
||||
startActivity(dialIntent);
|
||||
} catch (ActivityNotFoundException anfe) {
|
||||
Log.w(TAG, anfe);
|
||||
|
@ -821,11 +801,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (enabled) {
|
||||
String channel = NotificationChannels.createChannelFor(context, recipient);
|
||||
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient, channel);
|
||||
String channel = NotificationChannels.createChannelFor(context, recipient.get());
|
||||
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient.getId(), channel);
|
||||
} else {
|
||||
NotificationChannels.deleteChannelFor(context, recipient);
|
||||
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient, null);
|
||||
NotificationChannels.deleteChannelFor(context, recipient.get());
|
||||
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient.getId(), null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.registration.CaptchaActivity;
|
||||
import org.thoughtcrime.securesms.registration.PushChallengeRequest;
|
||||
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
||||
|
@ -735,7 +736,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||
TextSecurePreferences.setWebsocketRegistered(RegistrationActivity.this, true);
|
||||
|
||||
DatabaseFactory.getIdentityDatabase(RegistrationActivity.this)
|
||||
.saveIdentity(Address.fromSerialized(registrationState.e164number),
|
||||
.saveIdentity(Recipient.external(RegistrationActivity.this, registrationState.e164number).getId(),
|
||||
identityKey.getPublicKey(), IdentityDatabase.VerifiedStatus.VERIFIED,
|
||||
true, System.currentTimeMillis(), true);
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.thoughtcrime.securesms.mediasend.Media;
|
|||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
|
@ -55,6 +56,8 @@ import org.thoughtcrime.securesms.util.FileUtils;
|
|||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -72,7 +75,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||
private static final String TAG = ShareActivity.class.getSimpleName();
|
||||
|
||||
public static final String EXTRA_THREAD_ID = "thread_id";
|
||||
public static final String EXTRA_ADDRESS_MARSHALLED = "address_marshalled";
|
||||
public static final String EXTRA_RECIPIENT_ID = "recipient_id";
|
||||
public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type";
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||
|
@ -216,35 +219,30 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
private void handleResolvedMedia(Intent intent, boolean animate) {
|
||||
long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1);
|
||||
int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1);
|
||||
Address address = null;
|
||||
long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1);
|
||||
int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1);
|
||||
RecipientId recipientId = null;
|
||||
|
||||
if (intent.hasExtra(EXTRA_ADDRESS_MARSHALLED)) {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
byte[] marshalled = intent.getByteArrayExtra(EXTRA_ADDRESS_MARSHALLED);
|
||||
parcel.unmarshall(marshalled, 0, marshalled.length);
|
||||
parcel.setDataPosition(0);
|
||||
address = parcel.readParcelable(getClassLoader());
|
||||
parcel.recycle();
|
||||
if (intent.hasExtra(EXTRA_RECIPIENT_ID)) {
|
||||
recipientId = RecipientId.from(intent.getStringExtra(EXTRA_RECIPIENT_ID));
|
||||
}
|
||||
|
||||
boolean hasResolvedDestination = threadId != -1 && address != null && distributionType != -1;
|
||||
boolean hasResolvedDestination = threadId != -1 && recipientId != null && distributionType != -1;
|
||||
|
||||
if (!hasResolvedDestination && animate) {
|
||||
ViewUtil.fadeIn(contactsFragment.getView(), 300);
|
||||
if (hasResolvedDestination) {
|
||||
createConversation(threadId, recipientId, distributionType);
|
||||
} else if (animate) {
|
||||
ViewUtil.fadeIn(contactsFragment.requireView(), 300);
|
||||
ViewUtil.fadeOut(progressWheel, 300);
|
||||
} else if (!hasResolvedDestination) {
|
||||
contactsFragment.getView().setVisibility(View.VISIBLE);
|
||||
progressWheel.setVisibility(View.GONE);
|
||||
} else {
|
||||
createConversation(threadId, address, distributionType);
|
||||
contactsFragment.requireView().setVisibility(View.VISIBLE);
|
||||
progressWheel.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void createConversation(long threadId, Address address, int distributionType) {
|
||||
private void createConversation(long threadId, @NonNull RecipientId recipientId, int distributionType) {
|
||||
final Intent intent = getBaseShareIntent(ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, address);
|
||||
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipientId);
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||
|
||||
|
@ -277,9 +275,14 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
@Override
|
||||
public void onContactSelected(String number) {
|
||||
Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true);
|
||||
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
|
||||
createConversation(existingThread, recipient.getAddress(), ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
SimpleTask.run(this.getLifecycle(), () -> {
|
||||
Recipient recipient = Recipient.external(this, number);
|
||||
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
|
||||
return new Pair<>(existingThread, recipient);
|
||||
}, result -> {
|
||||
createConversation(result.first(), result.second().getId(), ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
@ -10,38 +9,36 @@ import androidx.core.app.TaskStackBuilder;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
|
||||
public class ShortcutLauncherActivity extends AppCompatActivity {
|
||||
|
||||
private static final String KEY_SERIALIZED_ADDRESS = "serialized_address";
|
||||
private static final String KEY_RECIPIENT = "recipient_id";
|
||||
|
||||
public static Intent createIntent(@NonNull Context context, @NonNull Address address) {
|
||||
public static Intent createIntent(@NonNull Context context, @NonNull RecipientId recipientId) {
|
||||
Intent intent = new Intent(context, ShortcutLauncherActivity.class);
|
||||
intent.setAction(Intent.ACTION_MAIN);
|
||||
intent.putExtra(KEY_SERIALIZED_ADDRESS, address.serialize());
|
||||
intent.putExtra(KEY_RECIPIENT, recipientId.serialize());
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String serializedAddress = getIntent().getStringExtra(KEY_SERIALIZED_ADDRESS);
|
||||
String rawId = getIntent().getStringExtra(KEY_RECIPIENT);
|
||||
|
||||
if (serializedAddress == null) {
|
||||
if (rawId == null) {
|
||||
Toast.makeText(this, R.string.ShortcutLauncherActivity_invalid_shortcut, Toast.LENGTH_SHORT).show();
|
||||
startActivity(new Intent(this, ConversationListActivity.class));
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
Address address = Address.fromSerialized(serializedAddress);
|
||||
Recipient recipient = Recipient.from(this, address, true);
|
||||
Recipient recipient = Recipient.live(RecipientId.from(rawId)).get();
|
||||
TaskStackBuilder backStack = TaskStackBuilder.create(this)
|
||||
.addNextIntent(new Intent(this, ConversationListActivity.class));
|
||||
|
||||
|
|
|
@ -48,13 +48,13 @@ public class SmsSendtoActivity extends Activity {
|
|||
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
|
||||
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Recipient recipient = Recipient.from(this, Address.fromExternal(this, destination.getDestination()), true);
|
||||
Recipient recipient = Recipient.external(this, destination.getDestination());
|
||||
long threadId = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
|
||||
|
||||
nextIntent = new Intent(this, ConversationActivity.class);
|
||||
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
|
||||
nextIntent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
nextIntent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
nextIntent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
}
|
||||
return nextIntent;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ import org.thoughtcrime.securesms.color.MaterialColor;
|
|||
import org.thoughtcrime.securesms.components.camera.CameraView;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
|
||||
|
@ -72,8 +71,9 @@ import org.thoughtcrime.securesms.permissions.Permissions;
|
|||
import org.thoughtcrime.securesms.qr.QrCode;
|
||||
import org.thoughtcrime.securesms.qr.ScanListener;
|
||||
import org.thoughtcrime.securesms.qr.ScanningThread;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
|
@ -98,13 +98,13 @@ import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
|||
* @author Moxie Marlinspike
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener, ScanListener, View.OnClickListener {
|
||||
public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity implements ScanListener, View.OnClickListener {
|
||||
|
||||
private static final String TAG = VerifyIdentityActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
public static final String IDENTITY_EXTRA = "recipient_identity";
|
||||
public static final String VERIFIED_EXTRA = "verified_state";
|
||||
public static final String RECIPIENT_EXTRA = "recipient_id";
|
||||
public static final String IDENTITY_EXTRA = "recipient_identity";
|
||||
public static final String VERIFIED_EXTRA = "verified_state";
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
@ -123,15 +123,14 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_safety_number);
|
||||
|
||||
Recipient recipient = Recipient.from(this, (Address)getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
|
||||
recipient.addListener(this);
|
||||
LiveRecipient recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
|
||||
recipient.observe(this, r -> setActionBarNotificationBarColor(r.getColor()));
|
||||
|
||||
setActionBarNotificationBarColor(recipient.getColor());
|
||||
setActionBarNotificationBarColor(recipient.get().getColor());
|
||||
|
||||
Bundle extras = new Bundle();
|
||||
extras.putParcelable(VerifyDisplayFragment.REMOTE_ADDRESS, getIntent().getParcelableExtra(ADDRESS_EXTRA));
|
||||
extras.putParcelable(VerifyDisplayFragment.RECIPIENT_ID, getIntent().getParcelableExtra(RECIPIENT_EXTRA));
|
||||
extras.putParcelable(VerifyDisplayFragment.REMOTE_IDENTITY, getIntent().getParcelableExtra(IDENTITY_EXTRA));
|
||||
extras.putString(VerifyDisplayFragment.REMOTE_NUMBER, recipient.getAddress().toPhoneString());
|
||||
extras.putParcelable(VerifyDisplayFragment.LOCAL_IDENTITY, new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this)));
|
||||
extras.putString(VerifyDisplayFragment.LOCAL_NUMBER, TextSecurePreferences.getLocalNumber(this));
|
||||
extras.putBoolean(VerifyDisplayFragment.VERIFIED_STATE, getIntent().getBooleanExtra(VERIFIED_EXTRA, false));
|
||||
|
@ -151,11 +150,6 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(() -> setActionBarNotificationBarColor(recipient.getColor()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQrDataFound(final String data) {
|
||||
Util.runOnMain(() -> {
|
||||
|
@ -198,18 +192,18 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
}
|
||||
|
||||
public static class VerifyDisplayFragment extends Fragment implements RecipientModifiedListener, CompoundButton.OnCheckedChangeListener {
|
||||
public static class VerifyDisplayFragment extends Fragment implements CompoundButton.OnCheckedChangeListener {
|
||||
|
||||
public static final String REMOTE_ADDRESS = "remote_address";
|
||||
public static final String RECIPIENT_ID = "recipient_id";
|
||||
public static final String REMOTE_NUMBER = "remote_number";
|
||||
public static final String REMOTE_IDENTITY = "remote_identity";
|
||||
public static final String LOCAL_IDENTITY = "local_identity";
|
||||
public static final String LOCAL_NUMBER = "local_number";
|
||||
public static final String VERIFIED_STATE = "verified_state";
|
||||
|
||||
private Recipient recipient;
|
||||
private String localNumber;
|
||||
private String remoteNumber;
|
||||
private LiveRecipient recipient;
|
||||
private String localNumber;
|
||||
private String remoteNumber;
|
||||
|
||||
private IdentityKey localIdentity;
|
||||
private IdentityKey remoteIdentity;
|
||||
|
@ -264,21 +258,21 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
|
||||
Address address = getArguments().getParcelable(REMOTE_ADDRESS);
|
||||
RecipientId recipientId = getArguments().getParcelable(RECIPIENT_ID);
|
||||
IdentityKeyParcelable localIdentityParcelable = getArguments().getParcelable(LOCAL_IDENTITY);
|
||||
IdentityKeyParcelable remoteIdentityParcelable = getArguments().getParcelable(REMOTE_IDENTITY);
|
||||
|
||||
if (address == null) throw new AssertionError("Address required");
|
||||
if (recipientId == null) throw new AssertionError("RecipientId required");
|
||||
if (localIdentityParcelable == null) throw new AssertionError("local identity required");
|
||||
if (remoteIdentityParcelable == null) throw new AssertionError("remote identity required");
|
||||
|
||||
this.localNumber = getArguments().getString(LOCAL_NUMBER);
|
||||
this.localIdentity = localIdentityParcelable.get();
|
||||
this.remoteNumber = getArguments().getString(REMOTE_NUMBER);
|
||||
this.recipient = Recipient.from(getActivity(), address, true);
|
||||
this.recipient = Recipient.live(recipientId);
|
||||
this.remoteNumber = recipient.get().requireAddress().serialize();
|
||||
this.remoteIdentity = remoteIdentityParcelable.get();
|
||||
|
||||
this.recipient.addListener(this);
|
||||
this.recipient.observe(this, this::setRecipientText);
|
||||
|
||||
new AsyncTask<Void, Void, Fingerprint>() {
|
||||
@Override
|
||||
|
@ -298,16 +292,11 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(() -> setRecipientText(recipient));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
setRecipientText(recipient);
|
||||
setRecipientText(recipient.get());
|
||||
|
||||
if (fingerprint != null) {
|
||||
setFingerprintViews(fingerprint, false);
|
||||
|
@ -322,12 +311,6 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
recipient.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view,
|
||||
ContextMenuInfo menuInfo)
|
||||
|
@ -587,31 +570,31 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||
protected Void doInBackground(Recipient... params) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
if (isChecked) {
|
||||
Log.i(TAG, "Saving identity: " + params[0].getAddress());
|
||||
Log.i(TAG, "Saving identity: " + params[0].requireAddress());
|
||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||
.saveIdentity(params[0].getAddress(),
|
||||
.saveIdentity(params[0].getId(),
|
||||
remoteIdentity,
|
||||
VerifiedStatus.VERIFIED, false,
|
||||
System.currentTimeMillis(), true);
|
||||
} else {
|
||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||
.setVerified(params[0].getAddress(),
|
||||
.setVerified(params[0].getId(),
|
||||
remoteIdentity,
|
||||
VerifiedStatus.DEFAULT);
|
||||
}
|
||||
|
||||
ApplicationContext.getInstance(getActivity())
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceVerifiedUpdateJob(recipient.getAddress(),
|
||||
.add(new MultiDeviceVerifiedUpdateJob(recipient.getId(),
|
||||
remoteIdentity,
|
||||
isChecked ? VerifiedStatus.VERIFIED :
|
||||
VerifiedStatus.DEFAULT));
|
||||
|
||||
IdentityUtil.markIdentityVerified(getActivity(), recipient, isChecked, false);
|
||||
IdentityUtil.markIdentityVerified(getActivity(), recipient.get(), isChecked, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient);
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.content.res.Configuration;
|
|||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.view.View;
|
||||
|
@ -47,7 +46,6 @@ import org.thoughtcrime.securesms.service.WebRtcCallService;
|
|||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
|
||||
|
@ -280,11 +278,11 @@ public class WebRtcCallActivity extends Activity {
|
|||
public void onClick(View v) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(WebRtcCallActivity.this);
|
||||
identityKeyStore.saveIdentity(new SignalProtocolAddress(recipient.getAddress().serialize(), 1), theirIdentity, true);
|
||||
identityKeyStore.saveIdentity(new SignalProtocolAddress(recipient.requireAddress().serialize(), 1), theirIdentity, true);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, recipient.getAddress());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_RECIPIENT, recipient.getId());
|
||||
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL);
|
||||
startService(intent);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
|||
import org.thoughtcrime.securesms.database.SearchDatabase;
|
||||
import org.thoughtcrime.securesms.database.StickerDatabase;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.util.Conversions;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
@ -162,7 +163,7 @@ public class FullBackupImporter extends FullBackupBase {
|
|||
}
|
||||
|
||||
private static void processAvatar(@NonNull Context context, @NonNull BackupProtos.Avatar avatar, @NonNull BackupRecordInputStream inputStream) throws IOException {
|
||||
inputStream.readAttachmentTo(new FileOutputStream(AvatarHelper.getAvatarFile(context, Address.fromExternal(context, avatar.getName()))), avatar.getLength());
|
||||
inputStream.readAttachmentTo(new FileOutputStream(AvatarHelper.getAvatarFile(context, Address.fromSerialized(PhoneNumberFormatter.get(context).format(avatar.getName())))), avatar.getLength());
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
|
|
|
@ -126,7 +126,7 @@ public final class AvatarImageView extends AppCompatImageView {
|
|||
}
|
||||
|
||||
private void setAvatarClickHandler(final Recipient recipient, boolean quickContactEnabled) {
|
||||
if (!recipient.isGroupRecipient() && quickContactEnabled) {
|
||||
if (!recipient.isGroup() && quickContactEnabled) {
|
||||
super.setOnClickListener(v -> {
|
||||
if (recipient.getContactUri() != null) {
|
||||
ContactsContract.QuickContact.showQuickContact(getContext(), AvatarImageView.this, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
||||
|
|
|
@ -171,7 +171,7 @@ public class InputPanel extends LinearLayout
|
|||
|
||||
public Optional<QuoteModel> getQuote() {
|
||||
if (quoteView.getQuoteId() > 0 && quoteView.getVisibility() == View.VISIBLE) {
|
||||
return Optional.of(new QuoteModel(quoteView.getQuoteId(), quoteView.getAuthor().getAddress(), quoteView.getBody(), false, quoteView.getAttachments()));
|
||||
return Optional.of(new QuoteModel(quoteView.getQuoteId(), quoteView.getAuthor().getId(), quoteView.getBody(), false, quoteView.getAttachments()));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
|
|
@ -26,12 +26,14 @@ import android.view.View;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.RecipientsAdapter;
|
||||
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -43,7 +45,7 @@ import java.util.StringTokenizer;
|
|||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
public class PushRecipientsPanel extends RelativeLayout implements RecipientModifiedListener {
|
||||
public class PushRecipientsPanel extends RelativeLayout implements RecipientForeverObserver {
|
||||
private final String TAG = PushRecipientsPanel.class.getSimpleName();
|
||||
private RecipientsPanelChangedListener panelChangeListener;
|
||||
|
||||
|
@ -67,9 +69,15 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientModi
|
|||
initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
Stream.of(getRecipients()).map(Recipient::live).forEach(r -> r.removeForeverObserver(this));
|
||||
}
|
||||
|
||||
public List<Recipient> getRecipients() {
|
||||
String rawText = recipientsText.getText().toString();
|
||||
return getRecipientsFromString(getContext(), rawText, true);
|
||||
return getRecipientsFromString(getContext(), rawText);
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
|
@ -98,9 +106,7 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientModi
|
|||
|
||||
List<Recipient> recipients = getRecipients();
|
||||
|
||||
for (Recipient recipient : recipients) {
|
||||
recipient.addListener(this);
|
||||
}
|
||||
Stream.of(recipients).map(Recipient::live).forEach(r -> r.observeForever(this));
|
||||
|
||||
recipientsText.setAdapter(new RecipientsAdapter(this.getContext()));
|
||||
recipientsText.populate(recipients);
|
||||
|
@ -117,7 +123,7 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientModi
|
|||
});
|
||||
}
|
||||
|
||||
private @NonNull List<Recipient> getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) {
|
||||
private @NonNull List<Recipient> getRecipientsFromString(Context context, @NonNull String rawText) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(rawText, ",");
|
||||
List<Recipient> recipients = new LinkedList<>();
|
||||
|
||||
|
@ -125,8 +131,8 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientModi
|
|||
String token = tokenizer.nextToken().trim();
|
||||
|
||||
if (!TextUtils.isEmpty(token)) {
|
||||
if (hasBracketedNumber(token)) recipients.add(Recipient.from(context, Address.fromExternal(context, parseBracketedNumber(token)), asynchronous));
|
||||
else recipients.add(Recipient.from(context, Address.fromExternal(context, token), asynchronous));
|
||||
if (hasBracketedNumber(token)) recipients.add(Recipient.external(context, parseBracketedNumber(token)));
|
||||
else recipients.add(Recipient.external(context, token));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +155,7 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientModi
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
recipientsText.populate(getRecipients());
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,15 @@ import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
|||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class QuoteView extends FrameLayout implements RecipientModifiedListener {
|
||||
public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
||||
|
||||
private static final String TAG = QuoteView.class.getSimpleName();
|
||||
|
||||
|
@ -52,16 +53,16 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||
private TextView attachmentNameView;
|
||||
private ImageView dismissView;
|
||||
|
||||
private long id;
|
||||
private Recipient author;
|
||||
private String body;
|
||||
private TextView mediaDescriptionText;
|
||||
private TextView missingLinkText;
|
||||
private SlideDeck attachments;
|
||||
private int messageType;
|
||||
private int largeCornerRadius;
|
||||
private int smallCornerRadius;
|
||||
private CornerMask cornerMask;
|
||||
private long id;
|
||||
private LiveRecipient author;
|
||||
private String body;
|
||||
private TextView mediaDescriptionText;
|
||||
private TextView missingLinkText;
|
||||
private SlideDeck attachments;
|
||||
private int messageType;
|
||||
private int largeCornerRadius;
|
||||
private int smallCornerRadius;
|
||||
private CornerMask cornerMask;
|
||||
|
||||
|
||||
public QuoteView(Context context) {
|
||||
|
@ -137,6 +138,12 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||
cornerMask.mask(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (author != null) author.removeForeverObserver(this);
|
||||
}
|
||||
|
||||
public void setQuote(GlideRequests glideRequests,
|
||||
long id,
|
||||
@NonNull Recipient author,
|
||||
|
@ -144,14 +151,14 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||
boolean originalMissing,
|
||||
@NonNull SlideDeck attachments)
|
||||
{
|
||||
if (this.author != null) this.author.removeListener(this);
|
||||
if (this.author != null) this.author.removeForeverObserver(this);
|
||||
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.author = author.live();
|
||||
this.body = body;
|
||||
this.attachments = attachments;
|
||||
|
||||
author.addListener(this);
|
||||
this.author.observeForever(this);
|
||||
setQuoteAuthor(author);
|
||||
setQuoteText(body, attachments);
|
||||
setQuoteAttachment(glideRequests, attachments);
|
||||
|
@ -164,7 +171,7 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||
}
|
||||
|
||||
public void dismiss() {
|
||||
if (this.author != null) this.author.removeListener(this);
|
||||
if (this.author != null) this.author.removeForeverObserver(this);
|
||||
|
||||
this.id = 0;
|
||||
this.author = null;
|
||||
|
@ -174,17 +181,13 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
Util.runOnMain(() -> {
|
||||
if (recipient == author) {
|
||||
setQuoteAuthor(recipient);
|
||||
}
|
||||
});
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
setQuoteAuthor(recipient);
|
||||
}
|
||||
|
||||
private void setQuoteAuthor(@NonNull Recipient author) {
|
||||
boolean outgoing = messageType != MESSAGE_TYPE_INCOMING;
|
||||
boolean isOwnNumber = Util.isOwnNumber(getContext(), author.getAddress());
|
||||
boolean isOwnNumber = Util.isOwnNumber(getContext(), author.requireAddress());
|
||||
|
||||
authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you)
|
||||
: author.toShortString());
|
||||
|
@ -259,7 +262,7 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||
|
||||
private void setQuoteMissingFooter(boolean missing) {
|
||||
footerView.setVisibility(missing ? VISIBLE : GONE);
|
||||
footerView.setBackgroundColor(author.getColor().toQuoteFooterColor(getContext(), messageType != MESSAGE_TYPE_INCOMING));
|
||||
footerView.setBackgroundColor(author.get().getColor().toQuoteFooterColor(getContext(), messageType != MESSAGE_TYPE_INCOMING));
|
||||
}
|
||||
|
||||
public long getQuoteId() {
|
||||
|
@ -267,7 +270,7 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||
}
|
||||
|
||||
public Recipient getAuthor() {
|
||||
return author;
|
||||
return author.get();
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
|
|
|
@ -24,9 +24,10 @@ import org.thoughtcrime.securesms.contactshare.Contact;
|
|||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -35,7 +36,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class SharedContactView extends LinearLayout implements RecipientModifiedListener {
|
||||
public class SharedContactView extends LinearLayout implements RecipientForeverObserver {
|
||||
|
||||
private ImageView avatarView;
|
||||
private TextView nameView;
|
||||
|
@ -51,7 +52,7 @@ public class SharedContactView extends LinearLayout implements RecipientModified
|
|||
private int bigCornerRadius;
|
||||
private int smallCornerRadius;
|
||||
|
||||
private final Map<String, Recipient> activeRecipients = new HashMap<>();
|
||||
private final Map<RecipientId, LiveRecipient> activeRecipients = new HashMap<>();
|
||||
|
||||
public SharedContactView(Context context) {
|
||||
super(context);
|
||||
|
@ -114,12 +115,16 @@ public class SharedContactView extends LinearLayout implements RecipientModified
|
|||
this.locale = locale;
|
||||
this.contact = contact;
|
||||
|
||||
Stream.of(activeRecipients.values()).forEach(recipient -> recipient.removeListener(this));
|
||||
Stream.of(activeRecipients.values()).forEach(recipient -> recipient.removeForeverObserver(this));
|
||||
this.activeRecipients.clear();
|
||||
|
||||
presentContact(contact);
|
||||
presentAvatar(contact.getAvatarAttachment() != null ? contact.getAvatarAttachment().getDataUri() : null);
|
||||
presentActionButtons(ContactUtil.getRecipients(getContext(), contact));
|
||||
|
||||
for (LiveRecipient recipient : activeRecipients.values()) {
|
||||
recipient.observeForever(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSingularStyle() {
|
||||
|
@ -150,8 +155,8 @@ public class SharedContactView extends LinearLayout implements RecipientModified
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
Util.runOnMain(() -> presentActionButtons(Collections.singletonList(recipient)));
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
presentActionButtons(Collections.singletonList(recipient.getId()));
|
||||
}
|
||||
|
||||
private void presentContact(@Nullable Contact contact) {
|
||||
|
@ -180,21 +185,19 @@ public class SharedContactView extends LinearLayout implements RecipientModified
|
|||
}
|
||||
}
|
||||
|
||||
private void presentActionButtons(@NonNull List<Recipient> recipients) {
|
||||
for (Recipient recipient : recipients) {
|
||||
activeRecipients.put(recipient.getAddress().serialize(), recipient);
|
||||
private void presentActionButtons(@NonNull List<RecipientId> recipients) {
|
||||
for (RecipientId recipientId : recipients) {
|
||||
activeRecipients.put(recipientId, Recipient.live(recipientId));
|
||||
}
|
||||
|
||||
List<Recipient> pushUsers = new ArrayList<>(recipients.size());
|
||||
List<Recipient> systemUsers = new ArrayList<>(recipients.size());
|
||||
|
||||
for (Recipient recipient : activeRecipients.values()) {
|
||||
recipient.addListener(this);
|
||||
|
||||
if (recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
pushUsers.add(recipient);
|
||||
} else if (recipient.isSystemContact()) {
|
||||
systemUsers.add(recipient);
|
||||
for (LiveRecipient recipient : activeRecipients.values()) {
|
||||
if (recipient.get().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
pushUsers.add(recipient.get());
|
||||
} else if (recipient.get().isSystemContact()) {
|
||||
systemUsers.add(recipient.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public class TypingStatusRepository {
|
|||
}
|
||||
|
||||
public synchronized void onTypingStarted(@NonNull Context context, long threadId, @NonNull Recipient author, int device) {
|
||||
if (author.getAddress().serialize().equals(TextSecurePreferences.getLocalNumber(context))) {
|
||||
if (author.requireAddress().serialize().equals(TextSecurePreferences.getLocalNumber(context))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ public class TypingStatusRepository {
|
|||
}
|
||||
|
||||
public synchronized void onTypingStopped(@NonNull Context context, long threadId, @NonNull Recipient author, int device, boolean isReplacedByIncomingMessage) {
|
||||
if (author.getAddress().serialize().equals(TextSecurePreferences.getLocalNumber(context))) {
|
||||
if (author.requireAddress().serialize().equals(TextSecurePreferences.getLocalNumber(context))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public class UntrustedSendDialog extends AlertDialog.Builder implements DialogIn
|
|||
protected Void doInBackground(Void... params) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
for (IdentityRecord identityRecord : untrustedRecords) {
|
||||
identityDatabase.setApproval(identityRecord.getAddress(), true);
|
||||
identityDatabase.setApproval(identityRecord.getRecipientId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogI
|
|||
protected Void doInBackground(Void... params) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
for (IdentityRecord identityRecord : untrustedRecords) {
|
||||
identityDatabase.setVerified(identityRecord.getAddress(),
|
||||
identityDatabase.setVerified(identityRecord.getRecipientId(),
|
||||
identityRecord.getIdentityKey(),
|
||||
IdentityDatabase.VerifiedStatus.DEFAULT);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.thoughtcrime.securesms.components.reminder;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -9,25 +10,19 @@ import android.view.View.OnClickListener;
|
|||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
|
||||
public class InviteReminder extends Reminder {
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public InviteReminder(final @NonNull Context context,
|
||||
final @NonNull Recipient recipient)
|
||||
{
|
||||
super(context.getString(R.string.reminder_header_invite_title),
|
||||
context.getString(R.string.reminder_header_invite_text, recipient.toShortString()));
|
||||
|
||||
setDismissListener(new OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
new AsyncTask<Void,Void,Void>() {
|
||||
|
||||
@Override protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setSeenInviteReminder(recipient, true);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
});
|
||||
setDismissListener(v -> SignalExecutors.BOUNDED.execute(() -> {
|
||||
DatabaseFactory.getRecipientDatabase(context).setSeenInviteReminder(recipient.getId(), true);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,9 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.util.VerifySpan;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.webrtc.CameraState;
|
||||
|
@ -57,7 +57,7 @@ import org.whispersystems.libsignal.IdentityKey;
|
|||
* @author Moxie Marlinspike
|
||||
*
|
||||
*/
|
||||
public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedListener {
|
||||
public class WebRtcCallScreen extends FrameLayout implements RecipientForeverObserver {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = WebRtcCallScreen.class.getSimpleName();
|
||||
|
@ -82,8 +82,8 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
|||
|
||||
private WebRtcAnswerDeclineButton incomingCallButton;
|
||||
|
||||
private Recipient recipient;
|
||||
private boolean minimized;
|
||||
private LiveRecipient recipient;
|
||||
private boolean minimized;
|
||||
|
||||
|
||||
public WebRtcCallScreen(Context context) {
|
||||
|
@ -124,14 +124,18 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
|||
}
|
||||
|
||||
public void setUntrustedIdentity(Recipient personInfo, IdentityKey untrustedIdentity) {
|
||||
String name = recipient.toShortString();
|
||||
String name = recipient.get().toShortString();
|
||||
String introduction = String.format(getContext().getString(R.string.WebRtcCallScreen_new_safety_numbers), name, name);
|
||||
SpannableString spannableString = new SpannableString(introduction + " " + getContext().getString(R.string.WebRtcCallScreen_you_may_wish_to_verify_this_contact));
|
||||
|
||||
spannableString.setSpan(new VerifySpan(getContext(), personInfo.getAddress(), untrustedIdentity),
|
||||
spannableString.setSpan(new VerifySpan(getContext(), personInfo.getId(), untrustedIdentity),
|
||||
introduction.length()+1, spannableString.length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
if (this.recipient != null) this.recipient.removeForeverObserver(this);
|
||||
this.recipient = personInfo.live();
|
||||
this.recipient.observeForever(this);
|
||||
|
||||
setPersonInfo(personInfo);
|
||||
|
||||
incomingCallButton.stopRingingAnimation();
|
||||
|
@ -294,9 +298,6 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
|||
}
|
||||
|
||||
private void setPersonInfo(final @NonNull Recipient recipient) {
|
||||
this.recipient = recipient;
|
||||
this.recipient.addListener(this);
|
||||
|
||||
GlideApp.with(getContext().getApplicationContext())
|
||||
.load(recipient.getContactPhoto())
|
||||
.fallback(recipient.getFallbackContactPhoto().asCallCard(getContext()))
|
||||
|
@ -307,14 +308,19 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
|||
this.name.setText(recipient.getName());
|
||||
|
||||
if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) {
|
||||
this.phoneNumber.setText(recipient.getAddress().serialize() + " (~" + recipient.getProfileName() + ")");
|
||||
this.phoneNumber.setText(recipient.requireAddress().serialize() + " (~" + recipient.getProfileName() + ")");
|
||||
} else {
|
||||
this.phoneNumber.setText(recipient.getAddress().serialize());
|
||||
this.phoneNumber.setText(recipient.requireAddress().serialize());
|
||||
}
|
||||
}
|
||||
|
||||
private void setCard(Recipient recipient, String status) {
|
||||
if (this.recipient != null) this.recipient.removeForeverObserver(this);
|
||||
this.recipient = recipient.live();
|
||||
this.recipient.observeForever(this);
|
||||
|
||||
setPersonInfo(recipient);
|
||||
|
||||
this.status.setText(status);
|
||||
this.untrustedIdentityContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -341,17 +347,11 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
Util.runOnMain(() -> {
|
||||
if (recipient == WebRtcCallScreen.this.recipient) {
|
||||
setPersonInfo(recipient);
|
||||
}
|
||||
});
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
setPersonInfo(recipient);
|
||||
}
|
||||
|
||||
public interface HangupButtonListener {
|
||||
void onClick();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -29,10 +29,14 @@ import android.provider.ContactsContract.PhoneLookup;
|
|||
import android.telephony.PhoneNumberUtils;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -72,7 +76,7 @@ public class ContactAccessor {
|
|||
try (Cursor cursor = context.getContentResolver().query(Phone.CONTENT_URI, new String[] {Phone.NUMBER}, null ,null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
if (!TextUtils.isEmpty(cursor.getString(0))) {
|
||||
results.add(Address.fromExternal(context, cursor.getString(0)));
|
||||
results.add(Address.fromSerialized(PhoneNumberFormatter.get(context).format(cursor.getString(0))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +109,7 @@ public class ContactAccessor {
|
|||
final ContentResolver resolver = context.getContentResolver();
|
||||
final String[] inProjection = new String[]{PhoneLookup._ID, PhoneLookup.DISPLAY_NAME};
|
||||
|
||||
final List<Address> registeredAddresses = DatabaseFactory.getRecipientDatabase(context).getRegistered();
|
||||
final List<Address> registeredAddresses = Stream.of(DatabaseFactory.getRecipientDatabase(context).getRegistered()).map(Recipient::resolved).map(Recipient::requireAddress).toList();
|
||||
final Collection<ContactData> lookupData = new ArrayList<>(registeredAddresses.size());
|
||||
|
||||
for (Address registeredAddress : registeredAddresses) {
|
||||
|
|
|
@ -13,13 +13,14 @@ import org.thoughtcrime.securesms.R;
|
|||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class ContactSelectionListItem extends LinearLayout implements RecipientModifiedListener {
|
||||
public class ContactSelectionListItem extends LinearLayout implements RecipientForeverObserver {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = ContactSelectionListItem.class.getSimpleName();
|
||||
|
@ -31,7 +32,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
|
|||
private CheckBox checkBox;
|
||||
|
||||
private String number;
|
||||
private Recipient recipient;
|
||||
private LiveRecipient recipient;
|
||||
private GlideRequests glideRequests;
|
||||
|
||||
public ContactSelectionListItem(Context context) {
|
||||
|
@ -60,22 +61,22 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
|
|||
|
||||
if (type == ContactsDatabase.NEW_TYPE) {
|
||||
this.recipient = null;
|
||||
this.contactPhotoImage.setAvatar(glideRequests, Recipient.from(getContext(), Address.UNKNOWN, true), false);
|
||||
this.contactPhotoImage.setAvatar(glideRequests, Recipient.UNKNOWN, false);
|
||||
} else if (!TextUtils.isEmpty(number)) {
|
||||
Address address = Address.fromExternal(getContext(), number);
|
||||
this.recipient = Recipient.from(getContext(), address, true);
|
||||
this.recipient.addListener(this);
|
||||
// TODO [greyson] We really don't want to have to do a read like this here
|
||||
this.recipient = Recipient.external(getContext(), number).live();
|
||||
this.recipient.observeForever(this);
|
||||
|
||||
if (this.recipient.getName() != null) {
|
||||
name = this.recipient.getName();
|
||||
if (this.recipient.get().getName() != null) {
|
||||
name = this.recipient.get().getName();
|
||||
}
|
||||
}
|
||||
|
||||
this.nameView.setTextColor(color);
|
||||
this.numberView.setTextColor(color);
|
||||
this.contactPhotoImage.setAvatar(glideRequests, recipient, false);
|
||||
this.contactPhotoImage.setAvatar(glideRequests, recipient != null ? recipient.get() : null, false);
|
||||
|
||||
if (!multiSelect && recipient != null && recipient.isLocalNumber()) {
|
||||
if (!multiSelect && recipient != null && recipient.get().isLocalNumber()) {
|
||||
name = getContext().getString(R.string.note_to_self);
|
||||
}
|
||||
|
||||
|
@ -91,7 +92,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
|
|||
|
||||
public void unbind(GlideRequests glideRequests) {
|
||||
if (recipient != null) {
|
||||
recipient.removeListener(this);
|
||||
recipient.removeForeverObserver(this);
|
||||
recipient = null;
|
||||
}
|
||||
}
|
||||
|
@ -120,12 +121,8 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
if (this.recipient == recipient) {
|
||||
Util.runOnMain(() -> {
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, false);
|
||||
nameView.setText(recipient.toShortString());
|
||||
});
|
||||
}
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, false);
|
||||
nameView.setText(recipient.toShortString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import androidx.loader.content.CursorLoader;
|
|||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
|
@ -36,7 +35,7 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
|||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -170,7 +169,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
ThreadRecord threadRecord;
|
||||
while ((threadRecord = reader.getNext()) != null) {
|
||||
recentConversations.addRow(new Object[] { threadRecord.getRecipient().toShortString(),
|
||||
threadRecord.getRecipient().getAddress().serialize(),
|
||||
threadRecord.getRecipient().requireAddress().serialize(),
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactsDatabase.RECENT_TYPE });
|
||||
|
@ -230,7 +229,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
final MatrixCursor matrix = new MatrixCursor(CONTACT_PROJECTION);
|
||||
while (cursor.moveToNext()) {
|
||||
final String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
|
||||
final Recipient recipient = Recipient.from(getContext(), Address.fromExternal(getContext(), number), false);
|
||||
final Recipient recipient = Recipient.external(getContext(), number);
|
||||
|
||||
if (recipient.resolve().getRegistered() != RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
matrix.addRow(new Object[]{cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NAME_COLUMN)),
|
||||
|
|
|
@ -40,6 +40,7 @@ import android.util.Pair;
|
|||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -484,7 +485,7 @@ public class ContactsDatabase {
|
|||
cursor = context.getContentResolver().query(currentContactsUri, projection, null, null, null);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Address currentAddress = Address.fromExternal(context, cursor.getString(1));
|
||||
Address currentAddress = Address.fromSerialized(PhoneNumberFormatter.get(context).format(cursor.getString(1)));
|
||||
long rawContactId = cursor.getLong(0);
|
||||
long contactId = cursor.getLong(3);
|
||||
String supportsVoice = cursor.getString(2);
|
||||
|
@ -518,7 +519,7 @@ public class ContactsDatabase {
|
|||
|
||||
while (numberCursor != null && numberCursor.moveToNext()) {
|
||||
String systemNumber = numberCursor.getString(0);
|
||||
Address systemAddress = Address.fromExternal(context, systemNumber);
|
||||
Address systemAddress = Address.fromSerialized(PhoneNumberFormatter.get(context).format(systemNumber));
|
||||
|
||||
if (systemAddress.equals(address)) {
|
||||
idCursor = context.getContentResolver().query(RawContacts.CONTENT_URI,
|
||||
|
|
|
@ -187,7 +187,7 @@ public class RecipientsEditor extends AppCompatMultiAutoCompleteTextView {
|
|||
|
||||
public static CharSequence contactToToken(Recipient c) {
|
||||
String name = c.getName();
|
||||
String number = c.getAddress().serialize();
|
||||
String number = c.requireAddress().serialize();
|
||||
SpannableString s = new SpannableString(RecipientsFormatter.formatNameAndNumber(name, number));
|
||||
int len = s.length();
|
||||
|
||||
|
@ -195,7 +195,7 @@ public class RecipientsEditor extends AppCompatMultiAutoCompleteTextView {
|
|||
return s;
|
||||
}
|
||||
|
||||
s.setSpan(new Annotation("number", c.getAddress().serialize()), 0, len,
|
||||
s.setSpan(new Annotation("number", c.requireAddress().serialize()), 0, len,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
return s;
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.contactshare.Contact.PostalAddress;
|
|||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
|
@ -267,7 +268,7 @@ public class ContactRepository {
|
|||
}
|
||||
|
||||
for (Phone phoneNumber : phoneNumbers) {
|
||||
AvatarInfo recipientAvatar = getRecipientAvatarInfo(Address.fromExternal(context, phoneNumber.getNumber()));
|
||||
AvatarInfo recipientAvatar = getRecipientAvatarInfo(PhoneNumberFormatter.get(context).format(phoneNumber.getNumber()));
|
||||
if (recipientAvatar != null) {
|
||||
return recipientAvatar;
|
||||
}
|
||||
|
@ -286,8 +287,8 @@ public class ContactRepository {
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
private @Nullable AvatarInfo getRecipientAvatarInfo(@NonNull Address address) {
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
private @Nullable AvatarInfo getRecipientAvatarInfo(String address) {
|
||||
Recipient recipient = Recipient.external(context, address);
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto();
|
||||
|
||||
if (contactPhoto != null) {
|
||||
|
|
|
@ -22,10 +22,12 @@ import org.thoughtcrime.securesms.components.emoji.EmojiStrings;
|
|||
import org.thoughtcrime.securesms.contactshare.Contact.Email;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact.PostalAddress;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
|
@ -112,8 +114,7 @@ public final class ContactUtil {
|
|||
}
|
||||
|
||||
public static @NonNull String getNormalizedPhoneNumber(@NonNull Context context, @NonNull String number) {
|
||||
Address address = Address.fromExternal(context, number);
|
||||
return address.serialize();
|
||||
return PhoneNumberFormatter.get(context).format(number);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
|
@ -122,7 +123,7 @@ public final class ContactUtil {
|
|||
CharSequence[] values = new CharSequence[choices.size()];
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = getPrettyPhoneNumber(choices.get(i).getAddress().toPhoneString(), locale);
|
||||
values[i] = getPrettyPhoneNumber(choices.get(i).requireAddress().toPhoneString(), locale);
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
|
@ -134,8 +135,8 @@ public final class ContactUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static List<Recipient> getRecipients(@NonNull Context context, @NonNull Contact contact) {
|
||||
return Stream.of(contact.getPhoneNumbers()).map(phone -> Recipient.from(context, Address.fromExternal(context, phone.getNumber()), true)).toList();
|
||||
public static List<RecipientId> getRecipients(@NonNull Context context, @NonNull Contact contact) {
|
||||
return Stream.of(contact.getPhoneNumbers()).map(phone -> Recipient.external(context, phone.getNumber())).map(Recipient::getId).toList();
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
|
|
@ -27,13 +27,13 @@ import org.thoughtcrime.securesms.database.RecipientDatabase;
|
|||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -43,7 +43,7 @@ import java.util.Map;
|
|||
|
||||
import static org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.*;
|
||||
|
||||
public class SharedContactDetailsActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener {
|
||||
public class SharedContactDetailsActivity extends PassphraseRequiredActionBarActivity {
|
||||
|
||||
private static final int CODE_ADD_EDIT_CONTACT = 2323;
|
||||
private static final String KEY_CONTACT = "contact";
|
||||
|
@ -64,7 +64,7 @@ public class SharedContactDetailsActivity extends PassphraseRequiredActionBarAct
|
|||
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
||||
private final Map<String, Recipient> activeRecipients = new HashMap<>();
|
||||
private final Map<RecipientId, LiveRecipient> activeRecipients = new HashMap<>();
|
||||
|
||||
public static Intent getIntent(@NonNull Context context, @NonNull Contact contact) {
|
||||
Intent intent = new Intent(context, SharedContactDetailsActivity.class);
|
||||
|
@ -97,6 +97,10 @@ public class SharedContactDetailsActivity extends PassphraseRequiredActionBarAct
|
|||
presentContact(contact);
|
||||
presentActionButtons(ContactUtil.getRecipients(this, contact));
|
||||
presentAvatar(contact.getAvatarAttachment() != null ? contact.getAvatarAttachment().getDataUri() : null);
|
||||
|
||||
for (LiveRecipient recipient : activeRecipients.values()) {
|
||||
recipient.observe(this, r -> presentActionButtons(Collections.singletonList(r.getId())));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,11 +148,6 @@ public class SharedContactDetailsActivity extends PassphraseRequiredActionBarAct
|
|||
glideRequests = GlideApp.with(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
Util.runOnMain(() -> presentActionButtons(Collections.singletonList(recipient)));
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private void presentContact(@Nullable Contact contact) {
|
||||
this.contact = contact;
|
||||
|
@ -193,21 +192,19 @@ public class SharedContactDetailsActivity extends PassphraseRequiredActionBarAct
|
|||
}
|
||||
}
|
||||
|
||||
private void presentActionButtons(@NonNull List<Recipient> recipients) {
|
||||
for (Recipient recipient : recipients) {
|
||||
activeRecipients.put(recipient.getAddress().serialize(), recipient);
|
||||
private void presentActionButtons(@NonNull List<RecipientId> recipients) {
|
||||
for (RecipientId recipientId : recipients) {
|
||||
activeRecipients.put(recipientId, Recipient.live(recipientId));
|
||||
}
|
||||
|
||||
List<Recipient> pushUsers = new ArrayList<>(recipients.size());
|
||||
List<Recipient> systemUsers = new ArrayList<>(recipients.size());
|
||||
|
||||
for (Recipient recipient : activeRecipients.values()) {
|
||||
recipient.addListener(this);
|
||||
|
||||
if (recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
pushUsers.add(recipient);
|
||||
} else if (recipient.isSystemContact()) {
|
||||
systemUsers.add(recipient);
|
||||
for (LiveRecipient recipient : activeRecipients.values()) {
|
||||
if (recipient.get().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
pushUsers.add(recipient.get());
|
||||
} else if (recipient.get().isSystemContact()) {
|
||||
systemUsers.add(recipient.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,7 +227,7 @@ public class SharedContactDetailsActivity extends PassphraseRequiredActionBarAct
|
|||
|
||||
inviteButtonView.setOnClickListener(v -> {
|
||||
ContactUtil.selectRecipientThroughDialog(this, systemUsers, dynamicLanguage.getCurrentLocale(), recipient -> {
|
||||
CommunicationActions.composeSmsThroughDefaultApp(this, recipient.getAddress(), getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)));
|
||||
CommunicationActions.composeSmsThroughDefaultApp(this, recipient.requireAddress(), getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -128,7 +128,6 @@ import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
|||
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.DraftDatabase;
|
||||
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
|
||||
|
@ -184,10 +183,10 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
|||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.profiles.GroupShareProfileView;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientExporter;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.search.model.MessageResult;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
|
@ -249,7 +248,6 @@ import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
|||
public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ConversationFragment.ConversationFragmentListener,
|
||||
AttachmentManager.AttachmentListener,
|
||||
RecipientModifiedListener,
|
||||
OnKeyboardShownListener,
|
||||
InputPanel.Listener,
|
||||
InputPanel.MediaListener,
|
||||
|
@ -259,7 +257,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
{
|
||||
private static final String TAG = ConversationActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
public static final String RECIPIENT_EXTRA = "recipient_id";
|
||||
public static final String THREAD_ID_EXTRA = "thread_id";
|
||||
public static final String IS_ARCHIVED_EXTRA = "is_archived";
|
||||
public static final String TEXT_EXTRA = "draft_text";
|
||||
|
@ -316,14 +314,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
private ConversationSearchViewModel searchViewModel;
|
||||
private ConversationStickerViewModel stickerViewModel;
|
||||
|
||||
private Recipient recipient;
|
||||
private long threadId;
|
||||
private int distributionType;
|
||||
private boolean archived;
|
||||
private boolean isSecureText;
|
||||
private boolean isDefaultSms = true;
|
||||
private boolean isMmsEnabled = true;
|
||||
private boolean isSecurityInitialized = false;
|
||||
private LiveRecipient recipient;
|
||||
private long threadId;
|
||||
private int distributionType;
|
||||
private boolean archived;
|
||||
private boolean isSecureText;
|
||||
private boolean isDefaultSms = true;
|
||||
private boolean isMmsEnabled = true;
|
||||
private boolean isSecurityInitialized = false;
|
||||
|
||||
private final IdentityRecordList identityRecords = new IdentityRecordList();
|
||||
private final DynamicNoActionBarTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||
|
@ -428,10 +426,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
initializeIdentityRecords();
|
||||
composeText.setTransport(sendButton.getSelectedTransport());
|
||||
|
||||
titleView.setTitle(glideRequests, recipient);
|
||||
setActionBarColor(recipient.getColor());
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
setGroupShareProfileReminder(recipient);
|
||||
Recipient recipientSnapshot = recipient.get();
|
||||
|
||||
titleView.setTitle(glideRequests, recipientSnapshot);
|
||||
setActionBarColor(recipientSnapshot.getColor());
|
||||
setBlockedUserState(recipientSnapshot, isSecureText, isDefaultSms);
|
||||
setGroupShareProfileReminder(recipientSnapshot);
|
||||
calculateCharactersRemaining();
|
||||
|
||||
MessageNotifier.setVisibleThread(threadId);
|
||||
|
@ -473,7 +473,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
@Override
|
||||
protected void onDestroy() {
|
||||
saveDraft();
|
||||
if (recipient != null) recipient.removeListener(this);
|
||||
if (securityUpdateReceiver != null) unregisterReceiver(securityUpdateReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
@ -508,11 +507,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
sendSharedContact(data.getParcelableArrayListExtra(ContactShareEditActivity.KEY_CONTACTS));
|
||||
break;
|
||||
case GROUP_EDIT:
|
||||
recipient = Recipient.from(this, data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true);
|
||||
recipient.addListener(this);
|
||||
titleView.setTitle(glideRequests, recipient);
|
||||
NotificationChannels.updateContactChannelName(this, recipient);
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
Recipient recipientSnapshot = recipient.get();
|
||||
|
||||
onRecipientChanged(recipientSnapshot);
|
||||
titleView.setTitle(glideRequests, recipientSnapshot);
|
||||
NotificationChannels.updateContactChannelName(this, recipientSnapshot);
|
||||
setBlockedUserState(recipientSnapshot, isSecureText, isDefaultSms);
|
||||
supportInvalidateOptionsMenu();
|
||||
break;
|
||||
case TAKE_PHOTO:
|
||||
|
@ -521,8 +521,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
break;
|
||||
case ADD_CONTACT:
|
||||
recipient = Recipient.from(this, recipient.getAddress(), true);
|
||||
recipient.addListener(this);
|
||||
onRecipientChanged(recipient.get());
|
||||
fragment.reloadList();
|
||||
break;
|
||||
case PICK_LOCATION:
|
||||
|
@ -539,7 +538,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
break;
|
||||
case MEDIA_SENDER:
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
long expiresIn = recipient.get().getExpireMessages() * 1000L;
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
boolean initiating = threadId == -1;
|
||||
TransportOption transport = data.getParcelableExtra(MediaSendActivity.EXTRA_TRANSPORT);
|
||||
|
@ -617,14 +616,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
menu.clear();
|
||||
|
||||
if (isSecureText) {
|
||||
if (recipient.getExpireMessages() > 0) {
|
||||
if (recipient.get().getExpireMessages() > 0) {
|
||||
inflater.inflate(R.menu.conversation_expiring_on, menu);
|
||||
|
||||
final MenuItem item = menu.findItem(R.id.menu_expiring_messages);
|
||||
final View actionView = MenuItemCompat.getActionView(item);
|
||||
final TextView badgeView = actionView.findViewById(R.id.expiration_badge);
|
||||
|
||||
badgeView.setText(ExpirationUtil.getExpirationAbbreviatedDisplayValue(this, recipient.getExpireMessages()));
|
||||
badgeView.setText(ExpirationUtil.getExpirationAbbreviatedDisplayValue(this, recipient.get().getExpireMessages()));
|
||||
actionView.setOnClickListener(v -> onOptionsItemSelected(item));
|
||||
} else {
|
||||
inflater.inflate(R.menu.conversation_expiring_off, menu);
|
||||
|
@ -657,14 +656,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
inflater.inflate(R.menu.conversation_insecure, menu);
|
||||
}
|
||||
|
||||
if (recipient != null && recipient.isMuted()) inflater.inflate(R.menu.conversation_muted, menu);
|
||||
else inflater.inflate(R.menu.conversation_unmuted, menu);
|
||||
if (recipient != null && recipient.get().isMuted()) inflater.inflate(R.menu.conversation_muted, menu);
|
||||
else inflater.inflate(R.menu.conversation_unmuted, menu);
|
||||
|
||||
if (isSingleConversation() && getRecipient().getContactUri() == null) {
|
||||
inflater.inflate(R.menu.conversation_add_to_contacts, menu);
|
||||
}
|
||||
|
||||
if (recipient != null && recipient.isLocalNumber()) {
|
||||
if (recipient != null && recipient.get().isLocalNumber()) {
|
||||
if (isSecureText) menu.findItem(R.id.menu_call_secure).setVisible(false);
|
||||
else menu.findItem(R.id.menu_call_insecure).setVisible(false);
|
||||
|
||||
|
@ -771,7 +770,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEvent(ReminderUpdateEvent event) {
|
||||
updateReminders(recipient.hasSeenInviteReminder());
|
||||
updateReminders(recipient.get().hasSeenInviteReminder());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -794,11 +793,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
//noinspection CodeBlock2Expr
|
||||
ExpirationDialog.show(this, recipient.getExpireMessages(), expirationTime -> {
|
||||
ExpirationDialog.show(this, recipient.get().getExpireMessages(), expirationTime -> {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient, expirationTime);
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient.getId(), expirationTime);
|
||||
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(getRecipient(), System.currentTimeMillis(), expirationTime * 1000L);
|
||||
MessageSender.send(ConversationActivity.this, outgoingMessage, threadId, false, null);
|
||||
|
||||
|
@ -816,13 +815,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
private void handleMuteNotifications() {
|
||||
MuteDialog.show(this, until -> {
|
||||
recipient.setMuted(until);
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
|
||||
.setMuted(recipient, until);
|
||||
.setMuted(recipient.getId(), until);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -832,7 +829,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
private void handleConversationSettings() {
|
||||
Intent intent = new Intent(ConversationActivity.this, RecipientPreferenceActivity.class);
|
||||
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENT_ID, recipient.getId());
|
||||
intent.putExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA,
|
||||
isSecureText && !isSelfConversation());
|
||||
|
||||
|
@ -840,13 +837,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
private void handleUnmuteNotifications() {
|
||||
recipient.setMuted(0);
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
|
||||
.setMuted(recipient, 0);
|
||||
.setMuted(recipient.getId(), 0);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -857,7 +852,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
int titleRes = R.string.ConversationActivity_unblock_this_contact_question;
|
||||
int bodyRes = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact;
|
||||
|
||||
if (recipient.isGroupRecipient()) {
|
||||
if (recipient.get().isGroup()) {
|
||||
titleRes = R.string.ConversationActivity_unblock_this_group_question;
|
||||
bodyRes = R.string.ConversationActivity_unblock_this_group_description;
|
||||
}
|
||||
|
@ -872,7 +867,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
|
||||
.setBlocked(recipient, false);
|
||||
.setBlocked(recipient.getId(), false);
|
||||
|
||||
ApplicationContext.getInstance(ConversationActivity.this)
|
||||
.getJobManager()
|
||||
|
@ -904,7 +899,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
composeText.appendInvite(inviteText);
|
||||
} else {
|
||||
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
||||
intent.setData(Uri.parse("smsto:" + recipient.getAddress().serialize()));
|
||||
intent.setData(Uri.parse("smsto:" + recipient.get().requireAddress().serialize()));
|
||||
intent.putExtra("sms_body", inviteText);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, inviteText);
|
||||
startActivity(intent);
|
||||
|
@ -943,12 +938,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
private void handleViewMedia() {
|
||||
Intent intent = new Intent(this, MediaOverviewActivity.class);
|
||||
intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(MediaOverviewActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void handleAddShortcut() {
|
||||
Log.i(TAG, "Creating home screen shortcut for recipient " + recipient.getAddress());
|
||||
Log.i(TAG, "Creating home screen shortcut for recipient " + recipient.get().requireAddress());
|
||||
|
||||
new AsyncTask<Void, Void, IconCompat>() {
|
||||
|
||||
|
@ -957,9 +952,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
Context context = getApplicationContext();
|
||||
IconCompat icon = null;
|
||||
|
||||
if (recipient.getContactPhoto() != null) {
|
||||
if (recipient.get().getContactPhoto() != null) {
|
||||
try {
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(recipient.getContactPhoto().openInputStream(context));
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(recipient.get().getContactPhoto().openInputStream(context));
|
||||
bitmap = BitmapUtil.createScaledBitmap(bitmap, 300, 300);
|
||||
icon = IconCompat.createWithAdaptiveBitmap(bitmap);
|
||||
} catch (IOException e) {
|
||||
|
@ -968,8 +963,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
if (icon == null) {
|
||||
icon = IconCompat.createWithResource(context, recipient.isGroupRecipient() ? R.mipmap.ic_group_shortcut
|
||||
: R.mipmap.ic_person_shortcut);
|
||||
icon = IconCompat.createWithResource(context, recipient.get().isGroup() ? R.mipmap.ic_group_shortcut
|
||||
: R.mipmap.ic_person_shortcut);
|
||||
}
|
||||
|
||||
return icon;
|
||||
|
@ -978,14 +973,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
@Override
|
||||
protected void onPostExecute(IconCompat icon) {
|
||||
Context context = getApplicationContext();
|
||||
String name = Optional.fromNullable(recipient.getName())
|
||||
.or(Optional.fromNullable(recipient.getProfileName()))
|
||||
.or(recipient.toShortString());
|
||||
String name = Optional.fromNullable(recipient.get().getName())
|
||||
.or(Optional.fromNullable(recipient.get().getProfileName()))
|
||||
.or(recipient.get().toShortString());
|
||||
|
||||
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, recipient.getAddress().serialize() + '-' + System.currentTimeMillis())
|
||||
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, recipient.get().requireAddress().serialize() + '-' + System.currentTimeMillis())
|
||||
.setShortLabel(name)
|
||||
.setIcon(icon)
|
||||
.setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getAddress()))
|
||||
.setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getId()))
|
||||
.build();
|
||||
|
||||
if (ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, null)) {
|
||||
|
@ -1020,9 +1015,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
MessageSender.send(this, leaveMessage.get(), threadId, false, null);
|
||||
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(this);
|
||||
String groupId = groupRecipient.getAddress().toGroupString();
|
||||
String groupId = groupRecipient.requireAddress().toGroupString();
|
||||
groupDatabase.setActive(groupId, false);
|
||||
groupDatabase.remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)));
|
||||
groupDatabase.remove(groupId, Recipient.self().getId());
|
||||
|
||||
initializeEnabledCheck();
|
||||
} else {
|
||||
|
@ -1036,7 +1031,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
private void handleEditPushGroup() {
|
||||
Intent intent = new Intent(ConversationActivity.this, GroupCreateActivity.class);
|
||||
intent.putExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA, recipient.get().requireAddress());
|
||||
startActivityForResult(intent, GROUP_EDIT);
|
||||
}
|
||||
|
||||
|
@ -1080,7 +1075,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
} else {
|
||||
try {
|
||||
Intent dialIntent = new Intent(Intent.ACTION_DIAL,
|
||||
Uri.parse("tel:" + recipient.getAddress().serialize()));
|
||||
Uri.parse("tel:" + recipient.requireAddress().serialize()));
|
||||
startActivity(dialIntent);
|
||||
} catch (ActivityNotFoundException anfe) {
|
||||
Log.w(TAG, anfe);
|
||||
|
@ -1096,20 +1091,20 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
private void handleAddToContacts() {
|
||||
if (recipient.getAddress().isGroup()) return;
|
||||
if (recipient.get().requireAddress().isGroup()) return;
|
||||
|
||||
try {
|
||||
startActivityForResult(RecipientExporter.export(recipient).asAddContactIntent(), ADD_CONTACT);
|
||||
startActivityForResult(RecipientExporter.export(recipient.get()).asAddContactIntent(), ADD_CONTACT);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleDisplayQuickContact() {
|
||||
if (recipient.getAddress().isGroup()) return false;
|
||||
if (recipient.get().requireAddress().isGroup()) return false;
|
||||
|
||||
if (recipient.getContactUri() != null) {
|
||||
ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
||||
if (recipient.get().getContactUri() != null) {
|
||||
ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.get().getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
||||
} else {
|
||||
handleAddToContacts();
|
||||
}
|
||||
|
@ -1193,14 +1188,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
this.isDefaultSms = isDefaultSms;
|
||||
this.isSecurityInitialized = true;
|
||||
|
||||
boolean isMediaMessage = recipient.isMmsGroupRecipient() || attachmentManager.isAttachmentPresent();
|
||||
boolean isMediaMessage = recipient.get().isMmsGroup() || attachmentManager.isAttachmentPresent();
|
||||
|
||||
sendButton.resetAvailableTransports(isMediaMessage);
|
||||
|
||||
if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE);
|
||||
if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS);
|
||||
if (recipient.get().isPushGroup()) sendButton.disableTransport(Type.SMS);
|
||||
|
||||
if (!recipient.isPushGroupRecipient() && recipient.isForceSmsSelection()) {
|
||||
if (!recipient.get().isPushGroup() && recipient.get().isForceSmsSelection()) {
|
||||
sendButton.setDefaultTransport(Type.SMS);
|
||||
} else {
|
||||
if (isSecureText || isPushGroupConversation()) sendButton.setDefaultTransport(Type.TEXTSECURE);
|
||||
|
@ -1209,7 +1204,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
calculateCharactersRemaining();
|
||||
supportInvalidateOptionsMenu();
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
setBlockedUserState(recipient.get(), isSecureText, isDefaultSms);
|
||||
}
|
||||
|
||||
///// Initializers
|
||||
|
@ -1229,7 +1224,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
if (!Util.isEmpty(mediaList)) {
|
||||
Intent sendIntent = MediaSendActivity.buildEditorIntent(this, mediaList, recipient, draftText, sendButton.getSelectedTransport());
|
||||
Intent sendIntent = MediaSendActivity.buildEditorIntent(this, mediaList, recipient.get(), draftText, sendButton.getSelectedTransport());
|
||||
startActivityForResult(sendIntent, MEDIA_SENDER);
|
||||
return new SettableFuture<>(false);
|
||||
}
|
||||
|
@ -1344,16 +1339,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
@Override
|
||||
protected boolean[] doInBackground(Recipient... params) {
|
||||
Context context = ConversationActivity.this;
|
||||
Recipient recipient = params[0];
|
||||
Recipient recipient = params[0].resolve();
|
||||
Log.i(TAG, "Resolving registered state...");
|
||||
RegisteredState registeredState;
|
||||
|
||||
if (recipient.isPushGroupRecipient()) {
|
||||
if (recipient.isPushGroup()) {
|
||||
Log.i(TAG, "Push group recipient...");
|
||||
registeredState = RegisteredState.REGISTERED;
|
||||
} else if (recipient.isResolving()) {
|
||||
Log.i(TAG, "Talking to DB directly.");
|
||||
registeredState = DatabaseFactory.getRecipientDatabase(ConversationActivity.this).isRegistered(recipient.getAddress());
|
||||
} else {
|
||||
Log.i(TAG, "Checking through resolved recipient");
|
||||
registeredState = recipient.resolve().getRegistered();
|
||||
|
@ -1364,7 +1356,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
if (registeredState == RegisteredState.UNKNOWN) {
|
||||
try {
|
||||
Log.i(TAG, "Refreshing directory for user: " + recipient.getAddress().serialize());
|
||||
Log.i(TAG, "Refreshing directory for user: " + recipient.requireAddress().serialize());
|
||||
registeredState = DirectoryHelper.refreshDirectoryFor(context, recipient);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
|
@ -1385,15 +1377,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
future.set(true);
|
||||
onSecurityUpdated();
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient);
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
private void onSecurityUpdated() {
|
||||
Log.i(TAG, "onSecurityUpdated()");
|
||||
updateReminders(recipient.hasSeenInviteReminder());
|
||||
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
|
||||
updateReminders(recipient.get().hasSeenInviteReminder());
|
||||
updateDefaultSubscriptionId(recipient.get().getDefaultSubscriptionId());
|
||||
}
|
||||
|
||||
protected void updateReminders(boolean seenInvite) {
|
||||
|
@ -1410,9 +1402,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
TextSecurePreferences.isShowInviteReminders(this) &&
|
||||
!isSecureText &&
|
||||
!seenInvite &&
|
||||
!recipient.isGroupRecipient())
|
||||
!recipient.get().isGroup())
|
||||
{
|
||||
InviteReminder reminder = new InviteReminder(this, recipient);
|
||||
InviteReminder reminder = new InviteReminder(this, recipient.get());
|
||||
reminder.setOkListener(v -> {
|
||||
handleInviteLink();
|
||||
reminderView.get().requestDismiss();
|
||||
|
@ -1452,16 +1444,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
IdentityRecordList identityRecordList = new IdentityRecordList();
|
||||
List<Recipient> recipients = new LinkedList<>();
|
||||
|
||||
if (params[0].isGroupRecipient()) {
|
||||
if (params[0].isGroup()) {
|
||||
recipients.addAll(DatabaseFactory.getGroupDatabase(ConversationActivity.this)
|
||||
.getGroupMembers(params[0].getAddress().toGroupString(), false));
|
||||
.getGroupMembers(params[0].requireAddress().toGroupString(), false));
|
||||
} else {
|
||||
recipients.add(params[0]);
|
||||
}
|
||||
|
||||
for (Recipient recipient : recipients) {
|
||||
Log.i(TAG, "Loading identity for: " + recipient.getAddress());
|
||||
identityRecordList.add(identityDatabase.getIdentity(recipient.getAddress()));
|
||||
Log.i(TAG, "Loading identity for: " + recipient.requireAddress());
|
||||
identityRecordList.add(identityDatabase.getIdentity(recipient.getId()));
|
||||
}
|
||||
|
||||
String message = null;
|
||||
|
@ -1493,7 +1485,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
future.set(true);
|
||||
}
|
||||
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient);
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
|
||||
|
||||
return future;
|
||||
}
|
||||
|
@ -1585,15 +1577,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
private void initializeResources() {
|
||||
if (recipient != null) recipient.removeListener(this);
|
||||
|
||||
recipient = Recipient.from(this, getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
|
||||
recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
|
||||
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
|
||||
archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false);
|
||||
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
glideRequests = GlideApp.with(this);
|
||||
|
||||
recipient.addListener(this);
|
||||
recipient.observe(this, this::onRecipientChanged);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1628,7 +1618,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
if (!result.getResults().isEmpty()) {
|
||||
MessageResult messageResult = result.getResults().get(result.getPosition());
|
||||
fragment.jumpToMessage(messageResult.messageRecipient.getAddress(), messageResult.receivedTimestampMs, searchViewModel::onMissingResult);
|
||||
fragment.jumpToMessage(messageResult.messageRecipient.getId(), messageResult.receivedTimestampMs, searchViewModel::onMissingResult);
|
||||
}
|
||||
|
||||
searchNav.setData(result.getPosition(), result.getResults().size());
|
||||
|
@ -1699,27 +1689,23 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
ApplicationContext.getInstance(this)
|
||||
.getJobManager()
|
||||
.add(new RetrieveProfileJob(recipient));
|
||||
.add(new RetrieveProfileJob(recipient.get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
Log.i(TAG, "onModified(" + recipient.getAddress().serialize() + ")");
|
||||
Util.runOnMain(() -> {
|
||||
Log.i(TAG, "onModifiedRun(): " + recipient.getRegistered());
|
||||
titleView.setTitle(glideRequests, recipient);
|
||||
titleView.setVerified(identityRecords.isVerified());
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
setActionBarColor(recipient.getColor());
|
||||
setGroupShareProfileReminder(recipient);
|
||||
updateReminders(recipient.hasSeenInviteReminder());
|
||||
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
|
||||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
private void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
Log.i(TAG, "onModified(" + recipient.requireAddress().serialize() + ") " + recipient.getRegistered());
|
||||
titleView.setTitle(glideRequests, recipient);
|
||||
titleView.setVerified(identityRecords.isVerified());
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
setActionBarColor(recipient.getColor());
|
||||
setGroupShareProfileReminder(recipient);
|
||||
updateReminders(recipient.hasSeenInviteReminder());
|
||||
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
|
||||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
|
||||
if (searchViewItem == null || !searchViewItem.isActionViewExpanded()) {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
});
|
||||
if (searchViewItem == null || !searchViewItem.isActionViewExpanded()) {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
@ -1760,7 +1746,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
Log.i(TAG, "Selected: " + type);
|
||||
switch (type) {
|
||||
case AttachmentTypeSelector.ADD_GALLERY:
|
||||
AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient, composeText.getTextTrimmed(), sendButton.getSelectedTransport()); break;
|
||||
AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedTransport()); break;
|
||||
case AttachmentTypeSelector.ADD_DOCUMENT:
|
||||
AttachmentManager.selectDocument(this, PICK_DOCUMENT); break;
|
||||
case AttachmentTypeSelector.ADD_SOUND:
|
||||
|
@ -1790,7 +1776,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
return new SettableFuture<>(false);
|
||||
} else if (MediaType.IMAGE.equals(mediaType) || MediaType.GIF.equals(mediaType) || MediaType.VIDEO.equals(mediaType)) {
|
||||
Media media = new Media(uri, MediaUtil.getMimeType(this, uri), 0, width, height, 0, Optional.absent(), Optional.absent());
|
||||
startActivityForResult(MediaSendActivity.buildEditorIntent(ConversationActivity.this, Collections.singletonList(media), recipient, composeText.getTextTrimmed(), sendButton.getSelectedTransport()), MEDIA_SENDER);
|
||||
startActivityForResult(MediaSendActivity.buildEditorIntent(ConversationActivity.this, Collections.singletonList(media), recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedTransport()), MEDIA_SENDER);
|
||||
return new SettableFuture<>(false);
|
||||
} else {
|
||||
return attachmentManager.setMedia(glideRequests, uri, mediaType, getCurrentMediaConstraints(), width, height);
|
||||
|
@ -1812,7 +1798,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
private void sendSharedContact(List<Contact> contacts) {
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
long expiresIn = recipient.get().getExpireMessages() * 1000L;
|
||||
boolean initiating = threadId == -1;
|
||||
|
||||
sendMediaMessage(isSmsForced(), "", attachmentManager.buildSlideDeck(), null, contacts, Collections.emptyList(), expiresIn, false, subscriptionId, initiating, false);
|
||||
|
@ -1933,7 +1919,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
private void setGroupShareProfileReminder(@NonNull Recipient recipient) {
|
||||
if (recipient.isPushGroupRecipient() && !recipient.isProfileSharing()) {
|
||||
if (recipient.isPushGroup() && !recipient.isProfileSharing()) {
|
||||
groupShareProfileView.get().setRecipient(recipient);
|
||||
groupShareProfileView.get().setVisibility(View.VISIBLE);
|
||||
} else if (groupShareProfileView.resolved()) {
|
||||
|
@ -1979,30 +1965,30 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
|
||||
private boolean isSingleConversation() {
|
||||
return getRecipient() != null && !getRecipient().isGroupRecipient();
|
||||
return getRecipient() != null && !getRecipient().isGroup();
|
||||
}
|
||||
|
||||
private boolean isActiveGroup() {
|
||||
if (!isGroupConversation()) return false;
|
||||
|
||||
Optional<GroupRecord> record = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getAddress().toGroupString());
|
||||
Optional<GroupRecord> record = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getId());
|
||||
return record.isPresent() && record.get().isActive();
|
||||
}
|
||||
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
private boolean isSelfConversation() {
|
||||
if (!TextSecurePreferences.isPushRegistered(this)) return false;
|
||||
if (recipient.isGroupRecipient()) return false;
|
||||
if (recipient.get().isGroup()) return false;
|
||||
|
||||
return Util.isOwnNumber(this, recipient.getAddress());
|
||||
return Util.isOwnNumber(this, recipient.get().requireAddress());
|
||||
}
|
||||
|
||||
private boolean isGroupConversation() {
|
||||
return getRecipient() != null && getRecipient().isGroupRecipient();
|
||||
return getRecipient() != null && getRecipient().isGroup();
|
||||
}
|
||||
|
||||
private boolean isPushGroupConversation() {
|
||||
return getRecipient() != null && getRecipient().isPushGroupRecipient();
|
||||
return getRecipient() != null && getRecipient().isPushGroup();
|
||||
}
|
||||
|
||||
private boolean isSmsForced() {
|
||||
|
@ -2010,7 +1996,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
protected Recipient getRecipient() {
|
||||
return this.recipient;
|
||||
return this.recipient.get();
|
||||
}
|
||||
|
||||
protected long getThreadId() {
|
||||
|
@ -2090,7 +2076,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
fragment.setLastSeen(0);
|
||||
|
||||
if (refreshFragment) {
|
||||
fragment.reload(recipient, threadId);
|
||||
fragment.reload(recipient.get(), threadId);
|
||||
MessageNotifier.setVisibleThread(threadId);
|
||||
}
|
||||
|
||||
|
@ -2121,8 +2107,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
boolean initiating = threadId == -1;
|
||||
boolean needsSplit = !transport.isSms() && message.length() > transport.calculateCharacters(message).maxPrimaryMessageSize;
|
||||
boolean isMediaMessage = attachmentManager.isAttachmentPresent() ||
|
||||
recipient.isGroupRecipient() ||
|
||||
recipient.getAddress().isEmail() ||
|
||||
recipient.isGroup() ||
|
||||
recipient.requireAddress().isEmail() ||
|
||||
inputPanel.getQuote().isPresent() ||
|
||||
linkPreviewViewModel.hasLinkPreview() ||
|
||||
needsSplit;
|
||||
|
@ -2130,7 +2116,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
Log.i(TAG, "isManual Selection: " + sendButton.isManualSelection());
|
||||
Log.i(TAG, "forceSms: " + forceSms);
|
||||
|
||||
if ((recipient.isMmsGroupRecipient() || recipient.getAddress().isEmail()) && !isMmsEnabled) {
|
||||
if ((recipient.isMmsGroup() || recipient.requireAddress().isEmail()) && !isMmsEnabled) {
|
||||
handleManualMmsRequired();
|
||||
} else if (!forceSms && identityRecords.isUnverified()) {
|
||||
handleUnverifiedRecipients();
|
||||
|
@ -2186,7 +2172,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
}
|
||||
|
||||
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient, slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, viewOnce, distributionType, quote, contacts, previews);
|
||||
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient.get(), slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, viewOnce, distributionType, quote, contacts, previews);
|
||||
|
||||
final SettableFuture<Void> future = new SettableFuture<>();
|
||||
final Context context = getApplicationContext();
|
||||
|
@ -2217,7 +2203,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
@Override
|
||||
protected Long doInBackground(Void... param) {
|
||||
if (initiating) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient.getId(), true);
|
||||
}
|
||||
|
||||
return MessageSender.send(context, outgoingMessage, threadId, forceSms, () -> fragment.releaseOutgoingMessage(id));
|
||||
|
@ -2250,10 +2236,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
OutgoingTextMessage message;
|
||||
|
||||
if (isSecureText && !forceSms) {
|
||||
message = new OutgoingEncryptedMessage(recipient, messageBody, expiresIn);
|
||||
message = new OutgoingEncryptedMessage(recipient.get(), messageBody, expiresIn);
|
||||
ApplicationContext.getInstance(context).getTypingStatusSender().onTypingStopped(threadId);
|
||||
} else {
|
||||
message = new OutgoingTextMessage(recipient, messageBody, expiresIn, subscriptionId);
|
||||
message = new OutgoingTextMessage(recipient.get(), messageBody, expiresIn, subscriptionId);
|
||||
}
|
||||
|
||||
Permissions.with(this)
|
||||
|
@ -2268,7 +2254,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
@Override
|
||||
protected Long doInBackground(OutgoingTextMessage... messages) {
|
||||
if (initiatingConversation) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient.getId(), true);
|
||||
}
|
||||
|
||||
return MessageSender.send(context, messages[0], threadId, forceSms, () -> fragment.releaseOutgoingMessage(id));
|
||||
|
@ -2331,10 +2317,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
protected Void doInBackground(Void... params) {
|
||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(ConversationActivity.this);
|
||||
|
||||
recipientDatabase.setDefaultSubscriptionId(recipient, transportOption.getSimSubscriptionId().or(-1));
|
||||
recipientDatabase.setDefaultSubscriptionId(recipient.getId(), transportOption.getSimSubscriptionId().or(-1));
|
||||
|
||||
if (!recipient.isPushGroupRecipient()) {
|
||||
recipientDatabase.setForceSmsSelection(recipient, recipient.getRegistered() == RegisteredState.REGISTERED && transportOption.isSms());
|
||||
if (!recipient.resolve().isPushGroup()) {
|
||||
recipientDatabase.setForceSmsSelection(recipient.getId(), recipient.get().getRegistered() == RegisteredState.REGISTERED && transportOption.isSms());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -2381,7 +2367,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
public void onSuccess(final @NonNull Pair<Uri, Long> result) {
|
||||
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
long expiresIn = recipient.get().getExpireMessages() * 1000L;
|
||||
boolean initiating = threadId == -1;
|
||||
AudioSlide audioSlide = new AudioSlide(ConversationActivity.this, result.first, result.second, MediaUtil.AUDIO_AAC, true);
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
|
@ -2502,12 +2488,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
private void sendSticker(@NonNull StickerLocator stickerLocator, @NonNull Uri uri, long size, boolean clearCompose) {
|
||||
if (sendButton.getSelectedTransport().isSms()) {
|
||||
Media media = new Media(uri, MediaUtil.IMAGE_WEBP, System.currentTimeMillis(), StickerSlide.WIDTH, StickerSlide.HEIGHT, size, Optional.absent(), Optional.absent());
|
||||
Intent intent = MediaSendActivity.buildEditorIntent(this, Collections.singletonList(media), recipient, composeText.getTextTrimmed(), sendButton.getSelectedTransport());
|
||||
Intent intent = MediaSendActivity.buildEditorIntent(this, Collections.singletonList(media), recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedTransport());
|
||||
startActivityForResult(intent, MEDIA_SENDER);
|
||||
return;
|
||||
}
|
||||
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
long expiresIn = recipient.get().getExpireMessages() * 1000L;
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
boolean initiating = threadId == -1;
|
||||
TransportOption transport = sendButton.getSelectedTransport();
|
||||
|
@ -2538,7 +2524,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
public void onQuickAttachment(Uri uri, String mimeType, String bucketId, long dateTaken, int width, int height, long size) {
|
||||
linkPreviewViewModel.onUserCancel();
|
||||
Media media = new Media(uri, mimeType, dateTaken, width, height, size, Optional.of(Media.ALL_MEDIA_BUCKET_ID), Optional.absent());
|
||||
startActivityForResult(MediaSendActivity.buildEditorIntent(ConversationActivity.this, Collections.singletonList(media), recipient, composeText.getTextTrimmed(), sendButton.getSelectedTransport()), MEDIA_SENDER);
|
||||
startActivityForResult(MediaSendActivity.buildEditorIntent(ConversationActivity.this, Collections.singletonList(media), recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedTransport()), MEDIA_SENDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2552,7 +2538,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
|
||||
.onAllGranted(() -> {
|
||||
composeText.clearFocus();
|
||||
startActivityForResult(MediaSendActivity.buildCameraIntent(ConversationActivity.this, recipient, sendButton.getSelectedTransport()), MEDIA_SENDER);
|
||||
startActivityForResult(MediaSendActivity.buildCameraIntent(ConversationActivity.this, recipient.get(), sendButton.getSelectedTransport()), MEDIA_SENDER);
|
||||
overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary);
|
||||
})
|
||||
.onAnyDenied(() -> Toast.makeText(ConversationActivity.this, R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show())
|
||||
|
@ -2662,7 +2648,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
Recipient author;
|
||||
|
||||
if (messageRecord.isOutgoing()) {
|
||||
author = Recipient.from(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)), true);
|
||||
author = Recipient.self();
|
||||
} else {
|
||||
author = messageRecord.getIndividualRecipient();
|
||||
}
|
||||
|
@ -2740,7 +2726,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
protected Void doInBackground(Void... params) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
for (IdentityRecord identityRecord : unverifiedIdentities) {
|
||||
identityDatabase.setVerified(identityRecord.getAddress(),
|
||||
identityDatabase.setVerified(identityRecord.getRecipientId(),
|
||||
identityRecord.getIdentityKey(),
|
||||
VerifiedStatus.DEFAULT);
|
||||
}
|
||||
|
@ -2763,7 +2749,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
Log.i(TAG, "onClicked: " + unverifiedIdentities.size());
|
||||
if (unverifiedIdentities.size() == 1) {
|
||||
Intent intent = new Intent(ConversationActivity.this, VerifyIdentityActivity.class);
|
||||
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, unverifiedIdentities.get(0).getAddress());
|
||||
intent.putExtra(VerifyIdentityActivity.RECIPIENT_EXTRA, unverifiedIdentities.get(0).getRecipientId());
|
||||
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(unverifiedIdentities.get(0).getIdentityKey()));
|
||||
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, false);
|
||||
|
||||
|
@ -2772,7 +2758,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
String[] unverifiedNames = new String[unverifiedIdentities.size()];
|
||||
|
||||
for (int i=0;i<unverifiedIdentities.size();i++) {
|
||||
unverifiedNames[i] = Recipient.from(ConversationActivity.this, unverifiedIdentities.get(i).getAddress(), false).toShortString();
|
||||
unverifiedNames[i] = Recipient.resolved(unverifiedIdentities.get(i).getRecipientId()).toShortString();
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ConversationActivity.this);
|
||||
|
@ -2780,7 +2766,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
builder.setTitle("No longer verified");
|
||||
builder.setItems(unverifiedNames, (dialog, which) -> {
|
||||
Intent intent = new Intent(ConversationActivity.this, VerifyIdentityActivity.class);
|
||||
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, unverifiedIdentities.get(which).getAddress());
|
||||
intent.putExtra(VerifyIdentityActivity.RECIPIENT_EXTRA, unverifiedIdentities.get(which).getRecipientId());
|
||||
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(unverifiedIdentities.get(which).getIdentityKey()));
|
||||
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, false);
|
||||
|
||||
|
@ -2803,7 +2789,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
|
||||
@Override
|
||||
protected MessageRecord doInBackground(Void... voids) {
|
||||
QuoteId quoteId = QuoteId.deserialize(serialized);
|
||||
QuoteId quoteId = QuoteId.deserialize(ConversationActivity.this, serialized);
|
||||
|
||||
if (quoteId != null) {
|
||||
return DatabaseFactory.getMmsSmsDatabase(getApplicationContext()).getMessageFor(quoteId.getId(), quoteId.getAuthor());
|
||||
|
|
|
@ -69,7 +69,6 @@ import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
|||
import org.thoughtcrime.securesms.contactshare.SharedContactDetailsActivity;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter.HeaderViewHolder;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickListener;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
|
@ -90,7 +89,9 @@ import org.thoughtcrime.securesms.mms.PartAuthority;
|
|||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.profiles.UnknownSenderView;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceMessageActivity;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
|
@ -134,7 +135,7 @@ public class ConversationFragment extends Fragment
|
|||
|
||||
private ConversationFragmentListener listener;
|
||||
|
||||
private Recipient recipient;
|
||||
private LiveRecipient recipient;
|
||||
private long threadId;
|
||||
private long lastSeen;
|
||||
private int startingPosition;
|
||||
|
@ -253,12 +254,12 @@ public class ConversationFragment extends Fragment
|
|||
}
|
||||
|
||||
private void initializeResources() {
|
||||
this.recipient = Recipient.from(getActivity(), getActivity().getIntent().getParcelableExtra(ConversationActivity.ADDRESS_EXTRA), true);
|
||||
this.recipient = Recipient.live(getActivity().getIntent().getParcelableExtra(ConversationActivity.RECIPIENT_EXTRA));
|
||||
this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
|
||||
this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
|
||||
this.startingPosition = this.getActivity().getIntent().getIntExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1);
|
||||
this.firstLoad = true;
|
||||
this.unknownSenderView = new UnknownSenderView(getActivity(), recipient, threadId);
|
||||
this.unknownSenderView = new UnknownSenderView(getActivity(), recipient.get(), threadId);
|
||||
|
||||
OnScrollListener scrollListener = new ConversationScrollListener(getActivity());
|
||||
list.addOnScrollListener(scrollListener);
|
||||
|
@ -266,7 +267,7 @@ public class ConversationFragment extends Fragment
|
|||
|
||||
private void initializeListAdapter() {
|
||||
if (this.recipient != null && this.threadId != -1) {
|
||||
ConversationAdapter adapter = new ConversationAdapter(getActivity(), GlideApp.with(this), locale, selectionClickListener, null, this.recipient);
|
||||
ConversationAdapter adapter = new ConversationAdapter(requireContext(), GlideApp.with(this), locale, selectionClickListener, null, this.recipient.get());
|
||||
list.setAdapter(adapter);
|
||||
list.addItemDecoration(new StickyHeaderDecoration(adapter, false, false));
|
||||
|
||||
|
@ -302,7 +303,7 @@ public class ConversationFragment extends Fragment
|
|||
replacedByIncomingMessage = false;
|
||||
}
|
||||
|
||||
typingView.setTypists(GlideApp.with(ConversationFragment.this), recipients, recipient.isGroupRecipient());
|
||||
typingView.setTypists(GlideApp.with(ConversationFragment.this), recipients, recipient.get().isGroup());
|
||||
|
||||
ConversationAdapter adapter = getListAdapter();
|
||||
|
||||
|
@ -417,7 +418,7 @@ public class ConversationFragment extends Fragment
|
|||
}
|
||||
|
||||
public void reload(Recipient recipient, long threadId) {
|
||||
this.recipient = recipient;
|
||||
this.recipient = recipient.live();
|
||||
|
||||
if (this.threadId != threadId) {
|
||||
this.threadId = threadId;
|
||||
|
@ -521,8 +522,8 @@ public class ConversationFragment extends Fragment
|
|||
intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, message.getId());
|
||||
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
|
||||
intent.putExtra(MessageDetailsActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, recipient.isGroupRecipient() && message.isPush());
|
||||
intent.putExtra(MessageDetailsActivity.RECIPIENT_EXTRA, recipient.getId());
|
||||
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, recipient.get().isGroup() && message.isPush());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
|
@ -663,7 +664,7 @@ public class ConversationFragment extends Fragment
|
|||
setLastSeen(loader.getLastSeen());
|
||||
}
|
||||
|
||||
if (!loader.hasSent() && !recipient.isSystemContact() && !recipient.isGroupRecipient() && recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
if (!loader.hasSent() && !recipient.get().isSystemContact() && !recipient.get().isGroup() && recipient.get().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
adapter.setHeaderView(unknownSenderView);
|
||||
} else {
|
||||
clearHeaderIfNotTyping(adapter);
|
||||
|
@ -789,7 +790,7 @@ public class ConversationFragment extends Fragment
|
|||
}
|
||||
}
|
||||
|
||||
public void jumpToMessage(@NonNull Address author, long timestamp, @Nullable Runnable onMessageNotFound) {
|
||||
public void jumpToMessage(@NonNull RecipientId author, long timestamp, @Nullable Runnable onMessageNotFound) {
|
||||
SimpleTask.run(getLifecycle(), () -> {
|
||||
return DatabaseFactory.getMmsSmsDatabase(getContext())
|
||||
.getMessagePositionInConversation(threadId, timestamp, author);
|
||||
|
@ -951,9 +952,9 @@ public class ConversationFragment extends Fragment
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms) {
|
||||
public void onMoreTextClicked(@NonNull RecipientId conversationRecipientId, long messageId, boolean isMms) {
|
||||
if (getContext() != null && getActivity() != null) {
|
||||
startActivity(LongMessageActivity.getIntent(getContext(), conversationAddress, messageId, isMms));
|
||||
startActivity(LongMessageActivity.getIntent(getContext(), conversationRecipientId, messageId, isMms));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -990,7 +991,7 @@ public class ConversationFragment extends Fragment
|
|||
|
||||
ApplicationContext.getInstance(requireContext())
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceViewOnceOpenJob(new MessagingDatabase.SyncMessageId(messageRecord.getIndividualRecipient().getAddress(), messageRecord.getDateSent())));
|
||||
.add(new MultiDeviceViewOnceOpenJob(new MessagingDatabase.SyncMessageId(messageRecord.getIndividualRecipient().getId(), messageRecord.getDateSent())));
|
||||
|
||||
return tempUri;
|
||||
} catch (IOException e) {
|
||||
|
@ -1046,7 +1047,7 @@ public class ConversationFragment extends Fragment
|
|||
if (getContext() == null) return;
|
||||
|
||||
ContactUtil.selectRecipientThroughDialog(getContext(), choices, locale, recipient -> {
|
||||
CommunicationActions.composeSmsThroughDefaultApp(getContext(), recipient.getAddress(), getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)));
|
||||
CommunicationActions.composeSmsThroughDefaultApp(getContext(), recipient.requireAddress(), getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,8 @@ import org.thoughtcrime.securesms.components.DocumentView;
|
|||
import org.thoughtcrime.securesms.components.LinkPreviewView;
|
||||
import org.thoughtcrime.securesms.components.Outliner;
|
||||
import org.thoughtcrime.securesms.components.QuoteView;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceMessageView;
|
||||
import org.thoughtcrime.securesms.components.SharedContactView;
|
||||
import org.thoughtcrime.securesms.components.StickerView;
|
||||
|
@ -98,7 +100,6 @@ import org.thoughtcrime.securesms.mms.SlideClickListener;
|
|||
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
||||
import org.thoughtcrime.securesms.mms.TextSlide;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
|
||||
import org.thoughtcrime.securesms.stickers.StickerUrl;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
|
@ -108,7 +109,6 @@ import org.thoughtcrime.securesms.util.LongClickMovementMethod;
|
|||
import org.thoughtcrime.securesms.util.SearchUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -127,8 +127,8 @@ import java.util.Set;
|
|||
*
|
||||
*/
|
||||
|
||||
public class ConversationItem extends LinearLayout
|
||||
implements RecipientModifiedListener, BindableConversationItem
|
||||
public class ConversationItem extends LinearLayout implements BindableConversationItem,
|
||||
RecipientForeverObserver
|
||||
{
|
||||
private static final String TAG = ConversationItem.class.getSimpleName();
|
||||
|
||||
|
@ -138,7 +138,7 @@ public class ConversationItem extends LinearLayout
|
|||
private MessageRecord messageRecord;
|
||||
private Locale locale;
|
||||
private boolean groupThread;
|
||||
private Recipient recipient;
|
||||
private LiveRecipient recipient;
|
||||
private GlideRequests glideRequests;
|
||||
|
||||
protected ViewGroup bodyBubble;
|
||||
|
@ -156,7 +156,7 @@ public class ConversationItem extends LinearLayout
|
|||
|
||||
private @NonNull Set<MessageRecord> batchSelected = new HashSet<>();
|
||||
private @NonNull Outliner outliner = new Outliner();
|
||||
private Recipient conversationRecipient;
|
||||
private LiveRecipient conversationRecipient;
|
||||
private Stub<ConversationItemThumbnail> mediaThumbnailStub;
|
||||
private Stub<AudioView> audioViewStub;
|
||||
private Stub<DocumentView> documentViewStub;
|
||||
|
@ -238,16 +238,19 @@ public class ConversationItem extends LinearLayout
|
|||
@Nullable String searchQuery,
|
||||
boolean pulseHighlight)
|
||||
{
|
||||
if (this.recipient != null) this.recipient.removeForeverObserver(this);
|
||||
if (this.conversationRecipient != null) this.conversationRecipient.removeForeverObserver(this);
|
||||
|
||||
this.messageRecord = messageRecord;
|
||||
this.locale = locale;
|
||||
this.glideRequests = glideRequests;
|
||||
this.batchSelected = batchSelected;
|
||||
this.conversationRecipient = conversationRecipient;
|
||||
this.groupThread = conversationRecipient.isGroupRecipient();
|
||||
this.recipient = messageRecord.getIndividualRecipient();
|
||||
this.conversationRecipient = conversationRecipient.live();
|
||||
this.groupThread = conversationRecipient.isGroup();
|
||||
this.recipient = messageRecord.getIndividualRecipient().live();
|
||||
|
||||
this.recipient.addListener(this);
|
||||
this.conversationRecipient.addListener(this);
|
||||
this.recipient.observeForever(this);
|
||||
this.conversationRecipient.observeForever(this);
|
||||
|
||||
setGutterSizes(messageRecord, groupThread);
|
||||
setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
||||
|
@ -256,8 +259,8 @@ public class ConversationItem extends LinearLayout
|
|||
setBodyText(messageRecord, searchQuery);
|
||||
setBubbleState(messageRecord);
|
||||
setStatusIcons(messageRecord);
|
||||
setContactPhoto(recipient);
|
||||
setGroupMessageStatus(messageRecord, recipient);
|
||||
setContactPhoto(recipient.get());
|
||||
setGroupMessageStatus(messageRecord, recipient.get());
|
||||
setGroupAuthorColor(messageRecord);
|
||||
setAuthor(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
||||
setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
||||
|
@ -320,6 +323,14 @@ public class ConversationItem extends LinearLayout
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecipientChanged(@NonNull Recipient modified) {
|
||||
setBubbleState(messageRecord);
|
||||
setContactPhoto(recipient.get());
|
||||
setGroupMessageStatus(messageRecord, recipient.get());
|
||||
setAudioViewTint(messageRecord, conversationRecipient.get());
|
||||
}
|
||||
|
||||
private int getAvailableMessageBubbleWidth(@NonNull View forView) {
|
||||
int availableWidth;
|
||||
if (hasAudio(messageRecord)) {
|
||||
|
@ -346,7 +357,7 @@ public class ConversationItem extends LinearLayout
|
|||
@Override
|
||||
public void unbind() {
|
||||
if (recipient != null) {
|
||||
recipient.removeListener(this);
|
||||
recipient.removeForeverObserver(this);;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,7 +383,7 @@ public class ConversationItem extends LinearLayout
|
|||
}
|
||||
|
||||
if (audioViewStub.resolved()) {
|
||||
setAudioViewTint(messageRecord, this.conversationRecipient);
|
||||
setAudioViewTint(messageRecord, this.conversationRecipient.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -820,7 +831,7 @@ public class ConversationItem extends LinearLayout
|
|||
if (current.isMms() && !current.isMmsNotification() && ((MediaMmsMessageRecord)current).getQuote() != null) {
|
||||
Quote quote = ((MediaMmsMessageRecord)current).getQuote();
|
||||
//noinspection ConstantConditions
|
||||
quoteView.setQuote(glideRequests, quote.getId(), Recipient.from(context, quote.getAuthor(), true), quote.getText(), quote.isOriginalMissing(), quote.getAttachment());
|
||||
quoteView.setQuote(glideRequests, quote.getId(), Recipient.live(quote.getAuthor()).get(), quote.getText(), quote.isOriginalMissing(), quote.getAttachment());
|
||||
quoteView.setVisibility(View.VISIBLE);
|
||||
quoteView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
|
||||
|
@ -944,7 +955,7 @@ public class ConversationItem extends LinearLayout
|
|||
if (isGroupThread && !current.isOutgoing()) {
|
||||
contactPhotoHolder.setVisibility(VISIBLE);
|
||||
|
||||
if (!previous.isPresent() || previous.get().isUpdate() || !current.getRecipient().getAddress().equals(previous.get().getRecipient().getAddress()) ||
|
||||
if (!previous.isPresent() || previous.get().isUpdate() || !current.getRecipient().requireAddress().equals(previous.get().getRecipient().requireAddress()) ||
|
||||
!DateUtils.isSameDay(previous.get().getTimestamp(), current.getTimestamp()))
|
||||
{
|
||||
groupSenderHolder.setVisibility(VISIBLE);
|
||||
|
@ -952,7 +963,7 @@ public class ConversationItem extends LinearLayout
|
|||
groupSenderHolder.setVisibility(GONE);
|
||||
}
|
||||
|
||||
if (!next.isPresent() || next.get().isUpdate() || !current.getRecipient().getAddress().equals(next.get().getRecipient().getAddress())) {
|
||||
if (!next.isPresent() || next.get().isUpdate() || !current.getRecipient().requireAddress().equals(next.get().getRecipient().requireAddress())) {
|
||||
contactPhoto.setVisibility(VISIBLE);
|
||||
} else {
|
||||
contactPhoto.setVisibility(GONE);
|
||||
|
@ -1012,7 +1023,7 @@ public class ConversationItem extends LinearLayout
|
|||
private boolean isStartOfMessageCluster(@NonNull MessageRecord current, @NonNull Optional<MessageRecord> previous, boolean isGroupThread) {
|
||||
if (isGroupThread) {
|
||||
return !previous.isPresent() || previous.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) ||
|
||||
!current.getRecipient().getAddress().equals(previous.get().getRecipient().getAddress());
|
||||
!current.getRecipient().requireAddress().equals(previous.get().getRecipient().requireAddress());
|
||||
} else {
|
||||
return !previous.isPresent() || previous.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) ||
|
||||
current.isOutgoing() != previous.get().isOutgoing();
|
||||
|
@ -1022,7 +1033,7 @@ public class ConversationItem extends LinearLayout
|
|||
private boolean isEndOfMessageCluster(@NonNull MessageRecord current, @NonNull Optional<MessageRecord> next, boolean isGroupThread) {
|
||||
if (isGroupThread) {
|
||||
return !next.isPresent() || next.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) ||
|
||||
!current.getRecipient().getAddress().equals(next.get().getRecipient().getAddress());
|
||||
!current.getRecipient().requireAddress().equals(next.get().getRecipient().requireAddress());
|
||||
} else {
|
||||
return !next.isPresent() || next.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) ||
|
||||
current.isOutgoing() != next.get().isOutgoing();
|
||||
|
@ -1074,7 +1085,7 @@ public class ConversationItem extends LinearLayout
|
|||
|
||||
if (slide != null && slide.asAttachment().getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
|
||||
message = getResources().getString(R.string.ConversationItem_read_more);
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getId(), messageRecord.getId(), messageRecord.isMms());
|
||||
} else if (slide != null && slide.asAttachment().getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_STARTED) {
|
||||
message = getResources().getString(R.string.ConversationItem_pending);
|
||||
action = () -> {};
|
||||
|
@ -1083,11 +1094,11 @@ public class ConversationItem extends LinearLayout
|
|||
action = () -> singleDownloadClickListener.onClick(bodyText, slide);
|
||||
} else {
|
||||
message = getResources().getString(R.string.ConversationItem_read_more);
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getId(), messageRecord.getId(), messageRecord.isMms());
|
||||
}
|
||||
} else {
|
||||
message = getResources().getString(R.string.ConversationItem_read_more);
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getId(), messageRecord.getId(), messageRecord.isMms());
|
||||
}
|
||||
|
||||
SpannableStringBuilder span = new SpannableStringBuilder(message);
|
||||
|
@ -1108,16 +1119,6 @@ public class ConversationItem extends LinearLayout
|
|||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient modified) {
|
||||
Util.runOnMain(() -> {
|
||||
setBubbleState(messageRecord);
|
||||
setContactPhoto(recipient);
|
||||
setGroupMessageStatus(messageRecord, recipient);
|
||||
setAudioViewTint(messageRecord, conversationRecipient);
|
||||
});
|
||||
}
|
||||
|
||||
private class SharedContactEventListener implements SharedContactView.EventListener {
|
||||
@Override
|
||||
public void onAddToContactsClicked(@NonNull Contact contact) {
|
||||
|
@ -1251,7 +1252,7 @@ public class ConversationItem extends LinearLayout
|
|||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setDataAndType(slide.getUri(), slide.getContentType());
|
||||
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
|
||||
intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, conversationRecipient.getId());
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, messageRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
|
||||
|
@ -1309,7 +1310,7 @@ public class ConversationItem extends LinearLayout
|
|||
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, messageRecord.getThreadId());
|
||||
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, messageRecord.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
|
||||
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, groupThread && messageRecord.isPush());
|
||||
intent.putExtra(MessageDetailsActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
|
||||
intent.putExtra(MessageDetailsActivity.RECIPIENT_EXTRA, conversationRecipient.getId());
|
||||
context.startActivity(intent);
|
||||
} else if (!messageRecord.isOutgoing() && messageRecord.isIdentityMismatchFailure()) {
|
||||
handleApproveIdentity();
|
||||
|
@ -1352,7 +1353,7 @@ public class ConversationItem extends LinearLayout
|
|||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new SmsSendJob(context, messageRecord.getId(),
|
||||
messageRecord.getIndividualRecipient().getAddress()));
|
||||
messageRecord.getIndividualRecipient()));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ public class ConversationPopupActivity extends ConversationActivity {
|
|||
public void onSuccess(Long result) {
|
||||
ActivityOptionsCompat transition = ActivityOptionsCompat.makeScaleUpAnimation(getWindow().getDecorView(), 0, 0, getWindow().getAttributes().width, getWindow().getAttributes().height);
|
||||
Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, getRecipient().getAddress());
|
||||
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, getRecipient().getId());
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, result);
|
||||
|
||||
startActivity(intent, transition.toBundle());
|
||||
|
|
|
@ -105,7 +105,7 @@ public class ConversationTitleView extends RelativeLayout {
|
|||
}
|
||||
|
||||
private void setRecipientTitle(Recipient recipient) {
|
||||
if (recipient.isGroupRecipient()) setGroupRecipientTitle(recipient);
|
||||
if (recipient.isGroup()) setGroupRecipientTitle(recipient);
|
||||
else if (recipient.isLocalNumber()) setSelfTitle();
|
||||
else if (TextUtils.isEmpty(recipient.getName())) setNonContactRecipientTitle(recipient);
|
||||
else setContactRecipientTitle(recipient);
|
||||
|
@ -116,7 +116,7 @@ public class ConversationTitleView extends RelativeLayout {
|
|||
|
||||
this.title.setText(recipient.getName());
|
||||
this.subtitle.setText(Stream.of(recipient.getParticipants())
|
||||
.filter(r -> !r.getAddress().serialize().equals(localNumber))
|
||||
.filter(r -> !r.requireAddress().serialize().equals(localNumber))
|
||||
.map(Recipient::toShortString)
|
||||
.collect(Collectors.joining(", ")));
|
||||
|
||||
|
@ -130,7 +130,7 @@ public class ConversationTitleView extends RelativeLayout {
|
|||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private void setNonContactRecipientTitle(Recipient recipient) {
|
||||
this.title.setText(recipient.getAddress().serialize());
|
||||
this.title.setText(recipient.requireAddress().serialize());
|
||||
|
||||
if (TextUtils.isEmpty(recipient.getProfileName())) {
|
||||
this.subtitle.setText(null);
|
||||
|
|
|
@ -22,13 +22,13 @@ import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
|||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
|
@ -37,7 +37,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class ConversationUpdateItem extends LinearLayout
|
||||
implements RecipientModifiedListener, BindableConversationItem
|
||||
implements RecipientForeverObserver, BindableConversationItem
|
||||
{
|
||||
private static final String TAG = ConversationUpdateItem.class.getSimpleName();
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
private TextView title;
|
||||
private TextView body;
|
||||
private TextView date;
|
||||
private Recipient sender;
|
||||
private LiveRecipient sender;
|
||||
private MessageRecord messageRecord;
|
||||
private Locale locale;
|
||||
|
||||
|
@ -98,12 +98,28 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
}
|
||||
|
||||
private void bind(@NonNull MessageRecord messageRecord, @NonNull Locale locale) {
|
||||
if (this.sender != null) {
|
||||
this.sender.removeForeverObserver(this);
|
||||
}
|
||||
|
||||
if (this.messageRecord != null && messageRecord.isGroupAction()) {
|
||||
GroupUtil.getDescription(getContext(), messageRecord.getBody()).removeObserver(this);
|
||||
}
|
||||
|
||||
this.messageRecord = messageRecord;
|
||||
this.sender = messageRecord.getIndividualRecipient();
|
||||
this.sender = messageRecord.getIndividualRecipient().live();
|
||||
this.locale = locale;
|
||||
|
||||
this.sender.addListener(this);
|
||||
this.sender.observeForever(this);
|
||||
|
||||
if (this.messageRecord != null && messageRecord.isGroupAction()) {
|
||||
GroupUtil.getDescription(getContext(), messageRecord.getBody()).addObserver(this);
|
||||
}
|
||||
|
||||
present(messageRecord);
|
||||
}
|
||||
|
||||
private void present(MessageRecord messageRecord) {
|
||||
if (messageRecord.isGroupAction()) setGroupRecord(messageRecord);
|
||||
else if (messageRecord.isCallLog()) setCallRecord(messageRecord);
|
||||
else if (messageRecord.isJoined()) setJoinedRecord(messageRecord);
|
||||
|
@ -174,7 +190,6 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
icon.setImageResource(R.drawable.ic_group_grey600_24dp);
|
||||
icon.clearColorFilter();
|
||||
|
||||
GroupUtil.getDescription(getContext(), messageRecord.getBody()).addListener(this);
|
||||
body.setText(messageRecord.getDisplayBody(getContext()));
|
||||
|
||||
title.setVisibility(GONE);
|
||||
|
@ -203,8 +218,8 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
Util.runOnMain(() -> bind(messageRecord, locale));
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
present(messageRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -215,7 +230,10 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
@Override
|
||||
public void unbind() {
|
||||
if (sender != null) {
|
||||
sender.removeListener(this);
|
||||
sender.removeForeverObserver(this);
|
||||
}
|
||||
if (this.messageRecord != null && messageRecord.isGroupAction()) {
|
||||
GroupUtil.getDescription(getContext(), messageRecord.getBody()).removeObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,14 +256,14 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
return;
|
||||
}
|
||||
|
||||
final Recipient sender = ConversationUpdateItem.this.sender;
|
||||
final Recipient sender = ConversationUpdateItem.this.sender.get();
|
||||
|
||||
IdentityUtil.getRemoteIdentityKey(getContext(), sender).addListener(new ListenableFuture.Listener<Optional<IdentityRecord>>() {
|
||||
@Override
|
||||
public void onSuccess(Optional<IdentityRecord> result) {
|
||||
if (result.isPresent()) {
|
||||
Intent intent = new Intent(getContext(), VerifyIdentityActivity.class);
|
||||
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, sender.getAddress());
|
||||
intent.putExtra(VerifyIdentityActivity.RECIPIENT_EXTRA, sender.getId());
|
||||
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(result.get().getIdentityKey()));
|
||||
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, result.get().getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
|
@ -47,12 +49,12 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
|
||||
synchronized (LOCK) {
|
||||
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
||||
Address signalAddress = Address.fromExternal(context, address.getName());
|
||||
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(signalAddress);
|
||||
Recipient recipient = Recipient.external(context, address.getName());
|
||||
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(recipient.getId());
|
||||
|
||||
if (!identityRecord.isPresent()) {
|
||||
Log.i(TAG, "Saving new identity...");
|
||||
identityDatabase.saveIdentity(signalAddress, identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval);
|
||||
identityDatabase.saveIdentity(recipient.getId(), identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -68,15 +70,15 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||
verifiedStatus = VerifiedStatus.DEFAULT;
|
||||
}
|
||||
|
||||
identityDatabase.saveIdentity(signalAddress, identityKey, verifiedStatus, false, System.currentTimeMillis(), nonBlockingApproval);
|
||||
IdentityUtil.markIdentityUpdate(context, Recipient.from(context, signalAddress, true));
|
||||
identityDatabase.saveIdentity(recipient.getId(), identityKey, verifiedStatus, false, System.currentTimeMillis(), nonBlockingApproval);
|
||||
IdentityUtil.markIdentityUpdate(context, recipient);
|
||||
SessionUtil.archiveSiblingSessions(context, address);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isNonBlockingApprovalRequired(identityRecord.get())) {
|
||||
Log.i(TAG, "Setting approval status...");
|
||||
identityDatabase.setApproval(signalAddress, nonBlockingApproval);
|
||||
identityDatabase.setApproval(recipient.getId(), nonBlockingApproval);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -93,15 +95,15 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
|
||||
synchronized (LOCK) {
|
||||
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
||||
String ourNumber = TextSecurePreferences.getLocalNumber(context);
|
||||
Address theirAddress = Address.fromExternal(context, address.getName());
|
||||
RecipientId ourRecipientId = Recipient.self().getId();
|
||||
RecipientId theirRecipientId = Recipient.external(context, address.getName()).getId();
|
||||
|
||||
if (ourNumber.equals(address.getName()) || Address.fromSerialized(ourNumber).equals(theirAddress)) {
|
||||
if (ourRecipientId.equals(theirRecipientId)) {
|
||||
return identityKey.equals(IdentityKeyUtil.getIdentityKey(context));
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
case SENDING: return isTrustedForSending(identityKey, identityDatabase.getIdentity(theirAddress));
|
||||
case SENDING: return isTrustedForSending(identityKey, identityDatabase.getIdentity(theirRecipientId));
|
||||
case RECEIVING: return true;
|
||||
default: throw new AssertionError("Unknown direction: " + direction);
|
||||
}
|
||||
|
@ -110,7 +112,8 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||
|
||||
@Override
|
||||
public IdentityKey getIdentity(SignalProtocolAddress address) {
|
||||
Optional<IdentityRecord> record = DatabaseFactory.getIdentityDatabase(context).getIdentity(Address.fromSerialized(address.getName()));
|
||||
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
|
||||
Optional<IdentityRecord> record = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipientId);
|
||||
|
||||
if (record.isPresent()) {
|
||||
return record.get().getIdentityKey();
|
||||
|
|
|
@ -7,6 +7,8 @@ import org.thoughtcrime.securesms.database.Address;
|
|||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.SessionDatabase;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
|
@ -29,7 +31,8 @@ public class TextSecureSessionStore implements SessionStore {
|
|||
@Override
|
||||
public SessionRecord loadSession(@NonNull SignalProtocolAddress address) {
|
||||
synchronized (FILE_LOCK) {
|
||||
SessionRecord sessionRecord = DatabaseFactory.getSessionDatabase(context).load(Address.fromSerialized(address.getName()), address.getDeviceId());
|
||||
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
|
||||
SessionRecord sessionRecord = DatabaseFactory.getSessionDatabase(context).load(recipientId, address.getDeviceId());
|
||||
|
||||
if (sessionRecord == null) {
|
||||
Log.w(TAG, "No existing session information found.");
|
||||
|
@ -43,14 +46,16 @@ public class TextSecureSessionStore implements SessionStore {
|
|||
@Override
|
||||
public void storeSession(@NonNull SignalProtocolAddress address, @NonNull SessionRecord record) {
|
||||
synchronized (FILE_LOCK) {
|
||||
DatabaseFactory.getSessionDatabase(context).store(Address.fromSerialized(address.getName()), address.getDeviceId(), record);
|
||||
RecipientId id = Recipient.external(context, address.getName()).getId();
|
||||
DatabaseFactory.getSessionDatabase(context).store(id, address.getDeviceId(), record);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsSession(SignalProtocolAddress address) {
|
||||
synchronized (FILE_LOCK) {
|
||||
SessionRecord sessionRecord = DatabaseFactory.getSessionDatabase(context).load(Address.fromSerialized(address.getName()), address.getDeviceId());
|
||||
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
|
||||
SessionRecord sessionRecord = DatabaseFactory.getSessionDatabase(context).load(recipientId, address.getDeviceId());
|
||||
|
||||
return sessionRecord != null &&
|
||||
sessionRecord.getSessionState().hasSenderChain() &&
|
||||
|
@ -61,32 +66,36 @@ public class TextSecureSessionStore implements SessionStore {
|
|||
@Override
|
||||
public void deleteSession(SignalProtocolAddress address) {
|
||||
synchronized (FILE_LOCK) {
|
||||
DatabaseFactory.getSessionDatabase(context).delete(Address.fromSerialized(address.getName()), address.getDeviceId());
|
||||
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
|
||||
DatabaseFactory.getSessionDatabase(context).delete(recipientId, address.getDeviceId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAllSessions(String name) {
|
||||
synchronized (FILE_LOCK) {
|
||||
DatabaseFactory.getSessionDatabase(context).deleteAllFor(Address.fromSerialized(name));
|
||||
RecipientId recipientId = Recipient.external(context, name).getId();
|
||||
DatabaseFactory.getSessionDatabase(context).deleteAllFor(recipientId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getSubDeviceSessions(String name) {
|
||||
synchronized (FILE_LOCK) {
|
||||
return DatabaseFactory.getSessionDatabase(context).getSubDevices(Address.fromSerialized(name));
|
||||
RecipientId recipientId = Recipient.external(context, name).getId();
|
||||
return DatabaseFactory.getSessionDatabase(context).getSubDevices(recipientId);
|
||||
}
|
||||
}
|
||||
|
||||
public void archiveSiblingSessions(@NonNull SignalProtocolAddress address) {
|
||||
synchronized (FILE_LOCK) {
|
||||
List<SessionDatabase.SessionRow> sessions = DatabaseFactory.getSessionDatabase(context).getAllFor(Address.fromSerialized(address.getName()));
|
||||
RecipientId recipientId = Recipient.external(context, address.getName()).getId();
|
||||
List<SessionDatabase.SessionRow> sessions = DatabaseFactory.getSessionDatabase(context).getAllFor(recipientId);
|
||||
|
||||
for (SessionDatabase.SessionRow row : sessions) {
|
||||
if (row.getDeviceId() != address.getDeviceId()) {
|
||||
row.getRecord().archiveCurrentState();
|
||||
storeSession(new SignalProtocolAddress(row.getAddress().serialize(), row.getDeviceId()), row.getRecord());
|
||||
storeSession(new SignalProtocolAddress(Recipient.resolved(row.getRecipientId()).requireAddress().serialize(), row.getDeviceId()), row.getRecord());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +107,7 @@ public class TextSecureSessionStore implements SessionStore {
|
|||
|
||||
for (SessionDatabase.SessionRow row : sessions) {
|
||||
row.getRecord().archiveCurrentState();
|
||||
storeSession(new SignalProtocolAddress(row.getAddress().serialize(), row.getDeviceId()), row.getRecord());
|
||||
storeSession(new SignalProtocolAddress(Recipient.resolved(row.getRecipientId()).requireAddress().serialize(), row.getDeviceId()), row.getRecord());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,12 @@
|
|||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.Phonenumber;
|
||||
import com.google.i18n.phonenumbers.ShortNumberInfo;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||
|
||||
public class Address implements Parcelable, Comparable<Address> {
|
||||
|
||||
|
@ -48,8 +24,6 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||
|
||||
private static final String TAG = Address.class.getSimpleName();
|
||||
|
||||
private static final AtomicReference<Pair<String, ExternalAddressFormatter>> cachedFormatter = new AtomicReference<>();
|
||||
|
||||
private final String address;
|
||||
|
||||
private Address(@NonNull String address) {
|
||||
|
@ -65,50 +39,6 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||
return new Address(serialized);
|
||||
}
|
||||
|
||||
public static Address fromExternal(@NonNull Context context, @Nullable String external) {
|
||||
return new Address(getExternalAddressFormatter(context).format(external));
|
||||
}
|
||||
|
||||
public static @NonNull List<Address> fromSerializedList(@NonNull String serialized, char delimiter) {
|
||||
String[] escapedAddresses = DelimiterUtil.split(serialized, delimiter);
|
||||
List<Address> addresses = new LinkedList<>();
|
||||
|
||||
for (String escapedAddress : escapedAddresses) {
|
||||
addresses.add(Address.fromSerialized(DelimiterUtil.unescape(escapedAddress, delimiter)));
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public static @NonNull String toSerializedList(@NonNull List<Address> addresses, char delimiter) {
|
||||
Collections.sort(addresses);
|
||||
|
||||
List<String> escapedAddresses = new LinkedList<>();
|
||||
|
||||
for (Address address : addresses) {
|
||||
escapedAddresses.add(DelimiterUtil.escape(address.serialize(), delimiter));
|
||||
}
|
||||
|
||||
return Util.join(escapedAddresses, delimiter + "");
|
||||
}
|
||||
|
||||
private static @NonNull ExternalAddressFormatter getExternalAddressFormatter(Context context) {
|
||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||
|
||||
if (!TextUtils.isEmpty(localNumber)) {
|
||||
Pair<String, ExternalAddressFormatter> cached = cachedFormatter.get();
|
||||
|
||||
if (cached != null && cached.first.equals(localNumber)) return cached.second;
|
||||
|
||||
ExternalAddressFormatter formatter = new ExternalAddressFormatter(localNumber);
|
||||
cachedFormatter.set(new Pair<>(localNumber, formatter));
|
||||
|
||||
return formatter;
|
||||
} else {
|
||||
return new ExternalAddressFormatter(Util.getSimCountryIso(context).or("US"), true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isGroup() {
|
||||
return GroupUtil.isEncodedGroup(address);
|
||||
}
|
||||
|
@ -179,160 +109,4 @@ public class Address implements Parcelable, Comparable<Address> {
|
|||
public int compareTo(@NonNull Address other) {
|
||||
return address.compareTo(other.address);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static class ExternalAddressFormatter {
|
||||
|
||||
private static final String TAG = ExternalAddressFormatter.class.getSimpleName();
|
||||
|
||||
private static final Set<String> SHORT_COUNTRIES = new HashSet<String>() {{
|
||||
add("NU");
|
||||
add("TK");
|
||||
add("NC");
|
||||
add("AC");
|
||||
}};
|
||||
|
||||
private static final Pattern US_NO_AREACODE = Pattern.compile("^(\\d{7})$");
|
||||
private static final Pattern BR_NO_AREACODE = Pattern.compile("^(9?\\d{8})$");
|
||||
|
||||
private final Optional<PhoneNumber> localNumber;
|
||||
private final String localCountryCode;
|
||||
|
||||
private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
|
||||
private final Pattern ALPHA_PATTERN = Pattern.compile("[a-zA-Z]");
|
||||
|
||||
ExternalAddressFormatter(@NonNull String localNumberString) {
|
||||
try {
|
||||
Phonenumber.PhoneNumber libNumber = phoneNumberUtil.parse(localNumberString, null);
|
||||
int countryCode = libNumber.getCountryCode();
|
||||
|
||||
this.localNumber = Optional.of(new PhoneNumber(localNumberString, countryCode, parseAreaCode(localNumberString, countryCode)));
|
||||
this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(libNumber);
|
||||
} catch (NumberParseException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
ExternalAddressFormatter(@NonNull String localCountryCode, boolean countryCode) {
|
||||
this.localNumber = Optional.absent();
|
||||
this.localCountryCode = localCountryCode;
|
||||
}
|
||||
|
||||
public String format(@Nullable String number) {
|
||||
if (number == null) return "Unknown";
|
||||
if (GroupUtil.isEncodedGroup(number)) return number;
|
||||
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
|
||||
|
||||
String bareNumber = number.replaceAll("[^0-9+]", "");
|
||||
|
||||
if (bareNumber.length() == 0) {
|
||||
if (number.trim().length() == 0) return "Unknown";
|
||||
else return number.trim();
|
||||
}
|
||||
|
||||
// libphonenumber doesn't seem to be correct for Germany and Finland
|
||||
if (bareNumber.length() <= 6 && ("DE".equals(localCountryCode) || "FI".equals(localCountryCode) || "SK".equals(localCountryCode))) {
|
||||
return bareNumber;
|
||||
}
|
||||
|
||||
// libphonenumber seems incorrect for Russia and a few other countries with 4 digit short codes.
|
||||
if (bareNumber.length() <= 4 && !SHORT_COUNTRIES.contains(localCountryCode)) {
|
||||
return bareNumber;
|
||||
}
|
||||
|
||||
if (isShortCode(bareNumber, localCountryCode)) {
|
||||
return bareNumber;
|
||||
}
|
||||
|
||||
String processedNumber = applyAreaCodeRules(localNumber, bareNumber);
|
||||
|
||||
try {
|
||||
Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(processedNumber, localCountryCode);
|
||||
return phoneNumberUtil.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
} catch (NumberParseException e) {
|
||||
Log.w(TAG, e);
|
||||
if (bareNumber.charAt(0) == '+')
|
||||
return bareNumber;
|
||||
|
||||
String localNumberImprecise = localNumber.isPresent() ? localNumber.get().getE164Number() : "";
|
||||
|
||||
if (localNumberImprecise.charAt(0) == '+')
|
||||
localNumberImprecise = localNumberImprecise.substring(1);
|
||||
|
||||
if (localNumberImprecise.length() == bareNumber.length() || bareNumber.length() > localNumberImprecise.length())
|
||||
return "+" + number;
|
||||
|
||||
int difference = localNumberImprecise.length() - bareNumber.length();
|
||||
|
||||
return "+" + localNumberImprecise.substring(0, difference) + bareNumber;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isShortCode(@NonNull String bareNumber, String localCountryCode) {
|
||||
try {
|
||||
Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(bareNumber, localCountryCode);
|
||||
return ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(parsedNumber, localCountryCode);
|
||||
} catch (NumberParseException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable String parseAreaCode(@NonNull String e164Number, int countryCode) {
|
||||
switch (countryCode) {
|
||||
case 1:
|
||||
return e164Number.substring(2, 5);
|
||||
case 55:
|
||||
return e164Number.substring(3, 5);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private @NonNull String applyAreaCodeRules(@NonNull Optional<PhoneNumber> localNumber, @NonNull String testNumber) {
|
||||
if (!localNumber.isPresent() || !localNumber.get().getAreaCode().isPresent()) {
|
||||
return testNumber;
|
||||
}
|
||||
|
||||
Matcher matcher;
|
||||
switch (localNumber.get().getCountryCode()) {
|
||||
case 1:
|
||||
matcher = US_NO_AREACODE.matcher(testNumber);
|
||||
if (matcher.matches()) {
|
||||
return localNumber.get().getAreaCode() + matcher.group();
|
||||
}
|
||||
break;
|
||||
|
||||
case 55:
|
||||
matcher = BR_NO_AREACODE.matcher(testNumber);
|
||||
if (matcher.matches()) {
|
||||
return localNumber.get().getAreaCode() + matcher.group();
|
||||
}
|
||||
}
|
||||
return testNumber;
|
||||
}
|
||||
|
||||
private static class PhoneNumber {
|
||||
private final String e164Number;
|
||||
private final int countryCode;
|
||||
private final Optional<String> areaCode;
|
||||
|
||||
PhoneNumber(String e164Number, int countryCode, @Nullable String areaCode) {
|
||||
this.e164Number = e164Number;
|
||||
this.countryCode = countryCode;
|
||||
this.areaCode = Optional.fromNullable(areaCode);
|
||||
}
|
||||
|
||||
String getE164Number() {
|
||||
return e164Number;
|
||||
}
|
||||
|
||||
int getCountryCode() {
|
||||
return countryCode;
|
||||
}
|
||||
|
||||
Optional<String> getAreaCode() {
|
||||
return areaCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.LRUCache;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -11,13 +14,17 @@ public class EarlyReceiptCache {
|
|||
|
||||
private static final String TAG = EarlyReceiptCache.class.getSimpleName();
|
||||
|
||||
private final LRUCache<Long, Map<Address, Long>> cache = new LRUCache<>(100);
|
||||
private final LRUCache<Long, Map<RecipientId, Long>> cache = new LRUCache<>(100);
|
||||
private final String name;
|
||||
|
||||
public synchronized void increment(long timestamp, Address origin) {
|
||||
Log.i(TAG, this+"");
|
||||
Log.i(TAG, String.format(Locale.US, "Early receipt: (%d, %s)", timestamp, origin.serialize()));
|
||||
public EarlyReceiptCache(@NonNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Map<Address, Long> receipts = cache.get(timestamp);
|
||||
public synchronized void increment(long timestamp, @NonNull RecipientId origin) {
|
||||
Log.i(TAG, String.format(Locale.US, "[%s] Timestamp: %d, Recipient: %s", name, timestamp, origin.serialize()));
|
||||
|
||||
Map<RecipientId, Long> receipts = cache.get(timestamp);
|
||||
|
||||
if (receipts == null) {
|
||||
receipts = new HashMap<>();
|
||||
|
@ -34,8 +41,8 @@ public class EarlyReceiptCache {
|
|||
cache.put(timestamp, receipts);
|
||||
}
|
||||
|
||||
public synchronized Map<Address, Long> remove(long timestamp) {
|
||||
Map<Address, Long> receipts = cache.remove(timestamp);
|
||||
public synchronized Map<RecipientId, Long> remove(long timestamp) {
|
||||
Map<RecipientId, Long> receipts = cache.remove(timestamp);
|
||||
|
||||
Log.i(TAG, this+"");
|
||||
Log.i(TAG, String.format(Locale.US, "Checking early receipts (%d): %d", timestamp, receipts == null ? 0 : receipts.size()));
|
||||
|
|
|
@ -15,7 +15,9 @@ import com.annimon.stream.Stream;
|
|||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
@ -37,6 +39,7 @@ public class GroupDatabase extends Database {
|
|||
static final String TABLE_NAME = "groups";
|
||||
private static final String ID = "_id";
|
||||
static final String GROUP_ID = "group_id";
|
||||
static final String RECIPIENT_ID = "recipient_id";
|
||||
private static final String TITLE = "title";
|
||||
private static final String MEMBERS = "members";
|
||||
private static final String AVATAR = "avatar";
|
||||
|
@ -53,6 +56,7 @@ public class GroupDatabase extends Database {
|
|||
"CREATE TABLE " + TABLE_NAME +
|
||||
" (" + ID + " INTEGER PRIMARY KEY, " +
|
||||
GROUP_ID + " TEXT, " +
|
||||
RECIPIENT_ID + " INTEGER, " +
|
||||
TITLE + " TEXT, " +
|
||||
MEMBERS + " TEXT, " +
|
||||
AVATAR + " BLOB, " +
|
||||
|
@ -67,10 +71,11 @@ public class GroupDatabase extends Database {
|
|||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS group_id_index ON " + TABLE_NAME + " (" + GROUP_ID + ");",
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS group_recipient_id_index ON " + TABLE_NAME + " (" + RECIPIENT_ID + ");",
|
||||
};
|
||||
|
||||
private static final String[] GROUP_PROJECTION = {
|
||||
GROUP_ID, TITLE, MEMBERS, AVATAR, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST,
|
||||
GROUP_ID, RECIPIENT_ID, TITLE, MEMBERS, AVATAR, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST,
|
||||
TIMESTAMP, ACTIVE, MMS
|
||||
};
|
||||
|
||||
|
@ -80,6 +85,16 @@ public class GroupDatabase extends Database {
|
|||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public Optional<GroupRecord> getGroup(RecipientId recipientId) {
|
||||
try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, RECIPIENT_ID + " = ?", new String[] {recipientId.serialize()}, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return getGroup(cursor);
|
||||
}
|
||||
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<GroupRecord> getGroup(String groupId) {
|
||||
try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, GROUP_ID + " = ?",
|
||||
new String[] {groupId},
|
||||
|
@ -111,12 +126,12 @@ public class GroupDatabase extends Database {
|
|||
return new Reader(cursor);
|
||||
}
|
||||
|
||||
public String getOrCreateGroupForMembers(List<Address> members, boolean mms) {
|
||||
public String getOrCreateGroupForMembers(List<RecipientId> members, boolean mms) {
|
||||
Collections.sort(members);
|
||||
|
||||
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {GROUP_ID},
|
||||
MEMBERS + " = ? AND " + MMS + " = ?",
|
||||
new String[] {Address.toSerializedList(members, ','), mms ? "1" : "0"},
|
||||
new String[] {RecipientId.toSerializedList(members), mms ? "1" : "0"},
|
||||
null, null, null);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
|
@ -138,28 +153,30 @@ public class GroupDatabase extends Database {
|
|||
}
|
||||
|
||||
public @NonNull List<Recipient> getGroupMembers(String groupId, boolean includeSelf) {
|
||||
List<Address> members = getCurrentMembers(groupId);
|
||||
List<Recipient> recipients = new LinkedList<>();
|
||||
List<RecipientId> members = getCurrentMembers(groupId);
|
||||
List<Recipient> recipients = new LinkedList<>();
|
||||
|
||||
for (Address member : members) {
|
||||
if (!includeSelf && Util.isOwnNumber(context, member))
|
||||
for (RecipientId member : members) {
|
||||
if (!includeSelf && Recipient.resolved(member).isLocalNumber()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
recipients.add(Recipient.from(context, member, false));
|
||||
recipients.add(Recipient.resolved(member));
|
||||
}
|
||||
|
||||
return recipients;
|
||||
}
|
||||
|
||||
public void create(@NonNull String groupId, @Nullable String title, @NonNull List<Address> members,
|
||||
public void create(@NonNull String groupId, @Nullable String title, @NonNull List<RecipientId> members,
|
||||
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay)
|
||||
{
|
||||
Collections.sort(members);
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(RECIPIENT_ID, DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId).serialize());
|
||||
contentValues.put(GROUP_ID, groupId);
|
||||
contentValues.put(TITLE, title);
|
||||
contentValues.put(MEMBERS, Address.toSerializedList(members, ','));
|
||||
contentValues.put(MEMBERS, RecipientId.toSerializedList(members));
|
||||
|
||||
if (avatar != null) {
|
||||
contentValues.put(AVATAR_ID, avatar.getId());
|
||||
|
@ -175,11 +192,8 @@ public class GroupDatabase extends Database {
|
|||
|
||||
databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
Recipient.applyCached(Address.fromSerialized(groupId), recipient -> {
|
||||
recipient.setName(title);
|
||||
recipient.setGroupAvatarId(avatar != null ? avatar.getId() : null);
|
||||
recipient.setParticipants(Stream.of(members).map(memberAddress -> Recipient.from(context, memberAddress, true)).toList());
|
||||
});
|
||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient.live(groupRecipient).refresh();
|
||||
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
@ -199,10 +213,8 @@ public class GroupDatabase extends Database {
|
|||
GROUP_ID + " = ?",
|
||||
new String[] {groupId});
|
||||
|
||||
Recipient.applyCached(Address.fromSerialized(groupId), recipient -> {
|
||||
recipient.setName(title);
|
||||
recipient.setGroupAvatarId(avatar != null ? avatar.getId() : null);
|
||||
});
|
||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient.live(groupRecipient).refresh();
|
||||
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
@ -213,8 +225,8 @@ public class GroupDatabase extends Database {
|
|||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
||||
new String[] {groupId});
|
||||
|
||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(groupId), false);
|
||||
recipient.setName(title);
|
||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient.live(groupRecipient).refresh();
|
||||
}
|
||||
|
||||
public void updateAvatar(String groupId, Bitmap avatar) {
|
||||
|
@ -235,44 +247,39 @@ public class GroupDatabase extends Database {
|
|||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
||||
new String[] {groupId});
|
||||
|
||||
Recipient.applyCached(Address.fromSerialized(groupId), recipient -> recipient.setGroupAvatarId(avatarId == 0 ? null : avatarId));
|
||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient.live(groupRecipient).refresh();
|
||||
}
|
||||
|
||||
public void updateMembers(String groupId, List<Address> members) {
|
||||
public void updateMembers(String groupId, List<RecipientId> members) {
|
||||
Collections.sort(members);
|
||||
|
||||
ContentValues contents = new ContentValues();
|
||||
contents.put(MEMBERS, Address.toSerializedList(members, ','));
|
||||
contents.put(MEMBERS, RecipientId.toSerializedList(members));
|
||||
contents.put(ACTIVE, 1);
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
||||
new String[] {groupId});
|
||||
|
||||
Recipient.applyCached(Address.fromSerialized(groupId), recipient -> {
|
||||
recipient.setParticipants(Stream.of(members).map(a -> Recipient.from(context, a, false)).toList());
|
||||
});
|
||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient.live(groupRecipient).refresh();
|
||||
}
|
||||
|
||||
public void remove(String groupId, Address source) {
|
||||
List<Address> currentMembers = getCurrentMembers(groupId);
|
||||
public void remove(String groupId, RecipientId source) {
|
||||
List<RecipientId> currentMembers = getCurrentMembers(groupId);
|
||||
currentMembers.remove(source);
|
||||
|
||||
ContentValues contents = new ContentValues();
|
||||
contents.put(MEMBERS, Address.toSerializedList(currentMembers, ','));
|
||||
contents.put(MEMBERS, RecipientId.toSerializedList(currentMembers));
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
||||
new String[] {groupId});
|
||||
|
||||
Recipient.applyCached(Address.fromSerialized(groupId), recipient -> {
|
||||
List<Recipient> current = recipient.getParticipants();
|
||||
Recipient removal = Recipient.from(context, source, false);
|
||||
|
||||
current.remove(removal);
|
||||
recipient.setParticipants(current);
|
||||
});
|
||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient.live(groupRecipient).refresh();
|
||||
}
|
||||
|
||||
private List<Address> getCurrentMembers(String groupId) {
|
||||
private List<RecipientId> getCurrentMembers(String groupId) {
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
|
@ -283,7 +290,7 @@ public class GroupDatabase extends Database {
|
|||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
String serializedMembers = cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS));
|
||||
return Address.fromSerializedList(serializedMembers, ',');
|
||||
return RecipientId.fromSerializedList(serializedMembers);
|
||||
}
|
||||
|
||||
return new LinkedList<>();
|
||||
|
@ -334,6 +341,7 @@ public class GroupDatabase extends Database {
|
|||
}
|
||||
|
||||
return new GroupRecord(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID)),
|
||||
RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(TITLE)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)),
|
||||
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR)),
|
||||
|
@ -355,23 +363,25 @@ public class GroupDatabase extends Database {
|
|||
|
||||
public static class GroupRecord {
|
||||
|
||||
private final String id;
|
||||
private final String title;
|
||||
private final List<Address> members;
|
||||
private final byte[] avatar;
|
||||
private final long avatarId;
|
||||
private final byte[] avatarKey;
|
||||
private final byte[] avatarDigest;
|
||||
private final String avatarContentType;
|
||||
private final String relay;
|
||||
private final boolean active;
|
||||
private final boolean mms;
|
||||
private final String id;
|
||||
private final RecipientId recipientId;
|
||||
private final String title;
|
||||
private final List<RecipientId> members;
|
||||
private final byte[] avatar;
|
||||
private final long avatarId;
|
||||
private final byte[] avatarKey;
|
||||
private final byte[] avatarDigest;
|
||||
private final String avatarContentType;
|
||||
private final String relay;
|
||||
private final boolean active;
|
||||
private final boolean mms;
|
||||
|
||||
public GroupRecord(String id, String title, String members, byte[] avatar,
|
||||
public GroupRecord(String id, @NonNull RecipientId recipientId, String title, String members, byte[] avatar,
|
||||
long avatarId, byte[] avatarKey, String avatarContentType,
|
||||
String relay, boolean active, byte[] avatarDigest, boolean mms)
|
||||
{
|
||||
this.id = id;
|
||||
this.recipientId = recipientId;
|
||||
this.title = title;
|
||||
this.avatar = avatar;
|
||||
this.avatarId = avatarId;
|
||||
|
@ -382,7 +392,7 @@ public class GroupDatabase extends Database {
|
|||
this.active = active;
|
||||
this.mms = mms;
|
||||
|
||||
if (!TextUtils.isEmpty(members)) this.members = Address.fromSerializedList(members, ',');
|
||||
if (!TextUtils.isEmpty(members)) this.members = RecipientId.fromSerializedList(members);
|
||||
else this.members = new LinkedList<>();
|
||||
}
|
||||
|
||||
|
@ -394,6 +404,10 @@ public class GroupDatabase extends Database {
|
|||
}
|
||||
}
|
||||
|
||||
public @NonNull RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public String getEncodedId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -402,7 +416,7 @@ public class GroupDatabase extends Database {
|
|||
return title;
|
||||
}
|
||||
|
||||
public List<Address> getMembers() {
|
||||
public List<RecipientId> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import androidx.annotation.NonNull;
|
|||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -19,7 +20,7 @@ public class GroupReceiptDatabase extends Database {
|
|||
|
||||
private static final String ID = "_id";
|
||||
public static final String MMS_ID = "mms_id";
|
||||
private static final String ADDRESS = "address";
|
||||
private static final String RECIPIENT_ID = "address";
|
||||
private static final String STATUS = "status";
|
||||
private static final String TIMESTAMP = "timestamp";
|
||||
private static final String UNIDENTIFIED = "unidentified";
|
||||
|
@ -30,7 +31,7 @@ public class GroupReceiptDatabase extends Database {
|
|||
public static final int STATUS_READ = 2;
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
||||
MMS_ID + " INTEGER, " + ADDRESS + " TEXT, " + STATUS + " INTEGER, " + TIMESTAMP + " INTEGER, " + UNIDENTIFIED + " INTEGER DEFAULT 0);";
|
||||
MMS_ID + " INTEGER, " + RECIPIENT_ID + " INTEGER, " + STATUS + " INTEGER, " + TIMESTAMP + " INTEGER, " + UNIDENTIFIED + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXES = {
|
||||
"CREATE INDEX IF NOT EXISTS group_receipt_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
|
||||
|
@ -40,13 +41,13 @@ public class GroupReceiptDatabase extends Database {
|
|||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public void insert(List<Address> addresses, long mmsId, int status, long timestamp) {
|
||||
public void insert(List<RecipientId> recipientIds, long mmsId, int status, long timestamp) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
for (Address address : addresses) {
|
||||
for (RecipientId recipientId : recipientIds) {
|
||||
ContentValues values = new ContentValues(4);
|
||||
values.put(MMS_ID, mmsId);
|
||||
values.put(ADDRESS, address.serialize());
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(STATUS, status);
|
||||
values.put(TIMESTAMP, timestamp);
|
||||
|
||||
|
@ -54,23 +55,23 @@ public class GroupReceiptDatabase extends Database {
|
|||
}
|
||||
}
|
||||
|
||||
public void update(Address address, long mmsId, int status, long timestamp) {
|
||||
public void update(@NonNull RecipientId recipientId, long mmsId, int status, long timestamp) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues(2);
|
||||
values.put(STATUS, status);
|
||||
values.put(TIMESTAMP, timestamp);
|
||||
|
||||
db.update(TABLE_NAME, values, MMS_ID + " = ? AND " + ADDRESS + " = ? AND " + STATUS + " < ?",
|
||||
new String[] {String.valueOf(mmsId), address.serialize(), String.valueOf(status)});
|
||||
db.update(TABLE_NAME, values, MMS_ID + " = ? AND " + RECIPIENT_ID + " = ? AND " + STATUS + " < ?",
|
||||
new String[] {String.valueOf(mmsId), recipientId.serialize(), String.valueOf(status)});
|
||||
}
|
||||
|
||||
public void setUnidentified(Address address, long mmsId, boolean unidentified) {
|
||||
public void setUnidentified(RecipientId recipientId, long mmsId, boolean unidentified) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(UNIDENTIFIED, unidentified ? 1 : 0);
|
||||
|
||||
db.update(TABLE_NAME, values, MMS_ID + " = ? AND " + ADDRESS + " = ?",
|
||||
new String[] {String.valueOf(mmsId), address.serialize()});
|
||||
db.update(TABLE_NAME, values, MMS_ID + " = ? AND " + RECIPIENT_ID + " = ?",
|
||||
new String[] {String.valueOf(mmsId), recipientId.serialize()});
|
||||
|
||||
}
|
||||
|
||||
|
@ -80,7 +81,7 @@ public class GroupReceiptDatabase extends Database {
|
|||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, null, MMS_ID + " = ?", new String[] {String.valueOf(mmsId)}, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(new GroupReceiptInfo(Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))),
|
||||
results.add(new GroupReceiptInfo(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(STATUS)),
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED)) == 1));
|
||||
|
@ -101,20 +102,20 @@ public class GroupReceiptDatabase extends Database {
|
|||
}
|
||||
|
||||
public static class GroupReceiptInfo {
|
||||
private final Address address;
|
||||
private final int status;
|
||||
private final long timestamp;
|
||||
private final boolean unidentified;
|
||||
private final RecipientId recipientId;
|
||||
private final int status;
|
||||
private final long timestamp;
|
||||
private final boolean unidentified;
|
||||
|
||||
GroupReceiptInfo(Address address, int status, long timestamp, boolean unidentified) {
|
||||
this.address = address;
|
||||
GroupReceiptInfo(@NonNull RecipientId recipientId, int status, long timestamp, boolean unidentified) {
|
||||
this.recipientId = recipientId;
|
||||
this.status = status;
|
||||
this.timestamp = timestamp;
|
||||
this.unidentified = unidentified;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
public @NonNull RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
|
|
|
@ -26,6 +26,7 @@ import net.sqlcipher.database.SQLiteDatabase;
|
|||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
|
@ -40,7 +41,7 @@ public class IdentityDatabase extends Database {
|
|||
|
||||
private static final String TABLE_NAME = "identities";
|
||||
private static final String ID = "_id";
|
||||
private static final String ADDRESS = "address";
|
||||
private static final String RECIPIENT_ID = "address";
|
||||
private static final String IDENTITY_KEY = "key";
|
||||
private static final String TIMESTAMP = "timestamp";
|
||||
private static final String FIRST_USE = "first_use";
|
||||
|
@ -49,7 +50,7 @@ public class IdentityDatabase extends Database {
|
|||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
|
||||
" (" + ID + " INTEGER PRIMARY KEY, " +
|
||||
ADDRESS + " TEXT UNIQUE, " +
|
||||
RECIPIENT_ID + " INTEGER UNIQUE, " +
|
||||
IDENTITY_KEY + " TEXT, " +
|
||||
FIRST_USE + " INTEGER DEFAULT 0, " +
|
||||
TIMESTAMP + " INTEGER DEFAULT 0, " +
|
||||
|
@ -88,13 +89,13 @@ public class IdentityDatabase extends Database {
|
|||
return new IdentityReader(cursor);
|
||||
}
|
||||
|
||||
public Optional<IdentityRecord> getIdentity(Address address) {
|
||||
public Optional<IdentityRecord> getIdentity(@NonNull RecipientId recipientId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?",
|
||||
new String[] {address.serialize()}, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, null, RECIPIENT_ID + " = ?",
|
||||
new String[] {recipientId.serialize()}, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return Optional.of(getIdentityRecord(cursor));
|
||||
|
@ -108,14 +109,14 @@ public class IdentityDatabase extends Database {
|
|||
return Optional.absent();
|
||||
}
|
||||
|
||||
public void saveIdentity(Address address, IdentityKey identityKey, VerifiedStatus verifiedStatus,
|
||||
public void saveIdentity(@NonNull RecipientId recipientId, IdentityKey identityKey, VerifiedStatus verifiedStatus,
|
||||
boolean firstUse, long timestamp, boolean nonBlockingApproval)
|
||||
{
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
String identityKeyString = Base64.encodeBytes(identityKey.serialize());
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(ADDRESS, address.serialize());
|
||||
contentValues.put(RECIPIENT_ID, recipientId.serialize());
|
||||
contentValues.put(IDENTITY_KEY, identityKeyString);
|
||||
contentValues.put(TIMESTAMP, timestamp);
|
||||
contentValues.put(VERIFIED, verifiedStatus.toInt());
|
||||
|
@ -124,36 +125,36 @@ public class IdentityDatabase extends Database {
|
|||
|
||||
database.replace(TABLE_NAME, null, contentValues);
|
||||
|
||||
EventBus.getDefault().post(new IdentityRecord(address, identityKey, verifiedStatus,
|
||||
EventBus.getDefault().post(new IdentityRecord(recipientId, identityKey, verifiedStatus,
|
||||
firstUse, timestamp, nonBlockingApproval));
|
||||
}
|
||||
|
||||
public void setApproval(Address address, boolean nonBlockingApproval) {
|
||||
public void setApproval(@NonNull RecipientId recipientId, boolean nonBlockingApproval) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
ContentValues contentValues = new ContentValues(2);
|
||||
contentValues.put(NONBLOCKING_APPROVAL, nonBlockingApproval);
|
||||
|
||||
database.update(TABLE_NAME, contentValues, ADDRESS + " = ?", new String[] {address.serialize()});
|
||||
database.update(TABLE_NAME, contentValues, RECIPIENT_ID + " = ?", new String[] {recipientId.serialize()});
|
||||
}
|
||||
|
||||
public void setVerified(Address address, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
||||
public void setVerified(@NonNull RecipientId recipientId, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(VERIFIED, verifiedStatus.toInt());
|
||||
|
||||
int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ? AND " + IDENTITY_KEY + " = ?",
|
||||
new String[] {address.serialize(), Base64.encodeBytes(identityKey.serialize())});
|
||||
int updated = database.update(TABLE_NAME, contentValues, RECIPIENT_ID + " = ? AND " + IDENTITY_KEY + " = ?",
|
||||
new String[] {recipientId.serialize(), Base64.encodeBytes(identityKey.serialize())});
|
||||
|
||||
if (updated > 0) {
|
||||
Optional<IdentityRecord> record = getIdentity(address);
|
||||
Optional<IdentityRecord> record = getIdentity(recipientId);
|
||||
if (record.isPresent()) EventBus.getDefault().post(record.get());
|
||||
}
|
||||
}
|
||||
|
||||
private IdentityRecord getIdentityRecord(@NonNull Cursor cursor) throws IOException, InvalidKeyException {
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID));
|
||||
String serializedIdentity = cursor.getString(cursor.getColumnIndexOrThrow(IDENTITY_KEY));
|
||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP));
|
||||
int verifiedStatus = cursor.getInt(cursor.getColumnIndexOrThrow(VERIFIED));
|
||||
|
@ -161,23 +162,23 @@ public class IdentityDatabase extends Database {
|
|||
boolean firstUse = cursor.getInt(cursor.getColumnIndexOrThrow(FIRST_USE)) == 1;
|
||||
IdentityKey identity = new IdentityKey(Base64.decode(serializedIdentity), 0);
|
||||
|
||||
return new IdentityRecord(Address.fromSerialized(address), identity, VerifiedStatus.forState(verifiedStatus), firstUse, timestamp, nonblockingApproval);
|
||||
return new IdentityRecord(RecipientId.from(recipientId), identity, VerifiedStatus.forState(verifiedStatus), firstUse, timestamp, nonblockingApproval);
|
||||
}
|
||||
|
||||
public static class IdentityRecord {
|
||||
|
||||
private final Address address;
|
||||
private final RecipientId recipientId;
|
||||
private final IdentityKey identitykey;
|
||||
private final VerifiedStatus verifiedStatus;
|
||||
private final boolean firstUse;
|
||||
private final long timestamp;
|
||||
private final boolean nonblockingApproval;
|
||||
|
||||
private IdentityRecord(Address address,
|
||||
private IdentityRecord(@NonNull RecipientId recipientId,
|
||||
IdentityKey identitykey, VerifiedStatus verifiedStatus,
|
||||
boolean firstUse, long timestamp, boolean nonblockingApproval)
|
||||
{
|
||||
this.address = address;
|
||||
this.recipientId = recipientId;
|
||||
this.identitykey = identitykey;
|
||||
this.verifiedStatus = verifiedStatus;
|
||||
this.firstUse = firstUse;
|
||||
|
@ -185,8 +186,8 @@ public class IdentityDatabase extends Database {
|
|||
this.nonblockingApproval = nonblockingApproval;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
public RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public IdentityKey getIdentityKey() {
|
||||
|
@ -211,7 +212,7 @@ public class IdentityDatabase extends Database {
|
|||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return "{address: " + address + ", identityKey: " + identitykey + ", verifiedStatus: " + verifiedStatus + ", firstUse: " + firstUse + "}";
|
||||
return "{recipientId: " + recipientId + ", identityKey: " + identitykey + ", verifiedStatus: " + verifiedStatus + ", firstUse: " + firstUse + "}";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import net.sqlcipher.database.SQLiteDatabase;
|
|||
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -41,7 +42,7 @@ public class MediaDatabase extends Database {
|
|||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.MESSAGE_BOX + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_SENT + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_RECEIVED + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.ADDRESS + " "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.RECIPIENT_ID + " "
|
||||
+ "FROM " + AttachmentDatabase.TABLE_NAME + " LEFT JOIN " + MmsDatabase.TABLE_NAME
|
||||
+ " ON " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " = " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " "
|
||||
+ "WHERE " + AttachmentDatabase.MMS_ID + " IN (SELECT " + MmsSmsColumns.ID
|
||||
|
@ -88,27 +89,22 @@ public class MediaDatabase extends Database {
|
|||
public static class MediaRecord {
|
||||
|
||||
private final DatabaseAttachment attachment;
|
||||
private final Address address;
|
||||
private final RecipientId recipientId;
|
||||
private final long date;
|
||||
private final boolean outgoing;
|
||||
|
||||
private MediaRecord(DatabaseAttachment attachment, @Nullable Address address, long date, boolean outgoing) {
|
||||
this.attachment = attachment;
|
||||
this.address = address;
|
||||
this.date = date;
|
||||
this.outgoing = outgoing;
|
||||
private MediaRecord(DatabaseAttachment attachment, @NonNull RecipientId recipientId, long date, boolean outgoing) {
|
||||
this.attachment = attachment;
|
||||
this.recipientId = recipientId;
|
||||
this.date = date;
|
||||
this.outgoing = outgoing;
|
||||
}
|
||||
|
||||
public static MediaRecord from(@NonNull Context context, @NonNull Cursor cursor) {
|
||||
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
|
||||
List<DatabaseAttachment> attachments = attachmentDatabase.getAttachment(cursor);
|
||||
String serializedAddress = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.RECIPIENT_ID)));
|
||||
boolean outgoing = MessagingDatabase.Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX)));
|
||||
Address address = null;
|
||||
|
||||
if (serializedAddress != null) {
|
||||
address = Address.fromSerialized(serializedAddress);
|
||||
}
|
||||
|
||||
long date;
|
||||
|
||||
|
@ -118,7 +114,7 @@ public class MediaDatabase extends Database {
|
|||
date = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.DATE_RECEIVED));
|
||||
}
|
||||
|
||||
return new MediaRecord(attachments != null && attachments.size() > 0 ? attachments.get(0) : null, address, date, outgoing);
|
||||
return new MediaRecord(attachments != null && attachments.size() > 0 ? attachments.get(0) : null, recipientId, date, outgoing);
|
||||
}
|
||||
|
||||
public DatabaseAttachment getAttachment() {
|
||||
|
@ -129,8 +125,8 @@ public class MediaDatabase extends Database {
|
|||
return attachment.getContentType();
|
||||
}
|
||||
|
||||
public @Nullable Address getAddress() {
|
||||
return address;
|
||||
public @NonNull RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public long getDate() {
|
||||
|
|
|
@ -13,11 +13,10 @@ import org.thoughtcrime.securesms.database.documents.Document;
|
|||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchList;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -40,41 +39,20 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
|
|||
public abstract void markAsSent(long messageId, boolean secure);
|
||||
public abstract void markUnidentified(long messageId, boolean unidentified);
|
||||
|
||||
public void setMismatchedIdentity(long messageId, final Address address, final IdentityKey identityKey) {
|
||||
List<IdentityKeyMismatch> items = new ArrayList<IdentityKeyMismatch>() {{
|
||||
add(new IdentityKeyMismatch(address, identityKey));
|
||||
}};
|
||||
|
||||
IdentityKeyMismatchList document = new IdentityKeyMismatchList(items);
|
||||
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
setDocument(database, messageId, MISMATCHED_IDENTITIES, document);
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, ioe);
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public void addMismatchedIdentity(long messageId, Address address, IdentityKey identityKey) {
|
||||
public void addMismatchedIdentity(long messageId, @NonNull RecipientId recipientId, IdentityKey identityKey) {
|
||||
try {
|
||||
addToDocument(messageId, MISMATCHED_IDENTITIES,
|
||||
new IdentityKeyMismatch(address, identityKey),
|
||||
new IdentityKeyMismatch(recipientId, identityKey),
|
||||
IdentityKeyMismatchList.class);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMismatchedIdentity(long messageId, Address address, IdentityKey identityKey) {
|
||||
public void removeMismatchedIdentity(long messageId, @NonNull RecipientId recipientId, IdentityKey identityKey) {
|
||||
try {
|
||||
removeFromDocument(messageId, MISMATCHED_IDENTITIES,
|
||||
new IdentityKeyMismatch(address, identityKey),
|
||||
new IdentityKeyMismatch(recipientId, identityKey),
|
||||
IdentityKeyMismatchList.class);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
|
@ -178,16 +156,16 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
|
|||
|
||||
public static class SyncMessageId {
|
||||
|
||||
private final Address address;
|
||||
private final long timetamp;
|
||||
private final RecipientId recipientId;
|
||||
private final long timetamp;
|
||||
|
||||
public SyncMessageId(Address address, long timetamp) {
|
||||
this.address = address;
|
||||
this.timetamp = timetamp;
|
||||
public SyncMessageId(@NonNull RecipientId recipientId, long timetamp) {
|
||||
this.recipientId = recipientId;
|
||||
this.timetamp = timetamp;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
public RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public long getTimetamp() {
|
||||
|
|
|
@ -62,7 +62,7 @@ import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
|||
import org.thoughtcrime.securesms.mms.QuoteModel;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
|
@ -115,7 +115,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
THREAD_ID + " INTEGER, " + DATE_SENT + " INTEGER, " + DATE_RECEIVED + " INTEGER, " + MESSAGE_BOX + " INTEGER, " +
|
||||
READ + " INTEGER DEFAULT 0, " + "m_id" + " TEXT, " + "sub" + " TEXT, " +
|
||||
"sub_cs" + " INTEGER, " + BODY + " TEXT, " + PART_COUNT + " INTEGER, " +
|
||||
"ct_t" + " TEXT, " + CONTENT_LOCATION + " TEXT, " + ADDRESS + " TEXT, " +
|
||||
"ct_t" + " TEXT, " + CONTENT_LOCATION + " TEXT, " + RECIPIENT_ID + " INTEGER, " +
|
||||
ADDRESS_DEVICE_ID + " INTEGER, " +
|
||||
EXPIRY + " INTEGER, " + "m_cls" + " TEXT, " + MESSAGE_TYPE + " INTEGER, " +
|
||||
"v" + " INTEGER, " + MESSAGE_SIZE + " INTEGER, " + "pri" + " INTEGER, " +
|
||||
|
@ -148,7 +148,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
MESSAGE_BOX, READ,
|
||||
CONTENT_LOCATION, EXPIRY, MESSAGE_TYPE,
|
||||
MESSAGE_SIZE, STATUS, TRANSACTION_ID,
|
||||
BODY, PART_COUNT, ADDRESS, ADDRESS_DEVICE_ID,
|
||||
BODY, PART_COUNT, RECIPIENT_ID, ADDRESS_DEVICE_ID,
|
||||
DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
|
||||
EXPIRES_IN, EXPIRE_STARTED, NOTIFIED, QUOTE_ID, QUOTE_AUTHOR, QUOTE_BODY, QUOTE_ATTACHMENT, QUOTE_MISSING,
|
||||
SHARED_CONTACTS, LINK_PREVIEWS, UNIDENTIFIED, VIEW_ONCE,
|
||||
|
@ -179,8 +179,8 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
|
||||
private static final String RAW_ID_WHERE = TABLE_NAME + "._id = ?";
|
||||
|
||||
private final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache();
|
||||
private final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache();
|
||||
private final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache("MmsDelivery");
|
||||
private final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache("MmsRead");
|
||||
|
||||
public MmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
|
@ -230,15 +230,15 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
boolean found = false;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, ADDRESS}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, RECIPIENT_ID}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
||||
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
Address ourAddress = messageId.getAddress();
|
||||
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||
RecipientId theirRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
|
||||
RecipientId ourRecipientId = messageId.getRecipientId();
|
||||
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
if (ourRecipientId.equals(theirRecipientId) || Recipient.resolved(theirRecipientId).isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
int status = deliveryReceipt ? GroupReceiptDatabase.STATUS_DELIVERED : GroupReceiptDatabase.STATUS_READ;
|
||||
|
@ -249,7 +249,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
columnName + " = " + columnName + " + 1 WHERE " + ID + " = ?",
|
||||
new String[] {String.valueOf(id)});
|
||||
|
||||
DatabaseFactory.getGroupReceiptDatabase(context).update(ourAddress, id, status, timestamp);
|
||||
DatabaseFactory.getGroupReceiptDatabase(context).update(ourRecipientId, id, status, timestamp);
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
@ -257,8 +257,8 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
if (!found) {
|
||||
if (deliveryReceipt) earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (readReceipt) earlyReadReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (deliveryReceipt) earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getRecipientId());
|
||||
if (readReceipt) earlyReadReceiptCache.increment(messageId.getTimetamp(), messageId.getRecipientId());
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
|
@ -285,12 +285,13 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
|
||||
private long getThreadIdFor(@NonNull IncomingMediaMessage retrieved) {
|
||||
if (retrieved.getGroupId() != null) {
|
||||
Recipient groupRecipients = Recipient.from(context, retrieved.getGroupId(), true);
|
||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(retrieved.getGroupId());
|
||||
Recipient groupRecipients = Recipient.resolved(groupRecipientId);
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
||||
} else {
|
||||
Recipient sender = Recipient.from(context, retrieved.getFrom(), true);
|
||||
Recipient sender = Recipient.resolved(retrieved.getFrom());
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(sender);
|
||||
}
|
||||
}
|
||||
|
@ -299,7 +300,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
String fromString = notification.getFrom() != null && notification.getFrom().getTextString() != null
|
||||
? Util.toIsoString(notification.getFrom().getTextString())
|
||||
: "";
|
||||
Recipient recipient = Recipient.from(context, Address.fromExternal(context, fromString), false);
|
||||
Recipient recipient = Recipient.external(context, fromString);
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
}
|
||||
|
||||
|
@ -462,11 +463,11 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED}, where, arguments, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED}, where, arguments, null, null, null);
|
||||
|
||||
while(cursor != null && cursor.moveToNext()) {
|
||||
if (Types.isSecureType(cursor.getLong(3))) {
|
||||
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(cursor.getString(1)), cursor.getLong(2));
|
||||
SyncMessageId syncMessageId = new SyncMessageId(RecipientId.from(cursor.getLong(1)), cursor.getLong(2));
|
||||
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), true);
|
||||
|
||||
result.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
|
||||
|
@ -492,13 +493,13 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, ADDRESS}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, RECIPIENT_ID}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
Address ourAddress = messageId.getAddress();
|
||||
RecipientId theirRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
|
||||
RecipientId ourRecipientId = messageId.getRecipientId();
|
||||
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
if (ourRecipientId.equals(theirRecipientId) || Recipient.resolved(theirRecipientId).isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
|
@ -583,7 +584,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
cursor = rawQuery(RAW_ID_WHERE, new String[] {String.valueOf(messageId)});
|
||||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return Optional.of(new MmsNotificationInfo(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)),
|
||||
return Optional.of(new MmsNotificationInfo(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(TRANSACTION_ID)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))));
|
||||
|
@ -614,14 +615,14 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
boolean viewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(VIEW_ONCE)) == 1;
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
int distributionType = DatabaseFactory.getThreadDatabase(context).getDistributionType(threadId);
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
||||
|
||||
long quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_ID));
|
||||
String quoteAuthor = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR));
|
||||
RecipientId quoteAuthor = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR)));
|
||||
String quoteText = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_BODY));
|
||||
boolean quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE_MISSING)) == 1;
|
||||
List<Attachment> quoteAttachments = Stream.of(associatedAttachments).filter(Attachment::isQuote).map(a -> (Attachment)a).toList();
|
||||
|
@ -634,13 +635,13 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
.filterNot(previewAttachments::contains)
|
||||
.map(a -> (Attachment)a).toList();
|
||||
|
||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(address), false);
|
||||
Recipient recipient = Recipient.resolved(RecipientId.from(recipientId));
|
||||
List<NetworkFailure> networkFailures = new LinkedList<>();
|
||||
List<IdentityKeyMismatch> mismatches = new LinkedList<>();
|
||||
QuoteModel quote = null;
|
||||
|
||||
if (quoteId > 0 && (!TextUtils.isEmpty(quoteText) || !quoteAttachments.isEmpty())) {
|
||||
quote = new QuoteModel(quoteId, Address.fromSerialized(quoteAuthor), quoteText, quoteMissing, quoteAttachments);
|
||||
quote = new QuoteModel(quoteId, quoteAuthor, quoteText, quoteMissing, quoteAttachments);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mismatchDocument)) {
|
||||
|
@ -762,7 +763,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
try {
|
||||
OutgoingMediaMessage request = getOutgoingMessage(messageId);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(ADDRESS, request.getRecipient().getAddress().serialize());
|
||||
contentValues.put(RECIPIENT_ID, request.getRecipient().getId().serialize());
|
||||
contentValues.put(DATE_SENT, request.getSentTimeMillis());
|
||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT);
|
||||
contentValues.put(THREAD_ID, getThreadIdForMessage(messageId));
|
||||
|
@ -814,19 +815,13 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
throws MmsException
|
||||
{
|
||||
if (threadId == -1 || retrieved.isGroupMessage()) {
|
||||
try {
|
||||
threadId = getThreadIdFor(retrieved);
|
||||
} catch (RecipientFormattingException e) {
|
||||
Log.w("MmsDatabase", e);
|
||||
if (threadId == -1)
|
||||
throw new MmsException(e);
|
||||
}
|
||||
threadId = getThreadIdFor(retrieved);
|
||||
}
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
|
||||
contentValues.put(DATE_SENT, retrieved.getSentTimeMillis());
|
||||
contentValues.put(ADDRESS, retrieved.getFrom().serialize());
|
||||
contentValues.put(RECIPIENT_ID, retrieved.getFrom().serialize());
|
||||
|
||||
contentValues.put(MESSAGE_BOX, mailbox);
|
||||
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
|
||||
|
@ -924,7 +919,8 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
contentBuilder.add(MESSAGE_TYPE, notification.getMessageType());
|
||||
|
||||
if (notification.getFrom() != null) {
|
||||
contentValues.put(ADDRESS, Address.fromExternal(context, Util.toIsoString(notification.getFrom().getTextString())).serialize());
|
||||
Recipient recipient = Recipient.external(context, Util.toIsoString(notification.getFrom().getTextString()));
|
||||
contentValues.put(RECIPIENT_ID, recipient.getId().serialize());
|
||||
}
|
||||
|
||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE);
|
||||
|
@ -980,8 +976,8 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
|
||||
}
|
||||
|
||||
Map<Address, Long> earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(message.getSentTimeMillis());
|
||||
Map<Address, Long> earlyReadReceipts = earlyReadReceiptCache.remove(message.getSentTimeMillis());
|
||||
Map<RecipientId, Long> earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(message.getSentTimeMillis());
|
||||
Map<RecipientId, Long> earlyReadReceipts = earlyReadReceiptCache.remove(message.getSentTimeMillis());
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(DATE_SENT, message.getSentTimeMillis());
|
||||
|
@ -994,7 +990,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||
contentValues.put(VIEW_ONCE, message.isViewOnce());
|
||||
contentValues.put(ADDRESS, message.getRecipient().getAddress().serialize());
|
||||
contentValues.put(RECIPIENT_ID, message.getRecipient().getId().serialize());
|
||||
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(Long::longValue).sum());
|
||||
contentValues.put(READ_RECEIPT_COUNT, Stream.of(earlyReadReceipts.values()).mapToLong(Long::longValue).sum());
|
||||
|
||||
|
@ -1011,15 +1007,15 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
|
||||
long messageId = insertMediaMessage(message.getBody(), message.getAttachments(), quoteAttachments, message.getSharedContacts(), message.getLinkPreviews(), contentValues, insertListener);
|
||||
|
||||
if (message.getRecipient().getAddress().isGroup()) {
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(message.getRecipient().getAddress().toGroupString(), false);
|
||||
if (message.getRecipient().requireAddress().isGroup()) {
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(message.getRecipient().requireAddress().toGroupString(), false);
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
|
||||
receiptDatabase.insert(Stream.of(members).map(Recipient::getAddress).toList(),
|
||||
receiptDatabase.insert(Stream.of(members).map(Recipient::getId).toList(),
|
||||
messageId, defaultReceiptStatus, message.getSentTimeMillis());
|
||||
|
||||
for (Address address : earlyDeliveryReceipts.keySet()) receiptDatabase.update(address, messageId, GroupReceiptDatabase.STATUS_DELIVERED, -1);
|
||||
for (Address address : earlyReadReceipts.keySet()) receiptDatabase.update(address, messageId, GroupReceiptDatabase.STATUS_READ, -1);
|
||||
for (RecipientId recipientId : earlyDeliveryReceipts.keySet()) receiptDatabase.update(recipientId, messageId, GroupReceiptDatabase.STATUS_DELIVERED, -1);
|
||||
for (RecipientId recipientId : earlyReadReceipts.keySet()) receiptDatabase.update(recipientId, messageId, GroupReceiptDatabase.STATUS_READ, -1);
|
||||
}
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||
|
@ -1171,7 +1167,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
|
||||
private boolean isDuplicate(IncomingMediaMessage message, long threadId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + RECIPIENT_ID + " = ? AND " + THREAD_ID + " = ?",
|
||||
new String[]{String.valueOf(message.getSentTimeMillis()), message.getFrom().serialize(), String.valueOf(threadId)},
|
||||
null, null, null, "1");
|
||||
|
||||
|
@ -1330,13 +1326,13 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
public static class MmsNotificationInfo {
|
||||
private final Address from;
|
||||
private final String contentLocation;
|
||||
private final String transactionId;
|
||||
private final int subscriptionId;
|
||||
private final RecipientId from;
|
||||
private final String contentLocation;
|
||||
private final String transactionId;
|
||||
private final int subscriptionId;
|
||||
|
||||
MmsNotificationInfo(@Nullable String from, String contentLocation, String transactionId, int subscriptionId) {
|
||||
this.from = from == null ? null : Address.fromSerialized(from);
|
||||
MmsNotificationInfo(@NonNull RecipientId from, String contentLocation, String transactionId, int subscriptionId) {
|
||||
this.from = from;
|
||||
this.contentLocation = contentLocation;
|
||||
this.transactionId = transactionId;
|
||||
this.subscriptionId = subscriptionId;
|
||||
|
@ -1354,7 +1350,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
return subscriptionId;
|
||||
}
|
||||
|
||||
public @Nullable Address getFrom() {
|
||||
public @NonNull RecipientId getFrom() {
|
||||
return from;
|
||||
}
|
||||
}
|
||||
|
@ -1428,9 +1424,9 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
||||
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
||||
Recipient recipient = getRecipientFor(address);
|
||||
Recipient recipient = Recipient.live(RecipientId.from(recipientId)).get();
|
||||
|
||||
String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.CONTENT_LOCATION));
|
||||
String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.TRANSACTION_ID));
|
||||
|
@ -1470,7 +1466,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
|
||||
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.READ_RECEIPT_COUNT));
|
||||
|
@ -1488,7 +1484,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
readReceiptCount = 0;
|
||||
}
|
||||
|
||||
Recipient recipient = getRecipientFor(address);
|
||||
Recipient recipient = Recipient.live(RecipientId.from(recipientId)).get();
|
||||
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
||||
List<NetworkFailure> networkFailures = getFailures(networkDocument);
|
||||
List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachment(cursor);
|
||||
|
@ -1506,18 +1502,6 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
isViewOnce, readReceiptCount, quote, contacts, previews, unidentified);
|
||||
}
|
||||
|
||||
private Recipient getRecipientFor(String serialized) {
|
||||
Address address;
|
||||
|
||||
if (TextUtils.isEmpty(serialized) || "insert-address-token".equals(serialized)) {
|
||||
address = Address.UNKNOWN;
|
||||
} else {
|
||||
address = Address.fromSerialized(serialized);
|
||||
|
||||
}
|
||||
return Recipient.from(context, address, true);
|
||||
}
|
||||
|
||||
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {
|
||||
if (!TextUtils.isEmpty(document)) {
|
||||
try {
|
||||
|
@ -1551,15 +1535,15 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
|
||||
private @Nullable Quote getQuote(@NonNull Cursor cursor) {
|
||||
long quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_ID));
|
||||
String quoteAuthor = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_AUTHOR));
|
||||
RecipientId quoteAuthor = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_AUTHOR)));
|
||||
String quoteText = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_BODY));
|
||||
boolean quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_MISSING)) == 1;
|
||||
List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachment(cursor);
|
||||
List<? extends Attachment> quoteAttachments = Stream.of(attachments).filter(Attachment::isQuote).toList();
|
||||
SlideDeck quoteDeck = new SlideDeck(context, quoteAttachments);
|
||||
|
||||
if (quoteId > 0 && !TextUtils.isEmpty(quoteAuthor)) {
|
||||
return new Quote(quoteId, Address.fromExternal(context, quoteAuthor), quoteText, quoteMissing, quoteDeck);
|
||||
if (quoteId > 0 && !quoteAuthor.isUnknown()) {
|
||||
return new Quote(quoteId, quoteAuthor, quoteText, quoteMissing, quoteDeck);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ public interface MmsSmsColumns {
|
|||
public static final String THREAD_ID = "thread_id";
|
||||
public static final String READ = "read";
|
||||
public static final String BODY = "body";
|
||||
public static final String ADDRESS = "address";
|
||||
public static final String RECIPIENT_ID = "address";
|
||||
public static final String ADDRESS_DEVICE_ID = "address_device_id";
|
||||
public static final String DELIVERY_RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String READ_RECEIPT_COUNT = "read_receipt_count";
|
||||
|
|
|
@ -27,6 +27,8 @@ import net.sqlcipher.database.SQLiteQueryBuilder;
|
|||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
@ -44,7 +46,7 @@ public class MmsSmsDatabase extends Database {
|
|||
private static final String[] PROJECTION = {MmsSmsColumns.ID, MmsSmsColumns.UNIQUE_ROW_ID,
|
||||
SmsDatabase.BODY, SmsDatabase.TYPE,
|
||||
MmsSmsColumns.THREAD_ID,
|
||||
SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT,
|
||||
SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT,
|
||||
MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
|
||||
|
@ -77,7 +79,7 @@ public class MmsSmsDatabase extends Database {
|
|||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public @Nullable MessageRecord getMessageFor(long timestamp, Address author) {
|
||||
public @Nullable MessageRecord getMessageFor(long timestamp, RecipientId author) {
|
||||
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
|
||||
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null)) {
|
||||
|
@ -86,8 +88,8 @@ public class MmsSmsDatabase extends Database {
|
|||
MessageRecord messageRecord;
|
||||
|
||||
while ((messageRecord = reader.getNext()) != null) {
|
||||
if ((Util.isOwnNumber(context, author) && messageRecord.isOutgoing()) ||
|
||||
(!Util.isOwnNumber(context, author) && messageRecord.getIndividualRecipient().getAddress().equals(author)))
|
||||
if ((Recipient.resolved(author).isLocalNumber() && messageRecord.isOutgoing()) ||
|
||||
(!Recipient.resolved(author).isLocalNumber() && messageRecord.getIndividualRecipient().getId().equals(author)))
|
||||
{
|
||||
return messageRecord;
|
||||
}
|
||||
|
@ -164,19 +166,18 @@ public class MmsSmsDatabase extends Database {
|
|||
DatabaseFactory.getMmsDatabase(context).incrementReceiptCount(syncMessageId, timestamp, false, true);
|
||||
}
|
||||
|
||||
public int getQuotedMessagePosition(long threadId, long quoteId, @NonNull Address address) {
|
||||
public int getQuotedMessagePosition(long threadId, long quoteId, @NonNull RecipientId recipientId) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
||||
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_SENT, MmsSmsColumns.ADDRESS }, selection, order, null)) {
|
||||
String serializedAddress = address.serialize();
|
||||
boolean isOwnNumber = Util.isOwnNumber(context, address);
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_SENT, MmsSmsColumns.RECIPIENT_ID}, selection, order, null)) {
|
||||
boolean isOwnNumber = Recipient.resolved(recipientId).isLocalNumber();
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
boolean quoteIdMatches = cursor.getLong(0) == quoteId;
|
||||
boolean addressMatches = serializedAddress.equals(cursor.getString(1));
|
||||
boolean quoteIdMatches = cursor.getLong(0) == quoteId;
|
||||
boolean recipientIdMatches = recipientId.equals(RecipientId.from(cursor.getLong(1)));
|
||||
|
||||
if (quoteIdMatches && (addressMatches || isOwnNumber)) {
|
||||
if (quoteIdMatches && (recipientIdMatches || isOwnNumber)) {
|
||||
return cursor.getPosition();
|
||||
}
|
||||
}
|
||||
|
@ -184,19 +185,18 @@ public class MmsSmsDatabase extends Database {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public int getMessagePositionInConversation(long threadId, long receivedTimestamp, @NonNull Address address) {
|
||||
public int getMessagePositionInConversation(long threadId, long receivedTimestamp, @NonNull RecipientId recipientId) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
||||
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_RECEIVED, MmsSmsColumns.ADDRESS }, selection, order, null)) {
|
||||
String serializedAddress = address.serialize();
|
||||
boolean isOwnNumber = Util.isOwnNumber(context, address);
|
||||
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_RECEIVED, MmsSmsColumns.RECIPIENT_ID}, selection, order, null)) {
|
||||
boolean isOwnNumber = Recipient.resolved(recipientId).isLocalNumber();
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
boolean timestampMatches = cursor.getLong(0) == receivedTimestamp;
|
||||
boolean addressMatches = serializedAddress.equals(cursor.getString(1));
|
||||
boolean timestampMatches = cursor.getLong(0) == receivedTimestamp;
|
||||
boolean recipientIdMatches = recipientId.equals(RecipientId.from(cursor.getLong(1)));
|
||||
|
||||
if (timestampMatches && (addressMatches || isOwnNumber)) {
|
||||
if (timestampMatches && (recipientIdMatches || isOwnNumber)) {
|
||||
return cursor.getPosition();
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ public class MmsSmsDatabase extends Database {
|
|||
"'" + AttachmentDatabase.STICKER_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_ID +
|
||||
")) AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
|
||||
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
|
||||
SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
|
||||
SmsDatabase.TYPE, SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
|
||||
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
||||
|
@ -282,7 +282,7 @@ public class MmsSmsDatabase extends Database {
|
|||
+ " AS " + MmsSmsColumns.UNIQUE_ROW_ID,
|
||||
"NULL AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
|
||||
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
|
||||
SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
|
||||
SmsDatabase.TYPE, SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
|
||||
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
||||
|
@ -318,7 +318,7 @@ public class MmsSmsDatabase extends Database {
|
|||
mmsColumnsPresent.add(MmsSmsColumns.READ);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.BODY);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.RECIPIENT_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.DELIVERY_RECEIPT_COUNT);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.READ_RECEIPT_COUNT);
|
||||
|
@ -375,7 +375,7 @@ public class MmsSmsDatabase extends Database {
|
|||
Set<String> smsColumnsPresent = new HashSet<>();
|
||||
smsColumnsPresent.add(MmsSmsColumns.ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.BODY);
|
||||
smsColumnsPresent.add(MmsSmsColumns.ADDRESS);
|
||||
smsColumnsPresent.add(MmsSmsColumns.RECIPIENT_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.READ);
|
||||
smsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.color.MaterialColor;
|
|||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -32,40 +33,53 @@ public class RecipientDatabase extends Database {
|
|||
|
||||
private static final String TAG = RecipientDatabase.class.getSimpleName();
|
||||
|
||||
static final String TABLE_NAME = "recipient_preferences";
|
||||
private static final String ID = "_id";
|
||||
static final String ADDRESS = "recipient_ids";
|
||||
private static final String BLOCK = "block";
|
||||
private static final String NOTIFICATION = "notification";
|
||||
private static final String VIBRATE = "vibrate";
|
||||
static final String TABLE_NAME = "recipient";
|
||||
public static final String ID = "_id";
|
||||
private static final String UUID = "uuid";
|
||||
static final String PHONE = "phone";
|
||||
static final String EMAIL = "email";
|
||||
static final String GROUP_ID = "group_id";
|
||||
private static final String BLOCKED = "blocked";
|
||||
private static final String MESSAGE_RINGTONE = "message_ringtone";
|
||||
private static final String MESSAGE_VIBRATE = "message_vibrate";
|
||||
private static final String CALL_RINGTONE = "call_ringtone";
|
||||
private static final String CALL_VIBRATE = "call_vibrate";
|
||||
private static final String NOTIFICATION_CHANNEL = "notification_channel";
|
||||
private static final String MUTE_UNTIL = "mute_until";
|
||||
private static final String COLOR = "color";
|
||||
private static final String SEEN_INVITE_REMINDER = "seen_invite_reminder";
|
||||
private static final String DEFAULT_SUBSCRIPTION_ID = "default_subscription_id";
|
||||
private static final String EXPIRE_MESSAGES = "expire_messages";
|
||||
private static final String MESSAGE_EXPIRATION_TIME = "message_expiration_time";
|
||||
static final String REGISTERED = "registered";
|
||||
private static final String PROFILE_KEY = "profile_key";
|
||||
private static final String SYSTEM_DISPLAY_NAME = "system_display_name";
|
||||
private static final String SYSTEM_PHOTO_URI = "system_contact_photo";
|
||||
private static final String SYSTEM_PHOTO_URI = "system_photo_uri";
|
||||
private static final String SYSTEM_PHONE_LABEL = "system_phone_label";
|
||||
private static final String SYSTEM_CONTACT_URI = "system_contact_uri";
|
||||
private static final String PROFILE_KEY = "profile_key";
|
||||
private static final String SIGNAL_PROFILE_NAME = "signal_profile_name";
|
||||
private static final String SIGNAL_PROFILE_AVATAR = "signal_profile_avatar";
|
||||
private static final String PROFILE_SHARING = "profile_sharing_approval";
|
||||
private static final String CALL_RINGTONE = "call_ringtone";
|
||||
private static final String CALL_VIBRATE = "call_vibrate";
|
||||
private static final String NOTIFICATION_CHANNEL = "notification_channel";
|
||||
private static final String PROFILE_SHARING = "profile_sharing";
|
||||
private static final String UNIDENTIFIED_ACCESS_MODE = "unidentified_access_mode";
|
||||
private static final String FORCE_SMS_SELECTION = "force_sms_selection";
|
||||
|
||||
private static final String[] RECIPIENT_PROJECTION = new String[] {
|
||||
BLOCK, NOTIFICATION, CALL_RINGTONE, VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED,
|
||||
UUID, PHONE, EMAIL, GROUP_ID,
|
||||
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
|
||||
PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI,
|
||||
SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL,
|
||||
UNIDENTIFIED_ACCESS_MODE,
|
||||
FORCE_SMS_SELECTION,
|
||||
};
|
||||
|
||||
private static final String[] ID_PROJECTION = new String[] { ID };
|
||||
|
||||
private static Address addressFromCursor(Cursor cursor) {
|
||||
String phone = cursor.getString(cursor.getColumnIndexOrThrow(PHONE));
|
||||
String email = cursor.getString(cursor.getColumnIndexOrThrow(EMAIL));
|
||||
String groupId = cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
|
||||
return phone != null ? Address.fromSerialized(phone) : email != null ? Address.fromSerialized(email) : Address.fromSerialized(groupId);
|
||||
}
|
||||
|
||||
static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION)
|
||||
.map(columnName -> TABLE_NAME + "." + columnName)
|
||||
.toList();
|
||||
|
@ -125,40 +139,105 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
|
||||
public static final String CREATE_TABLE =
|
||||
"CREATE TABLE " + TABLE_NAME +
|
||||
" (" + ID + " INTEGER PRIMARY KEY, " +
|
||||
ADDRESS + " TEXT UNIQUE, " +
|
||||
BLOCK + " INTEGER DEFAULT 0," +
|
||||
NOTIFICATION + " TEXT DEFAULT NULL, " +
|
||||
VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||
MUTE_UNTIL + " INTEGER DEFAULT 0, " +
|
||||
COLOR + " TEXT DEFAULT NULL, " +
|
||||
SEEN_INVITE_REMINDER + " INTEGER DEFAULT 0, " +
|
||||
DEFAULT_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
|
||||
EXPIRE_MESSAGES + " INTEGER DEFAULT 0, " +
|
||||
REGISTERED + " INTEGER DEFAULT 0, " +
|
||||
SYSTEM_DISPLAY_NAME + " TEXT DEFAULT NULL, " +
|
||||
SYSTEM_PHOTO_URI + " TEXT DEFAULT NULL, " +
|
||||
SYSTEM_PHONE_LABEL + " TEXT DEFAULT NULL, " +
|
||||
SYSTEM_CONTACT_URI + " TEXT DEFAULT NULL, " +
|
||||
PROFILE_KEY + " TEXT DEFAULT NULL, " +
|
||||
SIGNAL_PROFILE_NAME + " TEXT DEFAULT NULL, " +
|
||||
SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " +
|
||||
PROFILE_SHARING + " INTEGER DEFAULT 0, " +
|
||||
CALL_RINGTONE + " TEXT DEFAULT NULL, " +
|
||||
CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||
NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL, " +
|
||||
UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0, " +
|
||||
FORCE_SMS_SELECTION + " INTEGER DEFAULT 0);";
|
||||
"CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
UUID + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
PHONE + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
EMAIL + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
GROUP_ID + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
BLOCKED + " INTEGER DEFAULT 0," +
|
||||
MESSAGE_RINGTONE + " TEXT DEFAULT NULL, " +
|
||||
MESSAGE_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||
CALL_RINGTONE + " TEXT DEFAULT NULL, " +
|
||||
CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||
NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL, " +
|
||||
MUTE_UNTIL + " INTEGER DEFAULT 0, " +
|
||||
COLOR + " TEXT DEFAULT NULL, " +
|
||||
SEEN_INVITE_REMINDER + " INTEGER DEFAULT 0, " +
|
||||
DEFAULT_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
|
||||
MESSAGE_EXPIRATION_TIME + " INTEGER DEFAULT 0, " +
|
||||
REGISTERED + " INTEGER DEFAULT " + RegisteredState.UNKNOWN.getId() + ", " +
|
||||
SYSTEM_DISPLAY_NAME + " TEXT DEFAULT NULL, " +
|
||||
SYSTEM_PHOTO_URI + " TEXT DEFAULT NULL, " +
|
||||
SYSTEM_PHONE_LABEL + " TEXT DEFAULT NULL, " +
|
||||
SYSTEM_CONTACT_URI + " TEXT DEFAULT NULL, " +
|
||||
PROFILE_KEY + " TEXT DEFAULT NULL, " +
|
||||
SIGNAL_PROFILE_NAME + " TEXT DEFAULT NULL, " +
|
||||
SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " +
|
||||
PROFILE_SHARING + " INTEGER DEFAULT 0, " +
|
||||
UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0, " +
|
||||
FORCE_SMS_SELECTION + " INTEGER DEFAULT 0);";
|
||||
|
||||
public RecipientDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public RecipientId getOrInsertFromE164(@NonNull String e164) {
|
||||
if (TextUtils.isEmpty(e164)) {
|
||||
throw new AssertionError("Phone number cannot be empty.");
|
||||
}
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
String query = PHONE + " = ?";
|
||||
String[] args = new String[] { e164 };
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, query, args, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return RecipientId.from(cursor.getLong(0));
|
||||
} else {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(PHONE, e164);
|
||||
long id = db.insert(TABLE_NAME, null, values);
|
||||
return RecipientId.from(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RecipientId getOrInsertFromEmail(@NonNull String email) {
|
||||
if (TextUtils.isEmpty(email)) {
|
||||
throw new AssertionError("Email cannot be empty.");
|
||||
}
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
String query = EMAIL + " = ?";
|
||||
String[] args = new String[] { email };
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, query, args, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return RecipientId.from(cursor.getLong(0));
|
||||
} else {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(EMAIL, email);
|
||||
long id = db.insert(TABLE_NAME, null, values);
|
||||
return RecipientId.from(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RecipientId getOrInsertFromGroupId(@NonNull String groupId) {
|
||||
if (TextUtils.isEmpty(groupId)) {
|
||||
throw new AssertionError("GroupId cannot be empty.");
|
||||
}
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
String query = GROUP_ID + " = ?";
|
||||
String[] args = new String[] { groupId };
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, query, args, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return RecipientId.from(cursor.getLong(0));
|
||||
} else {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(GROUP_ID, groupId);
|
||||
long id = db.insert(TABLE_NAME, null, values);
|
||||
return RecipientId.from(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Cursor getBlocked() {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
|
||||
return database.query(TABLE_NAME, new String[] {ID, ADDRESS}, BLOCK + " = 1",
|
||||
return database.query(TABLE_NAME, ID_PROJECTION, BLOCKED + " = 1",
|
||||
null, null, null, null, null);
|
||||
}
|
||||
|
||||
|
@ -168,40 +247,40 @@ public class RecipientDatabase extends Database {
|
|||
|
||||
public RecipientReader getRecipientsWithNotificationChannels() {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS}, NOTIFICATION_CHANNEL + " NOT NULL",
|
||||
Cursor cursor = database.query(TABLE_NAME, ID_PROJECTION, NOTIFICATION_CHANNEL + " NOT NULL",
|
||||
null, null, null, null, null);
|
||||
|
||||
return new RecipientReader(context, cursor);
|
||||
}
|
||||
|
||||
public Optional<RecipientSettings> getRecipientSettings(@NonNull Address address) {
|
||||
public @NonNull RecipientSettings getRecipientSettings(@NonNull RecipientId id) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null);
|
||||
String query = ID + " = ?";
|
||||
String[] args = new String[] { id.serialize() };
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, null, query, args, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return getRecipientSettings(cursor);
|
||||
} else {
|
||||
// TODO: Maybe not make this an error?
|
||||
throw new AssertionError("Couldn't find recipient!");
|
||||
}
|
||||
|
||||
return Optional.absent();
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<RecipientSettings> getRecipientSettings(@NonNull Cursor cursor) {
|
||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
|
||||
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION));
|
||||
@NonNull RecipientSettings getRecipientSettings(@NonNull Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
Address address = addressFromCursor(cursor);
|
||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKED)) == 1;
|
||||
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE_RINGTONE));
|
||||
String callRingtone = cursor.getString(cursor.getColumnIndexOrThrow(CALL_RINGTONE));
|
||||
int messageVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE));
|
||||
int messageVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(MESSAGE_VIBRATE));
|
||||
int callVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(CALL_VIBRATE));
|
||||
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
|
||||
String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR));
|
||||
boolean seenInviteReminder = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER)) == 1;
|
||||
int defaultSubscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(DEFAULT_SUBSCRIPTION_ID));
|
||||
int expireMessages = cursor.getInt(cursor.getColumnIndexOrThrow(EXPIRE_MESSAGES));
|
||||
int expireMessages = cursor.getInt(cursor.getColumnIndexOrThrow(MESSAGE_EXPIRATION_TIME));
|
||||
int registeredState = cursor.getInt(cursor.getColumnIndexOrThrow(REGISTERED));
|
||||
String profileKeyString = cursor.getString(cursor.getColumnIndexOrThrow(PROFILE_KEY));
|
||||
String systemDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME));
|
||||
|
@ -234,18 +313,18 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
}
|
||||
|
||||
return Optional.of(new RecipientSettings(blocked, muteUntil,
|
||||
VibrateState.fromId(messageVibrateState),
|
||||
VibrateState.fromId(callVibrateState),
|
||||
Util.uri(messageRingtone), Util.uri(callRingtone),
|
||||
color, seenInviteReminder,
|
||||
defaultSubscriptionId, expireMessages,
|
||||
RegisteredState.fromId(registeredState),
|
||||
profileKey, systemDisplayName, systemContactPhoto,
|
||||
systemPhoneLabel, systemContactUri,
|
||||
signalProfileName, signalProfileAvatar, profileSharing,
|
||||
notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
|
||||
forceSmsSelection));
|
||||
return new RecipientSettings(RecipientId.from(id), address, blocked, muteUntil,
|
||||
VibrateState.fromId(messageVibrateState),
|
||||
VibrateState.fromId(callVibrateState),
|
||||
Util.uri(messageRingtone), Util.uri(callRingtone),
|
||||
color, seenInviteReminder,
|
||||
defaultSubscriptionId, expireMessages,
|
||||
RegisteredState.fromId(registeredState),
|
||||
profileKey, systemDisplayName, systemContactPhoto,
|
||||
systemPhoneLabel, systemContactUri,
|
||||
signalProfileName, signalProfileAvatar, profileSharing,
|
||||
notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
|
||||
forceSmsSelection);
|
||||
}
|
||||
|
||||
public BulkOperationsHandle resetAllSystemContactInfo() {
|
||||
|
@ -263,187 +342,185 @@ public class RecipientDatabase extends Database {
|
|||
return new BulkOperationsHandle(database);
|
||||
}
|
||||
|
||||
public void setColor(@NonNull Recipient recipient, @NonNull MaterialColor color) {
|
||||
public void setColor(@NonNull RecipientId id, @NonNull MaterialColor color) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(COLOR, color.serialize());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setColor(color);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setDefaultSubscriptionId(@NonNull Recipient recipient, int defaultSubscriptionId) {
|
||||
public void setDefaultSubscriptionId(@NonNull RecipientId id, int defaultSubscriptionId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId);
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setDefaultSubscriptionId(Optional.of(defaultSubscriptionId));
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setForceSmsSelection(@NonNull Recipient recipient, boolean forceSmsSelection) {
|
||||
public void setForceSmsSelection(@NonNull RecipientId id, boolean forceSmsSelection) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(FORCE_SMS_SELECTION, forceSmsSelection ? 1 : 0);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.resolve().setForceSmsSelection(forceSmsSelection);
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setBlocked(@NonNull Recipient recipient, boolean blocked) {
|
||||
public void setBlocked(@NonNull RecipientId id, boolean blocked) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(BLOCK, blocked ? 1 : 0);
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setBlocked(blocked);
|
||||
values.put(BLOCKED, blocked ? 1 : 0);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setMessageRingtone(@NonNull Recipient recipient, @Nullable Uri notification) {
|
||||
public void setMessageRingtone(@NonNull RecipientId id, @Nullable Uri notification) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NOTIFICATION, notification == null ? null : notification.toString());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setMessageRingtone(notification);
|
||||
values.put(MESSAGE_RINGTONE, notification == null ? null : notification.toString());
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setCallRingtone(@NonNull Recipient recipient, @Nullable Uri ringtone) {
|
||||
public void setCallRingtone(@NonNull RecipientId id, @Nullable Uri ringtone) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(CALL_RINGTONE, ringtone == null ? null : ringtone.toString());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setCallRingtone(ringtone);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setMessageVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) {
|
||||
public void setMessageVibrate(@NonNull RecipientId id, @NonNull VibrateState enabled) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(VIBRATE, enabled.getId());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setMessageVibrate(enabled);
|
||||
values.put(MESSAGE_VIBRATE, enabled.getId());
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setCallVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) {
|
||||
public void setCallVibrate(@NonNull RecipientId id, @NonNull VibrateState enabled) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(CALL_VIBRATE, enabled.getId());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setCallVibrate(enabled);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setMuted(@NonNull Recipient recipient, long until) {
|
||||
public void setMuted(@NonNull RecipientId id, long until) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MUTE_UNTIL, until);
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setMuted(until);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setSeenInviteReminder(@NonNull Recipient recipient, @SuppressWarnings("SameParameterValue") boolean seen) {
|
||||
public void setSeenInviteReminder(@NonNull RecipientId id, @SuppressWarnings("SameParameterValue") boolean seen) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(SEEN_INVITE_REMINDER, seen ? 1 : 0);
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setHasSeenInviteReminder(seen);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setExpireMessages(@NonNull Recipient recipient, int expiration) {
|
||||
recipient.setExpireMessages(expiration);
|
||||
|
||||
public void setExpireMessages(@NonNull RecipientId id, int expiration) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(EXPIRE_MESSAGES, expiration);
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setExpireMessages(expiration);
|
||||
values.put(MESSAGE_EXPIRATION_TIME, expiration);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setUnidentifiedAccessMode(@NonNull Recipient recipient, @NonNull UnidentifiedAccessMode unidentifiedAccessMode) {
|
||||
public void setUnidentifiedAccessMode(@NonNull RecipientId id, @NonNull UnidentifiedAccessMode unidentifiedAccessMode) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(UNIDENTIFIED_ACCESS_MODE, unidentifiedAccessMode.getMode());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setUnidentifiedAccessMode(unidentifiedAccessMode);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setProfileKey(@NonNull Recipient recipient, @Nullable byte[] profileKey) {
|
||||
public void setProfileKey(@NonNull RecipientId id, @Nullable byte[] profileKey) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(PROFILE_KEY, profileKey == null ? null : Base64.encodeBytes(profileKey));
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setProfileKey(profileKey);
|
||||
update(id, values);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setProfileName(@NonNull Recipient recipient, @Nullable String profileName) {
|
||||
public void setProfileName(@NonNull RecipientId id, @Nullable String profileName) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SIGNAL_PROFILE_NAME, profileName);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.resolve().setProfileName(profileName);
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setProfileAvatar(@NonNull Recipient recipient, @Nullable String profileAvatar) {
|
||||
public void setProfileAvatar(@NonNull RecipientId id, @Nullable String profileAvatar) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SIGNAL_PROFILE_AVATAR, profileAvatar);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.resolve().setProfileAvatar(profileAvatar);
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setProfileSharing(@NonNull Recipient recipient, @SuppressWarnings("SameParameterValue") boolean enabled) {
|
||||
public void setProfileSharing(@NonNull RecipientId id, @SuppressWarnings("SameParameterValue") boolean enabled) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(PROFILE_SHARING, enabled ? 1 : 0);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.setProfileSharing(enabled);
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setNotificationChannel(@NonNull Recipient recipient, @Nullable String notificationChannel) {
|
||||
public void setNotificationChannel(@NonNull RecipientId id, @Nullable String notificationChannel) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(NOTIFICATION_CHANNEL, notificationChannel);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.setNotificationChannel(notificationChannel);
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public Set<Address> getAllAddresses() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Set<Address> results = new HashSet<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, null, null, null, null, null)) {
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ID, UUID, PHONE, EMAIL, GROUP_ID }, null, null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(Address.fromExternal(context, cursor.getString(0)));
|
||||
results.add(addressFromCursor(cursor));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void setRegistered(@NonNull Recipient recipient, RegisteredState registeredState) {
|
||||
public void setRegistered(@NonNull RecipientId id, RegisteredState registeredState) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(REGISTERED, registeredState.getId());
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.setRegistered(registeredState);
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
||||
public void setRegistered(@NonNull List<Address> activeAddresses,
|
||||
@NonNull List<Address> inactiveAddresses)
|
||||
public void setRegistered(@NonNull List<RecipientId> activeIds,
|
||||
@NonNull List<RecipientId> inactiveIds)
|
||||
{
|
||||
for (Address activeAddress : activeAddresses) {
|
||||
for (RecipientId activeId : activeIds) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
|
||||
|
||||
updateOrInsert(activeAddress, contentValues);
|
||||
Recipient.applyCached(activeAddress, recipient -> recipient.setRegistered(RegisteredState.REGISTERED));
|
||||
update(activeId, contentValues);
|
||||
Recipient.live(activeId).refresh();
|
||||
}
|
||||
|
||||
for (Address inactiveAddress : inactiveAddresses) {
|
||||
for (RecipientId inactiveId : inactiveIds) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(REGISTERED, RegisteredState.NOT_REGISTERED.getId());
|
||||
|
||||
updateOrInsert(inactiveAddress, contentValues);
|
||||
Recipient.applyCached(inactiveAddress, recipient -> recipient.setRegistered(RegisteredState.NOT_REGISTERED));
|
||||
update(inactiveId, contentValues);
|
||||
Recipient.live(inactiveId).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Address> getRegistered() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<Address> results = new LinkedList<>();
|
||||
public List<RecipientId> getRegistered() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<RecipientId> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, REGISTERED + " = ?", new String[] {"1"}, null, null, null)) {
|
||||
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, REGISTERED + " = ?", new String[] {"1"}, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(Address.fromSerialized(cursor.getString(0)));
|
||||
results.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID))));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<Address> getSystemContacts() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<Address> results = new LinkedList<>();
|
||||
public List<RecipientId> getSystemContacts() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<RecipientId> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
|
||||
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(Address.fromSerialized(cursor.getString(0)));
|
||||
results.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID))));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,93 +528,61 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
|
||||
public void updateSystemContactColors(@NonNull ColorUpdater updater) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Map<Address, MaterialColor> updates = new HashMap<>();
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Map<RecipientId, MaterialColor> updates = new HashMap<>();
|
||||
|
||||
db.beginTransaction();
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS, COLOR, SYSTEM_DISPLAY_NAME}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ID, COLOR, SYSTEM_DISPLAY_NAME}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
MaterialColor newColor = updater.update(cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(COLOR)));
|
||||
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(COLOR, newColor.serialize());
|
||||
db.update(TABLE_NAME, contentValues, ADDRESS + " = ?", new String[]{address.serialize()});
|
||||
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] { String.valueOf(id) });
|
||||
|
||||
updates.put(address, newColor);
|
||||
updates.put(RecipientId.from(id), newColor);
|
||||
}
|
||||
} finally {
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
Stream.of(updates.entrySet()).forEach(entry -> {
|
||||
Recipient.applyCached(entry.getKey(), recipient -> {
|
||||
recipient.setColor(entry.getValue());
|
||||
});
|
||||
});
|
||||
Stream.of(updates.entrySet()).forEach(entry -> Recipient.live(entry.getKey()).refresh());
|
||||
}
|
||||
}
|
||||
|
||||
// XXX This shouldn't be here, and is just a temporary workaround
|
||||
public RegisteredState isRegistered(@NonNull Address address) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {REGISTERED}, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) return RegisteredState.fromId(cursor.getInt(0));
|
||||
else return RegisteredState.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOrInsert(Address address, ContentValues contentValues) {
|
||||
private void update(@NonNull RecipientId id, ContentValues contentValues) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
database.beginTransaction();
|
||||
|
||||
int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ?",
|
||||
new String[] {address.serialize()});
|
||||
|
||||
if (updated < 1) {
|
||||
contentValues.put(ADDRESS, address.serialize());
|
||||
database.insert(TABLE_NAME, null, contentValues);
|
||||
}
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
database.update(TABLE_NAME, contentValues, ID + " = ?", new String[] { id.serialize() });
|
||||
}
|
||||
|
||||
public class BulkOperationsHandle {
|
||||
|
||||
private final SQLiteDatabase database;
|
||||
|
||||
private final Map<Address, PendingContactInfo> pendingContactInfoMap = new HashMap<>();
|
||||
private final Map<RecipientId, PendingContactInfo> pendingContactInfoMap = new HashMap<>();
|
||||
|
||||
BulkOperationsHandle(SQLiteDatabase database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
public void setSystemContactInfo(@NonNull Address address, @Nullable String displayName, @Nullable String photoUri, @Nullable String systemPhoneLabel, @Nullable String systemContactUri) {
|
||||
public void setSystemContactInfo(@NonNull RecipientId id, @Nullable String displayName, @Nullable String photoUri, @Nullable String systemPhoneLabel, @Nullable String systemContactUri) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SYSTEM_DISPLAY_NAME, displayName);
|
||||
contentValues.put(SYSTEM_PHOTO_URI, photoUri);
|
||||
contentValues.put(SYSTEM_PHONE_LABEL, systemPhoneLabel);
|
||||
contentValues.put(SYSTEM_CONTACT_URI, systemContactUri);
|
||||
|
||||
updateOrInsert(address, contentValues);
|
||||
pendingContactInfoMap.put(address, new PendingContactInfo(displayName, photoUri, systemPhoneLabel, systemContactUri));
|
||||
update(id, contentValues);
|
||||
pendingContactInfoMap.put(id, new PendingContactInfo(displayName, photoUri, systemPhoneLabel, systemContactUri));
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
|
||||
Stream.of(pendingContactInfoMap.entrySet())
|
||||
.forEach(entry -> Recipient.applyCached(entry.getKey(), recipient -> {
|
||||
recipient.setName(entry.getValue().displayName);
|
||||
recipient.setSystemContactPhoto(Util.uri(entry.getValue().photoUri));
|
||||
recipient.setCustomLabel(entry.getValue().phoneLabel);
|
||||
recipient.setContactUri(Util.uri(entry.getValue().contactUri));
|
||||
}));
|
||||
Stream.of(pendingContactInfoMap.entrySet()).forEach(entry -> Recipient.live(entry.getKey()).refresh());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,6 +591,8 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
|
||||
public static class RecipientSettings {
|
||||
private final RecipientId id;
|
||||
private final Address address;
|
||||
private final boolean blocked;
|
||||
private final long muteUntil;
|
||||
private final VibrateState messageVibrateState;
|
||||
|
@ -569,7 +616,8 @@ public class RecipientDatabase extends Database {
|
|||
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
private final boolean forceSmsSelection;
|
||||
|
||||
RecipientSettings(boolean blocked, long muteUntil,
|
||||
RecipientSettings(@NonNull RecipientId id,
|
||||
@NonNull Address address, boolean blocked, long muteUntil,
|
||||
@NonNull VibrateState messageVibrateState,
|
||||
@NonNull VibrateState callVibrateState,
|
||||
@Nullable Uri messageRingtone,
|
||||
|
@ -591,6 +639,8 @@ public class RecipientDatabase extends Database {
|
|||
@NonNull UnidentifiedAccessMode unidentifiedAccessMode,
|
||||
boolean forceSmsSelection)
|
||||
{
|
||||
this.id = id;
|
||||
this.address = address;
|
||||
this.blocked = blocked;
|
||||
this.muteUntil = muteUntil;
|
||||
this.messageVibrateState = messageVibrateState;
|
||||
|
@ -615,6 +665,14 @@ public class RecipientDatabase extends Database {
|
|||
this.forceSmsSelection = forceSmsSelection;
|
||||
}
|
||||
|
||||
public RecipientId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @NonNull Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public @Nullable MaterialColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
@ -715,8 +773,8 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
|
||||
public @NonNull Recipient getCurrent() {
|
||||
String serialized = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
||||
return Recipient.from(context, Address.fromSerialized(serialized), false);
|
||||
RecipientId id = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
||||
return Recipient.live(id).get();
|
||||
}
|
||||
|
||||
public @Nullable Recipient getNext() {
|
||||
|
|
|
@ -20,12 +20,12 @@ public class SearchDatabase extends Database {
|
|||
public static final String SMS_FTS_TABLE_NAME = "sms_fts";
|
||||
public static final String MMS_FTS_TABLE_NAME = "mms_fts";
|
||||
|
||||
public static final String ID = "rowid";
|
||||
public static final String BODY = MmsSmsColumns.BODY;
|
||||
public static final String THREAD_ID = MmsSmsColumns.THREAD_ID;
|
||||
public static final String SNIPPET = "snippet";
|
||||
public static final String CONVERSATION_ADDRESS = "conversation_address";
|
||||
public static final String MESSAGE_ADDRESS = "message_address";
|
||||
public static final String ID = "rowid";
|
||||
public static final String BODY = MmsSmsColumns.BODY;
|
||||
public static final String THREAD_ID = MmsSmsColumns.THREAD_ID;
|
||||
public static final String SNIPPET = "snippet";
|
||||
public static final String CONVERSATION_RECIPIENT = "conversation_recipient";
|
||||
public static final String MESSAGE_RECIPIENT = "message_recipient";
|
||||
|
||||
public static final String[] CREATE_TABLE = {
|
||||
"CREATE VIRTUAL TABLE " + SMS_FTS_TABLE_NAME + " USING fts5(" + BODY + ", " + THREAD_ID + " UNINDEXED, content=" + SmsDatabase.TABLE_NAME + ", content_rowid=" + SmsDatabase.ID + ");",
|
||||
|
@ -58,8 +58,8 @@ public class SearchDatabase extends Database {
|
|||
|
||||
private static final String MESSAGES_QUERY =
|
||||
"SELECT " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.ADDRESS + " AS " + CONVERSATION_ADDRESS + ", " +
|
||||
MmsSmsColumns.ADDRESS + " AS " + MESSAGE_ADDRESS + ", " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + SMS_FTS_TABLE_NAME + ", -1, '', '', '...', 7) AS " + SNIPPET + ", " +
|
||||
SmsDatabase.TABLE_NAME + "." + SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + THREAD_ID + " " +
|
||||
|
@ -69,8 +69,8 @@ public class SearchDatabase extends Database {
|
|||
"WHERE " + SMS_FTS_TABLE_NAME + " MATCH ? " +
|
||||
"UNION ALL " +
|
||||
"SELECT " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.ADDRESS + " AS " + CONVERSATION_ADDRESS + ", " +
|
||||
MmsSmsColumns.ADDRESS + " AS " + MESSAGE_ADDRESS + ", " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + MMS_FTS_TABLE_NAME + ", -1, '', '', '...', 7) AS " + SNIPPET + ", " +
|
||||
MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + THREAD_ID + " " +
|
||||
|
@ -83,8 +83,8 @@ public class SearchDatabase extends Database {
|
|||
|
||||
private static final String MESSAGES_FOR_THREAD_QUERY =
|
||||
"SELECT " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.ADDRESS + " AS " + CONVERSATION_ADDRESS + ", " +
|
||||
MmsSmsColumns.ADDRESS + " AS " + MESSAGE_ADDRESS + ", " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + SMS_FTS_TABLE_NAME + ", -1, '', '', '...', 7) AS " + SNIPPET + ", " +
|
||||
SmsDatabase.TABLE_NAME + "." + SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
SMS_FTS_TABLE_NAME + "." + THREAD_ID + " " +
|
||||
|
@ -94,8 +94,8 @@ public class SearchDatabase extends Database {
|
|||
"WHERE " + SMS_FTS_TABLE_NAME + " MATCH ? AND " + SmsDatabase.TABLE_NAME + "." + MmsSmsColumns.THREAD_ID + " = ? " +
|
||||
"UNION ALL " +
|
||||
"SELECT " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.ADDRESS + " AS " + CONVERSATION_ADDRESS + ", " +
|
||||
MmsSmsColumns.ADDRESS + " AS " + MESSAGE_ADDRESS + ", " +
|
||||
ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " +
|
||||
MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " +
|
||||
"snippet(" + MMS_FTS_TABLE_NAME + ", -1, '', '', '...', 7) AS " + SNIPPET + ", " +
|
||||
MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " +
|
||||
MMS_FTS_TABLE_NAME + "." + THREAD_ID + " " +
|
||||
|
|
|
@ -11,6 +11,7 @@ import net.sqlcipher.database.SQLiteDatabase;
|
|||
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
|
@ -24,37 +25,37 @@ public class SessionDatabase extends Database {
|
|||
|
||||
public static final String TABLE_NAME = "sessions";
|
||||
|
||||
private static final String ID = "_id";
|
||||
public static final String ADDRESS = "address";
|
||||
public static final String DEVICE = "device";
|
||||
public static final String RECORD = "record";
|
||||
private static final String ID = "_id";
|
||||
public static final String RECIPIENT_ID = "address";
|
||||
public static final String DEVICE = "device";
|
||||
public static final String RECORD = "record";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
|
||||
"(" + ID + " INTEGER PRIMARY KEY, " + ADDRESS + " TEXT NOT NULL, " +
|
||||
"(" + ID + " INTEGER PRIMARY KEY, " + RECIPIENT_ID + " INTEGER NOT NULL, " +
|
||||
DEVICE + " INTEGER NOT NULL, " + RECORD + " BLOB NOT NULL, " +
|
||||
"UNIQUE(" + ADDRESS + "," + DEVICE + ") ON CONFLICT REPLACE);";
|
||||
"UNIQUE(" + RECIPIENT_ID + "," + DEVICE + ") ON CONFLICT REPLACE);";
|
||||
|
||||
SessionDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public void store(@NonNull Address address, int deviceId, @NonNull SessionRecord record) {
|
||||
public void store(@NonNull RecipientId recipientId, int deviceId, @NonNull SessionRecord record) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(ADDRESS, address.serialize());
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(DEVICE, deviceId);
|
||||
values.put(RECORD, record.serialize());
|
||||
|
||||
database.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
|
||||
public @Nullable SessionRecord load(@NonNull Address address, int deviceId) {
|
||||
public @Nullable SessionRecord load(@NonNull RecipientId recipientId, int deviceId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, new String[]{RECORD},
|
||||
ADDRESS + " = ? AND " + DEVICE + " = ?",
|
||||
new String[] {address.serialize(), String.valueOf(deviceId)},
|
||||
RECIPIENT_ID + " = ? AND " + DEVICE + " = ?",
|
||||
new String[] {recipientId.serialize(), String.valueOf(deviceId)},
|
||||
null, null, null))
|
||||
{
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
|
@ -69,18 +70,18 @@ public class SessionDatabase extends Database {
|
|||
return null;
|
||||
}
|
||||
|
||||
public @NonNull List<SessionRow> getAllFor(@NonNull Address address) {
|
||||
public @NonNull List<SessionRow> getAllFor(@NonNull RecipientId recipientId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
List<SessionRow> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, null,
|
||||
ADDRESS + " = ?",
|
||||
new String[] {address.serialize()},
|
||||
RECIPIENT_ID + " = ?",
|
||||
new String[] {recipientId.serialize()},
|
||||
null, null, null))
|
||||
{
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(new SessionRow(address,
|
||||
results.add(new SessionRow(recipientId,
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE)),
|
||||
new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)))));
|
||||
} catch (IOException e) {
|
||||
|
@ -99,7 +100,7 @@ public class SessionDatabase extends Database {
|
|||
try (Cursor cursor = database.query(TABLE_NAME, null, null, null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
try {
|
||||
results.add(new SessionRow(Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))),
|
||||
results.add(new SessionRow(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE)),
|
||||
new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)))));
|
||||
} catch (IOException e) {
|
||||
|
@ -111,13 +112,13 @@ public class SessionDatabase extends Database {
|
|||
return results;
|
||||
}
|
||||
|
||||
public @NonNull List<Integer> getSubDevices(@NonNull Address address) {
|
||||
public @NonNull List<Integer> getSubDevices(@NonNull RecipientId recipientId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
List<Integer> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, new String[] {DEVICE},
|
||||
ADDRESS + " = ?",
|
||||
new String[] {address.serialize()},
|
||||
RECIPIENT_ID + " = ?",
|
||||
new String[] {recipientId.serialize()},
|
||||
null, null, null))
|
||||
{
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
|
@ -132,31 +133,31 @@ public class SessionDatabase extends Database {
|
|||
return results;
|
||||
}
|
||||
|
||||
public void delete(@NonNull Address address, int deviceId) {
|
||||
public void delete(@NonNull RecipientId recipientId, int deviceId) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
database.delete(TABLE_NAME, ADDRESS + " = ? AND " + DEVICE + " = ?",
|
||||
new String[] {address.serialize(), String.valueOf(deviceId)});
|
||||
database.delete(TABLE_NAME, RECIPIENT_ID + " = ? AND " + DEVICE + " = ?",
|
||||
new String[] {recipientId.serialize(), String.valueOf(deviceId)});
|
||||
}
|
||||
|
||||
public void deleteAllFor(@NonNull Address address) {
|
||||
public void deleteAllFor(@NonNull RecipientId recipientId) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
database.delete(TABLE_NAME, ADDRESS + " = ?", new String[] {address.serialize()});
|
||||
database.delete(TABLE_NAME, RECIPIENT_ID + " = ?", new String[] {recipientId.serialize()});
|
||||
}
|
||||
|
||||
public static final class SessionRow {
|
||||
private final Address address;
|
||||
private final RecipientId recipientId;
|
||||
private final int deviceId;
|
||||
private final SessionRecord record;
|
||||
|
||||
public SessionRow(Address address, int deviceId, SessionRecord record) {
|
||||
this.address = address;
|
||||
this.deviceId = deviceId;
|
||||
this.record = record;
|
||||
public SessionRow(@NonNull RecipientId recipientId, int deviceId, SessionRecord record) {
|
||||
this.recipientId = recipientId;
|
||||
this.deviceId = deviceId;
|
||||
this.record = record;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
public RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public int getDeviceId() {
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
|||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
|
@ -73,7 +74,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
public static final String SERVICE_CENTER = "service_center";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " integer PRIMARY KEY, " +
|
||||
THREAD_ID + " INTEGER, " + ADDRESS + " TEXT, " + ADDRESS_DEVICE_ID + " INTEGER DEFAULT 1, " + PERSON + " INTEGER, " +
|
||||
THREAD_ID + " INTEGER, " + RECIPIENT_ID + " INTEGER, " + ADDRESS_DEVICE_ID + " INTEGER DEFAULT 1, " + PERSON + " INTEGER, " +
|
||||
DATE_RECEIVED + " INTEGER, " + DATE_SENT + " INTEGER, " + PROTOCOL + " INTEGER, " + READ + " INTEGER DEFAULT 0, " +
|
||||
STATUS + " INTEGER DEFAULT -1," + TYPE + " INTEGER, " + REPLY_PATH_PRESENT + " INTEGER, " +
|
||||
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0," + SUBJECT + " TEXT, " + BODY + " TEXT, " +
|
||||
|
@ -91,7 +92,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
};
|
||||
|
||||
private static final String[] MESSAGE_PROJECTION = new String[] {
|
||||
ID, THREAD_ID, ADDRESS, ADDRESS_DEVICE_ID, PERSON,
|
||||
ID, THREAD_ID, RECIPIENT_ID, ADDRESS_DEVICE_ID, PERSON,
|
||||
DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
||||
DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
||||
PROTOCOL, READ, STATUS, TYPE,
|
||||
|
@ -100,8 +101,8 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED
|
||||
};
|
||||
|
||||
private static final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache();
|
||||
private static final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache();
|
||||
private static final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache("SmsDelivery");
|
||||
private static final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache("SmsRead");
|
||||
|
||||
public SmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
|
@ -310,17 +311,17 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
boolean foundMessage = false;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, ADDRESS, TYPE},
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, RECIPIENT_ID, TYPE},
|
||||
DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())},
|
||||
null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)))) {
|
||||
Address theirAddress = messageId.getAddress();
|
||||
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||
RecipientId theirRecipientId = messageId.getRecipientId();
|
||||
RecipientId outRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
|
||||
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||
|
||||
if (ourAddress.equals(theirAddress)) {
|
||||
if (outRecipientId.equals(theirRecipientId)) {
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
|
||||
database.execSQL("UPDATE " + TABLE_NAME +
|
||||
|
@ -336,8 +337,8 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
if (!foundMessage) {
|
||||
if (deliveryReceipt) earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (readReceipt) earlyReadReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (deliveryReceipt) earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getRecipientId());
|
||||
if (readReceipt) earlyReadReceiptCache.increment(messageId.getTimetamp(), messageId.getRecipientId());
|
||||
}
|
||||
|
||||
} finally {
|
||||
|
@ -352,15 +353,15 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, ADDRESS, TYPE, EXPIRES_IN, EXPIRE_STARTED},
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, RECIPIENT_ID, TYPE, EXPIRES_IN, EXPIRE_STARTED},
|
||||
DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())},
|
||||
null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
Address theirAddress = messageId.getAddress();
|
||||
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
RecipientId theirRecipientId = messageId.getRecipientId();
|
||||
RecipientId outRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
|
||||
|
||||
if (ourAddress.equals(theirAddress)) {
|
||||
if (outRecipientId.equals(theirRecipientId)) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
|
@ -405,11 +406,11 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
|
||||
database.beginTransaction();
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED}, where, arguments, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED}, where, arguments, null, null, null);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
if (Types.isSecureType(cursor.getLong(3))) {
|
||||
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(cursor.getString(1)), cursor.getLong(2));
|
||||
SyncMessageId syncMessageId = new SyncMessageId(RecipientId.from(cursor.getLong(1)), cursor.getLong(2));
|
||||
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), false);
|
||||
|
||||
results.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
|
||||
|
@ -461,7 +462,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(TYPE, (record.getType() & ~Types.BASE_TYPE_MASK) | Types.BASE_INBOX_TYPE);
|
||||
contentValues.put(ADDRESS, record.getIndividualRecipient().getAddress().serialize());
|
||||
contentValues.put(RECIPIENT_ID, record.getIndividualRecipient().getId().serialize());
|
||||
contentValues.put(ADDRESS_DEVICE_ID, record.getRecipientDeviceId());
|
||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
contentValues.put(DATE_SENT, record.getDateSent());
|
||||
|
@ -485,24 +486,24 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
public @NonNull Pair<Long, Long> insertReceivedCall(@NonNull Address address) {
|
||||
public @NonNull Pair<Long, Long> insertReceivedCall(@NonNull RecipientId address) {
|
||||
return insertCallLog(address, Types.INCOMING_CALL_TYPE, false);
|
||||
}
|
||||
|
||||
public @NonNull Pair<Long, Long> insertOutgoingCall(@NonNull Address address) {
|
||||
public @NonNull Pair<Long, Long> insertOutgoingCall(@NonNull RecipientId address) {
|
||||
return insertCallLog(address, Types.OUTGOING_CALL_TYPE, false);
|
||||
}
|
||||
|
||||
public @NonNull Pair<Long, Long> insertMissedCall(@NonNull Address address) {
|
||||
public @NonNull Pair<Long, Long> insertMissedCall(@NonNull RecipientId address) {
|
||||
return insertCallLog(address, Types.MISSED_CALL_TYPE, true);
|
||||
}
|
||||
|
||||
private @NonNull Pair<Long, Long> insertCallLog(@NonNull Address address, long type, boolean unread) {
|
||||
Recipient recipient = Recipient.from(context, address, true);
|
||||
private @NonNull Pair<Long, Long> insertCallLog(@NonNull RecipientId recipientId, long type, boolean unread) {
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
|
||||
ContentValues values = new ContentValues(6);
|
||||
values.put(ADDRESS, address.serialize());
|
||||
values.put(RECIPIENT_ID, recipientId.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
|
@ -547,14 +548,15 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
||||
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
||||
|
||||
Recipient recipient = Recipient.from(context, message.getSender(), true);
|
||||
Recipient recipient = Recipient.resolved(message.getSender());
|
||||
|
||||
Recipient groupRecipient;
|
||||
|
||||
if (message.getGroupId() == null) {
|
||||
groupRecipient = null;
|
||||
} else {
|
||||
groupRecipient = Recipient.from(context, message.getGroupId(), true);
|
||||
RecipientId id = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(message.getGroupId().serialize());
|
||||
groupRecipient = Recipient.resolved(id);
|
||||
}
|
||||
|
||||
boolean unread = (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
|
||||
|
@ -567,7 +569,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||
|
||||
ContentValues values = new ContentValues(6);
|
||||
values.put(ADDRESS, message.getSender().serialize());
|
||||
values.put(RECIPIENT_ID, message.getSender().serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId());
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, message.getSentTimestampMillis());
|
||||
|
@ -602,7 +604,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
if (message.getSubscriptionId() != -1) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setDefaultSubscriptionId(recipient, message.getSubscriptionId());
|
||||
DatabaseFactory.getRecipientDatabase(context).setDefaultSubscriptionId(recipient.getId(), message.getSubscriptionId());
|
||||
}
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
|
@ -632,12 +634,12 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
||||
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
||||
|
||||
Address address = message.getRecipient().getAddress();
|
||||
Map<Address, Long> earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(date);
|
||||
Map<Address, Long> earlyReadReceipts = earlyReadReceiptCache.remove(date);
|
||||
RecipientId recipientId = message.getRecipient().getId();
|
||||
Map<RecipientId, Long> earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(date);
|
||||
Map<RecipientId, Long> earlyReadReceipts = earlyReadReceiptCache.remove(date);
|
||||
|
||||
ContentValues contentValues = new ContentValues(6);
|
||||
contentValues.put(ADDRESS, address.serialize());
|
||||
contentValues.put(RECIPIENT_ID, recipientId.serialize());
|
||||
contentValues.put(THREAD_ID, threadId);
|
||||
contentValues.put(BODY, message.getMessageBody());
|
||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
|
@ -650,7 +652,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
contentValues.put(READ_RECEIPT_COUNT, Stream.of(earlyReadReceipts.values()).mapToLong(Long::longValue).sum());
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
if (insertListener != null) {
|
||||
insertListener.onComplete();
|
||||
|
@ -724,7 +726,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
|
||||
private boolean isDuplicate(IncomingTextMessage message, long threadId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + RECIPIENT_ID + " = ? AND " + THREAD_ID + " = ?",
|
||||
new String[]{String.valueOf(message.getSentTimestampMillis()), message.getSender().serialize(), String.valueOf(threadId)},
|
||||
null, null, null, "1");
|
||||
|
||||
|
@ -783,19 +785,19 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
/*package*/ SQLiteStatement createInsertStatement(SQLiteDatabase database) {
|
||||
return database.compileStatement("INSERT INTO " + TABLE_NAME + " (" + ADDRESS + ", " +
|
||||
PERSON + ", " +
|
||||
DATE_SENT + ", " +
|
||||
DATE_RECEIVED + ", " +
|
||||
PROTOCOL + ", " +
|
||||
READ + ", " +
|
||||
STATUS + ", " +
|
||||
TYPE + ", " +
|
||||
REPLY_PATH_PRESENT + ", " +
|
||||
SUBJECT + ", " +
|
||||
BODY + ", " +
|
||||
SERVICE_CENTER +
|
||||
", " + THREAD_ID + ") " +
|
||||
return database.compileStatement("INSERT INTO " + TABLE_NAME + " (" + RECIPIENT_ID + ", " +
|
||||
PERSON + ", " +
|
||||
DATE_SENT + ", " +
|
||||
DATE_RECEIVED + ", " +
|
||||
PROTOCOL + ", " +
|
||||
READ + ", " +
|
||||
STATUS + ", " +
|
||||
TYPE + ", " +
|
||||
REPLY_PATH_PRESENT + ", " +
|
||||
SUBJECT + ", " +
|
||||
BODY + ", " +
|
||||
SERVICE_CENTER +
|
||||
", " + THREAD_ID + ") " +
|
||||
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
}
|
||||
|
||||
|
@ -859,7 +861,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
|
||||
public SmsMessageRecord getCurrent() {
|
||||
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID));
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS)));
|
||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.RECIPIENT_ID));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS_DEVICE_ID));
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.TYPE));
|
||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_RECEIVED));
|
||||
|
@ -880,7 +882,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
}
|
||||
|
||||
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
||||
Recipient recipient = Recipient.from(context, address, true);
|
||||
Recipient recipient = Recipient.live(RecipientId.from(recipientId)).get();
|
||||
|
||||
return new SmsMessageRecord(messageId, body, recipient,
|
||||
recipient,
|
||||
|
|
|
@ -22,15 +22,18 @@ import android.database.sqlite.SQLiteException;
|
|||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
import net.sqlcipher.database.SQLiteStatement;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
@ -39,6 +42,20 @@ public class SmsMigrator {
|
|||
|
||||
private static final String TAG = SmsMigrator.class.getSimpleName();
|
||||
|
||||
private static class SystemColumns {
|
||||
private static final String ADDRESS = "address";
|
||||
private static final String PERSON = "person";
|
||||
private static final String DATE_RECEIVED = "date";
|
||||
private static final String PROTOCOL = "protocol";
|
||||
private static final String READ = "read";
|
||||
private static final String STATUS = "status";
|
||||
private static final String TYPE = "type";
|
||||
private static final String SUBJECT = "subject";
|
||||
private static final String REPLY_PATH_PRESENT = "reply_path_present";
|
||||
private static final String BODY = "body";
|
||||
private static final String SERVICE_CENTER = "service_center";
|
||||
}
|
||||
|
||||
private static void addStringToStatement(SQLiteStatement statement, Cursor cursor,
|
||||
int index, String key)
|
||||
{
|
||||
|
@ -85,23 +102,22 @@ public class SmsMigrator {
|
|||
ourType == MmsSmsColumns.Types.BASE_SENT_FAILED_TYPE;
|
||||
}
|
||||
|
||||
private static void getContentValuesForRow(Context context, Cursor cursor,
|
||||
long threadId, SQLiteStatement statement)
|
||||
{
|
||||
String theirAddress = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS));
|
||||
statement.bindString(1, Address.fromExternal(context, theirAddress).serialize());
|
||||
private static void getContentValuesForRow(Context context, Cursor cursor, long threadId, SQLiteStatement statement) {
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(SystemColumns.ADDRESS));
|
||||
RecipientId id = Recipient.external(context, address).getId();
|
||||
|
||||
addIntToStatement(statement, cursor, 2, SmsDatabase.PERSON);
|
||||
addIntToStatement(statement, cursor, 3, SmsDatabase.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 4, SmsDatabase.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 5, SmsDatabase.PROTOCOL);
|
||||
addIntToStatement(statement, cursor, 6, SmsDatabase.READ);
|
||||
addIntToStatement(statement, cursor, 7, SmsDatabase.STATUS);
|
||||
addTranslatedTypeToStatement(statement, cursor, 8, SmsDatabase.TYPE);
|
||||
addIntToStatement(statement, cursor, 9, SmsDatabase.REPLY_PATH_PRESENT);
|
||||
addStringToStatement(statement, cursor, 10, SmsDatabase.SUBJECT);
|
||||
addStringToStatement(statement, cursor, 11, SmsDatabase.BODY);
|
||||
addStringToStatement(statement, cursor, 12, SmsDatabase.SERVICE_CENTER);
|
||||
statement.bindString(1, id.serialize());
|
||||
addIntToStatement(statement, cursor, 2, SystemColumns.PERSON);
|
||||
addIntToStatement(statement, cursor, 3, SystemColumns.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 4, SystemColumns.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 5, SystemColumns.PROTOCOL);
|
||||
addIntToStatement(statement, cursor, 6, SystemColumns.READ);
|
||||
addIntToStatement(statement, cursor, 7, SystemColumns.STATUS);
|
||||
addTranslatedTypeToStatement(statement, cursor, 8, SystemColumns.TYPE);
|
||||
addIntToStatement(statement, cursor, 9, SystemColumns.REPLY_PATH_PRESENT);
|
||||
addStringToStatement(statement, cursor, 10, SystemColumns.SUBJECT);
|
||||
addStringToStatement(statement, cursor, 11, SystemColumns.BODY);
|
||||
addStringToStatement(statement, cursor, 12, SystemColumns.SERVICE_CENTER);
|
||||
|
||||
statement.bindLong(13, threadId);
|
||||
}
|
||||
|
@ -136,7 +152,7 @@ public class SmsMigrator {
|
|||
String address = getTheirCanonicalAddress(context, theirRecipientId);
|
||||
|
||||
if (address != null) {
|
||||
recipientList.add(Recipient.from(context, Address.fromExternal(context, address), true));
|
||||
recipientList.add(Recipient.external(context, address));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,17 +228,14 @@ public class SmsMigrator {
|
|||
long ourThreadId = threadDatabase.getThreadIdFor(ourRecipients.iterator().next());
|
||||
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
||||
} else if (ourRecipients.size() > 1) {
|
||||
ourRecipients.add(Recipient.from(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), true));
|
||||
ourRecipients.add(Recipient.self());
|
||||
|
||||
List<Address> memberAddresses = new LinkedList<>();
|
||||
List<RecipientId> recipientIds = Stream.of(ourRecipients).map(Recipient::getId).toList();
|
||||
|
||||
for (Recipient recipient : ourRecipients) {
|
||||
memberAddresses.add(recipient.getAddress());
|
||||
}
|
||||
|
||||
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, true);
|
||||
Recipient ourGroupRecipient = Recipient.from(context, Address.fromSerialized(ourGroupId), true);
|
||||
long ourThreadId = threadDatabase.getThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(recipientIds, true);
|
||||
RecipientId ourGroupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(ourGroupId);
|
||||
Recipient ourGroupRecipient = Recipient.resolved(ourGroupRecipientId);
|
||||
long ourThreadId = threadDatabase.getThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||
|
||||
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
||||
}
|
||||
|
|
|
@ -32,9 +32,7 @@ import net.sqlcipher.database.SQLiteDatabase;
|
|||
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
|
@ -44,12 +42,11 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
@ -65,7 +62,7 @@ public class ThreadDatabase extends Database {
|
|||
public static final String ID = "_id";
|
||||
public static final String DATE = "date";
|
||||
public static final String MESSAGE_COUNT = "message_count";
|
||||
public static final String ADDRESS = "recipient_ids";
|
||||
public static final String RECIPIENT_ID = "recipient_ids";
|
||||
public static final String SNIPPET = "snippet";
|
||||
private static final String SNIPPET_CHARSET = "snippet_cs";
|
||||
public static final String READ = "read";
|
||||
|
@ -86,7 +83,7 @@ public class ThreadDatabase extends Database {
|
|||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
|
||||
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
|
||||
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESS + " TEXT, " + SNIPPET + " TEXT, " +
|
||||
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + RECIPIENT_ID + " INTEGER, " + SNIPPET + " TEXT, " +
|
||||
SNIPPET_CHARSET + " INTEGER DEFAULT 0, " + READ + " INTEGER DEFAULT 1, " +
|
||||
TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
||||
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
|
||||
|
@ -97,12 +94,12 @@ public class ThreadDatabase extends Database {
|
|||
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + UNREAD_COUNT + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESS + ");",
|
||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + RECIPIENT_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS archived_count_index ON " + TABLE_NAME + " (" + ARCHIVED + ", " + MESSAGE_COUNT + ");",
|
||||
};
|
||||
|
||||
private static final String[] THREAD_PROJECTION = {
|
||||
ID, DATE, MESSAGE_COUNT, ADDRESS, SNIPPET, SNIPPET_CHARSET, READ, UNREAD_COUNT, TYPE, ERROR, SNIPPET_TYPE,
|
||||
ID, DATE, MESSAGE_COUNT, RECIPIENT_ID, SNIPPET, SNIPPET_CHARSET, READ, UNREAD_COUNT, TYPE, ERROR, SNIPPET_TYPE,
|
||||
SNIPPET_URI, SNIPPET_CONTENT_TYPE, SNIPPET_EXTRAS, ARCHIVED, STATUS, DELIVERY_RECEIPT_COUNT, EXPIRES_IN, LAST_SEEN, READ_RECEIPT_COUNT
|
||||
};
|
||||
|
||||
|
@ -119,12 +116,12 @@ public class ThreadDatabase extends Database {
|
|||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
private long createThreadForRecipient(Address address, boolean group, int distributionType) {
|
||||
private long createThreadForRecipient(@NonNull RecipientId recipientId, boolean group, int distributionType) {
|
||||
ContentValues contentValues = new ContentValues(4);
|
||||
long date = System.currentTimeMillis();
|
||||
|
||||
contentValues.put(DATE, date - date % 1000);
|
||||
contentValues.put(ADDRESS, address.serialize());
|
||||
contentValues.put(RECIPIENT_ID, recipientId.serialize());
|
||||
|
||||
if (group)
|
||||
contentValues.put(TYPE, distributionType);
|
||||
|
@ -340,24 +337,24 @@ public class ThreadDatabase extends Database {
|
|||
|
||||
}
|
||||
|
||||
public Cursor getFilteredConversationList(@Nullable List<Address> filter) {
|
||||
public Cursor getFilteredConversationList(@Nullable List<RecipientId> filter) {
|
||||
if (filter == null || filter.size() == 0)
|
||||
return null;
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<List<Address>> partitionedAddresses = Util.partition(filter, 900);
|
||||
List<Cursor> cursors = new LinkedList<>();
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<List<RecipientId>> splitRecipientIds = Util.partition(filter, 900);
|
||||
List<Cursor> cursors = new LinkedList<>();
|
||||
|
||||
for (List<Address> addresses : partitionedAddresses) {
|
||||
String selection = TABLE_NAME + "." + ADDRESS + " = ?";
|
||||
String[] selectionArgs = new String[addresses.size()];
|
||||
for (List<RecipientId> recipientIds : splitRecipientIds) {
|
||||
String selection = TABLE_NAME + "." + RECIPIENT_ID + " = ?";
|
||||
String[] selectionArgs = new String[recipientIds.size()];
|
||||
|
||||
for (int i=0;i<addresses.size()-1;i++)
|
||||
selection += (" OR " + TABLE_NAME + "." + ADDRESS + " = ?");
|
||||
for (int i=0;i<recipientIds.size()-1;i++)
|
||||
selection += (" OR " + TABLE_NAME + "." + RECIPIENT_ID + " = ?");
|
||||
|
||||
int i= 0;
|
||||
for (Address address : addresses) {
|
||||
selectionArgs[i++] = DelimiterUtil.escape(address.serialize(), ' ');
|
||||
for (RecipientId recipientId : recipientIds) {
|
||||
selectionArgs[i++] = recipientId.serialize();
|
||||
}
|
||||
|
||||
String query = createQuery(selection, 0);
|
||||
|
@ -378,7 +375,7 @@ public class ThreadDatabase extends Database {
|
|||
|
||||
public Cursor getRecentPushConversationList(int limit) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = MESSAGE_COUNT + " != 0 AND (" + RecipientDatabase.REGISTERED + " = " + RecipientDatabase.RegisteredState.REGISTERED.getId() + " OR " + GroupDatabase.GROUP_ID + " NOT NULL)";
|
||||
String where = MESSAGE_COUNT + " != 0 AND (" + RecipientDatabase.REGISTERED + " = " + RecipientDatabase.RegisteredState.REGISTERED.getId() + " OR " + GroupDatabase.TABLE_NAME + "." + GroupDatabase.GROUP_ID + " NOT NULL)";
|
||||
String query = createQuery(where, limit);
|
||||
|
||||
return db.rawQuery(query, null);
|
||||
|
@ -496,10 +493,10 @@ public class ThreadDatabase extends Database {
|
|||
}
|
||||
|
||||
public long getThreadIdIfExistsFor(Recipient recipient) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = ADDRESS + " = ?";
|
||||
String[] recipientsArg = new String[] {recipient.getAddress().serialize()};
|
||||
Cursor cursor = null;
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = RECIPIENT_ID + " = ?";
|
||||
String[] recipientsArg = new String[] {recipient.getId().serialize()};
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null);
|
||||
|
@ -520,8 +517,8 @@ public class ThreadDatabase extends Database {
|
|||
|
||||
public long getThreadIdFor(Recipient recipient, int distributionType) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = ADDRESS + " = ?";
|
||||
String[] recipientsArg = new String[]{recipient.getAddress().serialize()};
|
||||
String where = RECIPIENT_ID + " = ?";
|
||||
String[] recipientsArg = new String[]{recipient.getId().serialize()};
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
|
@ -530,7 +527,7 @@ public class ThreadDatabase extends Database {
|
|||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
} else {
|
||||
return createThreadForRecipient(recipient.getAddress(), recipient.isGroupRecipient(), distributionType);
|
||||
return createThreadForRecipient(recipient.getId(), recipient.isGroup(), distributionType);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
|
@ -546,8 +543,8 @@ public class ThreadDatabase extends Database {
|
|||
cursor = db.query(TABLE_NAME, null, ID + " = ?", new String[] {threadId+""}, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
return Recipient.from(context, address, false);
|
||||
RecipientId id = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
|
||||
return Recipient.resolved(id);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
|
@ -664,9 +661,9 @@ public class ThreadDatabase extends Database {
|
|||
String query =
|
||||
"SELECT " + projection + " FROM " + TABLE_NAME +
|
||||
" LEFT OUTER JOIN " + RecipientDatabase.TABLE_NAME +
|
||||
" ON " + TABLE_NAME + "." + ADDRESS + " = " + RecipientDatabase.TABLE_NAME + "." + RecipientDatabase.ADDRESS +
|
||||
" ON " + TABLE_NAME + "." + RECIPIENT_ID + " = " + RecipientDatabase.TABLE_NAME + "." + RecipientDatabase.ID +
|
||||
" LEFT OUTER JOIN " + GroupDatabase.TABLE_NAME +
|
||||
" ON " + TABLE_NAME + "." + ADDRESS + " = " + GroupDatabase.TABLE_NAME + "." + GroupDatabase.GROUP_ID +
|
||||
" ON " + TABLE_NAME + "." + RECIPIENT_ID + " = " + GroupDatabase.TABLE_NAME + "." + GroupDatabase.RECIPIENT_ID +
|
||||
" WHERE " + where +
|
||||
" ORDER BY " + TABLE_NAME + "." + DATE + " DESC";
|
||||
|
||||
|
@ -709,22 +706,11 @@ public class ThreadDatabase extends Database {
|
|||
}
|
||||
|
||||
public ThreadRecord getCurrent() {
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
||||
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESS)));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
||||
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
|
||||
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_ID)));
|
||||
|
||||
Optional<RecipientSettings> settings;
|
||||
Optional<GroupRecord> groupRecord;
|
||||
|
||||
if (distributionType != DistributionTypes.ARCHIVE && distributionType != DistributionTypes.INBOX_ZERO) {
|
||||
settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(cursor);
|
||||
groupRecord = DatabaseFactory.getGroupDatabase(context).getGroup(cursor);
|
||||
} else {
|
||||
settings = Optional.absent();
|
||||
groupRecord = Optional.absent();
|
||||
}
|
||||
|
||||
Recipient recipient = Recipient.from(context, address, settings, groupRecord, true);
|
||||
Recipient recipient = Recipient.live(recipientId).get();
|
||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET));
|
||||
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
|
||||
long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT));
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package org.thoughtcrime.securesms.database.documents;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
@ -13,20 +18,26 @@ import com.fasterxml.jackson.databind.SerializerProvider;
|
|||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class IdentityKeyMismatch {
|
||||
|
||||
private static final String TAG = IdentityKeyMismatch.class.getSimpleName();
|
||||
|
||||
/** DEPRECATED */
|
||||
@JsonProperty(value = "a")
|
||||
private String address;
|
||||
|
||||
@JsonProperty(value = "r")
|
||||
private String recipientId;
|
||||
|
||||
@JsonProperty(value = "k")
|
||||
@JsonSerialize(using = IdentityKeySerializer.class)
|
||||
@JsonDeserialize(using = IdentityKeyDeserializer.class)
|
||||
|
@ -34,14 +45,19 @@ public class IdentityKeyMismatch {
|
|||
|
||||
public IdentityKeyMismatch() {}
|
||||
|
||||
public IdentityKeyMismatch(Address address, IdentityKey identityKey) {
|
||||
this.address = address.serialize();
|
||||
public IdentityKeyMismatch(RecipientId recipientId, IdentityKey identityKey) {
|
||||
this.recipientId = recipientId.serialize();
|
||||
this.address = "";
|
||||
this.identityKey = identityKey;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public Address getAddress() {
|
||||
return Address.fromSerialized(address);
|
||||
public RecipientId getRecipientId(@NonNull Context context) {
|
||||
if (!TextUtils.isEmpty(recipientId)) {
|
||||
return RecipientId.from(recipientId);
|
||||
} else {
|
||||
return Recipient.external(context, address).getId();
|
||||
}
|
||||
}
|
||||
|
||||
public IdentityKey getIdentityKey() {
|
||||
|
@ -49,18 +65,18 @@ public class IdentityKeyMismatch {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || !(other instanceof IdentityKeyMismatch)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IdentityKeyMismatch that = (IdentityKeyMismatch)other;
|
||||
return that.address.equals(this.address) && that.identityKey.equals(this.identityKey);
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
IdentityKeyMismatch that = (IdentityKeyMismatch) o;
|
||||
return Objects.equals(address, that.address) &&
|
||||
Objects.equals(recipientId, that.recipientId) &&
|
||||
Objects.equals(identityKey, that.identityKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return address.hashCode() ^ identityKey.hashCode();
|
||||
return Objects.hash(address, recipientId, identityKey);
|
||||
}
|
||||
|
||||
private static class IdentityKeySerializer extends JsonSerializer<IdentityKey> {
|
||||
|
|
|
@ -1,36 +1,56 @@
|
|||
package org.thoughtcrime.securesms.database.documents;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class NetworkFailure {
|
||||
|
||||
/** DEPRECATED */
|
||||
@JsonProperty(value = "a")
|
||||
private String address;
|
||||
|
||||
public NetworkFailure(Address address) {
|
||||
this.address = address.serialize();
|
||||
@JsonProperty(value = "r")
|
||||
private String recipientId;
|
||||
|
||||
public NetworkFailure(@NonNull RecipientId recipientId) {
|
||||
this.recipientId = recipientId.serialize();
|
||||
this.address = "";
|
||||
}
|
||||
|
||||
public NetworkFailure() {}
|
||||
|
||||
@JsonIgnore
|
||||
public Address getAddress() {
|
||||
return Address.fromSerialized(address);
|
||||
public RecipientId getRecipientId(@NonNull Context context) {
|
||||
if (!TextUtils.isEmpty(recipientId)) {
|
||||
return RecipientId.from(recipientId);
|
||||
} else {
|
||||
return Recipient.external(context, address).getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || !(other instanceof NetworkFailure)) return false;
|
||||
|
||||
NetworkFailure that = (NetworkFailure)other;
|
||||
return this.address.equals(that.address);
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
NetworkFailure that = (NetworkFailure) o;
|
||||
return Objects.equals(address, that.address) &&
|
||||
Objects.equals(recipientId, that.recipientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return address.hashCode();
|
||||
return Objects.hash(address, recipientId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
package org.thoughtcrime.securesms.database.helpers;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class RecipientIdMigrationHelper {
|
||||
|
||||
private static final String TAG = Log.tag(RecipientIdMigrationHelper.class);
|
||||
|
||||
public static void execute(SQLiteDatabase db) {
|
||||
Log.i(TAG, "Starting the recipient ID migration.");
|
||||
|
||||
long insertStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting inserts for missing recipients.");
|
||||
db.execSQL(buildInsertMissingRecipientStatement("identities", "address"));
|
||||
db.execSQL(buildInsertMissingRecipientStatement("sessions", "address"));
|
||||
db.execSQL(buildInsertMissingRecipientStatement("thread", "recipient_ids"));
|
||||
db.execSQL(buildInsertMissingRecipientStatement("sms", "address"));
|
||||
db.execSQL(buildInsertMissingRecipientStatement("mms", "address"));
|
||||
db.execSQL(buildInsertMissingRecipientStatement("mms", "quote_author"));
|
||||
db.execSQL(buildInsertMissingRecipientStatement("group_receipts", "address"));
|
||||
db.execSQL(buildInsertMissingRecipientStatement("groups", "group_id"));
|
||||
Log.i(TAG, "Finished inserts for missing recipients in " + (System.currentTimeMillis() - insertStart) + " ms.");
|
||||
|
||||
long updateMissingStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting updates for invalid or missing addresses.");
|
||||
db.execSQL(buildMissingAddressUpdateStatement("sms", "address"));
|
||||
db.execSQL(buildMissingAddressUpdateStatement("mms", "address"));
|
||||
db.execSQL(buildMissingAddressUpdateStatement("mms", "quote_author"));
|
||||
Log.i(TAG, "Finished updates for invalid or missing addresses in " + (System.currentTimeMillis() - updateMissingStart) + " ms.");
|
||||
|
||||
db.execSQL("ALTER TABLE groups ADD COLUMN recipient_id INTEGER DEFAULT 0");
|
||||
|
||||
long updateStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting recipient ID updates.");
|
||||
db.execSQL(buildUpdateAddressToRecipientIdStatement("identities", "address"));
|
||||
db.execSQL(buildUpdateAddressToRecipientIdStatement("sessions", "address"));
|
||||
db.execSQL(buildUpdateAddressToRecipientIdStatement("thread", "recipient_ids"));
|
||||
db.execSQL(buildUpdateAddressToRecipientIdStatement("sms", "address"));
|
||||
db.execSQL(buildUpdateAddressToRecipientIdStatement("mms", "address"));
|
||||
db.execSQL(buildUpdateAddressToRecipientIdStatement("mms", "quote_author"));
|
||||
db.execSQL(buildUpdateAddressToRecipientIdStatement("group_receipts", "address"));
|
||||
db.execSQL("UPDATE groups SET recipient_id = (SELECT _id FROM recipient_preferences WHERE recipient_preferences.recipient_ids = groups.group_id)");
|
||||
Log.i(TAG, "Finished recipient ID updates in " + (System.currentTimeMillis() - updateStart) + " ms.");
|
||||
|
||||
// NOTE: Because there's an open cursor on the same table, inserts and updates aren't visible
|
||||
// until afterwards, which is why this group stuff is split into multiple loops
|
||||
|
||||
long findGroupStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting to find missing group recipients.");
|
||||
Set<String> missingGroupMembers = new HashSet<>();
|
||||
|
||||
try (Cursor cursor = db.rawQuery("SELECT members FROM groups", null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
String serializedMembers = cursor.getString(cursor.getColumnIndexOrThrow("members"));
|
||||
String[] members = DelimiterUtil.split(serializedMembers, ',');
|
||||
|
||||
for (String rawMember : members) {
|
||||
String member = DelimiterUtil.unescape(rawMember, ',');
|
||||
|
||||
if (!TextUtils.isEmpty(member) && !recipientExists(db, member)) {
|
||||
missingGroupMembers.add(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.i(TAG, "Finished finding " + missingGroupMembers.size() + " missing group recipients in " + (System.currentTimeMillis() - findGroupStart) + " ms.");
|
||||
|
||||
long insertGroupStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting the insert of missing group recipients.");
|
||||
for (String member : missingGroupMembers) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("recipient_ids", member);
|
||||
db.insert("recipient_preferences", null, values);
|
||||
}
|
||||
Log.i(TAG, "Finished inserting missing group recipients in " + (System.currentTimeMillis() - insertGroupStart) + " ms.");
|
||||
|
||||
long updateGroupStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting group recipient ID updates.");
|
||||
try (Cursor cursor = db.rawQuery("SELECT _id, members FROM groups", null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long groupId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
|
||||
String serializedMembers = cursor.getString(cursor.getColumnIndexOrThrow("members"));
|
||||
String[] members = DelimiterUtil.split(serializedMembers, ',');
|
||||
long[] memberIds = new long[members.length];
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
String member = DelimiterUtil.unescape(members[i], ',');
|
||||
memberIds[i] = requireRecipientId(db, member);
|
||||
}
|
||||
|
||||
String serializedMemberIds = Util.join(memberIds, ",");
|
||||
|
||||
db.execSQL("UPDATE groups SET members = ? WHERE _id = ?", new String[]{ serializedMemberIds, String.valueOf(groupId) });
|
||||
}
|
||||
}
|
||||
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS group_recipient_id_index ON groups (recipient_id)");
|
||||
Log.i(TAG, "Finished group recipient ID updates in " + (System.currentTimeMillis() - updateGroupStart) + " ms.");
|
||||
|
||||
|
||||
long tableCopyStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting to copy the recipient table.");
|
||||
db.execSQL("CREATE TABLE recipient (_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"uuid TEXT UNIQUE DEFAULT NULL, " +
|
||||
"phone TEXT UNIQUE DEFAULT NULL, " +
|
||||
"email TEXT UNIQUE DEFAULT NULL, " +
|
||||
"group_id TEXT UNIQUE DEFAULT NULL, " +
|
||||
"blocked INTEGER DEFAULT 0, " +
|
||||
"message_ringtone TEXT DEFAULT NULL, " +
|
||||
"message_vibrate INTEGER DEFAULT 0, " +
|
||||
"call_ringtone TEXT DEFAULT NULL, " +
|
||||
"call_vibrate INTEGER DEFAULT 0, " +
|
||||
"notification_channel TEXT DEFAULT NULL, " +
|
||||
"mute_until INTEGER DEFAULT 0, " +
|
||||
"color TEXT DEFAULT NULL, " +
|
||||
"seen_invite_reminder INTEGER DEFAULT 0, " +
|
||||
"default_subscription_id INTEGER DEFAULT -1, " +
|
||||
"message_expiration_time INTEGER DEFAULT 0, " +
|
||||
"registered INTEGER DEFAULT 0, " +
|
||||
"system_display_name TEXT DEFAULT NULL, " +
|
||||
"system_photo_uri TEXT DEFAULT NULL, " +
|
||||
"system_phone_label TEXT DEFAULT NULL, " +
|
||||
"system_contact_uri TEXT DEFAULT NULL, " +
|
||||
"profile_key TEXT DEFAULT NULL, " +
|
||||
"signal_profile_name TEXT DEFAULT NULL, " +
|
||||
"signal_profile_avatar TEXT DEFAULT NULL, " +
|
||||
"profile_sharing INTEGER DEFAULT 0, " +
|
||||
"unidentified_access_mode INTEGER DEFAULT 0, " +
|
||||
"force_sms_selection INTEGER DEFAULT 0)");
|
||||
|
||||
try (Cursor cursor = db.query("recipient_preferences", null, null, null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||
boolean isGroup = GroupUtil.isEncodedGroup(address);
|
||||
boolean isEmail = !isGroup && NumberUtil.isValidEmail(address);
|
||||
boolean isPhone = !isGroup && !isEmail;
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
values.put("_id", cursor.getLong(cursor.getColumnIndexOrThrow("_id")));
|
||||
values.put("uuid", (String) null);
|
||||
values.put("phone", isPhone ? address : null);
|
||||
values.put("email", isEmail ? address : null);
|
||||
values.put("group_id", isGroup ? address : null);
|
||||
values.put("blocked", cursor.getInt(cursor.getColumnIndexOrThrow("block")));
|
||||
values.put("message_ringtone", cursor.getString(cursor.getColumnIndexOrThrow("notification")));
|
||||
values.put("message_vibrate", cursor.getString(cursor.getColumnIndexOrThrow("vibrate")));
|
||||
values.put("call_ringtone", cursor.getString(cursor.getColumnIndexOrThrow("call_ringtone")));
|
||||
values.put("call_vibrate", cursor.getString(cursor.getColumnIndexOrThrow("call_vibrate")));
|
||||
values.put("notification_channel", cursor.getString(cursor.getColumnIndexOrThrow("notification_channel")));
|
||||
values.put("mute_until", cursor.getLong(cursor.getColumnIndexOrThrow("mute_until")));
|
||||
values.put("color", cursor.getString(cursor.getColumnIndexOrThrow("color")));
|
||||
values.put("seen_invite_reminder", cursor.getInt(cursor.getColumnIndexOrThrow("seen_invite_reminder")));
|
||||
values.put("default_subscription_id", cursor.getInt(cursor.getColumnIndexOrThrow("default_subscription_id")));
|
||||
values.put("message_expiration_time", cursor.getInt(cursor.getColumnIndexOrThrow("expire_messages")));
|
||||
values.put("registered", cursor.getInt(cursor.getColumnIndexOrThrow("registered")));
|
||||
values.put("system_display_name", cursor.getString(cursor.getColumnIndexOrThrow("system_display_name")));
|
||||
values.put("system_photo_uri", cursor.getString(cursor.getColumnIndexOrThrow("system_contact_photo")));
|
||||
values.put("system_phone_label", cursor.getString(cursor.getColumnIndexOrThrow("system_phone_label")));
|
||||
values.put("system_contact_uri", cursor.getString(cursor.getColumnIndexOrThrow("system_contact_uri")));
|
||||
values.put("profile_key", cursor.getString(cursor.getColumnIndexOrThrow("profile_key")));
|
||||
values.put("signal_profile_name", cursor.getString(cursor.getColumnIndexOrThrow("signal_profile_name")));
|
||||
values.put("signal_profile_avatar", cursor.getString(cursor.getColumnIndexOrThrow("signal_profile_avatar")));
|
||||
values.put("profile_sharing", cursor.getInt(cursor.getColumnIndexOrThrow("profile_sharing_approval")));
|
||||
values.put("unidentified_access_mode", cursor.getInt(cursor.getColumnIndexOrThrow("unidentified_access_mode")));
|
||||
values.put("force_sms_selection", cursor.getInt(cursor.getColumnIndexOrThrow("force_sms_selection")));
|
||||
|
||||
db.insert("recipient", null, values);
|
||||
}
|
||||
}
|
||||
|
||||
db.execSQL("DROP TABLE recipient_preferences");
|
||||
Log.i(TAG, "Finished copying the recipient table in " + (System.currentTimeMillis() - tableCopyStart) + " ms.");
|
||||
|
||||
long sanityCheckStart = System.currentTimeMillis();
|
||||
|
||||
Log.i(TAG, "Starting DB integrity sanity checks.");
|
||||
assertEmptyQuery(db, "identities", buildSanityCheckQuery("identities", "address"));
|
||||
assertEmptyQuery(db, "sessions", buildSanityCheckQuery("sessions", "address"));
|
||||
assertEmptyQuery(db, "groups", buildSanityCheckQuery("groups", "recipient_id"));
|
||||
assertEmptyQuery(db, "thread", buildSanityCheckQuery("thread", "recipient_ids"));
|
||||
assertEmptyQuery(db, "sms", buildSanityCheckQuery("sms", "address"));
|
||||
assertEmptyQuery(db, "mms -- address", buildSanityCheckQuery("mms", "address"));
|
||||
assertEmptyQuery(db, "mms -- quote_author", buildSanityCheckQuery("mms", "quote_author"));
|
||||
assertEmptyQuery(db, "group_receipts", buildSanityCheckQuery("group_receipts", "address"));
|
||||
Log.i(TAG, "Finished DB integrity sanity checks in " + (System.currentTimeMillis() - sanityCheckStart) + " ms.");
|
||||
|
||||
Log.i(TAG, "Finished recipient ID migration in " + (System.currentTimeMillis() - insertStart) + " ms.");
|
||||
}
|
||||
|
||||
private static String buildUpdateAddressToRecipientIdStatement(@NonNull String table, @NonNull String addressColumn) {
|
||||
return "UPDATE " + table + " SET " + addressColumn + "=(SELECT _id " +
|
||||
"FROM recipient_preferences " +
|
||||
"WHERE recipient_preferences.recipient_ids = " + table + "." + addressColumn + ")";
|
||||
}
|
||||
|
||||
private static String buildInsertMissingRecipientStatement(@NonNull String table, @NonNull String addressColumn) {
|
||||
return "INSERT INTO recipient_preferences(recipient_ids) SELECT DISTINCT " + addressColumn + " " +
|
||||
"FROM " + table + " " +
|
||||
"WHERE " + addressColumn + " != '' AND " +
|
||||
addressColumn + " != 'insert-address-column' AND " +
|
||||
addressColumn + " NOT NULL AND " +
|
||||
addressColumn + " NOT IN (SELECT recipient_ids FROM recipient_preferences)";
|
||||
}
|
||||
|
||||
private static String buildMissingAddressUpdateStatement(@NonNull String table, @NonNull String addressColumn) {
|
||||
return "UPDATE " + table + " SET " + addressColumn + " = -1 " +
|
||||
"WHERE " + addressColumn + " = '' OR " +
|
||||
addressColumn + " IS NULL OR " +
|
||||
addressColumn + " = 'insert-address-token'";
|
||||
}
|
||||
|
||||
private static boolean recipientExists(@NonNull SQLiteDatabase db, @NonNull String address) {
|
||||
return getRecipientId(db, address) != null;
|
||||
}
|
||||
|
||||
private static @Nullable Long getRecipientId(@NonNull SQLiteDatabase db, @NonNull String address) {
|
||||
try (Cursor cursor = db.rawQuery("SELECT _id FROM recipient_preferences WHERE recipient_ids = ?", new String[]{ address })) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getLong(cursor.getColumnIndex("_id"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long requireRecipientId(@NonNull SQLiteDatabase db, @NonNull String address) {
|
||||
Long id = getRecipientId(db, address);
|
||||
|
||||
if (id != null) {
|
||||
return id;
|
||||
} else {
|
||||
throw new MissingRecipientError(address);
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildSanityCheckQuery(@NonNull String table, @NonNull String idColumn) {
|
||||
return "SELECT " + idColumn + " FROM " + table + " WHERE " + idColumn + " != -1 AND " + idColumn + " NOT IN (SELECT _id FROM recipient)";
|
||||
}
|
||||
|
||||
private static void assertEmptyQuery(@NonNull SQLiteDatabase db, @NonNull String tag, @NonNull String query) {
|
||||
try (Cursor cursor = db.rawQuery(query, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
throw new FailedSanityCheckError(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MissingRecipientError extends AssertionError {
|
||||
MissingRecipientError(@NonNull String address) {
|
||||
super("Could not find recipient with address " + address);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FailedSanityCheckError extends AssertionError {
|
||||
FailedSanityCheckError(@NonNull String tableName) {
|
||||
super("Sanity check failed for tag '" + tableName + "'");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ import android.database.Cursor;
|
|||
import android.net.Uri;
|
||||
import android.os.SystemClock;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
|
@ -36,8 +38,13 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
|||
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -68,8 +75,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
private static final int STICKERS = 21;
|
||||
private static final int REVEALABLE_MESSAGES = 22;
|
||||
private static final int VIEW_ONCE_ONLY = 23;
|
||||
private static final int RECIPIENT_IDS = 24;
|
||||
|
||||
private static final int DATABASE_VERSION = 23;
|
||||
private static final int DATABASE_VERSION = 25;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
|
@ -287,18 +295,18 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
|
||||
try (Cursor cursor = db.rawQuery("SELECT recipient_ids, system_display_name, signal_profile_name, notification, vibrate FROM recipient_preferences WHERE notification NOT NULL OR vibrate != 0", null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
String addressString = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||
Address address = Address.fromExternal(context, addressString);
|
||||
String rawAddress = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||
String address = PhoneNumberFormatter.get(context).format(rawAddress);
|
||||
String systemName = cursor.getString(cursor.getColumnIndexOrThrow("system_display_name"));
|
||||
String profileName = cursor.getString(cursor.getColumnIndexOrThrow("signal_profile_name"));
|
||||
String messageSound = cursor.getString(cursor.getColumnIndexOrThrow("notification"));
|
||||
Uri messageSoundUri = messageSound != null ? Uri.parse(messageSound) : null;
|
||||
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow("vibrate"));
|
||||
String displayName = NotificationChannels.getChannelDisplayNameFor(context, systemName, profileName, address);
|
||||
String displayName = NotificationChannels.getChannelDisplayNameFor(context, systemName, profileName, Address.fromSerialized(address));
|
||||
boolean vibrateEnabled = vibrateState == 0 ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == 1;
|
||||
|
||||
if (address.isGroup()) {
|
||||
try(Cursor groupCursor = db.rawQuery("SELECT title FROM groups WHERE group_id = ?", new String[] { address.toGroupString() })) {
|
||||
if (GroupUtil.isEncodedGroup(address)) {
|
||||
try(Cursor groupCursor = db.rawQuery("SELECT title FROM groups WHERE group_id = ?", new String[] { address })) {
|
||||
if (groupCursor != null && groupCursor.moveToFirst()) {
|
||||
String title = groupCursor.getString(groupCursor.getColumnIndexOrThrow("title"));
|
||||
|
||||
|
@ -309,11 +317,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
}
|
||||
}
|
||||
|
||||
String channelId = NotificationChannels.createChannelFor(context, address, displayName, messageSoundUri, vibrateEnabled);
|
||||
String channelId = NotificationChannels.createChannelFor(context, Address.fromSerialized(address), displayName, messageSoundUri, vibrateEnabled);
|
||||
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put("notification_channel", channelId);
|
||||
db.update("recipient_preferences", values, "recipient_ids = ?", new String[] { addressString });
|
||||
db.update("recipient_preferences", values, "recipient_ids = ?", new String[] { rawAddress });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,6 +486,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
db.execSQL("UPDATE mms SET reveal_start_time = 0");
|
||||
}
|
||||
|
||||
if (oldVersion < RECIPIENT_IDS) {
|
||||
RecipientIdMigrationHelper.execute(db);
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
|
|
@ -79,7 +79,7 @@ class SessionStoreMigrationHelper {
|
|||
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(SessionDatabase.ADDRESS, address.serialize());
|
||||
contentValues.put(SessionDatabase.RECIPIENT_ID, address.serialize());
|
||||
contentValues.put(SessionDatabase.DEVICE, deviceId);
|
||||
contentValues.put(SessionDatabase.RECORD, sessionRecord.serialize());
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public class IdentityRecordList {
|
|||
|
||||
for (IdentityRecord identityRecord : identityRecords) {
|
||||
if (isUntrusted(identityRecord)) {
|
||||
untrusted.add(Recipient.from(context, identityRecord.getAddress(), false));
|
||||
untrusted.add(Recipient.resolved(identityRecord.getRecipientId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ public class IdentityRecordList {
|
|||
|
||||
for (IdentityRecord identityRecord : identityRecords) {
|
||||
if (identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED) {
|
||||
unverified.add(Recipient.from(context, identityRecord.getAddress(), false));
|
||||
unverified.add(Recipient.resolved(identityRecord.getRecipientId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@ public class BlockedContactsLoader extends AbstractCursorLoader {
|
|||
|
||||
@Override
|
||||
public Cursor getCursor() {
|
||||
return DatabaseFactory.getRecipientDatabase(getContext())
|
||||
.getBlocked();
|
||||
return DatabaseFactory.getRecipientDatabase(getContext()).getBlocked();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.Address;
|
|||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -31,13 +32,13 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
|||
@SuppressWarnings("unused")
|
||||
private static final String TAG = BucketedThreadMediaLoader.class.getSimpleName();
|
||||
|
||||
private final Address address;
|
||||
private final RecipientId recipientId;
|
||||
private final ContentObserver observer;
|
||||
|
||||
public BucketedThreadMediaLoader(@NonNull Context context, @NonNull Address address) {
|
||||
public BucketedThreadMediaLoader(@NonNull Context context, @NonNull RecipientId recipientId) {
|
||||
super(context);
|
||||
this.address = address;
|
||||
this.observer = new ForceLoadContentObserver();
|
||||
this.recipientId = recipientId;
|
||||
this.observer = new ForceLoadContentObserver();
|
||||
|
||||
onContentChanged();
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
|||
@Override
|
||||
public BucketedThreadMedia loadInBackground() {
|
||||
BucketedThreadMedia result = new BucketedThreadMedia(getContext());
|
||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.from(getContext(), address, true));
|
||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.resolved(recipientId));
|
||||
|
||||
DatabaseFactory.getMediaDatabase(getContext()).subscribeToMediaChanges(observer);
|
||||
try (Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId)) {
|
||||
|
|
|
@ -9,6 +9,9 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
|||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
@ -42,7 +45,7 @@ public class ConversationListLoader extends AbstractCursorLoader {
|
|||
if (archivedCount > 0) {
|
||||
MatrixCursor switchToArchiveCursor = new MatrixCursor(new String[] {
|
||||
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
||||
ThreadDatabase.ADDRESS, ThreadDatabase.SNIPPET, ThreadDatabase.READ, ThreadDatabase.UNREAD_COUNT,
|
||||
ThreadDatabase.RECIPIENT_ID, ThreadDatabase.SNIPPET, ThreadDatabase.READ, ThreadDatabase.UNREAD_COUNT,
|
||||
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
||||
ThreadDatabase.SNIPPET_CONTENT_TYPE, ThreadDatabase.SNIPPET_EXTRAS,
|
||||
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.DELIVERY_RECEIPT_COUNT,
|
||||
|
@ -70,13 +73,13 @@ public class ConversationListLoader extends AbstractCursorLoader {
|
|||
}
|
||||
|
||||
private Cursor getFilteredConversationList(String filter) {
|
||||
List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(context, filter);
|
||||
List<Address> addresses = new LinkedList<>();
|
||||
List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(context, filter);
|
||||
List<RecipientId> recipientIds = new LinkedList<>();
|
||||
|
||||
for (String number : numbers) {
|
||||
addresses.add(Address.fromExternal(context, number));
|
||||
recipientIds.add(Recipient.external(context, number).getId());
|
||||
}
|
||||
|
||||
return DatabaseFactory.getThreadDatabase(context).getFilteredConversationList(addresses);
|
||||
return DatabaseFactory.getThreadDatabase(context).getFilteredConversationList(recipientIds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,29 +8,30 @@ import androidx.annotation.NonNull;
|
|||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
||||
|
||||
public class ThreadMediaLoader extends AbstractCursorLoader {
|
||||
|
||||
private final Address address;
|
||||
private final boolean gallery;
|
||||
private final RecipientId recipientId;
|
||||
private final boolean gallery;
|
||||
|
||||
public ThreadMediaLoader(@NonNull Context context, @NonNull Address address, boolean gallery) {
|
||||
public ThreadMediaLoader(@NonNull Context context, @NonNull RecipientId recipientId, boolean gallery) {
|
||||
super(context);
|
||||
this.address = address;
|
||||
this.gallery = gallery;
|
||||
this.recipientId = recipientId;
|
||||
this.gallery = gallery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getCursor() {
|
||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.from(getContext(), address, true));
|
||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.resolved(recipientId));
|
||||
|
||||
if (gallery) return DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId);
|
||||
else return DatabaseFactory.getMediaDatabase(getContext()).getDocumentMediaForThread(threadId);
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
public RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,16 +6,18 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
public class Quote {
|
||||
|
||||
private final long id;
|
||||
private final Address author;
|
||||
private final String text;
|
||||
private final boolean missing;
|
||||
private final SlideDeck attachment;
|
||||
private final long id;
|
||||
private final RecipientId author;
|
||||
private final String text;
|
||||
private final boolean missing;
|
||||
private final SlideDeck attachment;
|
||||
|
||||
public Quote(long id, @NonNull Address author, @Nullable String text, boolean missing, @NonNull SlideDeck attachment) {
|
||||
public Quote(long id, @NonNull RecipientId author, @Nullable String text, boolean missing, @NonNull SlideDeck attachment) {
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.text = text;
|
||||
|
@ -27,7 +29,7 @@ public class Quote {
|
|||
return id;
|
||||
}
|
||||
|
||||
public @NonNull Address getAuthor() {
|
||||
public @NonNull RecipientId getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import android.text.style.StyleSpan;
|
|||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase.Extra;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||
|
@ -111,7 +110,7 @@ public class ThreadRecord extends DisplayRecord {
|
|||
String time = ExpirationUtil.getExpirationDisplayValue(context, seconds);
|
||||
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time));
|
||||
} else if (SmsDatabase.Types.isIdentityUpdate(type)) {
|
||||
if (getRecipient().isGroupRecipient()) return emphasisAdded(context.getString(R.string.ThreadRecord_safety_number_changed));
|
||||
if (getRecipient().isGroup()) return emphasisAdded(context.getString(R.string.ThreadRecord_safety_number_changed));
|
||||
else return emphasisAdded(context.getString(R.string.ThreadRecord_your_safety_number_with_s_has_changed, getRecipient().toShortString()));
|
||||
} else if (SmsDatabase.Types.isIdentityVerified(type)) {
|
||||
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_verified));
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package org.thoughtcrime.securesms.dependencies;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.IncomingMessageProcessor;
|
||||
import org.thoughtcrime.securesms.gcm.MessageRetriever;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipientCache;
|
||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
|
@ -32,6 +32,7 @@ public class ApplicationDependencies {
|
|||
private static SignalServiceMessageReceiver messageReceiver;
|
||||
private static IncomingMessageProcessor incomingMessageProcessor;
|
||||
private static MessageRetriever messageRetriever;
|
||||
private static LiveRecipientCache recipientCache;
|
||||
|
||||
public static synchronized void init(@NonNull Application application, @NonNull Provider provider) {
|
||||
if (ApplicationDependencies.application != null || ApplicationDependencies.provider != null) {
|
||||
|
@ -105,6 +106,16 @@ public class ApplicationDependencies {
|
|||
return messageRetriever;
|
||||
}
|
||||
|
||||
public static synchronized @NonNull LiveRecipientCache getRecipientCache() {
|
||||
assertInitialization();
|
||||
|
||||
if (recipientCache == null) {
|
||||
recipientCache = provider.provideRecipientCache();
|
||||
}
|
||||
|
||||
return recipientCache;
|
||||
}
|
||||
|
||||
private static void assertInitialization() {
|
||||
if (application == null || provider == null) {
|
||||
throw new UninitializedException();
|
||||
|
@ -118,6 +129,8 @@ public class ApplicationDependencies {
|
|||
@NonNull SignalServiceNetworkAccess provideSignalServiceNetworkAccess();
|
||||
@NonNull IncomingMessageProcessor provideIncomingMessageProcessor();
|
||||
@NonNull MessageRetriever provideMessageRetriever();
|
||||
@NonNull
|
||||
LiveRecipientCache provideRecipientCache();
|
||||
}
|
||||
|
||||
private static class UninitializedException extends IllegalStateException {
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.gcm.MessageRetriever;
|
|||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.push.SecurityEventListener;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipientCache;
|
||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -85,6 +86,12 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
|
|||
return new MessageRetriever();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull
|
||||
LiveRecipientCache provideRecipientCache() {
|
||||
return new LiveRecipientCache(context);
|
||||
}
|
||||
|
||||
private static class DynamicCredentialsProvider implements CredentialsProvider {
|
||||
|
||||
private final Context context;
|
||||
|
|
|
@ -118,6 +118,6 @@ public class WebRtcViewModel {
|
|||
}
|
||||
|
||||
public @NonNull String toString() {
|
||||
return "[State: " + state + ", recipient: " + recipient.getAddress() + ", identity: " + identityKey + ", remoteVideo: " + remoteVideoEnabled + ", localVideo: " + localCameraState.isEnabled() + "]";
|
||||
return "[State: " + state + ", recipient: " + recipient.requireAddress() + ", identity: " + identityKey + ", remoteVideo: " + remoteVideoEnabled + ", localVideo: " + localCameraState.isEnabled() + "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -22,7 +23,7 @@ public final class GroupManager {
|
|||
@Nullable String name,
|
||||
boolean mms)
|
||||
{
|
||||
Set<Address> addresses = getMemberAddresses(members);
|
||||
Set<RecipientId> addresses = getMemberIds(members);
|
||||
|
||||
return V1GroupManager.createGroup(context, addresses, avatar, name, mms);
|
||||
}
|
||||
|
@ -34,15 +35,15 @@ public final class GroupManager {
|
|||
@Nullable String name)
|
||||
throws InvalidNumberException
|
||||
{
|
||||
Set<Address> addresses = getMemberAddresses(members);
|
||||
Set<RecipientId> addresses = getMemberIds(members);
|
||||
|
||||
return V1GroupManager.updateGroup(context, groupId, addresses, avatar, name);
|
||||
}
|
||||
|
||||
private static Set<Address> getMemberAddresses(Collection<Recipient> recipients) {
|
||||
final Set<Address> results = new HashSet<>();
|
||||
private static Set<RecipientId> getMemberIds(Collection<Recipient> recipients) {
|
||||
final Set<RecipientId> results = new HashSet<>();
|
||||
for (Recipient recipient : recipients) {
|
||||
results.add(recipient.getAddress());
|
||||
results.add(recipient.getId());
|
||||
}
|
||||
|
||||
return results;
|
||||
|
|
|
@ -8,7 +8,6 @@ import androidx.annotation.Nullable;
|
|||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
||||
|
@ -21,6 +20,7 @@ import org.thoughtcrime.securesms.mms.MmsException;
|
|||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
|
@ -86,11 +86,11 @@ public class GroupMessageProcessor {
|
|||
builder.setType(GroupContext.Type.UPDATE);
|
||||
|
||||
SignalServiceAttachment avatar = group.getAvatar().orNull();
|
||||
List<Address> members = group.getMembers().isPresent() ? new LinkedList<Address>() : null;
|
||||
List<RecipientId> members = new LinkedList<>();
|
||||
|
||||
if (group.getMembers().isPresent()) {
|
||||
for (String member : group.getMembers().get()) {
|
||||
members.add(Address.fromExternal(context, member));
|
||||
members.add(Recipient.external(context, member).getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,31 +110,31 @@ public class GroupMessageProcessor {
|
|||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
|
||||
|
||||
Set<Address> recordMembers = new HashSet<>(groupRecord.getMembers());
|
||||
Set<Address> messageMembers = new HashSet<>();
|
||||
Set<RecipientId> recordMembers = new HashSet<>(groupRecord.getMembers());
|
||||
Set<RecipientId> messageMembers = new HashSet<>();
|
||||
|
||||
for (String messageMember : group.getMembers().get()) {
|
||||
messageMembers.add(Address.fromExternal(context, messageMember));
|
||||
messageMembers.add(Recipient.external(context, messageMember).getId());
|
||||
}
|
||||
|
||||
Set<Address> addedMembers = new HashSet<>(messageMembers);
|
||||
Set<RecipientId> addedMembers = new HashSet<>(messageMembers);
|
||||
addedMembers.removeAll(recordMembers);
|
||||
|
||||
Set<Address> missingMembers = new HashSet<>(recordMembers);
|
||||
Set<RecipientId> missingMembers = new HashSet<>(recordMembers);
|
||||
missingMembers.removeAll(messageMembers);
|
||||
|
||||
GroupContext.Builder builder = createGroupContext(group);
|
||||
builder.setType(GroupContext.Type.UPDATE);
|
||||
|
||||
if (addedMembers.size() > 0) {
|
||||
Set<Address> unionMembers = new HashSet<>(recordMembers);
|
||||
Set<RecipientId> unionMembers = new HashSet<>(recordMembers);
|
||||
unionMembers.addAll(messageMembers);
|
||||
database.updateMembers(id, new LinkedList<>(unionMembers));
|
||||
|
||||
builder.clearMembers();
|
||||
|
||||
for (Address addedMember : addedMembers) {
|
||||
builder.addMembers(addedMember.serialize());
|
||||
for (RecipientId addedMember : addedMembers) {
|
||||
builder.addMembers(Recipient.resolved(addedMember).requireAddress().serialize());
|
||||
}
|
||||
} else {
|
||||
builder.clearMembers();
|
||||
|
@ -163,10 +163,12 @@ public class GroupMessageProcessor {
|
|||
@NonNull SignalServiceGroup group,
|
||||
@NonNull GroupRecord record)
|
||||
{
|
||||
if (record.getMembers().contains(Address.fromExternal(context, content.getSender()))) {
|
||||
Recipient sender = Recipient.external(context, content.getSender());
|
||||
|
||||
if (record.getMembers().contains(sender.getId())) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new PushGroupUpdateJob(content.getSender(), group.getGroupId()));
|
||||
.add(new PushGroupUpdateJob(sender.getId(), group.getGroupId()));
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -178,15 +180,15 @@ public class GroupMessageProcessor {
|
|||
@NonNull GroupRecord record,
|
||||
boolean outgoing)
|
||||
{
|
||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
|
||||
List<Address> members = record.getMembers();
|
||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
|
||||
List<RecipientId> members = record.getMembers();
|
||||
|
||||
GroupContext.Builder builder = createGroupContext(group);
|
||||
builder.setType(GroupContext.Type.QUIT);
|
||||
|
||||
if (members.contains(Address.fromExternal(context, content.getSender()))) {
|
||||
database.remove(id, Address.fromExternal(context, content.getSender()));
|
||||
if (members.contains(Recipient.external(context, content.getSender()).getId())) {
|
||||
database.remove(id, Recipient.external(context, content.getSender()).getId());
|
||||
if (outgoing) database.setActive(id, false);
|
||||
|
||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||
|
@ -210,8 +212,8 @@ public class GroupMessageProcessor {
|
|||
try {
|
||||
if (outgoing) {
|
||||
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||
Address addres = Address.fromExternal(context, GroupUtil.getEncodedId(group.getGroupId(), false));
|
||||
Recipient recipient = Recipient.from(context, addres, false);
|
||||
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupUtil.getEncodedId(group.getGroupId(), false));
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, false, null, Collections.emptyList(), Collections.emptyList());
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
|
||||
|
@ -222,7 +224,7 @@ public class GroupMessageProcessor {
|
|||
} else {
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
String body = Base64.encodeBytes(storage.toByteArray());
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(Address.fromExternal(context, content.getSender()), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(group), 0, content.isNeedsReceipt());
|
||||
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.external(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(group), 0, content.isNeedsReceipt());
|
||||
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
||||
|
||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
||||
|
|
|
@ -10,7 +10,6 @@ import com.google.protobuf.ByteString;
|
|||
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
|
@ -19,6 +18,7 @@ import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
|
|||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
|
@ -28,50 +28,49 @@ import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
final class V1GroupManager {
|
||||
|
||||
static @NonNull GroupActionResult createGroup(@NonNull Context context,
|
||||
@NonNull Set<Address> memberAddresses,
|
||||
@Nullable Bitmap avatar,
|
||||
@Nullable String name,
|
||||
boolean mms)
|
||||
static @NonNull GroupActionResult createGroup(@NonNull Context context,
|
||||
@NonNull Set<RecipientId> memberIds,
|
||||
@Nullable Bitmap avatar,
|
||||
@Nullable String name,
|
||||
boolean mms)
|
||||
{
|
||||
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
final String groupId = GroupUtil.getEncodedId(groupDatabase.allocateGroupId(), mms);
|
||||
final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), false);
|
||||
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
final String groupId = GroupUtil.getEncodedId(groupDatabase.allocateGroupId(), mms);
|
||||
final RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
final Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||
|
||||
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
||||
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null);
|
||||
memberIds.add(Recipient.external(context, TextSecurePreferences.getLocalNumber(context)).getId());
|
||||
groupDatabase.create(groupId, name, new LinkedList<>(memberIds), null, null);
|
||||
|
||||
if (!mms) {
|
||||
groupDatabase.updateAvatar(groupId, avatarBytes);
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true);
|
||||
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes);
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
|
||||
return sendGroupUpdate(context, groupId, memberIds, name, avatarBytes);
|
||||
} else {
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||
return new GroupActionResult(groupRecipient, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
static GroupActionResult updateGroup(@NonNull Context context,
|
||||
@NonNull String groupId,
|
||||
@NonNull Set<Address> memberAddresses,
|
||||
@Nullable Bitmap avatar,
|
||||
@Nullable String name)
|
||||
static GroupActionResult updateGroup(@NonNull Context context,
|
||||
@NonNull String groupId,
|
||||
@NonNull Set<RecipientId> memberAddresses,
|
||||
@Nullable Bitmap avatar,
|
||||
@Nullable String name)
|
||||
throws InvalidNumberException
|
||||
{
|
||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
||||
|
||||
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
||||
memberAddresses.add(Recipient.external(context, TextSecurePreferences.getLocalNumber(context)).getId());
|
||||
groupDatabase.updateMembers(groupId, new LinkedList<>(memberAddresses));
|
||||
groupDatabase.updateTitle(groupId, name);
|
||||
groupDatabase.updateAvatar(groupId, avatarBytes);
|
||||
|
@ -79,27 +78,28 @@ final class V1GroupManager {
|
|||
if (!GroupUtil.isMmsGroup(groupId)) {
|
||||
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes);
|
||||
} else {
|
||||
Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), true);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||
return new GroupActionResult(groupRecipient, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
||||
@NonNull String groupId,
|
||||
@NonNull Set<Address> members,
|
||||
@Nullable String groupName,
|
||||
@Nullable byte[] avatar)
|
||||
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
||||
@NonNull String groupId,
|
||||
@NonNull Set<RecipientId> members,
|
||||
@Nullable String groupName,
|
||||
@Nullable byte[] avatar)
|
||||
{
|
||||
try {
|
||||
Attachment avatarAttachment = null;
|
||||
Address groupAddress = Address.fromSerialized(groupId);
|
||||
Recipient groupRecipient = Recipient.from(context, groupAddress, false);
|
||||
Attachment avatarAttachment = null;
|
||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||
|
||||
List<String> numbers = new LinkedList<>();
|
||||
|
||||
for (Address member : members) {
|
||||
numbers.add(member.serialize());
|
||||
for (RecipientId member : members) {
|
||||
numbers.add(Recipient.resolved(member).requireAddress().serialize());
|
||||
}
|
||||
|
||||
GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
|
||||
|
|
|
@ -27,23 +27,23 @@ public abstract class JobMigration {
|
|||
return endVersion;
|
||||
}
|
||||
|
||||
protected static class JobData {
|
||||
public static class JobData {
|
||||
|
||||
private final String factoryKey;
|
||||
private final String queueKey;
|
||||
private final Data data;
|
||||
|
||||
JobData(@NonNull String factoryKey, @Nullable String queueKey, @NonNull Data data) {
|
||||
public JobData(@NonNull String factoryKey, @Nullable String queueKey, @NonNull Data data) {
|
||||
this.factoryKey = factoryKey;
|
||||
this.queueKey = queueKey;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
protected @NonNull JobData withQueueKey(@Nullable String newQueueKey) {
|
||||
public @NonNull JobData withQueueKey(@Nullable String newQueueKey) {
|
||||
return new JobData(factoryKey, newQueueKey, data);
|
||||
}
|
||||
|
||||
protected @NonNull JobData withData(@NonNull Data newData) {
|
||||
public @NonNull JobData withData(@NonNull Data newData) {
|
||||
return new JobData(factoryKey, queueKey, newData);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class RecipientIdJobMigration extends JobMigration {
|
||||
|
||||
private final Application application;
|
||||
|
||||
public RecipientIdJobMigration(@NonNull Application application) {
|
||||
super(2);
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull JobData migrate(@NonNull JobData jobData) {
|
||||
switch(jobData.getFactoryKey()) {
|
||||
case "MultiDeviceContactUpdateJob": return migrateMultiDeviceContactUpdateJob(jobData);
|
||||
case "MultiDeviceRevealUpdateJob": return migrateMultiDeviceViewOnceOpenJob(jobData);
|
||||
case "RequestGroupInfoJob": return migrateRequestGroupInfoJob(jobData);
|
||||
case "SendDeliveryReceiptJob": return migrateSendDeliveryReceiptJob(jobData);
|
||||
case "MultiDeviceVerifiedUpdateJob": return migrateMultiDeviceVerifiedUpdateJob(jobData);
|
||||
case "RetrieveProfileJob": return migrateRetrieveProfileJob(jobData);
|
||||
case "PushGroupSendJob": return migratePushGroupSendJob(jobData);
|
||||
case "PushGroupUpdateJob": return migratePushGroupUpdateJob(jobData);
|
||||
case "DirectoryRefreshJob": return migrateDirectoryRefreshJob(jobData);
|
||||
case "RetrieveProfileAvatarJob": return migrateRetrieveProfileAvatarJob(jobData);
|
||||
case "MultiDeviceReadUpdateJob": return migrateMultiDeviceReadUpdateJob(jobData);
|
||||
case "PushTextSendJob": return migratePushTextSendJob(jobData);
|
||||
case "PushMediaSendJob": return migratePushMediaSendJob(jobData);
|
||||
case "SmsSendJob": return migrateSmsSendJob(jobData);
|
||||
default: return jobData;
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceContactUpdateJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("address");
|
||||
Data updatedData = new Data.Builder().putString("recipient", Recipient.external(application, address).getId().serialize())
|
||||
.putBoolean("force_sync", jobData.getData().getBoolean("force_sync"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceViewOnceOpenJob(@NonNull JobData jobData) {
|
||||
try {
|
||||
String rawOld = jobData.getData().getString("message_id");
|
||||
OldSerializableSyncMessageId old = JsonUtils.fromJson(rawOld, OldSerializableSyncMessageId.class);
|
||||
Recipient recipient = Recipient.external(application, old.sender);
|
||||
NewSerializableSyncMessageId updated = new NewSerializableSyncMessageId(recipient.getId().serialize(), old.timestamp);
|
||||
String rawUpdated = JsonUtils.toJson(updated);
|
||||
Data updatedData = new Data.Builder().putString("message_id", rawUpdated).build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateRequestGroupInfoJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("source");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("source", recipient.getId().serialize()).build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateSendDeliveryReceiptJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient.getId().serialize()).build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceVerifiedUpdateJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("destination");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("destination", recipient.getId().serialize())
|
||||
.putString("identity_key", jobData.getData().getString("identity_key"))
|
||||
.putInt("verified_status", jobData.getData().getInt("verified_status"))
|
||||
.putLong("timestamp", jobData.getData().getLong("timestamp"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateRetrieveProfileJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient.getId().serialize()).build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushGroupSendJob(@NonNull JobData jobData) {
|
||||
// noinspection ConstantConditions
|
||||
Recipient queueRecipient = Recipient.external(application, jobData.getQueueKey());
|
||||
String address = jobData.getData().getString("filter_address");
|
||||
RecipientId recipientId = address != null ? Recipient.external(application, address).getId() : null;
|
||||
Data updatedData = new Data.Builder().putString("filter_recipient", recipientId != null ? recipientId.serialize() : null)
|
||||
.putLong("message_id", jobData.getData().getLong("message_id"))
|
||||
.build();
|
||||
|
||||
return jobData.withQueueKey(queueRecipient.getId().toQueueKey())
|
||||
.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushGroupUpdateJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("source");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("source", recipient.getId().serialize())
|
||||
.putString("group_id", jobData.getData().getString("group_id"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateDirectoryRefreshJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("address");
|
||||
Recipient recipient = address != null ? Recipient.external(application, address) : null;
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient != null ? recipient.getId().serialize() : null)
|
||||
.putBoolean("notify_of_new_users", jobData.getData().getBoolean("notify_of_new_users"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateRetrieveProfileAvatarJob(@NonNull JobData jobData) {
|
||||
//noinspection ConstantConditions
|
||||
String queueAddress = jobData.getQueueKey().substring("RetrieveProfileAvatarJob".length());
|
||||
Recipient queueRecipient = Recipient.external(application, queueAddress);
|
||||
String address = jobData.getData().getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient.getId().serialize())
|
||||
.putString("profile_avatar", jobData.getData().getString("profile_avatar"))
|
||||
.build();
|
||||
|
||||
return jobData.withQueueKey("RetrieveProfileAvatarJob::" + queueRecipient.getId().toQueueKey())
|
||||
.withData(updatedData);
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceReadUpdateJob(@NonNull JobData jobData) {
|
||||
try {
|
||||
String[] rawOld = jobData.getData().getStringArray("message_ids");
|
||||
String[] rawUpdated = new String[rawOld.length];
|
||||
|
||||
for (int i = 0; i < rawOld.length; i++) {
|
||||
OldSerializableSyncMessageId old = JsonUtils.fromJson(rawOld[i], OldSerializableSyncMessageId.class);
|
||||
Recipient recipient = Recipient.external(application, old.sender);
|
||||
NewSerializableSyncMessageId updated = new NewSerializableSyncMessageId(recipient.getId().serialize(), old.timestamp);
|
||||
|
||||
rawUpdated[i] = JsonUtils.toJson(updated);
|
||||
}
|
||||
|
||||
Data updatedData = new Data.Builder().putStringArray("message_ids", rawUpdated).build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushTextSendJob(@NonNull JobData jobData) {
|
||||
//noinspection ConstantConditions
|
||||
Recipient recipient = Recipient.external(application, jobData.getQueueKey());
|
||||
return jobData.withQueueKey(recipient.getId().toQueueKey());
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushMediaSendJob(@NonNull JobData jobData) {
|
||||
//noinspection ConstantConditions
|
||||
Recipient recipient = Recipient.external(application, jobData.getQueueKey());
|
||||
return jobData.withQueueKey(recipient.getId().toQueueKey());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateSmsSendJob(@NonNull JobData jobData) {
|
||||
//noinspection ConstantConditions
|
||||
Recipient recipient = Recipient.external(application, jobData.getQueueKey());
|
||||
return jobData.withQueueKey(recipient.getId().toQueueKey());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class OldSerializableSyncMessageId implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty
|
||||
private final String sender;
|
||||
@JsonProperty
|
||||
private final long timestamp;
|
||||
|
||||
OldSerializableSyncMessageId(@JsonProperty("sender") String sender, @JsonProperty("timestamp") long timestamp) {
|
||||
this.sender = sender;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class NewSerializableSyncMessageId implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty
|
||||
private final String recipientId;
|
||||
@JsonProperty
|
||||
private final long timestamp;
|
||||
|
||||
NewSerializableSyncMessageId(@JsonProperty("recipientId") String recipientId, @JsonProperty("timestamp") long timestamp) {
|
||||
this.recipientId = recipientId;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,15 @@
|
|||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.app.Application;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.DirectoryHelper;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
|
@ -22,7 +21,7 @@ public class DirectoryRefreshJob extends BaseJob {
|
|||
|
||||
private static final String TAG = DirectoryRefreshJob.class.getSimpleName();
|
||||
|
||||
private static final String KEY_ADDRESS = "address";
|
||||
private static final String KEY_RECIPIENT = "recipient";
|
||||
private static final String KEY_NOTIFY_OF_NEW_USERS = "notify_of_new_users";
|
||||
|
||||
@Nullable private Recipient recipient;
|
||||
|
@ -53,7 +52,7 @@ public class DirectoryRefreshJob extends BaseJob {
|
|||
|
||||
@Override
|
||||
public @NonNull Data serialize() {
|
||||
return new Data.Builder().putString(KEY_ADDRESS, recipient != null ? recipient.getAddress().serialize() : null)
|
||||
return new Data.Builder().putString(KEY_RECIPIENT, recipient != null ? recipient.getId().serialize() : null)
|
||||
.putBoolean(KEY_NOTIFY_OF_NEW_USERS, notifyOfNewUsers)
|
||||
.build();
|
||||
}
|
||||
|
@ -85,18 +84,11 @@ public class DirectoryRefreshJob extends BaseJob {
|
|||
|
||||
public static final class Factory implements Job.Factory<DirectoryRefreshJob> {
|
||||
|
||||
private final Application application;
|
||||
|
||||
public Factory(@NonNull Application application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull DirectoryRefreshJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||
String serializedAddress = data.getString(KEY_ADDRESS);
|
||||
Address address = serializedAddress != null ? Address.fromSerialized(serializedAddress) : null;
|
||||
Recipient recipient = address != null ? Recipient.from(application, address, true) : null;
|
||||
boolean notifyOfNewUsers = data.getBoolean(KEY_NOTIFY_OF_NEW_USERS);
|
||||
String serialized = data.getString(KEY_RECIPIENT);
|
||||
Recipient recipient = serialized != null ? Recipient.resolved(RecipientId.from(serialized)) : null;
|
||||
boolean notifyOfNewUsers = data.getBoolean(KEY_NOTIFY_OF_NEW_USERS);
|
||||
|
||||
return new DirectoryRefreshJob(parameters, recipient, notifyOfNewUsers);
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver;
|
|||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
||||
import org.thoughtcrime.securesms.jobmanager.migrations.RecipientIdJobMigration;
|
||||
import org.thoughtcrime.securesms.migrations.DatabaseMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.LegacyMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.MigrationCompleteJob;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -35,7 +35,7 @@ public final class JobManagerFactories {
|
|||
put(AvatarDownloadJob.KEY, new AvatarDownloadJob.Factory());
|
||||
put(CleanPreKeysJob.KEY, new CleanPreKeysJob.Factory());
|
||||
put(CreateSignedPreKeyJob.KEY, new CreateSignedPreKeyJob.Factory());
|
||||
put(DirectoryRefreshJob.KEY, new DirectoryRefreshJob.Factory(application));
|
||||
put(DirectoryRefreshJob.KEY, new DirectoryRefreshJob.Factory());
|
||||
put(FcmRefreshJob.KEY, new FcmRefreshJob.Factory());
|
||||
put(LocalBackupJob.KEY, new LocalBackupJob.Factory());
|
||||
put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory());
|
||||
|
@ -61,13 +61,13 @@ public final class JobManagerFactories {
|
|||
put(RefreshPreKeysJob.KEY, new RefreshPreKeysJob.Factory());
|
||||
put(RefreshUnidentifiedDeliveryAbilityJob.KEY, new RefreshUnidentifiedDeliveryAbilityJob.Factory());
|
||||
put(RequestGroupInfoJob.KEY, new RequestGroupInfoJob.Factory());
|
||||
put(RetrieveProfileAvatarJob.KEY, new RetrieveProfileAvatarJob.Factory(application));
|
||||
put(RetrieveProfileJob.KEY, new RetrieveProfileJob.Factory(application));
|
||||
put(RetrieveProfileAvatarJob.KEY, new RetrieveProfileAvatarJob.Factory());
|
||||
put(RetrieveProfileJob.KEY, new RetrieveProfileJob.Factory());
|
||||
put(RotateCertificateJob.KEY, new RotateCertificateJob.Factory());
|
||||
put(RotateProfileKeyJob.KEY, new RotateProfileKeyJob.Factory());
|
||||
put(RotateSignedPreKeyJob.KEY, new RotateSignedPreKeyJob.Factory());
|
||||
put(SendDeliveryReceiptJob.KEY, new SendDeliveryReceiptJob.Factory());
|
||||
put(SendReadReceiptJob.KEY, new SendReadReceiptJob.Factory());
|
||||
put(SendReadReceiptJob.KEY, new SendReadReceiptJob.Factory(application));
|
||||
put(ServiceOutageDetectionJob.KEY, new ServiceOutageDetectionJob.Factory());
|
||||
put(SmsReceiveJob.KEY, new SmsReceiveJob.Factory());
|
||||
put(SmsSendJob.KEY, new SmsSendJob.Factory());
|
||||
|
@ -105,7 +105,7 @@ public final class JobManagerFactories {
|
|||
new SqlCipherMigrationConstraintObserver());
|
||||
}
|
||||
|
||||
public static List<JobMigration> getJobMigrations() {
|
||||
return Collections.emptyList();
|
||||
public static List<JobMigration> getJobMigrations(@NonNull Application application) {
|
||||
return Arrays.asList(new RecipientIdJobMigration(application));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.net.Uri;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
import com.google.android.mms.pdu_alt.CharacterSets;
|
||||
import com.google.android.mms.pdu_alt.EncodedStringValue;
|
||||
import com.google.android.mms.pdu_alt.PduBody;
|
||||
|
@ -28,6 +29,8 @@ import org.thoughtcrime.securesms.mms.MmsRadioException;
|
|||
import org.thoughtcrime.securesms.mms.PartParser;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
@ -39,6 +42,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -155,18 +159,6 @@ public class MmsDownloadJob extends BaseJob {
|
|||
handleDownloadError(messageId, threadId,
|
||||
MmsDatabase.Status.DOWNLOAD_SOFT_FAILURE,
|
||||
automatic);
|
||||
} catch (DuplicateMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
database.markAsDecryptDuplicate(messageId, threadId);
|
||||
} catch (LegacyMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
database.markAsLegacyVersion(messageId, threadId);
|
||||
} catch (NoSessionException e) {
|
||||
Log.w(TAG, e);
|
||||
database.markAsNoSession(messageId, threadId);
|
||||
} catch (InvalidMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
database.markAsDecryptFailed(messageId, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,40 +180,39 @@ public class MmsDownloadJob extends BaseJob {
|
|||
|
||||
private void storeRetrievedMms(String contentLocation,
|
||||
long messageId, long threadId, RetrieveConf retrieved,
|
||||
int subscriptionId, @Nullable Address notificationFrom)
|
||||
throws MmsException, NoSessionException, DuplicateMessageException, InvalidMessageException,
|
||||
LegacyMessageException
|
||||
int subscriptionId, @Nullable RecipientId notificationFrom)
|
||||
throws MmsException
|
||||
{
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Optional<Address> group = Optional.absent();
|
||||
Set<Address> members = new HashSet<>();
|
||||
String body = null;
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Optional<String> group = Optional.absent();
|
||||
Set<RecipientId> members = new HashSet<>();
|
||||
String body = null;
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
|
||||
Address from;
|
||||
RecipientId from;
|
||||
|
||||
if (retrieved.getFrom() != null) {
|
||||
from = Address.fromExternal(context, Util.toIsoString(retrieved.getFrom().getTextString()));
|
||||
from = Recipient.external(context, Util.toIsoString(retrieved.getFrom().getTextString())).getId();
|
||||
} else if (notificationFrom != null) {
|
||||
from = notificationFrom;
|
||||
} else {
|
||||
from = Address.UNKNOWN;
|
||||
from = RecipientId.UNKNOWN;
|
||||
}
|
||||
|
||||
if (retrieved.getTo() != null) {
|
||||
for (EncodedStringValue toValue : retrieved.getTo()) {
|
||||
members.add(Address.fromExternal(context, Util.toIsoString(toValue.getTextString())));
|
||||
members.add(Recipient.external(context, Util.toIsoString(toValue.getTextString())).getId());
|
||||
}
|
||||
}
|
||||
|
||||
if (retrieved.getCc() != null) {
|
||||
for (EncodedStringValue ccValue : retrieved.getCc()) {
|
||||
members.add(Address.fromExternal(context, Util.toIsoString(ccValue.getTextString())));
|
||||
members.add(Recipient.external(context, Util.toIsoString(ccValue.getTextString())).getId());
|
||||
}
|
||||
}
|
||||
|
||||
members.add(from);
|
||||
members.add(Address.fromExternal(context, TextSecurePreferences.getLocalNumber(context)));
|
||||
members.add(Recipient.self().getId());
|
||||
|
||||
if (retrieved.getBody() != null) {
|
||||
body = PartParser.getMessageText(retrieved.getBody());
|
||||
|
@ -244,7 +235,8 @@ public class MmsDownloadJob extends BaseJob {
|
|||
}
|
||||
|
||||
if (members.size() > 2) {
|
||||
group = Optional.of(Address.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), true)));
|
||||
List<RecipientId> recipients = new ArrayList<>(members);
|
||||
group = Optional.of(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(recipients, true));
|
||||
}
|
||||
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false, false, false);
|
||||
|
|
|
@ -101,7 +101,7 @@ public class MmsReceiveJob extends BaseJob {
|
|||
|
||||
private boolean isBlocked(GenericPdu pdu) {
|
||||
if (pdu.getFrom() != null && pdu.getFrom().getTextString() != null) {
|
||||
Recipient recipients = Recipient.from(context, Address.fromExternal(context, Util.toIsoString(pdu.getFrom().getTextString())), false);
|
||||
Recipient recipients = Recipient.external(context, Util.toIsoString(pdu.getFrom().getTextString()));
|
||||
return recipients.isBlocked();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
|||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
|
@ -221,7 +221,7 @@ public final class MmsSendJob extends SendJob {
|
|||
{
|
||||
SendReq req = new SendReq();
|
||||
String lineNumber = getMyNumber(context);
|
||||
Address destination = message.getRecipient().getAddress();
|
||||
Address destination = message.getRecipient().requireAddress();
|
||||
MediaConstraints mediaConstraints = MediaConstraints.getMmsMediaConstraints(message.getSubscriptionId());
|
||||
List<Attachment> scaledAttachments = message.getAttachments();
|
||||
|
||||
|
@ -236,9 +236,9 @@ public final class MmsSendJob extends SendJob {
|
|||
|
||||
for (Recipient member : members) {
|
||||
if (message.getDistributionType() == ThreadDatabase.DistributionTypes.BROADCAST) {
|
||||
req.addBcc(new EncodedStringValue(member.getAddress().serialize()));
|
||||
req.addBcc(new EncodedStringValue(member.requireAddress().serialize()));
|
||||
} else {
|
||||
req.addTo(new EncodedStringValue(member.getAddress().serialize()));
|
||||
req.addTo(new EncodedStringValue(member.requireAddress().serialize()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -73,10 +73,10 @@ public class MultiDeviceBlockedUpdateJob extends BaseJob {
|
|||
Recipient recipient;
|
||||
|
||||
while ((recipient = reader.getNext()) != null) {
|
||||
if (recipient.isGroupRecipient()) {
|
||||
blockedGroups.add(GroupUtil.getDecodedId(recipient.getAddress().toGroupString()));
|
||||
if (recipient.isGroup()) {
|
||||
blockedGroups.add(GroupUtil.getDecodedId(recipient.requireAddress().toGroupString()));
|
||||
} else {
|
||||
blockedIndividuals.add(recipient.getAddress().serialize());
|
||||
blockedIndividuals.add(recipient.requireAddress().serialize());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -55,48 +56,46 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
|
|||
|
||||
private static final long FULL_SYNC_TIME = TimeUnit.HOURS.toMillis(6);
|
||||
|
||||
private static final String KEY_ADDRESS = "address";
|
||||
private static final String KEY_RECIPIENT = "recipient";
|
||||
private static final String KEY_FORCE_SYNC = "force_sync";
|
||||
|
||||
private @Nullable String address;
|
||||
private @Nullable RecipientId recipientId;
|
||||
|
||||
private boolean forceSync;
|
||||
|
||||
public MultiDeviceContactUpdateJob(@NonNull Context context) {
|
||||
this(context, false);
|
||||
public MultiDeviceContactUpdateJob() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) {
|
||||
this(context, null, forceSync);
|
||||
public MultiDeviceContactUpdateJob(boolean forceSync) {
|
||||
this(null, forceSync);
|
||||
}
|
||||
|
||||
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address) {
|
||||
this(context, address, true);
|
||||
public MultiDeviceContactUpdateJob(@Nullable RecipientId recipientId) {
|
||||
this(recipientId, true);
|
||||
}
|
||||
|
||||
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address, boolean forceSync) {
|
||||
public MultiDeviceContactUpdateJob(@Nullable RecipientId recipientId, boolean forceSync) {
|
||||
this(new Job.Parameters.Builder()
|
||||
.addConstraint(NetworkConstraint.KEY)
|
||||
.setQueue("MultiDeviceContactUpdateJob")
|
||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||
.setMaxAttempts(Parameters.UNLIMITED)
|
||||
.build(),
|
||||
address,
|
||||
recipientId,
|
||||
forceSync);
|
||||
}
|
||||
|
||||
private MultiDeviceContactUpdateJob(@NonNull Job.Parameters parameters, @Nullable Address address, boolean forceSync) {
|
||||
private MultiDeviceContactUpdateJob(@NonNull Job.Parameters parameters, @Nullable RecipientId recipientId, boolean forceSync) {
|
||||
super(parameters);
|
||||
|
||||
this.forceSync = forceSync;
|
||||
|
||||
if (address != null) this.address = address.serialize();
|
||||
else this.address = null;
|
||||
this.recipientId = recipientId;
|
||||
this.forceSync = forceSync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Data serialize() {
|
||||
return new Data.Builder().putString(KEY_ADDRESS, address)
|
||||
return new Data.Builder().putString(KEY_RECIPIENT, recipientId != null ? recipientId.serialize() : null)
|
||||
.putBoolean(KEY_FORCE_SYNC, forceSync)
|
||||
.build();
|
||||
}
|
||||
|
@ -115,22 +114,22 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
|
|||
return;
|
||||
}
|
||||
|
||||
if (address == null) generateFullContactUpdate();
|
||||
else generateSingleContactUpdate(Address.fromSerialized(address));
|
||||
if (recipientId == null) generateFullContactUpdate();
|
||||
else generateSingleContactUpdate(recipientId);
|
||||
}
|
||||
|
||||
private void generateSingleContactUpdate(@NonNull Address address)
|
||||
private void generateSingleContactUpdate(@NonNull RecipientId recipientId)
|
||||
throws IOException, UntrustedIdentityException, NetworkException
|
||||
{
|
||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||
|
||||
try {
|
||||
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(address);
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getId());
|
||||
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
|
||||
|
||||
out.write(new DeviceContact(address.toPhoneString(),
|
||||
out.write(new DeviceContact(recipient.requireAddress().toPhoneString(),
|
||||
Optional.fromNullable(recipient.getName()),
|
||||
getAvatar(recipient.getContactUri()),
|
||||
Optional.fromNullable(recipient.getColor().serialize()),
|
||||
|
@ -181,9 +180,8 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
|
|||
|
||||
for (ContactData contactData : contacts) {
|
||||
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id));
|
||||
Address address = Address.fromExternal(context, contactData.numbers.get(0).number);
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
Optional<IdentityDatabase.IdentityRecord> identity = DatabaseFactory.getIdentityDatabase(context).getIdentity(address);
|
||||
Recipient recipient = Recipient.external(context, contactData.numbers.get(0).number);
|
||||
Optional<IdentityDatabase.IdentityRecord> identity = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getId());
|
||||
Optional<VerifiedMessage> verified = getVerifiedMessage(recipient, identity);
|
||||
Optional<String> name = Optional.fromNullable(contactData.name);
|
||||
Optional<String> color = Optional.of(recipient.getColor().serialize());
|
||||
|
@ -191,11 +189,11 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
|
|||
boolean blocked = recipient.isBlocked();
|
||||
Optional<Integer> expireTimer = recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent();
|
||||
|
||||
out.write(new DeviceContact(address.toPhoneString(), name, getAvatar(contactUri), color, verified, profileKey, blocked, expireTimer));
|
||||
out.write(new DeviceContact(recipient.requireAddress().toPhoneString(), name, getAvatar(contactUri), color, verified, profileKey, blocked, expireTimer));
|
||||
}
|
||||
|
||||
if (ProfileKeyUtil.hasProfileKey(context)) {
|
||||
Recipient self = Recipient.from(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), false);
|
||||
Recipient self = Recipient.self();
|
||||
out.write(new DeviceContact(TextSecurePreferences.getLocalNumber(context),
|
||||
Optional.absent(), Optional.absent(),
|
||||
Optional.of(self.getColor().serialize()), Optional.absent(),
|
||||
|
@ -302,7 +300,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
|
|||
private Optional<VerifiedMessage> getVerifiedMessage(Recipient recipient, Optional<IdentityDatabase.IdentityRecord> identity) throws InvalidNumberException {
|
||||
if (!identity.isPresent()) return Optional.absent();
|
||||
|
||||
String destination = recipient.getAddress().toPhoneString();
|
||||
String destination = recipient.requireAddress().toPhoneString();
|
||||
IdentityKey identityKey = identity.get().getIdentityKey();
|
||||
|
||||
VerifiedMessage.VerifiedState state;
|
||||
|
@ -334,8 +332,8 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
|
|||
public static final class Factory implements Job.Factory<MultiDeviceContactUpdateJob> {
|
||||
@Override
|
||||
public @NonNull MultiDeviceContactUpdateJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||
String serialized = data.getString(KEY_ADDRESS);
|
||||
Address address = serialized != null ? Address.fromSerialized(serialized) : null;
|
||||
String serialized = data.getString(KEY_RECIPIENT);
|
||||
RecipientId address = serialized != null ? RecipientId.from(serialized) : null;
|
||||
|
||||
return new MultiDeviceContactUpdateJob(parameters, address, data.getBoolean(KEY_FORCE_SYNC));
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
|
@ -13,6 +12,7 @@ import org.thoughtcrime.securesms.jobmanager.Job;
|
|||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -84,11 +84,12 @@ public class MultiDeviceGroupUpdateJob extends BaseJob {
|
|||
if (!record.isMms()) {
|
||||
List<String> members = new LinkedList<>();
|
||||
|
||||
for (Address member : record.getMembers()) {
|
||||
members.add(member.serialize());
|
||||
for (RecipientId member : record.getMembers()) {
|
||||
members.add(Recipient.resolved(member).requireAddress().serialize());
|
||||
}
|
||||
|
||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(record.getId(), record.isMms())), false);
|
||||
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupUtil.getEncodedId(record.getId(), record.isMms()));
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
Optional<Integer> expirationTimer = recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent();
|
||||
|
||||
out.write(new DeviceGroup(record.getId(), Optional.fromNullable(record.getTitle()),
|
||||
|
|
|
@ -5,7 +5,6 @@ import androidx.annotation.NonNull;
|
|||
import com.annimon.stream.Stream;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
|
@ -14,6 +13,8 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
|
@ -53,7 +54,7 @@ public class MultiDeviceReadUpdateJob extends BaseJob {
|
|||
this.messageIds = new LinkedList<>();
|
||||
|
||||
for (SyncMessageId messageId : messageIds) {
|
||||
this.messageIds.add(new SerializableSyncMessageId(messageId.getAddress().toPhoneString(), messageId.getTimetamp()));
|
||||
this.messageIds.add(new SerializableSyncMessageId(messageId.getRecipientId().serialize(), messageId.getTimetamp()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +88,8 @@ public class MultiDeviceReadUpdateJob extends BaseJob {
|
|||
List<ReadMessage> readMessages = new LinkedList<>();
|
||||
|
||||
for (SerializableSyncMessageId messageId : messageIds) {
|
||||
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
||||
Recipient recipient = Recipient.resolved(RecipientId.from(messageId.recipientId));
|
||||
readMessages.add(new ReadMessage(recipient.requireAddress().serialize(), messageId.timestamp));
|
||||
}
|
||||
|
||||
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
||||
|
@ -109,14 +111,14 @@ public class MultiDeviceReadUpdateJob extends BaseJob {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty
|
||||
private final String sender;
|
||||
private final String recipientId;
|
||||
|
||||
@JsonProperty
|
||||
private final long timestamp;
|
||||
|
||||
private SerializableSyncMessageId(@JsonProperty("sender") String sender, @JsonProperty("timestamp") long timestamp) {
|
||||
this.sender = sender;
|
||||
this.timestamp = timestamp;
|
||||
private SerializableSyncMessageId(@JsonProperty("recipientId") String recipientId, @JsonProperty("timestamp") long timestamp) {
|
||||
this.recipientId = recipientId;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,11 +133,10 @@ public class MultiDeviceReadUpdateJob extends BaseJob {
|
|||
throw new AssertionError(e);
|
||||
}
|
||||
})
|
||||
.map(id -> new SyncMessageId(Address.fromSerialized(id.sender), id.timestamp))
|
||||
.map(id -> new SyncMessageId(RecipientId.from(id.recipientId), id.timestamp))
|
||||
.toList();
|
||||
|
||||
return new MultiDeviceReadUpdateJob(parameters, ids);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
@ -37,12 +38,12 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob {
|
|||
private static final String KEY_VERIFIED_STATUS = "verified_status";
|
||||
private static final String KEY_TIMESTAMP = "timestamp";
|
||||
|
||||
private String destination;
|
||||
private RecipientId destination;
|
||||
private byte[] identityKey;
|
||||
private VerifiedStatus verifiedStatus;
|
||||
private long timestamp;
|
||||
|
||||
public MultiDeviceVerifiedUpdateJob(Address destination, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
||||
public MultiDeviceVerifiedUpdateJob(@NonNull RecipientId destination, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
||||
this(new Job.Parameters.Builder()
|
||||
.addConstraint(NetworkConstraint.KEY)
|
||||
.setQueue("__MULTI_DEVICE_VERIFIED_UPDATE__")
|
||||
|
@ -56,14 +57,14 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob {
|
|||
}
|
||||
|
||||
private MultiDeviceVerifiedUpdateJob(@NonNull Job.Parameters parameters,
|
||||
@NonNull Address destination,
|
||||
@NonNull RecipientId destination,
|
||||
@NonNull byte[] identityKey,
|
||||
@NonNull VerifiedStatus verifiedStatus,
|
||||
long timestamp)
|
||||
{
|
||||
super(parameters);
|
||||
|
||||
this.destination = destination.serialize();
|
||||
this.destination = destination;
|
||||
this.identityKey = identityKey;
|
||||
this.verifiedStatus = verifiedStatus;
|
||||
this.timestamp = timestamp;
|
||||
|
@ -71,7 +72,7 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob {
|
|||
|
||||
@Override
|
||||
public @NonNull Data serialize() {
|
||||
return new Data.Builder().putString(KEY_DESTINATION, destination)
|
||||
return new Data.Builder().putString(KEY_DESTINATION, destination.serialize())
|
||||
.putString(KEY_IDENTITY_KEY, Base64.encodeBytes(identityKey))
|
||||
.putInt(KEY_VERIFIED_STATUS, verifiedStatus.toInt())
|
||||
.putLong(KEY_TIMESTAMP, timestamp)
|
||||
|
@ -97,12 +98,13 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob {
|
|||
}
|
||||
|
||||
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
||||
Address canonicalDestination = Address.fromSerialized(destination);
|
||||
Recipient recipient = Recipient.resolved(destination);
|
||||
Address canonicalDestination = recipient.requireAddress();
|
||||
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
||||
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage),
|
||||
UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(destination), false)));
|
||||
UnidentifiedAccessUtil.getAccessFor(context, recipient));
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
@ -135,7 +137,7 @@ public class MultiDeviceVerifiedUpdateJob extends BaseJob {
|
|||
@Override
|
||||
public @NonNull MultiDeviceVerifiedUpdateJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||
try {
|
||||
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
||||
RecipientId destination = RecipientId.from(data.getString(KEY_DESTINATION));
|
||||
VerifiedStatus verifiedStatus = VerifiedStatus.forState(data.getInt(KEY_VERIFIED_STATUS));
|
||||
long timestamp = data.getLong(KEY_TIMESTAMP);
|
||||
byte[] identityKey = Base64.decode(data.getString(KEY_IDENTITY_KEY));
|
||||
|
|
|
@ -5,13 +5,14 @@ import androidx.annotation.NonNull;
|
|||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
|
@ -45,7 +46,7 @@ public class MultiDeviceViewOnceOpenJob extends BaseJob {
|
|||
|
||||
private MultiDeviceViewOnceOpenJob(@NonNull Parameters parameters, @NonNull SyncMessageId syncMessageId) {
|
||||
super(parameters);
|
||||
this.messageId = new SerializableSyncMessageId(syncMessageId.getAddress().toPhoneString(), syncMessageId.getTimetamp());
|
||||
this.messageId = new SerializableSyncMessageId(syncMessageId.getRecipientId().serialize(), syncMessageId.getTimetamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,7 +75,8 @@ public class MultiDeviceViewOnceOpenJob extends BaseJob {
|
|||
}
|
||||
|
||||
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
||||
ViewOnceOpenMessage openMessage = new ViewOnceOpenMessage(messageId.sender, messageId.timestamp);
|
||||
Recipient recipient = Recipient.resolved(RecipientId.from(messageId.recipientId));
|
||||
ViewOnceOpenMessage openMessage = new ViewOnceOpenMessage(recipient.requireAddress().serialize(), messageId.timestamp);
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forViewOnceOpen(openMessage), UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
@ -94,14 +96,14 @@ public class MultiDeviceViewOnceOpenJob extends BaseJob {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonProperty
|
||||
private final String sender;
|
||||
private final String recipientId;
|
||||
|
||||
@JsonProperty
|
||||
private final long timestamp;
|
||||
|
||||
private SerializableSyncMessageId(@JsonProperty("sender") String sender, @JsonProperty("timestamp") long timestamp) {
|
||||
this.sender = sender;
|
||||
this.timestamp = timestamp;
|
||||
private SerializableSyncMessageId(@JsonProperty("recipientId") String recipientId, @JsonProperty("timestamp") long timestamp) {
|
||||
this.recipientId = recipientId;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,7 +118,7 @@ public class MultiDeviceViewOnceOpenJob extends BaseJob {
|
|||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(messageId.sender), messageId.timestamp);
|
||||
SyncMessageId syncMessageId = new SyncMessageId(RecipientId.from(messageId.recipientId), messageId.timestamp);
|
||||
|
||||
return new MultiDeviceViewOnceOpenJob(parameters, syncMessageId);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
|
|||
import org.signal.libsignal.metadata.SelfSendException;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.IncomingMessageProcessor;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
|
@ -81,6 +80,7 @@ import org.thoughtcrime.securesms.mms.StickerSlide;
|
|||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
||||
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
|
||||
|
@ -287,7 +287,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Log.w(TAG, "Got unrecognized message...");
|
||||
}
|
||||
|
||||
resetRecipientToPush(Recipient.from(context, Address.fromExternal(context, content.getSender()), false));
|
||||
resetRecipientToPush(Recipient.external(context, content.getSender()));
|
||||
|
||||
if (envelope.isPreKeySignalMessage()) {
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob());
|
||||
|
@ -337,7 +337,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_INCOMING_CALL);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_RECIPIENT, Recipient.external(context, content.getSender()).getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_TIMESTAMP, content.getTimestamp());
|
||||
|
||||
|
@ -353,7 +353,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_RESPONSE_MESSAGE);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_RECIPIENT, Recipient.external(context, content.getSender()).getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
||||
|
||||
context.startService(intent);
|
||||
|
@ -367,7 +367,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_ICE_MESSAGE);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_RECIPIENT, Recipient.external(context, content.getSender()).getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP, message.getSdp());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_MID, message.getSdpMid());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_LINE_INDEX, message.getSdpMLineIndex());
|
||||
|
@ -387,7 +387,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_REMOTE_HANGUP);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_RECIPIENT, Recipient.external(context, content.getSender()).getId());
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
@ -399,7 +399,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_REMOTE_BUSY);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, content.getSender()));
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_RECIPIENT, Recipient.external(context, content.getSender()).getId());
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Address.fromExternal(context, content.getSender()),
|
||||
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Recipient.external(context, content.getSender()).getId(),
|
||||
content.getSenderDevice(),
|
||||
content.getTimestamp(),
|
||||
"", Optional.absent(), 0,
|
||||
|
@ -445,9 +445,9 @@ public class PushDecryptJob extends BaseJob {
|
|||
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
|
||||
if (!recipient.isGroupRecipient()) {
|
||||
if (!recipient.isGroup()) {
|
||||
SessionStore sessionStore = new TextSecureSessionStore(context);
|
||||
sessionStore.deleteAllSessions(recipient.getAddress().toPhoneString());
|
||||
sessionStore.deleteAllSessions(recipient.requireAddress().toPhoneString());
|
||||
|
||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||
|
||||
|
@ -481,7 +481,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
{
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RequestGroupInfoJob(content.getSender(), group.getGroupId()));
|
||||
.add(new RequestGroupInfoJob(Recipient.external(context, content.getSender()).getId(), group.getGroupId()));
|
||||
}
|
||||
|
||||
private void handleExpirationUpdate(@NonNull SignalServiceContent content,
|
||||
|
@ -492,7 +492,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getMessageDestination(content, message);
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(recipient.getId(),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, true,
|
||||
false,
|
||||
|
@ -507,7 +507,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
|
||||
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, message.getExpiresInSeconds());
|
||||
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient.getId(), message.getExpiresInSeconds());
|
||||
|
||||
if (smsMessageId.isPresent()) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||
|
@ -574,12 +574,12 @@ public class PushDecryptJob extends BaseJob {
|
|||
if (message.getMessage().getProfileKey().isPresent()) {
|
||||
Recipient recipient = null;
|
||||
|
||||
if (message.getDestination().isPresent()) recipient = Recipient.from(context, Address.fromExternal(context, message.getDestination().get()), false);
|
||||
else if (message.getMessage().getGroupInfo().isPresent()) recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false)), false);
|
||||
if (message.getDestination().isPresent()) recipient = Recipient.external(context, message.getDestination().get());
|
||||
else if (message.getMessage().getGroupInfo().isPresent()) recipient = Recipient.external(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false));
|
||||
|
||||
|
||||
if (recipient != null && !recipient.isSystemContact() && !recipient.isProfileSharing()) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient.getId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,7 +599,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
if (message.isContactsRequest()) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceContactUpdateJob(context, true));
|
||||
.add(new MultiDeviceContactUpdateJob(true));
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
|
@ -635,8 +635,8 @@ public class PushDecryptJob extends BaseJob {
|
|||
private void handleSynchronizeReadMessage(@NonNull List<ReadMessage> readMessages, long envelopeTimestamp)
|
||||
{
|
||||
for (ReadMessage readMessage : readMessages) {
|
||||
List<Pair<Long, Long>> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(Address.fromExternal(context, readMessage.getSender()), readMessage.getTimestamp()), envelopeTimestamp);
|
||||
List<Pair<Long, Long>> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(Address.fromExternal(context, readMessage.getSender()), readMessage.getTimestamp()), envelopeTimestamp);
|
||||
List<Pair<Long, Long>> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.external(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), envelopeTimestamp);
|
||||
List<Pair<Long, Long>> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.external(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), envelopeTimestamp);
|
||||
|
||||
for (Pair<Long, Long> expiringMessage : expiringText) {
|
||||
ApplicationContext.getInstance(context)
|
||||
|
@ -657,7 +657,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
}
|
||||
|
||||
private void handleSynchronizeViewOnceOpenMessage(@NonNull ViewOnceOpenMessage openMessage, long envelopeTimestamp) {
|
||||
Address author = Address.fromExternal(context, openMessage.getSender());
|
||||
RecipientId author = Recipient.external(context, openMessage.getSender()).getId();
|
||||
long timestamp = openMessage.getTimestamp();
|
||||
MessageRecord record = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(timestamp, author);
|
||||
|
||||
|
@ -687,7 +687,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Optional<List<Contact>> sharedContacts = getContacts(message.getSharedContacts());
|
||||
Optional<List<LinkPreview>> linkPreviews = getLinkPreviews(message.getPreviews(), message.getBody().or(""));
|
||||
Optional<Attachment> sticker = getStickerAttachment(message.getSticker());
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Recipient.external(context, content.getSender()).getId(),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, false,
|
||||
message.isViewOnce(),
|
||||
|
@ -749,7 +749,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
|
||||
database.markAsSent(messageId, true);
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, message.getMessage().getExpiresInSeconds());
|
||||
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient.getId(), message.getMessage().getExpiresInSeconds());
|
||||
|
||||
return threadId;
|
||||
}
|
||||
|
@ -793,12 +793,12 @@ public class PushDecryptJob extends BaseJob {
|
|||
try {
|
||||
long messageId = database.insertMessageOutbox(mediaMessage, threadId, false, GroupReceiptDatabase.STATUS_UNKNOWN, null);
|
||||
|
||||
if (recipients.getAddress().isGroup()) {
|
||||
updateGroupReceiptStatus(message, messageId, recipients.getAddress().toGroupString());
|
||||
if (recipients.requireAddress().isGroup()) {
|
||||
updateGroupReceiptStatus(message, messageId, recipients.requireAddress().toGroupString());
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipients.getAddress().serialize()));
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipients.requireAddress().serialize()));
|
||||
|
||||
List<DatabaseAttachment> allAttachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(messageId);
|
||||
List<DatabaseAttachment> stickerAttachments = Stream.of(allAttachments).filter(Attachment::isSticker).toList();
|
||||
|
@ -822,7 +822,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
}
|
||||
|
||||
if (recipients.isLocalNumber()) {
|
||||
SyncMessageId id = new SyncMessageId(recipients.getAddress(), message.getTimestamp());
|
||||
SyncMessageId id = new SyncMessageId(recipients.getId(), message.getTimestamp());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis());
|
||||
}
|
||||
|
@ -837,14 +837,13 @@ public class PushDecryptJob extends BaseJob {
|
|||
private void handleGroupRecipientUpdate(@NonNull SentTranscriptMessage message) {
|
||||
Recipient recipient = getSyncMessageDestination(message);
|
||||
|
||||
if (!recipient.isGroupRecipient()) {
|
||||
if (!recipient.isGroup()) {
|
||||
Log.w(TAG, "Got recipient update for a non-group message! Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
MmsSmsDatabase database = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
MessageRecord record = database.getMessageFor(message.getTimestamp(),
|
||||
Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
||||
MessageRecord record = database.getMessageFor(message.getTimestamp(), Recipient.self().getId());
|
||||
|
||||
if (record == null) {
|
||||
Log.w(TAG, "Got recipient update for non-existing message! Skipping.");
|
||||
|
@ -856,26 +855,27 @@ public class PushDecryptJob extends BaseJob {
|
|||
return;
|
||||
}
|
||||
|
||||
updateGroupReceiptStatus(message, record.getId(), recipient.getAddress().toGroupString());
|
||||
updateGroupReceiptStatus(message, record.getId(), recipient.requireAddress().toGroupString());
|
||||
}
|
||||
|
||||
private void updateGroupReceiptStatus(@NonNull SentTranscriptMessage message, long messageId, @NonNull String groupString) {
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, false);
|
||||
Map<String, Integer> localReceipts = Stream.of(receiptDatabase.getGroupReceiptInfo(messageId))
|
||||
.collect(Collectors.toMap(info -> info.getAddress().serialize(), GroupReceiptInfo::getStatus));
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> messageRecipients = Stream.of(message.getRecipients()).map(address -> Recipient.external(context, address)).toList();
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, false);
|
||||
Map<RecipientId, Integer> localReceipts = Stream.of(receiptDatabase.getGroupReceiptInfo(messageId))
|
||||
.collect(Collectors.toMap(GroupReceiptInfo::getRecipientId, GroupReceiptInfo::getStatus));
|
||||
|
||||
for (String address : message.getRecipients()) {
|
||||
for (Recipient messageRecipient : messageRecipients) {
|
||||
//noinspection ConstantConditions
|
||||
if (localReceipts.containsKey(address) && localReceipts.get(address) < GroupReceiptDatabase.STATUS_UNDELIVERED) {
|
||||
receiptDatabase.update(Address.fromSerialized(address), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
|
||||
} else if (!localReceipts.containsKey(address)) {
|
||||
receiptDatabase.insert(Collections.singletonList(Address.fromSerialized(address)), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
|
||||
if (localReceipts.containsKey(messageRecipient.getId()) && localReceipts.get(messageRecipient.getId()) < GroupReceiptDatabase.STATUS_UNDELIVERED) {
|
||||
receiptDatabase.update(messageRecipient.getId(), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
|
||||
} else if (!localReceipts.containsKey(messageRecipient.getId())) {
|
||||
receiptDatabase.insert(Collections.singletonList(messageRecipient.getId()), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
for (Recipient member : members) {
|
||||
receiptDatabase.setUnidentified(member.getAddress(), messageId, message.isUnidentified(member.getAddress().serialize()));
|
||||
receiptDatabase.setUnidentified(member.getId(), messageId, message.isUnidentified(member.requireAddress().serialize()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -899,7 +899,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
} else {
|
||||
notifyTypingStoppedFromIncomingMessage(recipient, content.getSender(), content.getSenderDevice());
|
||||
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, content.getSender()),
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.external(context, content.getSender()).getId(),
|
||||
content.getSenderDevice(),
|
||||
message.getTimestamp(), body,
|
||||
message.getGroupInfo(),
|
||||
|
@ -932,7 +932,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
}
|
||||
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
boolean isGroup = recipient.getAddress().isGroup();
|
||||
boolean isGroup = recipient.requireAddress().isGroup();
|
||||
|
||||
MessagingDatabase database;
|
||||
long messageId;
|
||||
|
@ -944,13 +944,13 @@ public class PushDecryptJob extends BaseJob {
|
|||
messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, GroupReceiptDatabase.STATUS_UNKNOWN, null);
|
||||
database = DatabaseFactory.getMmsDatabase(context);
|
||||
|
||||
updateGroupReceiptStatus(message, messageId, recipient.getAddress().toGroupString());
|
||||
updateGroupReceiptStatus(message, messageId, recipient.requireAddress().toGroupString());
|
||||
} else {
|
||||
OutgoingTextMessage outgoingTextMessage = new OutgoingEncryptedMessage(recipient, body, expiresInMillis);
|
||||
|
||||
messageId = DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoingTextMessage, false, message.getTimestamp(), null);
|
||||
database = DatabaseFactory.getSmsDatabase(context);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipient.getAddress().serialize()));
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipient.requireAddress().serialize()));
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
|
@ -963,7 +963,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
}
|
||||
|
||||
if (recipient.isLocalNumber()) {
|
||||
SyncMessageId id = new SyncMessageId(recipient.getAddress(), message.getTimestamp());
|
||||
SyncMessageId id = new SyncMessageId(recipient.getId(), message.getTimestamp());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis());
|
||||
}
|
||||
|
@ -1098,13 +1098,12 @@ public class PushDecryptJob extends BaseJob {
|
|||
private void handleProfileKey(@NonNull SignalServiceContent content,
|
||||
@NonNull SignalServiceDataMessage message)
|
||||
{
|
||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||
Address sourceAddress = Address.fromExternal(context, content.getSender());
|
||||
Recipient recipient = Recipient.from(context, sourceAddress, false);
|
||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||
Recipient recipient = Recipient.external(context, content.getSender());
|
||||
|
||||
if (recipient.getProfileKey() == null || !MessageDigest.isEqual(recipient.getProfileKey(), message.getProfileKey().get())) {
|
||||
database.setProfileKey(recipient, message.getProfileKey().get());
|
||||
database.setUnidentifiedAccessMode(recipient, RecipientDatabase.UnidentifiedAccessMode.UNKNOWN);
|
||||
database.setProfileKey(recipient.getId(), message.getProfileKey().get());
|
||||
database.setUnidentifiedAccessMode(recipient.getId(), RecipientDatabase.UnidentifiedAccessMode.UNKNOWN);
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new RetrieveProfileJob(recipient));
|
||||
}
|
||||
}
|
||||
|
@ -1114,7 +1113,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
{
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new SendDeliveryReceiptJob(Address.fromExternal(context, content.getSender()), message.getTimestamp()));
|
||||
.add(new SendDeliveryReceiptJob(Recipient.external(context, content.getSender()).getId(), message.getTimestamp()));
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
|
@ -1124,7 +1123,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
for (long timestamp : message.getTimestamps()) {
|
||||
Log.i(TAG, String.format("Received encrypted delivery receipt: (XXXXX, %d)", timestamp));
|
||||
DatabaseFactory.getMmsSmsDatabase(context)
|
||||
.incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, content.getSender()), timestamp), System.currentTimeMillis());
|
||||
.incrementDeliveryReceiptCount(new SyncMessageId(Recipient.external(context, content.getSender()).getId(), timestamp), System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1137,7 +1136,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
Log.i(TAG, String.format("Received encrypted read receipt: (XXXXX, %d)", timestamp));
|
||||
|
||||
DatabaseFactory.getMmsSmsDatabase(context)
|
||||
.incrementReadReceiptCount(new SyncMessageId(Address.fromExternal(context, content.getSender()), timestamp), content.getTimestamp());
|
||||
.incrementReadReceiptCount(new SyncMessageId(Recipient.external(context, content.getSender()).getId(), timestamp), content.getTimestamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1149,13 +1148,13 @@ public class PushDecryptJob extends BaseJob {
|
|||
return;
|
||||
}
|
||||
|
||||
Recipient author = Recipient.from(context, Address.fromExternal(context, content.getSender()), false);
|
||||
Recipient author = Recipient.external(context, content.getSender());
|
||||
|
||||
long threadId;
|
||||
|
||||
if (typingMessage.getGroupId().isPresent()) {
|
||||
Address groupAddress = Address.fromExternal(context, GroupUtil.getEncodedId(typingMessage.getGroupId().get(), false));
|
||||
Recipient groupRecipient = Recipient.from(context, groupAddress, false);
|
||||
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupUtil.getEncodedId(typingMessage.getGroupId().get(), false));
|
||||
Recipient groupRecipient = Recipient.resolved(recipientId);
|
||||
|
||||
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||
} else {
|
||||
|
@ -1200,7 +1199,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
return Optional.absent();
|
||||
}
|
||||
|
||||
Address author = Address.fromExternal(context, quote.get().getAuthor().getNumber());
|
||||
RecipientId author = Recipient.external(context, quote.get().getAuthor().getNumber()).getId();
|
||||
MessageRecord message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quote.get().getId(), author);
|
||||
|
||||
if (message != null) {
|
||||
|
@ -1315,7 +1314,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
|
||||
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp, Optional<SignalServiceGroup> group) {
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, sender),
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.external(context, sender).getId(),
|
||||
senderDevice, timestamp, "",
|
||||
group, 0, false);
|
||||
|
||||
|
@ -1325,22 +1324,22 @@ public class PushDecryptJob extends BaseJob {
|
|||
|
||||
private Recipient getSyncMessageDestination(SentTranscriptMessage message) {
|
||||
if (message.getMessage().getGroupInfo().isPresent()) {
|
||||
return Recipient.from(context, Address.fromExternal(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false)), false);
|
||||
return Recipient.external(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false));
|
||||
} else {
|
||||
return Recipient.from(context, Address.fromExternal(context, message.getDestination().get()), false);
|
||||
return Recipient.external(context, message.getDestination().get());
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
if (message.getGroupInfo().isPresent()) {
|
||||
return Recipient.from(context, Address.fromExternal(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false)), false);
|
||||
return Recipient.external(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false));
|
||||
} else {
|
||||
return Recipient.from(context, Address.fromExternal(context, content.getSender()), false);
|
||||
return Recipient.external(context, content.getSender());
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient conversationRecipient, @NonNull String sender, int device) {
|
||||
Recipient author = Recipient.from(context, Address.fromExternal(context, sender), false);
|
||||
Recipient author = Recipient.external(context, sender);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(conversationRecipient);
|
||||
|
||||
if (threadId > 0) {
|
||||
|
@ -1355,15 +1354,15 @@ public class PushDecryptJob extends BaseJob {
|
|||
return true;
|
||||
}
|
||||
|
||||
Recipient sender = Recipient.from(context, Address.fromExternal(context, content.getSender()), false);
|
||||
Recipient sender = Recipient.external(context, content.getSender());
|
||||
|
||||
if (content.getDataMessage().isPresent()) {
|
||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||
Recipient conversation = getMessageDestination(content, message);
|
||||
|
||||
if (conversation.isGroupRecipient() && conversation.isBlocked()) {
|
||||
if (conversation.isGroup() && conversation.isBlocked()) {
|
||||
return true;
|
||||
} else if (conversation.isGroupRecipient()) {
|
||||
} else if (conversation.isGroup()) {
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
Optional<String> groupId = message.getGroupInfo().isPresent() ? Optional.of(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))
|
||||
: Optional.absent();
|
||||
|
@ -1392,7 +1391,7 @@ public class PushDecryptJob extends BaseJob {
|
|||
|
||||
private void resetRecipientToPush(@NonNull Recipient recipient) {
|
||||
if (recipient.isForceSmsSelection()) {
|
||||
DatabaseFactory.getRecipientDatabase(context).setForceSmsSelection(recipient, false);
|
||||
DatabaseFactory.getRecipientDatabase(context).setForceSmsSelection(recipient.getId(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue