Switch MMS groups to use the group database infrastructure

Eliminate the concept of 'Recipients' (plural). There is now just
a 'Recipient', which contains an Address that is either an individual
or a group ID.

MMS groups now exist as part of the group database, just like push
groups.

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-08-01 08:56:00 -07:00
parent 81682e0302
commit 375207f073
106 changed files with 1587 additions and 2192 deletions

View File

@ -4,7 +4,7 @@ import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Locale;
import java.util.Set;
@ -14,7 +14,7 @@ public interface BindableConversationItem extends Unbindable {
@NonNull MessageRecord messageRecord,
@NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected,
@NonNull Recipients recipients);
@NonNull Recipient recipients);
MessageRecord getMessageRecord();
}

View File

@ -20,13 +20,11 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.loaders.BlockedContactsLoader;
import org.thoughtcrime.securesms.preferences.BlockedContactListItem;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import java.util.List;
public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity {
private final DynamicTheme dynamicTheme = new DynamicTheme();
@ -106,9 +104,9 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Recipients recipients = ((BlockedContactListItem)view).getRecipients();
Intent intent = new Intent(getActivity(), RecipientPreferenceActivity.class);
intent.putExtra(RecipientPreferenceActivity.ADDRESSES_EXTRA, recipients.getAddresses());
Recipient recipient = ((BlockedContactListItem)view).getRecipient();
Intent intent = new Intent(getActivity(), RecipientPreferenceActivity.class);
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
startActivity(intent);
}
@ -127,12 +125,10 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
@Override
public void bindView(View view, Context context, Cursor cursor) {
String addressesConcat = cursor.getString(1);
List<Address> addresses = Address.fromSerializedList(addressesConcat, ' ');
String address = cursor.getString(1);
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(address), true);
Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), true);
((BlockedContactListItem) view).set(recipients);
((BlockedContactListItem) view).set(recipient);
}
}

View File

@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsAddressDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.PushDatabase;
@ -24,7 +23,6 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.jobs.PushDecryptJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.VerifySpan;
@ -138,17 +136,17 @@ public class ConfirmIdentityDialog extends AlertDialog {
private void processOutgoingMessageRecord(MessageRecord messageRecord) {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(getContext());
MmsAddressDatabase mmsAddressDatabase = DatabaseFactory.getMmsAddressDatabase(getContext());
if (messageRecord.isMms()) {
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getAddress(),
mismatch.getIdentityKey());
Recipients recipients = mmsAddressDatabase.getRecipientsForId(messageRecord.getId());
if (recipients.isGroupRecipient()) MessageSender.resendGroupMessage(getContext(), masterSecret, messageRecord, mismatch.getAddress());
else MessageSender.resend(getContext(), masterSecret, messageRecord);
if (messageRecord.getRecipient().isPushGroupRecipient()) {
MessageSender.resendGroupMessage(getContext(), messageRecord, mismatch.getAddress());
} else {
MessageSender.resend(getContext(), masterSecret, messageRecord);
}
} else {
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getAddress(),

View File

@ -132,8 +132,7 @@ import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipients.RecipientsModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.WebRtcCallService;
@ -165,7 +164,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@ -184,7 +183,7 @@ import static org.whispersystems.signalservice.internal.push.SignalServiceProtos
public class ConversationActivity extends PassphraseRequiredActionBarActivity
implements ConversationFragment.ConversationFragmentListener,
AttachmentManager.AttachmentListener,
RecipientsModifiedListener,
RecipientModifiedListener,
OnKeyboardShownListener,
AttachmentDrawerListener,
InputPanel.Listener,
@ -192,7 +191,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
{
private static final String TAG = ConversationActivity.class.getSimpleName();
public static final String ADDRESSES_EXTRA = "addresses";
public static final String ADDRESS_EXTRA = "address";
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";
@ -236,7 +235,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private QuickAttachmentDrawer quickAttachmentDrawer;
private InputPanel inputPanel;
private Recipients recipients;
private Recipient recipient;
private long threadId;
private int distributionType;
private boolean archived;
@ -325,9 +324,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
initializeIdentityRecords();
composeText.setTransport(sendButton.getSelectedTransport());
titleView.setTitle(recipients);
setActionBarColor(recipients.getColor());
setBlockedUserState(recipients, isSecureText, isDefaultSms);
titleView.setTitle(recipient);
setActionBarColor(recipient.getColor());
setBlockedUserState(recipient, isSecureText, isDefaultSms);
calculateCharactersRemaining();
MessageNotifier.setVisibleThread(threadId);
@ -371,7 +370,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onDestroy() {
saveDraft();
if (recipients != null) recipients.removeListener(this);
if (recipient != null) recipient.removeListener(this);
if (securityUpdateReceiver != null) unregisterReceiver(securityUpdateReceiver);
if (recipientsStaleReceiver != null) unregisterReceiver(recipientsStaleReceiver);
super.onDestroy();
@ -410,10 +409,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
addAttachmentContactInfo(data.getData());
break;
case GROUP_EDIT:
recipients = RecipientFactory.getRecipientsFor(this, RecipientFactory.getRecipientFor(this, (Address)data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true), true);
recipients.addListener(this);
titleView.setTitle(recipients);
setBlockedUserState(recipients, isSecureText, isDefaultSms);
recipient = RecipientFactory.getRecipientFor(this, (Address)data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true);
recipient.addListener(this);
titleView.setTitle(recipient);
setBlockedUserState(recipient, isSecureText, isDefaultSms);
supportInvalidateOptionsMenu();
break;
case TAKE_PHOTO:
@ -422,8 +421,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
break;
case ADD_CONTACT:
recipients = RecipientFactory.getRecipientsFor(this, recipients.getAddresses(), true);
recipients.addListener(this);
recipient = RecipientFactory.getRecipientFor(this, recipient.getAddress(), true);
recipient.addListener(this);
fragment.reloadList();
break;
case PICK_LOCATION:
@ -462,14 +461,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
menu.clear();
if (isSecureText) {
if (recipients.getExpireMessages() > 0) {
if (recipient.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 = (TextView)actionView.findViewById(R.id.expiration_badge);
badgeView.setText(ExpirationUtil.getExpirationAbbreviatedDisplayValue(this, recipients.getExpireMessages()));
badgeView.setText(ExpirationUtil.getExpirationAbbreviatedDisplayValue(this, recipient.getExpireMessages()));
actionView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@ -507,10 +506,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
inflater.inflate(R.menu.conversation_insecure, menu);
}
if (recipients != null && recipients.isMuted()) inflater.inflate(R.menu.conversation_muted, menu);
else inflater.inflate(R.menu.conversation_unmuted, menu);
if (recipient != null && recipient.isMuted()) inflater.inflate(R.menu.conversation_muted, menu);
else inflater.inflate(R.menu.conversation_unmuted, menu);
if (isSingleConversation() && getRecipients().getPrimaryRecipient().getContactUri() == null) {
if (isSingleConversation() && getRecipient().getContactUri() == null) {
inflater.inflate(R.menu.conversation_add_to_contacts, menu);
}
@ -523,7 +522,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.menu_call_secure:
case R.id.menu_call_insecure: handleDial(getRecipients().getPrimaryRecipient()); return true;
case R.id.menu_call_insecure: handleDial(getRecipient()); return true;
case R.id.menu_add_attachment: handleAddAttachment(); return true;
case R.id.menu_view_media: handleViewMedia(); return true;
case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
@ -571,17 +570,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
return;
}
ExpirationDialog.show(this, recipients.getExpireMessages(), new ExpirationDialog.OnClickListener() {
ExpirationDialog.show(this, recipient.getExpireMessages(), new ExpirationDialog.OnClickListener() {
@Override
public void onClick(final int expirationTime) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
.setExpireMessages(recipients, expirationTime);
recipients.setExpireMessages(expirationTime);
.setExpireMessages(recipient, expirationTime);
recipient.setExpireMessages(expirationTime);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(getRecipients(), System.currentTimeMillis(), expirationTime * 1000);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(getRecipient(), System.currentTimeMillis(), expirationTime * 1000);
MessageSender.send(ConversationActivity.this, masterSecret, outgoingMessage, threadId, false, null);
return null;
@ -601,13 +600,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
MuteDialog.show(this, new MuteDialog.MuteSelectionListener() {
@Override
public void onMuted(final long until) {
recipients.setMuted(until);
recipient.setMuted(until);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
.setMuted(recipients, until);
.setMuted(recipient, until);
return null;
}
@ -621,13 +620,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void handleUnmuteNotifications() {
recipients.setMuted(0);
recipient.setMuted(0);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
.setMuted(recipients, 0);
.setMuted(recipient, 0);
return null;
}
@ -642,13 +641,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
.setPositiveButton(R.string.ConversationActivity_unblock, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
recipients.setBlocked(false);
recipient.setBlocked(false);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
.setBlocked(recipients, false);
.setBlocked(recipient, false);
ApplicationContext.getInstance(ConversationActivity.this)
.getJobManager()
@ -680,7 +679,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
composeText.appendInvite(inviteText);
} else {
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:" + recipients.getPrimaryRecipient().getAddress().serialize()));
intent.setData(Uri.parse("smsto:" + recipient.getAddress().serialize()));
intent.putExtra("sms_body", inviteText);
intent.putExtra(Intent.EXTRA_TEXT, inviteText);
startActivity(intent);
@ -703,7 +702,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
final Context context = getApplicationContext();
OutgoingEndSessionMessage endSessionMessage =
new OutgoingEndSessionMessage(new OutgoingTextMessage(getRecipients(), "TERMINATE", 0, -1));
new OutgoingEndSessionMessage(new OutgoingTextMessage(getRecipient(), "TERMINATE", 0, -1));
new AsyncTask<OutgoingEndSessionMessage, Void, Long>() {
@Override
@ -726,12 +725,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void handleViewMedia() {
Intent intent = new Intent(this, MediaOverviewActivity.class);
intent.putExtra(MediaOverviewActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(MediaOverviewActivity.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, recipient.getAddress());
startActivity(intent);
}
private void handleLeavePushGroup() {
if (getRecipients() == null) {
if (getRecipient() == null) {
Toast.makeText(this, getString(R.string.ConversationActivity_invalid_recipient),
Toast.LENGTH_LONG).show();
return;
@ -747,15 +746,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
public void onClick(DialogInterface dialog, int which) {
Context self = ConversationActivity.this;
try {
byte[] groupId = GroupUtil.getDecodedId(getRecipients().getPrimaryRecipient().getAddress().toGroupString());
String groupId = getRecipient().getAddress().toGroupString();
DatabaseFactory.getGroupDatabase(self).setActive(groupId, false);
GroupContext context = GroupContext.newBuilder()
.setId(ByteString.copyFrom(groupId))
.setId(ByteString.copyFrom(GroupUtil.getDecodedId(groupId)))
.setType(GroupContext.Type.QUIT)
.build();
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipients(), context, null, System.currentTimeMillis(), 0);
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipient(), context, null, System.currentTimeMillis(), 0);
MessageSender.send(self, masterSecret, outgoingMessage, threadId, false, null);
DatabaseFactory.getGroupDatabase(self).remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(self)));
initializeEnabledCheck();
@ -772,7 +771,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void handleEditPushGroup() {
Intent intent = new Intent(ConversationActivity.this, GroupCreateActivity.class);
intent.putExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA, recipients.getPrimaryRecipient().getAddress());
intent.putExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA, recipient.getAddress());
startActivityForResult(intent, GROUP_EDIT);
}
@ -835,18 +834,18 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void handleDisplayGroupRecipients() {
new GroupMembersDialog(this, getRecipients()).display();
new GroupMembersDialog(this, getRecipient()).display();
}
private void handleAddToContacts() {
if (recipients.getPrimaryRecipient().getAddress().isGroup()) return;
if (recipient.getAddress().isGroup()) return;
try {
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
if (recipients.getPrimaryRecipient().getAddress().isEmail()) {
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipients.getPrimaryRecipient().getAddress().toEmailString());
if (recipient.getAddress().isEmail()) {
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipient.getAddress().toEmailString());
} else {
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipients.getPrimaryRecipient().getAddress().toPhoneString());
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getAddress().toPhoneString());
}
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
startActivityForResult(intent, ADD_CONTACT);
@ -928,19 +927,19 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
this.isSecureText = isSecureText;
this.isDefaultSms = isDefaultSms;
boolean isMediaMessage = !recipients.isSingleRecipient() || attachmentManager.isAttachmentPresent();
boolean isMediaMessage = recipient.isMmsGroupRecipient() || attachmentManager.isAttachmentPresent();
sendButton.resetAvailableTransports(isMediaMessage);
if (!isSecureText) sendButton.disableTransport(Type.TEXTSECURE);
if (recipients.isGroupRecipient()) sendButton.disableTransport(Type.SMS);
if (!isSecureText) sendButton.disableTransport(Type.TEXTSECURE);
if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS);
if (isSecureText) sendButton.setDefaultTransport(Type.TEXTSECURE);
else sendButton.setDefaultTransport(Type.SMS);
calculateCharactersRemaining();
supportInvalidateOptionsMenu();
setBlockedUserState(recipients, isSecureText, isDefaultSms);
setBlockedUserState(recipient, isSecureText, isDefaultSms);
}
///// Initializers
@ -1012,18 +1011,18 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
handleSecurityChange(currentSecureText || isPushGroupConversation(), currentIsDefaultSms);
new AsyncTask<Recipients, Void, boolean[]>() {
new AsyncTask<Recipient, Void, boolean[]>() {
@Override
protected boolean[] doInBackground(Recipients... params) {
protected boolean[] doInBackground(Recipient... params) {
Context context = ConversationActivity.this;
Recipients recipients = params[0];
UserCapabilities capabilities = DirectoryHelper.getUserCapabilities(context, recipients);
Recipient recipient = params[0];
UserCapabilities capabilities = DirectoryHelper.getUserCapabilities(context, recipient);
if (capabilities.getTextCapability() == Capability.UNKNOWN ||
capabilities.getVideoCapability() == Capability.UNKNOWN)
{
try {
capabilities = DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients);
capabilities = DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipient);
} catch (IOException e) {
Log.w(TAG, e);
}
@ -1040,7 +1039,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
future.set(true);
onSecurityUpdated();
}
}.execute(recipients);
}.execute(recipient);
return future;
}
@ -1050,7 +1049,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void updateRecipientPreferences() {
new RecipientPreferencesTask().execute(recipients);
new RecipientPreferencesTask().execute(recipient);
}
protected void updateInviteReminder(boolean seenInvite) {
@ -1059,11 +1058,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
TextSecurePreferences.isShowInviteReminders(this) &&
!isSecureText &&
!seenInvite &&
recipients.isSingleRecipient() &&
recipients.getPrimaryRecipient() != null &&
recipients.getPrimaryRecipient().getContactUri() != null)
!recipient.isGroupRecipient())
{
InviteReminder reminder = new InviteReminder(this, recipients);
InviteReminder reminder = new InviteReminder(this, recipient);
reminder.setOkListener(new OnClickListener() {
@Override
public void onClick(View v) {
@ -1099,34 +1096,32 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private ListenableFuture<Boolean> initializeIdentityRecords() {
final SettableFuture<Boolean> future = new SettableFuture<>();
new AsyncTask<Recipients, Void, Pair<IdentityRecordList, String>>() {
new AsyncTask<Recipient, Void, Pair<IdentityRecordList, String>>() {
@Override
protected @NonNull Pair<IdentityRecordList, String> doInBackground(Recipients... params) {
try {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this);
IdentityRecordList identityRecordList = new IdentityRecordList();
Recipients recipients = params[0];
protected @NonNull Pair<IdentityRecordList, String> doInBackground(Recipient... params) {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this);
IdentityRecordList identityRecordList = new IdentityRecordList();
List<Recipient> recipients = new LinkedList<>();
if (recipients.isGroupRecipient()) {
recipients = DatabaseFactory.getGroupDatabase(ConversationActivity.this)
.getGroupMembers(GroupUtil.getDecodedId(recipients.getPrimaryRecipient().getAddress().toGroupString()), false);
}
for (Address recipientAddress : recipients.getAddresses()) {
Log.w(TAG, "Loading identity for: " + recipientAddress);
identityRecordList.add(identityDatabase.getIdentity(recipientAddress));
}
String message = null;
if (identityRecordList.isUnverified()) {
message = IdentityUtil.getUnverifiedBannerDescription(ConversationActivity.this, identityRecordList.getUnverifiedRecipients(ConversationActivity.this));
}
return new Pair<>(identityRecordList, message);
} catch (IOException e) {
throw new AssertionError(e);
if (params[0].isGroupRecipient()) {
recipients.addAll(DatabaseFactory.getGroupDatabase(ConversationActivity.this)
.getGroupMembers(params[0].getAddress().toGroupString(), false));
} else {
recipients.add(params[0]);
}
for (Recipient recipient : recipients) {
Log.w(TAG, "Loading identity for: " + recipient.getAddress());
identityRecordList.add(identityDatabase.getIdentity(recipient.getAddress()));
}
String message = null;
if (identityRecordList.isUnverified()) {
message = IdentityUtil.getUnverifiedBannerDescription(ConversationActivity.this, identityRecordList.getUnverifiedRecipients(ConversationActivity.this));
}
return new Pair<>(identityRecordList, message);
}
@Override
@ -1149,7 +1144,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
future.set(true);
}
}.execute(recipients);
}.execute(recipient);
return future;
}
@ -1212,7 +1207,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
public void onClick(View v) {
Intent intent = new Intent(ConversationActivity.this, RecipientPreferenceActivity.class);
intent.putExtra(RecipientPreferenceActivity.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA,
isSecureText && !isSelfConversation());
@ -1257,9 +1252,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void initializeResources() {
if (recipients != null) recipients.removeListener(this);
if (recipient != null) recipient.removeListener(this);
recipients = RecipientFactory.getRecipientsFor(this, Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA)), true);
recipient = RecipientFactory.getRecipientFor(this, (Address)getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false);
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
@ -1270,7 +1265,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
conversationContainer.setClipToPadding(true);
}
recipients.addListener(this);
recipient.addListener(this);
}
private void initializeProfiles() {
@ -1281,18 +1276,18 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
ApplicationContext.getInstance(this)
.getJobManager()
.add(new RetrieveProfileJob(this, recipients));
.add(new RetrieveProfileJob(this, recipient));
}
@Override
public void onModified(final Recipients recipients) {
public void onModified(final Recipient recipient) {
titleView.post(new Runnable() {
@Override
public void run() {
titleView.setTitle(recipients);
titleView.setTitle(recipient);
titleView.setVerified(identityRecords.isVerified());
setBlockedUserState(recipients, isSecureText, isDefaultSms);
setActionBarColor(recipients.getColor());
setBlockedUserState(recipient, isSecureText, isDefaultSms);
setActionBarColor(recipient.getColor());
invalidateOptionsMenu();
updateRecipientPreferences();
}
@ -1301,8 +1296,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Subscribe(threadMode = ThreadMode.MAIN)
public void onRecipientPreferenceUpdate(final RecipientPreferenceEvent event) {
if (Arrays.equals(event.getRecipients().getAddresses(), this.recipients.getAddresses())) {
new RecipientPreferencesTask().execute(this.recipients);
if (event.getRecipient().getAddress().equals(this.recipient.getAddress())) {
new RecipientPreferencesTask().execute(this.recipient);
}
}
@ -1324,11 +1319,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "Group update received...");
if (recipients != null) {
if (recipient != null) {
Log.w(TAG, "Looking up new recipients...");
recipients = RecipientFactory.getRecipientsFor(context, recipients.getAddresses(), true);
recipients.addListener(ConversationActivity.this);
onModified(recipients);
recipient = RecipientFactory.getRecipientFor(context, recipient.getAddress(), true);
recipient.addListener(ConversationActivity.this);
onModified(recipient);
fragment.reloadList();
}
}
@ -1422,7 +1417,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
protected ListenableFuture<Long> saveDraft() {
final SettableFuture<Long> future = new SettableFuture<>();
if (this.recipients == null || this.recipients.isEmpty()) {
if (this.recipient == null) {
future.set(threadId);
return future;
}
@ -1440,7 +1435,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
long threadId = params[0];
if (drafts.size() > 0) {
if (threadId == -1) threadId = threadDatabase.getThreadIdFor(getRecipients(), thisDistributionType);
if (threadId == -1) threadId = threadDatabase.getThreadIdFor(getRecipient(), thisDistributionType);
draftDatabase.insertDrafts(new MasterCipher(thisMasterSecret), threadId, drafts);
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
@ -1468,8 +1463,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
setStatusBarColor(color.toStatusBarColor(this));
}
private void setBlockedUserState(Recipients recipients, boolean isSecureText, boolean isDefaultSms) {
if (recipients.isBlocked()) {
private void setBlockedUserState(Recipient recipient, boolean isSecureText, boolean isDefaultSms) {
if (recipient.isBlocked()) {
unblockButton.setVisibility(View.VISIBLE);
composePanel.setVisibility(View.GONE);
makeDefaultSmsButton.setVisibility(View.GONE);
@ -1499,42 +1494,33 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private boolean isSingleConversation() {
return getRecipients() != null && getRecipients().isSingleRecipient() && !getRecipients().isGroupRecipient();
return getRecipient() != null && !getRecipient().isGroupRecipient();
}
private boolean isActiveGroup() {
if (!isGroupConversation()) return false;
try {
byte[] groupId = GroupUtil.getDecodedId(getRecipients().getPrimaryRecipient().getAddress().toGroupString());
GroupRecord record = DatabaseFactory.getGroupDatabase(this).getGroup(groupId);
return record != null && record.isActive();
} catch (IOException e) {
Log.w("ConversationActivity", e);
return false;
}
GroupRecord record = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getAddress().toGroupString());
return record != null && record.isActive();
}
private boolean isSelfConversation() {
if (!TextSecurePreferences.isPushRegistered(this)) return false;
if (!recipients.isSingleRecipient()) return false;
if (recipients.getPrimaryRecipient().isGroupRecipient()) return false;
if (!TextSecurePreferences.isPushRegistered(this)) return false;
if (recipient.isGroupRecipient()) return false;
return Util.isOwnNumber(this, recipients.getPrimaryRecipient().getAddress());
return Util.isOwnNumber(this, recipient.getAddress());
}
private boolean isGroupConversation() {
return getRecipients() != null &&
(!getRecipients().isSingleRecipient() || getRecipients().isGroupRecipient());
return getRecipient() != null && getRecipient().isGroupRecipient();
}
private boolean isPushGroupConversation() {
return getRecipients() != null && getRecipients().isGroupRecipient();
return getRecipient() != null && getRecipient().isPushGroupRecipient();
}
protected Recipients getRecipients() {
return this.recipients;
protected Recipient getRecipient() {
return this.recipient;
}
protected long getThreadId() {
@ -1592,7 +1578,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
fragment.setLastSeen(0);
if (refreshFragment) {
fragment.reload(recipients, threadId);
fragment.reload(recipient, threadId);
MessageNotifier.setVisibleThread(threadId);
}
@ -1602,26 +1588,26 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void sendMessage() {
try {
Recipients recipients = getRecipients();
Recipient recipient = getRecipient();
if (recipients == null) {
if (recipient == null) {
throw new RecipientFormattingException("Badly formatted");
}
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
long expiresIn = recipients.getExpireMessages() * 1000;
long expiresIn = recipient.getExpireMessages() * 1000;
Log.w(TAG, "isManual Selection: " + sendButton.isManualSelection());
Log.w(TAG, "forceSms: " + forceSms);
if ((!recipients.isSingleRecipient() || recipients.isEmailRecipient()) && !isMmsEnabled) {
if ((!recipient.isMmsGroupRecipient() || recipient.getAddress().isEmail()) && !isMmsEnabled) {
handleManualMmsRequired();
} else if (!forceSms && identityRecords.isUnverified()) {
handleUnverifiedRecipients();
} else if (!forceSms && identityRecords.isUntrusted()) {
handleUntrustedRecipients();
} else if (attachmentManager.isAttachmentPresent() || !recipients.isSingleRecipient() || recipients.isGroupRecipient() || recipients.isEmailRecipient()) {
} else if (attachmentManager.isAttachmentPresent() || recipient.isGroupRecipient() || recipient.getAddress().isEmail()) {
sendMediaMessage(forceSms, expiresIn, subscriptionId);
} else {
sendTextMessage(forceSms, expiresIn, subscriptionId);
@ -1649,7 +1635,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
{
final SettableFuture<Void> future = new SettableFuture<>();
final Context context = getApplicationContext();
OutgoingMediaMessage outgoingMessage = new OutgoingMediaMessage(recipients,
OutgoingMediaMessage outgoingMessage = new OutgoingMediaMessage(recipient,
slideDeck,
body,
System.currentTimeMillis(),
@ -1693,9 +1679,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
OutgoingTextMessage message;
if (isSecureText && !forceSms) {
message = new OutgoingEncryptedMessage(recipients, getMessage(), expiresIn);
message = new OutgoingEncryptedMessage(recipient, getMessage(), expiresIn);
} else {
message = new OutgoingTextMessage(recipients, getMessage(), expiresIn, subscriptionId);
message = new OutgoingTextMessage(recipient, getMessage(), expiresIn, subscriptionId);
}
this.composeText.setText("");
@ -1734,7 +1720,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
.setDefaultSubscriptionId(recipients, subscriptionId.or(-1));
.setDefaultSubscriptionId(recipient, subscriptionId.or(-1));
return null;
}
}.execute();
@ -1796,7 +1782,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
try {
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
long expiresIn = recipients.getExpireMessages() * 1000;
long expiresIn = recipient.getExpireMessages() * 1000;
AudioSlide audioSlide = new AudioSlide(ConversationActivity.this, result.first, result.second, MediaUtil.AUDIO_AAC, true);
SlideDeck slideDeck = new SlideDeck();
slideDeck.addSlide(audioSlide);
@ -1997,21 +1983,21 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
updateToggleButtonState();
}
private class RecipientPreferencesTask extends AsyncTask<Recipients, Void, Pair<Recipients,RecipientsPreferences>> {
private class RecipientPreferencesTask extends AsyncTask<Recipient, Void, Pair<Recipient,RecipientsPreferences>> {
@Override
protected Pair<Recipients, RecipientsPreferences> doInBackground(Recipients... recipients) {
if (recipients.length != 1 || recipients[0] == null) {
protected Pair<Recipient, RecipientsPreferences> doInBackground(Recipient... recipient) {
if (recipient.length != 1 || recipient[0] == null) {
throw new AssertionError("task needs exactly one Recipients object");
}
Optional<RecipientsPreferences> prefs = DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
.getRecipientsPreferences(recipients[0].getAddresses());
return new Pair<>(recipients[0], prefs.orNull());
.getRecipientsPreferences(recipient[0].getAddress());
return new Pair<>(recipient[0], prefs.orNull());
}
@Override
protected void onPostExecute(@NonNull Pair<Recipients, RecipientsPreferences> result) {
if (result.first == recipients) {
protected void onPostExecute(@NonNull Pair<Recipient, RecipientsPreferences> result) {
if (result.first == recipient) {
updateInviteReminder(result.second != null && result.second.hasSeenInviteReminder());
updateDefaultSubscriptionId(result.second != null ? result.second.getDefaultSubscriptionId() : Optional.<Integer>absent());
}

View File

@ -41,7 +41,7 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.LRUCache;
@ -93,7 +93,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
private final @Nullable ItemClickListener clickListener;
private final @NonNull MasterSecret masterSecret;
private final @NonNull Locale locale;
private final @NonNull Recipients recipients;
private final @NonNull Recipient recipient;
private final @NonNull MmsSmsDatabase db;
private final @NonNull LayoutInflater inflater;
private final @NonNull Calendar calendar;
@ -143,7 +143,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
this.masterSecret = null;
this.locale = null;
this.clickListener = null;
this.recipients = null;
this.recipient = null;
this.inflater = null;
this.db = null;
this.calendar = null;
@ -158,7 +158,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@NonNull Locale locale,
@Nullable ItemClickListener clickListener,
@Nullable Cursor cursor,
@NonNull Recipients recipients)
@NonNull Recipient recipient)
{
super(context, cursor);
@ -166,7 +166,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
this.masterSecret = masterSecret;
this.locale = locale;
this.clickListener = clickListener;
this.recipients = recipients;
this.recipient = recipient;
this.inflater = LayoutInflater.from(context);
this.db = DatabaseFactory.getMmsSmsDatabase(context);
this.calendar = Calendar.getInstance();
@ -188,7 +188,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) {
long start = System.currentTimeMillis();
viewHolder.getView().bind(masterSecret, messageRecord, locale, batchSelected, recipients);
viewHolder.getView().bind(masterSecret, messageRecord, locale, batchSelected, recipient);
Log.w(TAG, "Bind time: " + (System.currentTimeMillis() - start));
}

View File

@ -61,8 +61,8 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
@ -91,7 +91,7 @@ public class ConversationFragment extends Fragment
private ConversationFragmentListener listener;
private MasterSecret masterSecret;
private Recipients recipients;
private Recipient recipient;
private long threadId;
private long lastSeen;
private boolean firstLoad;
@ -184,7 +184,7 @@ public class ConversationFragment extends Fragment
}
private void initializeResources() {
this.recipients = RecipientFactory.getRecipientsFor(getActivity(), Address.fromParcelable(getActivity().getIntent().getParcelableArrayExtra(ConversationActivity.ADDRESSES_EXTRA)), true);
this.recipient = RecipientFactory.getRecipientFor(getActivity(), (Address)getActivity().getIntent().getParcelableExtra(ConversationActivity.ADDRESS_EXTRA), true);
this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
this.firstLoad = true;
@ -194,8 +194,8 @@ public class ConversationFragment extends Fragment
}
private void initializeListAdapter() {
if (this.recipients != null && this.threadId != -1) {
ConversationAdapter adapter = new ConversationAdapter(getActivity(), masterSecret, locale, selectionClickListener, null, this.recipients);
if (this.recipient != null && this.threadId != -1) {
ConversationAdapter adapter = new ConversationAdapter(getActivity(), masterSecret, locale, selectionClickListener, null, this.recipient);
list.setAdapter(adapter);
list.addItemDecoration(new StickyHeaderDecoration(adapter, false, false));
@ -256,8 +256,8 @@ public class ConversationFragment extends Fragment
else throw new AssertionError();
}
public void reload(Recipients recipients, long threadId) {
this.recipients = recipients;
public void reload(Recipient recipient, long threadId) {
this.recipient = recipient;
if (this.threadId != threadId) {
this.threadId = threadId;
@ -359,8 +359,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.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, (!recipients.isSingleRecipient() || recipients.isGroupRecipient()) && message.isPush());
intent.putExtra(MessageDetailsActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, recipient.isGroupRecipient() && message.isPush());
startActivity(intent);
}

View File

@ -70,7 +70,7 @@ import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicTheme;
@ -97,7 +97,7 @@ import java.util.Set;
*/
public class ConversationItem extends LinearLayout
implements Recipient.RecipientModifiedListener, Recipients.RecipientsModifiedListener, BindableConversationItem
implements RecipientModifiedListener, BindableConversationItem
{
private final static String TAG = ConversationItem.class.getSimpleName();
@ -119,7 +119,7 @@ public class ConversationItem extends LinearLayout
private AlertView alertView;
private @NonNull Set<MessageRecord> batchSelected = new HashSet<>();
private @Nullable Recipients conversationRecipients;
private @Nullable Recipient conversationRecipient;
private @NonNull Stub<ThumbnailView> mediaThumbnailStub;
private @NonNull Stub<AudioView> audioViewStub;
private @NonNull Stub<DocumentView> documentViewStub;
@ -180,18 +180,18 @@ public class ConversationItem extends LinearLayout
@NonNull MessageRecord messageRecord,
@NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected,
@NonNull Recipients conversationRecipients)
@NonNull Recipient conversationRecipient)
{
this.masterSecret = masterSecret;
this.messageRecord = messageRecord;
this.locale = locale;
this.batchSelected = batchSelected;
this.conversationRecipients = conversationRecipients;
this.groupThread = !conversationRecipients.isSingleRecipient() || conversationRecipients.isGroupRecipient();
this.conversationRecipient = conversationRecipient;
this.groupThread = conversationRecipient.isGroupRecipient();
this.recipient = messageRecord.getIndividualRecipient();
this.recipient.addListener(this);
this.conversationRecipients.addListener(this);
this.conversationRecipient.addListener(this);
setMediaAttributes(messageRecord);
setInteractionState(messageRecord);
@ -241,35 +241,35 @@ public class ConversationItem extends LinearLayout
}
if (audioViewStub.resolved()) {
setAudioViewTint(messageRecord, conversationRecipients);
setAudioViewTint(messageRecord, conversationRecipient);
}
if (documentViewStub.resolved()) {
setDocumentViewTint(messageRecord, conversationRecipients);
setDocumentViewTint(messageRecord, conversationRecipient);
}
}
private void setAudioViewTint(MessageRecord messageRecord, Recipients recipients) {
private void setAudioViewTint(MessageRecord messageRecord, Recipient recipient) {
if (messageRecord.isOutgoing()) {
if (DynamicTheme.LIGHT.equals(TextSecurePreferences.getTheme(context))) {
audioViewStub.get().setTint(recipients.getColor().toConversationColor(context), defaultBubbleColor);
audioViewStub.get().setTint(recipient.getColor().toConversationColor(context), defaultBubbleColor);
} else {
audioViewStub.get().setTint(Color.WHITE, defaultBubbleColor);
}
} else {
audioViewStub.get().setTint(Color.WHITE, recipients.getColor().toConversationColor(context));
audioViewStub.get().setTint(Color.WHITE, recipient.getColor().toConversationColor(context));
}
}
private void setDocumentViewTint(MessageRecord messageRecord, Recipients recipients) {
private void setDocumentViewTint(MessageRecord messageRecord, Recipient recipient) {
if (messageRecord.isOutgoing()) {
if (DynamicTheme.LIGHT.equals(TextSecurePreferences.getTheme(context))) {
documentViewStub.get().setTint(recipients.getColor().toConversationColor(context), defaultBubbleColor);
documentViewStub.get().setTint(recipient.getColor().toConversationColor(context), defaultBubbleColor);
} else {
documentViewStub.get().setTint(Color.WHITE, defaultBubbleColor);
}
} else {
documentViewStub.get().setTint(Color.WHITE, recipients.getColor().toConversationColor(context));
documentViewStub.get().setTint(Color.WHITE, recipient.getColor().toConversationColor(context));
}
}
@ -535,16 +535,7 @@ public class ConversationItem extends LinearLayout
setBubbleState(messageRecord, recipient);
setContactPhoto(recipient);
setGroupMessageStatus(messageRecord, recipient);
}
});
}
@Override
public void onModified(final Recipients recipients) {
Util.runOnMain(new Runnable() {
@Override
public void run() {
setAudioViewTint(messageRecord, recipients);
setAudioViewTint(messageRecord, recipient);
}
});
}
@ -635,7 +626,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.ADDRESSES_EXTRA, conversationRecipients.getAddresses());
intent.putExtra(MessageDetailsActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
context.startActivity(intent);
} else if (!messageRecord.isOutgoing() && messageRecord.isIdentityMismatchFailure()) {
handleApproveIdentity();

View File

@ -37,8 +37,8 @@ import org.thoughtcrime.securesms.components.RatingManager;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
@ -160,9 +160,9 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
}
@Override
public void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeen) {
public void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen) {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis());

View File

@ -78,13 +78,8 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
@Override
public long getItemId(@NonNull Cursor cursor) {
ThreadRecord record = getThreadRecord(cursor);
StringBuilder builder = new StringBuilder("" + record.getThreadId());
for (Address address : record.getRecipients().getAddresses()) {
builder.append("::").append(address.serialize());
}
return Conversions.byteArrayToLong(digest.digest(builder.toString().getBytes()));
return Conversions.byteArrayToLong(digest.digest(record.getRecipient().getAddress().serialize().getBytes()));
}
public ConversationListAdapter(@NonNull Context context,

View File

@ -6,7 +6,7 @@ import android.support.annotation.NonNull;
import android.view.MenuItem;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
@ -54,9 +54,9 @@ public class ConversationListArchiveActivity extends PassphraseRequiredActionBar
}
@Override
public void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeenTime) {
public void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeenTime) {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.IS_ARCHIVED_EXTRA, true);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);

View File

@ -69,7 +69,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask;
@ -309,8 +309,8 @@ public class ConversationListFragment extends Fragment
getListAdapter().getBatchSelections().size()));
}
private void handleCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeen) {
((ConversationSelectedListener)getActivity()).onCreateConversation(threadId, recipients, distributionType, lastSeen);
private void handleCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen) {
((ConversationSelectedListener)getActivity()).onCreateConversation(threadId, recipient, distributionType, lastSeen);
}
@Override
@ -331,7 +331,7 @@ public class ConversationListFragment extends Fragment
@Override
public void onItemClick(ConversationListItem item) {
if (actionMode == null) {
handleCreateConversation(item.getThreadId(), item.getRecipients(),
handleCreateConversation(item.getThreadId(), item.getRecipient(),
item.getDistributionType(), item.getLastSeen());
} else {
ConversationListAdapter adapter = (ConversationListAdapter)list.getAdapter();
@ -363,7 +363,7 @@ public class ConversationListFragment extends Fragment
}
public interface ConversationSelectedListener {
void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeen);
void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen);
void onSwitchToArchive();
}

View File

@ -31,14 +31,15 @@ import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.components.AlertView;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.DeliveryStatusView;
import org.thoughtcrime.securesms.components.AlertView;
import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.ResUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -56,7 +57,7 @@ import static org.thoughtcrime.securesms.util.SpanUtil.color;
*/
public class ConversationListItem extends RelativeLayout
implements Recipients.RecipientsModifiedListener,
implements RecipientModifiedListener,
BindableConversationListItem, Unbindable
{
private final static String TAG = ConversationListItem.class.getSimpleName();
@ -65,7 +66,7 @@ public class ConversationListItem extends RelativeLayout
private final static Typeface LIGHT_TYPEFACE = Typeface.create("sans-serif-light", Typeface.NORMAL);
private Set<Long> selectedThreads;
private Recipients recipients;
private Recipient recipient;
private long threadId;
private TextView subjectView;
private FromTextView fromView;
@ -116,14 +117,14 @@ public class ConversationListItem extends RelativeLayout
@NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode)
{
this.selectedThreads = selectedThreads;
this.recipients = thread.getRecipients();
this.recipient = thread.getRecipient();
this.threadId = thread.getThreadId();
this.read = thread.isRead();
this.distributionType = thread.getDistributionType();
this.lastSeen = thread.getLastSeen();
this.recipients.addListener(this);
this.fromView.setText(recipients, read);
this.recipient.addListener(this);
this.fromView.setText(recipient, read);
this.subjectView.setText(thread.getDisplayBody());
this.subjectView.setTypeface(read ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
@ -144,21 +145,21 @@ public class ConversationListItem extends RelativeLayout
setThumbnailSnippet(masterSecret, thread);
setBatchState(batchMode);
setBackground(thread);
setRippleColor(recipients);
this.contactPhotoImage.setAvatar(recipients, true);
setRippleColor(recipient);
this.contactPhotoImage.setAvatar(recipient, true);
}
@Override
public void unbind() {
if (this.recipients != null) this.recipients.removeListener(this);
if (this.recipient != null) this.recipient.removeListener(this);
}
private void setBatchState(boolean batch) {
setSelected(batch && selectedThreads.contains(threadId));
}
public Recipients getRecipients() {
return recipients;
public Recipient getRecipient() {
return recipient;
}
public long getThreadId() {
@ -226,21 +227,21 @@ public class ConversationListItem extends RelativeLayout
}
@TargetApi(VERSION_CODES.LOLLIPOP)
private void setRippleColor(Recipients recipients) {
private void setRippleColor(Recipient recipient) {
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
((RippleDrawable)(getBackground()).mutate())
.setColor(ColorStateList.valueOf(recipients.getColor().toConversationColor(getContext())));
.setColor(ColorStateList.valueOf(recipient.getColor().toConversationColor(getContext())));
}
}
@Override
public void onModified(final Recipients recipients) {
public void onModified(final Recipient recipient) {
handler.post(new Runnable() {
@Override
public void run() {
fromView.setText(recipients, read);
contactPhotoImage.setAvatar(recipients, true);
setRippleColor(recipients);
fromView.setText(recipient, read);
contactPhotoImage.setAvatar(recipient, true);
setRippleColor(recipient);
}
});
}

View File

@ -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.ADDRESSES_EXTRA, getRecipients().getAddresses());
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, getRecipient().getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, result);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {

View File

@ -10,7 +10,6 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.ViewUtil;
public class ConversationTitleView extends LinearLayout {
@ -42,14 +41,13 @@ public class ConversationTitleView extends LinearLayout {
ViewUtil.setTextViewGravityStart(this.subtitle, getContext());
}
public void setTitle(@Nullable Recipients recipients) {
if (recipients == null) setComposeTitle();
else if (recipients.isSingleRecipient()) setRecipientTitle(recipients.getPrimaryRecipient());
else setRecipientsTitle(recipients);
public void setTitle(@Nullable Recipient recipient) {
if (recipient == null) setComposeTitle();
else setRecipientTitle(recipient);
if (recipients != null && recipients.isBlocked()) {
if (recipient != null && recipient.isBlocked()) {
title.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_block_white_18dp, 0, 0, 0);
} else if (recipients != null && recipients.isMuted()) {
} else if (recipient != null && recipient.isMuted()) {
title.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_volume_off_white_18dp, 0, 0, 0);
} else {
title.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
@ -86,17 +84,4 @@ public class ConversationTitleView extends LinearLayout {
this.subtitle.setVisibility(View.GONE);
}
}
private void setRecipientsTitle(Recipients recipients) {
int size = recipients.getRecipientsList().size();
title.setText(getContext().getString(R.string.ConversationActivity_group_conversation));
subtitle.setText(getContext().getResources().getQuantityString(R.plurals.ConversationActivity_d_recipients_in_group, size, size));
subtitle.setVisibility(View.VISIBLE);
}
}

View File

@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.IdentityUtil;
@ -33,7 +33,7 @@ import java.util.Set;
import java.util.concurrent.ExecutionException;
public class ConversationUpdateItem extends LinearLayout
implements Recipients.RecipientsModifiedListener, Recipient.RecipientModifiedListener, BindableConversationItem
implements RecipientModifiedListener, BindableConversationItem
{
private static final String TAG = ConversationUpdateItem.class.getSimpleName();
@ -71,7 +71,7 @@ public class ConversationUpdateItem extends LinearLayout
@NonNull MessageRecord messageRecord,
@NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected,
@NonNull Recipients conversationRecipients)
@NonNull Recipient conversationRecipient)
{
this.masterSecret = masterSecret;
this.batchSelected = batchSelected;
@ -167,12 +167,7 @@ public class ConversationUpdateItem extends LinearLayout
body.setText(messageRecord.getDisplayBody());
date.setVisibility(View.GONE);
}
@Override
public void onModified(Recipients recipients) {
onModified(recipients.getPrimaryRecipient());
}
@Override
public void onModified(Recipient recipient) {
Util.runOnMain(new Runnable() {

View File

@ -62,11 +62,9 @@ import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
import org.thoughtcrime.securesms.mms.RoundedCorners;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@ -76,7 +74,6 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
@ -214,17 +211,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
private void initializeExistingGroup() {
final Address groupAddress = getIntent().getParcelableExtra(GROUP_ADDRESS_EXTRA);
byte[] groupId;
try {
if (groupAddress != null) groupId = GroupUtil.getDecodedId(groupAddress.toGroupString());
else groupId = null;
} catch (IOException ioe) {
Log.w(TAG, "Couldn't decode the encoded groupId passed in via intent", ioe);
groupId = null;
}
if (groupId != null) {
new FillExistingGroupInfoAsyncTask(this).execute(groupId);
if (groupAddress != null) {
new FillExistingGroupInfoAsyncTask(this).execute(groupAddress.toGroupString());
}
}
@ -261,8 +249,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
@Override
public void onRecipientsPanelUpdate(Recipients recipients) {
if (recipients != null) addSelectedContacts(recipients.getRecipientsList());
public void onRecipientsPanelUpdate(List<Recipient> recipients) {
if (recipients != null && !recipients.isEmpty()) addSelectedContacts(recipients);
}
private void handleGroupCreate() {
@ -274,7 +262,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
if (isSignalGroup()) {
new CreateSignalGroupTask(this, masterSecret, avatarBmp, getGroupName(), getAdapter().getRecipients()).execute();
} else {
new CreateMmsGroupTask(this, getAdapter().getRecipients()).execute();
new CreateMmsGroupTask(this, masterSecret, getAdapter().getRecipients()).execute();
}
}
@ -283,11 +271,11 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
getGroupName(), getAdapter().getRecipients()).execute();
}
private void handleOpenConversation(long threadId, Recipients recipients) {
private void handleOpenConversation(long threadId, Recipient recipient) {
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.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
startActivity(intent);
finish();
}
@ -347,31 +335,35 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
}
private static class CreateMmsGroupTask extends AsyncTask<Void,Void,Long> {
private GroupCreateActivity activity;
private Set<Recipient> members;
private static class CreateMmsGroupTask extends AsyncTask<Void,Void,GroupActionResult> {
private final GroupCreateActivity activity;
private final MasterSecret masterSecret;
private final Set<Recipient> members;
public CreateMmsGroupTask(GroupCreateActivity activity, Set<Recipient> members) {
this.activity = activity;
this.members = members;
public CreateMmsGroupTask(GroupCreateActivity activity, MasterSecret masterSecret, Set<Recipient> members) {
this.activity = activity;
this.masterSecret = masterSecret;
this.members = members;
}
@Override
protected Long doInBackground(Void... avoid) {
Recipients recipients = RecipientFactory.getRecipientsFor(activity, members, false);
return DatabaseFactory.getThreadDatabase(activity)
.getThreadIdFor(recipients, ThreadDatabase.DistributionTypes.CONVERSATION);
}
protected GroupActionResult doInBackground(Void... avoid) {
List<Address> memberAddresses = new LinkedList<>();
@Override
protected void onPostExecute(Long resultThread) {
if (resultThread > -1) {
activity.handleOpenConversation(resultThread,
RecipientFactory.getRecipientsFor(activity, members, true));
} else {
Toast.makeText(activity, R.string.GroupCreateActivity_contacts_mms_exception, Toast.LENGTH_LONG).show();
activity.finish();
for (Recipient recipient : members) {
memberAddresses.add(recipient.getAddress());
}
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true);
Recipient groupRecipient = RecipientFactory.getRecipientFor(activity, Address.fromSerialized(groupId), true);
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
return new GroupActionResult(groupRecipient, threadId);
}
@Override
protected void onPostExecute(GroupActionResult result) {
activity.handleOpenConversation(result.getThreadId(), result.getGroupRecipient());
}
@Override
@ -427,11 +419,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
@Override
protected Optional<GroupActionResult> doInBackground(Void... aVoid) {
try {
return Optional.of(GroupManager.createGroup(activity, masterSecret, members, avatar, name));
} catch (InvalidNumberException e) {
return Optional.absent();
}
return Optional.of(GroupManager.createGroup(activity, masterSecret, members, avatar, name, false));
}
@Override
@ -449,10 +437,10 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
private static class UpdateSignalGroupTask extends SignalGroupTask {
private byte[] groupId;
private String groupId;
public UpdateSignalGroupTask(GroupCreateActivity activity,
MasterSecret masterSecret, byte[] groupId, Bitmap avatar, String name,
MasterSecret masterSecret, String groupId, Bitmap avatar, String name,
Set<Recipient> members)
{
super(activity, masterSecret, avatar, name, members);
@ -474,7 +462,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().getPrimaryRecipient().getAddress());
intent.putExtra(GROUP_ADDRESS_EXTRA, result.get().getGroupRecipient().getAddress());
activity.setResult(RESULT_OK, intent);
activity.finish();
}
@ -541,7 +529,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
}
private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask<byte[],Void,Optional<GroupData>> {
private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask<String,Void,Optional<GroupData>> {
private GroupCreateActivity activity;
public FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) {
@ -552,12 +540,12 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
@Override
protected Optional<GroupData> doInBackground(byte[]... groupIds) {
protected Optional<GroupData> doInBackground(String... groupIds) {
final GroupDatabase db = DatabaseFactory.getGroupDatabase(activity);
final Recipients recipients = db.getGroupMembers(groupIds[0], false);
final List<Recipient> recipients = db.getGroupMembers(groupIds[0], false);
final GroupRecord group = db.getGroup(groupIds[0]);
final Set<Recipient> existingContacts = new HashSet<>(recipients.getRecipientsList().size());
existingContacts.addAll(recipients.getRecipientsList());
final Set<Recipient> existingContacts = new HashSet<>(recipients.size());
existingContacts.addAll(recipients);
if (group != null) {
return Optional.of(new GroupData(groupIds[0],
@ -600,13 +588,13 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
private static class GroupData {
byte[] id;
String id;
Set<Recipient> recipients;
Bitmap avatarBmp;
byte[] avatarBytes;
String name;
public GroupData(byte[] id, Set<Recipient> recipients, Bitmap avatarBmp, byte[] avatarBytes, String name) {
public GroupData(String id, Set<Recipient> recipients, Bitmap avatarBmp, byte[] avatarBytes, String name) {
this.id = id;
this.recipients = recipients;
this.avatarBmp = avatarBmp;

View File

@ -7,48 +7,36 @@ import android.graphics.Rect;
import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
public class GroupMembersDialog extends AsyncTask<Void, Void, Recipients> {
public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
private static final String TAG = GroupMembersDialog.class.getSimpleName();
private final Recipients recipients;
private final Recipient recipient;
private final Context context;
public GroupMembersDialog(Context context, Recipients recipients) {
this.recipients = recipients;
this.context = context;
public GroupMembersDialog(Context context, Recipient recipient) {
this.recipient = recipient;
this.context = context;
}
@Override
public void onPreExecute() {}
@Override
protected Recipients doInBackground(Void... params) {
try {
String groupId = recipients.getPrimaryRecipient().getAddress().toGroupString();
return DatabaseFactory.getGroupDatabase(context)
.getGroupMembers(GroupUtil.getDecodedId(groupId), true);
} catch (IOException e) {
Log.w(TAG, e);
return RecipientFactory.getRecipientsFor(context, new LinkedList<Recipient>(), true);
}
protected List<Recipient> doInBackground(Void... params) {
return DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), true);
}
@Override
public void onPostExecute(Recipients members) {
public void onPostExecute(List<Recipient> members) {
GroupMembers groupMembers = new GroupMembers(members);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.ConversationActivity_group_members);
@ -60,8 +48,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, Recipients> {
}
public void display() {
if (recipients.isGroupRecipient()) execute();
else onPostExecute(recipients);
execute();
}
private static class GroupMembersOnClickListener implements DialogInterface.OnClickListener {
@ -107,8 +94,8 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, Recipients> {
private final LinkedList<Recipient> members = new LinkedList<>();
public GroupMembers(Recipients recipients) {
for (Recipient recipient : recipients.getRecipientsList()) {
public GroupMembers(List<Recipient> recipients) {
for (Recipient recipient : recipients) {
if (isLocalNumber(recipient)) {
members.push(recipient);
} else {

View File

@ -30,8 +30,8 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -231,19 +231,17 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
if (context == null) return null;
for (String number : numbers) {
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, number)}, false);
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromExternal(context, number), false);
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipient.getAddress());
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
if (recipients.getPrimaryRecipient() != null) {
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipients.getAddresses());
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipient, message, subscriptionId), -1L, true, null);
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipients, message, subscriptionId), -1L, true, null);
if (recipients.getPrimaryRecipient().getContactUri() != null) {
DatabaseFactory.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipients, true);
}
if (recipient.getContactUri() != null) {
DatabaseFactory.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipient, true);
}
}
return null;
}

View File

@ -24,7 +24,6 @@ import android.database.Cursor;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
@ -43,8 +42,9 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
@ -59,7 +59,7 @@ import java.util.List;
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private final static String TAG = MediaOverviewActivity.class.getSimpleName();
public static final String ADDRESSES_EXTRA = "addresses";
public static final String ADDRESS_EXTRA = "address";
public static final String THREAD_ID_EXTRA = "thread_id";
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@ -69,7 +69,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
private RecyclerView gridView;
private GridLayoutManager gridManager;
private TextView noImages;
private Recipients recipients;
private Recipient recipient;
private long threadId;
@Override
@ -114,9 +114,9 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
}
private void initializeActionBar() {
getSupportActionBar().setTitle(recipients == null
getSupportActionBar().setTitle(recipient == null
? getString(R.string.AndroidManifest__all_media)
: getString(R.string.AndroidManifest__all_media_named, recipients.toShortString()));
: getString(R.string.AndroidManifest__all_media_named, recipient.toShortString()));
}
@Override
@ -133,20 +133,20 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
gridView.setLayoutManager(gridManager);
gridView.setHasFixedSize(true);
Parcelable[] parcelables = getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA);
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
if (parcelables != null) {
recipients = RecipientFactory.getRecipientsFor(this, Address.fromParcelable(parcelables), true);
if (address != null) {
recipient = RecipientFactory.getRecipientFor(this, address, true);
} else if (threadId > -1) {
recipients = DatabaseFactory.getThreadDatabase(this).getRecipientsForThreadId(threadId);
recipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadId);
} else {
recipients = null;
recipient = null;
}
if (recipients != null) {
recipients.addListener(new Recipients.RecipientsModifiedListener() {
if (recipient != null) {
recipient.addListener(new RecipientModifiedListener() {
@Override
public void onModified(Recipients recipients) {
public void onModified(Recipient recipients) {
initializeActionBar();
}
});

View File

@ -37,7 +37,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.mms.VideoSlide;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicLanguage;

View File

@ -47,26 +47,25 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
/**
* @author Jake McGinty
*/
public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks<Cursor>, Recipients.RecipientsModifiedListener {
public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks<Cursor>, RecipientModifiedListener {
private final static String TAG = MessageDetailsActivity.class.getSimpleName();
public final static String MASTER_SECRET_EXTRA = "master_secret";
@ -74,7 +73,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
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 ADDRESSES_EXTRA = "addresses";
public final static String ADDRESS_EXTRA = "address";
private MasterSecret masterSecret;
private long threadId;
@ -139,10 +138,10 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
private void initializeActionBar() {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Recipients recipients = RecipientFactory.getRecipientsFor(this, Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA)), true);
recipients.addListener(this);
Recipient recipient = RecipientFactory.getRecipientFor(this, (Address)getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
recipient.addListener(this);
setActionBarColor(recipients.getColor());
setActionBarColor(recipient.getColor());
}
private void setActionBarColor(MaterialColor color) {
@ -154,11 +153,11 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
}
@Override
public void onModified(final Recipients recipients) {
public void onModified(final Recipient recipient) {
Util.runOnMain(new Runnable() {
@Override
public void run() {
setActionBarColor(recipients.getColor());
setActionBarColor(recipient.getColor());
}
});
}
@ -243,7 +242,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
});
}
private void updateRecipients(MessageRecord messageRecord, Recipients recipients) {
private void updateRecipients(MessageRecord messageRecord, Recipient recipient, List<Recipient> recipients) {
final int toFromRes;
if (messageRecord.isMms() && !messageRecord.isPush() && !messageRecord.isOutgoing()) {
toFromRes = R.string.message_details_header__with;
@ -254,7 +253,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
}
toFrom.setText(toFromRes);
conversationItem.bind(masterSecret, messageRecord, dynamicLanguage.getCurrentLocale(),
new HashSet<MessageRecord>(), recipients);
new HashSet<MessageRecord>(), recipient);
recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, masterSecret, messageRecord,
recipients, isPushGroup));
}
@ -321,7 +320,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
return false;
}
private class MessageRecipientAsyncTask extends AsyncTask<Void,Void,Recipients> {
private class MessageRecipientAsyncTask extends AsyncTask<Void,Void,List<Recipient>> {
private WeakReference<Context> weakContext;
private MessageRecord messageRecord;
@ -335,41 +334,27 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
}
@Override
public Recipients doInBackground(Void... voids) {
public List<Recipient> doInBackground(Void... voids) {
Context context = getContext();
if (context == null) {
Log.w(TAG, "associated context is destroyed, finishing early");
return null;
}
Recipients recipients;
List<Recipient> recipients = new LinkedList<>();
final Recipients intermediaryRecipients;
if (messageRecord.isMms()) {
intermediaryRecipients = DatabaseFactory.getMmsAddressDatabase(context).getRecipientsForId(messageRecord.getId());
} else {
intermediaryRecipients = messageRecord.getRecipients();
}
if (!intermediaryRecipients.isGroupRecipient()) {
if (!messageRecord.getRecipient().isGroupRecipient()) {
Log.w(TAG, "Recipient is not a group, resolving members immediately.");
recipients = intermediaryRecipients;
recipients.add(messageRecord.getRecipient());
} else {
try {
Address groupId = intermediaryRecipients.getPrimaryRecipient().getAddress();
recipients = DatabaseFactory.getGroupDatabase(context)
.getGroupMembers(GroupUtil.getDecodedId(groupId.toGroupString()), false);
} catch (IOException e) {
Log.w(TAG, e);
recipients = RecipientFactory.getRecipientsFor(MessageDetailsActivity.this, new LinkedList<Recipient>(), false);
}
recipients.addAll(DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().getAddress().toGroupString(), false));
}
return recipients;
}
@Override
public void onPostExecute(Recipients recipients) {
public void onPostExecute(List<Recipient> recipients) {
if (getContext() == null) {
Log.w(TAG, "AsyncTask finished with a destroyed context, leaving early.");
return;
@ -377,7 +362,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
inflateMessageViewIfAbsent(messageRecord);
updateRecipients(messageRecord, recipients);
updateRecipients(messageRecord, messageRecord.getRecipient(), recipients);
if (messageRecord.isFailed()) {
errorText.setVisibility(View.VISIBLE);
metadataContainer.setVisibility(View.GONE);

View File

@ -10,22 +10,22 @@ import android.widget.BaseAdapter;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.Conversions;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.RecyclerListener {
private final Context context;
private final MasterSecret masterSecret;
private final MessageRecord record;
private final Recipients recipients;
private final boolean isPushGroup;
private final Context context;
private final MasterSecret masterSecret;
private final MessageRecord record;
private final List<Recipient> recipients;
private final boolean isPushGroup;
public MessageDetailsRecipientAdapter(Context context, MasterSecret masterSecret,
MessageRecord record, Recipients recipients,
MessageRecord record, List<Recipient> recipients,
boolean isPushGroup)
{
this.context = context;
@ -37,18 +37,18 @@ public class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsLi
@Override
public int getCount() {
return recipients.getRecipientsList().size();
return recipients.size();
}
@Override
public Object getItem(int position) {
return recipients.getRecipientsList().get(position);
return recipients.get(position);
}
@Override
public long getItemId(int position) {
try {
return Conversions.byteArrayToLong(MessageDigest.getInstance("SHA1").digest(recipients.getRecipientsList().get(position).getAddress().serialize().getBytes()));
return Conversions.byteArrayToLong(MessageDigest.getInstance("SHA1").digest(recipients.get(position).getAddress().serialize().getBytes()));
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
@ -60,7 +60,7 @@ public class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsLi
convertView = LayoutInflater.from(context).inflate(R.layout.message_recipient_list_item, parent, false);
}
Recipient recipient = recipients.getRecipientsList().get(position);
Recipient recipient = recipients.get(position);
((MessageRecipientListItem)convertView).set(masterSecret, record, recipient, isPushGroup);
return convertView;
}

View File

@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.sms.MessageSender;
/**
@ -43,7 +44,7 @@ import org.thoughtcrime.securesms.sms.MessageSender;
* @author Jake McGinty
*/
public class MessageRecipientListItem extends RelativeLayout
implements Recipient.RecipientModifiedListener
implements RecipientModifiedListener
{
private final static String TAG = MessageRecipientListItem.class.getSimpleName();
@ -67,6 +68,7 @@ public class MessageRecipientListItem extends RelativeLayout
@Override
protected void onFinishInflate() {
super.onFinishInflate();
this.fromView = (FromTextView) findViewById(R.id.from);
this.errorDescription = (TextView) findViewById(R.id.error_description);
this.actionDescription = (TextView) findViewById(R.id.action_description);
@ -172,11 +174,13 @@ public class MessageRecipientListItem extends RelativeLayout
}
private class ResendAsyncTask extends AsyncTask<Void,Void,Void> {
private final Context context;
private final MasterSecret masterSecret;
private final MessageRecord record;
private final NetworkFailure failure;
public ResendAsyncTask(MasterSecret masterSecret, MessageRecord record, NetworkFailure failure) {
this.context = getContext().getApplicationContext();
this.masterSecret = masterSecret;
this.record = record;
this.failure = failure;
@ -184,13 +188,13 @@ public class MessageRecipientListItem extends RelativeLayout
@Override
protected Void doInBackground(Void... params) {
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(getContext());
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
mmsDatabase.removeFailure(record.getId(), failure);
if (record.getRecipients().isGroupRecipient()) {
MessageSender.resendGroupMessage(getContext(), masterSecret, record, failure.getAddress());
if (record.getRecipient().isPushGroupRecipient()) {
MessageSender.resendGroupMessage(context, record, failure.getAddress());
} else {
MessageSender.resend(getContext(), masterSecret, record);
MessageSender.resend(context, masterSecret, record);
}
return null;
}

View File

@ -28,8 +28,8 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
/**
* Activity container for starting a new conversation.
@ -50,14 +50,14 @@ public class NewConversationActivity extends ContactSelectionActivity {
@Override
public void onContactSelected(String number) {
Recipients recipients = RecipientFactory.getRecipientsFor(this, new Address[] {Address.fromExternal(this, number)}, true);
Recipient recipient = RecipientFactory.getRecipientFor(this, Address.fromExternal(this, number), true);
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA));
intent.setDataAndType(getIntent().getData(), getIntent().getType());
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipients);
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);

View File

@ -41,8 +41,9 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.preferences.AdvancedRingtonePreference;
import org.thoughtcrime.securesms.preferences.ColorPreference;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
@ -53,11 +54,11 @@ import org.whispersystems.libsignal.util.guava.Optional;
import java.util.concurrent.ExecutionException;
public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements Recipients.RecipientsModifiedListener
public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener
{
private static final String TAG = RecipientPreferenceActivity.class.getSimpleName();
public static final String ADDRESSES_EXTRA = "recipient_addresses";
public static final String ADDRESS_EXTRA = "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";
@ -86,16 +87,16 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) {
setContentView(R.layout.recipient_preference_activity);
Address[] addresses = Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA));
Recipients recipients = RecipientFactory.getRecipientsFor(this, addresses, true);
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
Recipient recipient = RecipientFactory.getRecipientFor(this, address, true);
initializeToolbar();
initializeReceivers();
setHeader(recipients);
recipients.addListener(this);
setHeader(recipient);
recipient.addListener(this);
Bundle bundle = new Bundle();
bundle.putParcelableArray(ADDRESSES_EXTRA, addresses);
bundle.putParcelable(ADDRESS_EXTRA, address);
initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), masterSecret, null, bundle);
}
@ -149,9 +150,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
this.staleReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Recipients recipients = RecipientFactory.getRecipientsFor(context, Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA)), true);
recipients.addListener(RecipientPreferenceActivity.this);
onModified(recipients);
Recipient recipient = RecipientFactory.getRecipientFor(context, (Address)getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
recipient.addListener(RecipientPreferenceActivity.this);
onModified(recipient);
}
};
@ -162,37 +163,37 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
registerReceiver(staleReceiver, staleFilter);
}
private void setHeader(Recipients recipients) {
this.avatar.setAvatar(recipients, true);
this.title.setText(recipients.toShortString());
this.toolbar.setBackgroundColor(recipients.getColor().toActionBarColor(this));
private void setHeader(Recipient recipient) {
this.avatar.setAvatar(recipient, true);
this.title.setText(recipient.toShortString());
this.toolbar.setBackgroundColor(recipient.getColor().toActionBarColor(this));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(recipients.getColor().toStatusBarColor(this));
getWindow().setStatusBarColor(recipient.getColor().toStatusBarColor(this));
}
if (recipients.isBlocked()) this.blockedIndicator.setVisibility(View.VISIBLE);
else this.blockedIndicator.setVisibility(View.GONE);
if (recipient.isBlocked()) this.blockedIndicator.setVisibility(View.VISIBLE);
else this.blockedIndicator.setVisibility(View.GONE);
}
@Override
public void onModified(final Recipients recipients) {
public void onModified(final Recipient recipient) {
title.post(new Runnable() {
@Override
public void run() {
setHeader(recipients);
setHeader(recipient);
}
});
}
public static class RecipientPreferenceFragment
extends PreferenceFragment
implements Recipients.RecipientsModifiedListener
implements RecipientModifiedListener
{
private final Handler handler = new Handler();
private Recipients recipients;
private Recipient recipient;
private BroadcastReceiver staleReceiver;
private MasterSecret masterSecret;
private boolean canHaveSafetyNumber;
@ -223,29 +224,29 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
public void onResume() {
super.onResume();
setSummaries(recipients);
setSummaries(recipient);
}
@Override
public void onDestroy() {
super.onDestroy();
this.recipients.removeListener(this);
this.recipient.removeListener(this);
getActivity().unregisterReceiver(staleReceiver);
}
private void initializeRecipients() {
this.recipients = RecipientFactory.getRecipientsFor(getActivity(),
Address.fromParcelable(getArguments().getParcelableArray(ADDRESSES_EXTRA)),
true);
this.recipient = RecipientFactory.getRecipientFor(getActivity(),
(Address)getArguments().getParcelable(ADDRESS_EXTRA),
true);
this.recipients.addListener(this);
this.recipient.addListener(this);
this.staleReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
recipients.removeListener(RecipientPreferenceFragment.this);
recipients = RecipientFactory.getRecipientsFor(getActivity(), Address.fromParcelable(getArguments().getParcelableArray(ADDRESSES_EXTRA)), true);
onModified(recipients);
recipient.removeListener(RecipientPreferenceFragment.this);
recipient = RecipientFactory.getRecipientFor(getActivity(), (Address)getArguments().getParcelable(ADDRESS_EXTRA), true);
onModified(recipient);
}
};
@ -256,7 +257,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
getActivity().registerReceiver(staleReceiver, intentFilter);
}
private void setSummaries(Recipients recipients) {
private void setSummaries(Recipient recipient) {
CheckBoxPreference mutePreference = (CheckBoxPreference) this.findPreference(PREFERENCE_MUTED);
AdvancedRingtonePreference ringtonePreference = (AdvancedRingtonePreference) this.findPreference(PREFERENCE_TONE);
ListPreference vibratePreference = (ListPreference) this.findPreference(PREFERENCE_VIBRATE);
@ -264,9 +265,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
Preference blockPreference = this.findPreference(PREFERENCE_BLOCK);
final Preference identityPreference = this.findPreference(PREFERENCE_IDENTITY);
mutePreference.setChecked(recipients.isMuted());
mutePreference.setChecked(recipient.isMuted());
final Uri toneUri = recipients.getRingtone();
final Uri toneUri = recipient.getRingtone();
if (toneUri == null) {
ringtonePreference.setSummary(R.string.preferences__default);
@ -283,10 +284,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
}
}
if (recipients.getVibrate() == VibrateState.DEFAULT) {
if (recipient.getVibrate() == VibrateState.DEFAULT) {
vibratePreference.setSummary(R.string.preferences__default);
vibratePreference.setValueIndex(0);
} else if (recipients.getVibrate() == VibrateState.ENABLED) {
} else if (recipient.getVibrate() == VibrateState.ENABLED) {
vibratePreference.setSummary(R.string.RecipientPreferenceActivity_enabled);
vibratePreference.setValueIndex(1);
} else {
@ -294,18 +295,18 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
vibratePreference.setValueIndex(2);
}
if (!recipients.isSingleRecipient() || recipients.isGroupRecipient()) {
if (recipient.isGroupRecipient()) {
if (colorPreference != null) getPreferenceScreen().removePreference(colorPreference);
if (blockPreference != null) getPreferenceScreen().removePreference(blockPreference);
if (identityPreference != null) getPreferenceScreen().removePreference(identityPreference);
} else {
colorPreference.setChoices(MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(getActivity()));
colorPreference.setValue(recipients.getColor().toActionBarColor(getActivity()));
colorPreference.setValue(recipient.getColor().toActionBarColor(getActivity()));
if (recipients.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock);
if (recipient.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock);
else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block);
IdentityUtil.getRemoteIdentityKey(getActivity(), recipients.getPrimaryRecipient()).addListener(new ListenableFuture.Listener<Optional<IdentityRecord>>() {
IdentityUtil.getRemoteIdentityKey(getActivity(), recipient).addListener(new ListenableFuture.Listener<Optional<IdentityRecord>>() {
@Override
public void onSuccess(Optional<IdentityRecord> result) {
if (result.isPresent()) {
@ -328,11 +329,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
}
@Override
public void onModified(final Recipients recipients) {
public void onModified(final Recipient recipient) {
handler.post(new Runnable() {
@Override
public void run() {
setSummaries(recipients);
setSummaries(recipient);
}
});
}
@ -350,13 +351,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
uri = Uri.parse(value);
}
recipients.setRingtone(uri);
recipient.setRingtone(uri);
new AsyncTask<Uri, Void, Void>() {
@Override
protected Void doInBackground(Uri... params) {
DatabaseFactory.getRecipientPreferenceDatabase(getActivity())
.setRingtone(recipients, params[0]);
.setRingtone(recipient, params[0]);
return null;
}
}.execute(uri);
@ -371,13 +372,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
int value = Integer.parseInt((String) newValue);
final VibrateState vibrateState = VibrateState.fromId(value);
recipients.setVibrate(vibrateState);
recipient.setVibrate(vibrateState);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(getActivity())
.setVibrate(recipients, vibrateState);
.setVibrate(recipient, vibrateState);
return null;
}
}.execute();
@ -392,26 +393,26 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
public boolean onPreferenceChange(Preference preference, Object newValue) {
final int value = (Integer) newValue;
final MaterialColor selectedColor = MaterialColors.CONVERSATION_PALETTE.getByColor(getActivity(), value);
final MaterialColor currentColor = recipients.getColor();
final MaterialColor currentColor = recipient.getColor();
if (selectedColor == null) return true;
if (preference.isEnabled() && !currentColor.equals(selectedColor)) {
recipients.setColor(selectedColor);
recipient.setColor(selectedColor);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Context context = getActivity();
DatabaseFactory.getRecipientPreferenceDatabase(context)
.setColor(recipients, selectedColor);
.setColor(recipient, selectedColor);
if (DirectoryHelper.getUserCapabilities(context, recipients)
if (DirectoryHelper.getUserCapabilities(context, recipient)
.getTextCapability() == DirectoryHelper.UserCapabilities.Capability.SUPPORTED)
{
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceContactUpdateJob(context, recipients.getPrimaryRecipient().getAddress()));
.add(new MultiDeviceContactUpdateJob(context, recipient.getAddress()));
}
return null;
}
@ -424,8 +425,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
private class MuteClickedListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
if (recipients.isMuted()) handleUnmute();
else handleMute();
if (recipient.isMuted()) handleUnmute();
else handleMute();
return true;
}
@ -434,25 +435,25 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
MuteDialog.show(getActivity(), new MuteDialog.MuteSelectionListener() {
@Override
public void onMuted(long until) {
setMuted(recipients, until);
setMuted(recipient, until);
}
});
setSummaries(recipients);
setSummaries(recipient);
}
private void handleUnmute() {
setMuted(recipients, 0);
setMuted(recipient, 0);
}
private void setMuted(final Recipients recipients, final long until) {
recipients.setMuted(until);
private void setMuted(final Recipient recipient, final long until) {
recipient.setMuted(until);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(getActivity())
.setMuted(recipients, until);
.setMuted(recipient, until);
return null;
}
}.execute();
@ -471,7 +472,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
public boolean onPreferenceClick(Preference preference) {
Intent verifyIdentityIntent = new Intent(getActivity(), VerifyIdentityActivity.class);
verifyIdentityIntent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, recipients.getPrimaryRecipient().getAddress());
verifyIdentityIntent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, recipient.getAddress());
verifyIdentityIntent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(identityKey.getIdentityKey()));
verifyIdentityIntent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, identityKey.getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
startActivity(verifyIdentityIntent);
@ -483,8 +484,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
private class BlockClickedListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
if (recipients.isBlocked()) handleUnblock();
else handleBlock();
if (recipient.isBlocked()) handleUnblock();
else handleBlock();
return true;
}
@ -498,7 +499,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
.setPositiveButton(R.string.RecipientPreferenceActivity_block, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setBlocked(recipients, true);
setBlocked(recipient, true);
}
}).show();
}
@ -512,13 +513,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setBlocked(recipients, false);
setBlocked(recipient, false);
}
}).show();
}
private void setBlocked(final Recipients recipients, final boolean blocked) {
recipients.setBlocked(blocked);
private void setBlocked(final Recipient recipient, final boolean blocked) {
recipient.setBlocked(blocked);
new AsyncTask<Void, Void, Void>() {
@Override
@ -526,7 +527,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
Context context = getActivity();
DatabaseFactory.getRecipientPreferenceDatabase(context)
.setBlocked(recipients, blocked);
.setBlocked(recipient, blocked);
ApplicationContext.getInstance(context)
.getJobManager()

View File

@ -39,7 +39,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FileUtils;
@ -60,9 +60,9 @@ 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_ADDRESSES_MARSHALLED = "addresses";
public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type";
public static final String EXTRA_THREAD_ID = "thread_id";
public static final String EXTRA_ADDRESS_MARSHALLED = "address_marshalled";
public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type";
private final DynamicTheme dynamicTheme = new DynamicTheme ();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@ -165,25 +165,25 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
}
@Override
public void onCreateConversation(long threadId, Recipients recipients, int distributionType) {
createConversation(threadId, recipients.getAddresses(), distributionType);
public void onCreateConversation(long threadId, Recipient recipient, int distributionType) {
createConversation(threadId, recipient.getAddress(), distributionType);
}
private void handleResolvedMedia(Intent intent, boolean animate) {
long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1);
int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1);
Address[] addresses = null;
Address address = null;
if (intent.hasExtra(EXTRA_ADDRESSES_MARSHALLED)) {
if (intent.hasExtra(EXTRA_ADDRESS_MARSHALLED)) {
Parcel parcel = Parcel.obtain();
byte[] marshalled = intent.getByteArrayExtra(EXTRA_ADDRESSES_MARSHALLED);
byte[] marshalled = intent.getByteArrayExtra(EXTRA_ADDRESS_MARSHALLED);
parcel.unmarshall(marshalled, 0, marshalled.length);
parcel.setDataPosition(0);
addresses = parcel.createTypedArray(Address.CREATOR);
address = parcel.readParcelable(getClassLoader());
parcel.recycle();
}
boolean hasResolvedDestination = threadId != -1 && addresses != null && distributionType != -1;
boolean hasResolvedDestination = threadId != -1 && address != null && distributionType != -1;
if (!hasResolvedDestination && animate) {
ViewUtil.fadeIn(fragmentContainer, 300);
@ -192,13 +192,13 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
fragmentContainer.setVisibility(View.VISIBLE);
progressWheel.setVisibility(View.GONE);
} else {
createConversation(threadId, addresses, distributionType);
createConversation(threadId, address, distributionType);
}
}
private void createConversation(long threadId, Address[] addresses, int distributionType) {
private void createConversation(long threadId, Address address, int distributionType) {
final Intent intent = getBaseShareIntent(ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, addresses);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, address);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);

View File

@ -28,10 +28,9 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.recipients.Recipient;
/**
* A fragment to select and share to open conversations
@ -73,7 +72,7 @@ public class ShareFragment extends ListFragment implements LoaderManager.LoaderC
if (v instanceof ShareListItem) {
ShareListItem headerView = (ShareListItem) v;
handleCreateConversation(headerView.getThreadId(), headerView.getRecipients(),
handleCreateConversation(headerView.getThreadId(), headerView.getRecipient(),
headerView.getDistributionType());
}
}
@ -84,8 +83,8 @@ public class ShareFragment extends ListFragment implements LoaderManager.LoaderC
getLoaderManager().restartLoader(0, null, this);
}
private void handleCreateConversation(long threadId, Recipients recipients, int distributionType) {
listener.onCreateConversation(threadId, recipients, distributionType);
private void handleCreateConversation(long threadId, Recipient recipient, int distributionType) {
listener.onCreateConversation(threadId, recipient, distributionType);
}
@Override
@ -104,6 +103,6 @@ public class ShareFragment extends ListFragment implements LoaderManager.LoaderC
}
public interface ConversationSelectedListener {
public void onCreateConversation(long threadId, Recipients recipients, int distributionType);
public void onCreateConversation(long threadId, Recipient recipient, int distributionType);
}
}

View File

@ -25,7 +25,8 @@ import android.widget.RelativeLayout;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
/**
* A simple view to show the recipients of an open conversation
@ -33,12 +34,12 @@ import org.thoughtcrime.securesms.recipients.Recipients;
* @author Jake McGinty
*/
public class ShareListItem extends RelativeLayout
implements Recipients.RecipientsModifiedListener
implements RecipientModifiedListener
{
private final static String TAG = ShareListItem.class.getSimpleName();
private Context context;
private Recipients recipients;
private Recipient recipient;
private long threadId;
private FromTextView fromView;
@ -59,24 +60,25 @@ public class ShareListItem extends RelativeLayout
@Override
protected void onFinishInflate() {
super.onFinishInflate();
this.fromView = (FromTextView) findViewById(R.id.from);
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
}
public void set(ThreadRecord thread) {
this.recipients = thread.getRecipients();
this.recipient = thread.getRecipient();
this.threadId = thread.getThreadId();
this.distributionType = thread.getDistributionType();
this.recipients.addListener(this);
this.fromView.setText(recipients);
this.recipient.addListener(this);
this.fromView.setText(recipient);
setBackground();
this.contactPhotoImage.setAvatar(this.recipients, false);
this.contactPhotoImage.setAvatar(this.recipient, false);
}
public void unbind() {
if (this.recipients != null) this.recipients.removeListener(this);
if (this.recipient != null) this.recipient.removeListener(this);
}
private void setBackground() {
@ -88,8 +90,8 @@ public class ShareListItem extends RelativeLayout
drawables.recycle();
}
public Recipients getRecipients() {
return recipients;
public Recipient getRecipient() {
return recipient;
}
public long getThreadId() {
@ -101,12 +103,12 @@ public class ShareListItem extends RelativeLayout
}
@Override
public void onModified(final Recipients recipients) {
public void onModified(final Recipient recipient) {
handler.post(new Runnable() {
@Override
public void run() {
fromView.setText(recipients);
contactPhotoImage.setAvatar(recipients, false);
fromView.setText(recipient);
contactPhotoImage.setAvatar(recipient, false);
}
});
}

View File

@ -12,8 +12,8 @@ import android.widget.Toast;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.Rfc5724Uri;
import java.net.URISyntaxException;
@ -47,13 +47,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 {
Recipients recipients = RecipientFactory.getRecipientsFor(this, new Address[] {Address.fromExternal(this, destination.getDestination())}, true);
long threadId = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipients);
Recipient recipient = RecipientFactory.getRecipientFor(this, Address.fromExternal(this, destination.getDestination()), true);
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.ADDRESSES_EXTRA, recipients.getAddresses());
nextIntent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
}
return nextIntent;
}

View File

@ -74,6 +74,7 @@ import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.qr.ScanningThread;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.IdentityUtil;
@ -96,7 +97,7 @@ import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
*
* @author Moxie Marlinspike
*/
public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity implements Recipient.RecipientModifiedListener, ScanListener, View.OnClickListener {
public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener, ScanListener, View.OnClickListener {
private static final String TAG = VerifyIdentityActivity.class.getSimpleName();
@ -191,7 +192,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
}
}
public static class VerifyDisplayFragment extends Fragment implements Recipient.RecipientModifiedListener, CompoundButton.OnCheckedChangeListener {
public static class VerifyDisplayFragment extends Fragment implements RecipientModifiedListener, CompoundButton.OnCheckedChangeListener {
public static final String REMOTE_ADDRESS = "remote_address";
public static final String REMOTE_NUMBER = "remote_number";

View File

@ -14,8 +14,6 @@ import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
public class AvatarImageView extends ImageView {
@ -37,31 +35,25 @@ public class AvatarImageView extends ImageView {
}
}
public void setAvatar(final @Nullable Recipients recipients, boolean quickContactEnabled) {
if (recipients != null) {
MaterialColor backgroundColor = recipients.getColor();
setImageDrawable(recipients.getContactPhoto().asDrawable(getContext(), backgroundColor.toConversationColor(getContext()), inverted));
setAvatarClickHandler(recipients, quickContactEnabled);
public void setAvatar(final @Nullable Recipient recipient, boolean quickContactEnabled) {
if (recipient != null) {
MaterialColor backgroundColor = recipient.getColor();
setImageDrawable(recipient.getContactPhoto().asDrawable(getContext(), backgroundColor.toConversationColor(getContext()), inverted));
setAvatarClickHandler(recipient, quickContactEnabled);
} else {
setImageDrawable(ContactPhotoFactory.getDefaultContactPhoto(null).asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted));
setOnClickListener(null);
}
}
public void setAvatar(@Nullable Recipient recipient, boolean quickContactEnabled) {
setAvatar(RecipientFactory.getRecipientsFor(getContext(), recipient, true), quickContactEnabled);
}
private void setAvatarClickHandler(final Recipients recipients, boolean quickContactEnabled) {
if (!recipients.isGroupRecipient() && quickContactEnabled) {
private void setAvatarClickHandler(final Recipient recipient, boolean quickContactEnabled) {
if (!recipient.isGroupRecipient() && quickContactEnabled) {
setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Recipient recipient = recipients.getPrimaryRecipient();
if (recipient != null && recipient.getContactUri() != null) {
if (recipient.getContactUri() != null) {
ContactsContract.QuickContact.showQuickContact(getContext(), AvatarImageView.this, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
} else if (recipient != null) {
} else {
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
if (recipient.getAddress().isEmail()) {
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipient.getAddress().toEmailString());

View File

@ -11,8 +11,6 @@ import android.util.AttributeSet;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
public class FromTextView extends EmojiTextView {
@ -27,17 +25,13 @@ public class FromTextView extends EmojiTextView {
}
public void setText(Recipient recipient) {
setText(RecipientFactory.getRecipientsFor(getContext(), recipient, true));
setText(recipient, true);
}
public void setText(Recipients recipients) {
setText(recipients, true);
}
public void setText(Recipients recipients, boolean read) {
public void setText(Recipient recipient, boolean read) {
int attributes[] = new int[]{R.attr.conversation_list_item_count_color};
TypedArray colors = getContext().obtainStyledAttributes(attributes);
String fromString = recipients.toShortString();
String fromString = recipient.toShortString();
int typeface;
@ -55,9 +49,9 @@ public class FromTextView extends EmojiTextView {
setText(builder);
if (recipients.isBlocked()) setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_block_grey600_18dp, 0, 0, 0);
else if (recipients.isMuted()) setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_volume_off_grey600_18dp, 0, 0, 0);
else setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
if (recipient.isBlocked()) setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_block_grey600_18dp, 0, 0, 0);
else if (recipient.isMuted()) setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_volume_off_grey600_18dp, 0, 0, 0);
else setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}

View File

@ -19,7 +19,6 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@ -33,9 +32,7 @@ import org.thoughtcrime.securesms.contacts.RecipientsEditor;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipients.RecipientsModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import java.util.LinkedList;
import java.util.List;
@ -47,7 +44,7 @@ import java.util.StringTokenizer;
*
* @author Moxie Marlinspike
*/
public class PushRecipientsPanel extends RelativeLayout implements RecipientsModifiedListener {
public class PushRecipientsPanel extends RelativeLayout implements RecipientModifiedListener {
private final String TAG = PushRecipientsPanel.class.getSimpleName();
private RecipientsPanelChangedListener panelChangeListener;
@ -71,14 +68,9 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientsMod
initialize();
}
public Recipients getRecipients() throws RecipientFormattingException {
String rawText = recipientsText.getText().toString();
Recipients recipients = getRecipientsFromString(getContext(), rawText, true);
if (recipients == null || recipients.isEmpty())
throw new RecipientFormattingException("Recipient List Is Empty!");
return recipients;
public List<Recipient> getRecipients() {
String rawText = recipientsText.getText().toString();
return getRecipientsFromString(getContext(), rawText, true);
}
public void disable() {
@ -104,15 +96,14 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientsMod
}
private void initRecipientsEditor() {
Recipients recipients;
recipientsText = (RecipientsEditor)findViewById(R.id.recipients_text);
try {
recipients = getRecipients();
} catch (RecipientFormattingException e) {
recipients = RecipientFactory.getRecipientsFor(getContext(), new LinkedList<Recipient>(), true);
this.recipientsText = (RecipientsEditor)findViewById(R.id.recipients_text);
List<Recipient> recipients = getRecipients();
for (Recipient recipient : recipients) {
recipient.addListener(this);
}
recipients.addListener(this);
recipientsText.setAdapter(new RecipientsAdapter(this.getContext()));
recipientsText.populate(recipients);
@ -122,32 +113,27 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientsMod
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (panelChangeListener != null) {
try {
panelChangeListener.onRecipientsPanelUpdate(getRecipients());
} catch (RecipientFormattingException rfe) {
panelChangeListener.onRecipientsPanelUpdate(null);
}
panelChangeListener.onRecipientsPanelUpdate(getRecipients());
}
recipientsText.setText("");
}
});
}
private @Nullable Recipients getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) {
StringTokenizer tokenizer = new StringTokenizer(rawText, ",");
List<Address> addresses = new LinkedList<>();
private @NonNull List<Recipient> getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) {
StringTokenizer tokenizer = new StringTokenizer(rawText, ",");
List<Recipient> recipients = new LinkedList<>();
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken().trim();
if (!TextUtils.isEmpty(token)) {
if (hasBracketedNumber(token)) addresses.add(Address.fromExternal(context, parseBracketedNumber(token)));
else addresses.add(Address.fromExternal(context, token));
if (hasBracketedNumber(token)) recipients.add(RecipientFactory.getRecipientFor(context, Address.fromExternal(context, parseBracketedNumber(token)), asynchronous));
else recipients.add(RecipientFactory.getRecipientFor(context, Address.fromExternal(context, token), asynchronous));
}
}
if (addresses.size() == 0) return null;
else return RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), asynchronous);
return recipients;
}
private boolean hasBracketedNumber(String recipient) {
@ -166,24 +152,20 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientsMod
}
@Override
public void onModified(Recipients recipients) {
recipientsText.populate(recipients);
public void onModified(Recipient recipient) {
recipientsText.populate(getRecipients());
}
private class FocusChangedListener implements View.OnFocusChangeListener {
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus && (panelChangeListener != null)) {
try {
panelChangeListener.onRecipientsPanelUpdate(getRecipients());
} catch (RecipientFormattingException rfe) {
panelChangeListener.onRecipientsPanelUpdate(null);
}
panelChangeListener.onRecipientsPanelUpdate(getRecipients());
}
}
}
public interface RecipientsPanelChangedListener {
public void onRecipientsPanelUpdate(Recipients recipients);
public void onRecipientsPanelUpdate(List<Recipient> recipients);
}
}

View File

@ -8,22 +8,22 @@ import android.view.View.OnClickListener;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
public class InviteReminder extends Reminder {
public InviteReminder(final @NonNull Context context,
final @NonNull Recipients recipients)
final @NonNull Recipient recipient)
{
super(context.getString(R.string.reminder_header_invite_title),
context.getString(R.string.reminder_header_invite_text, recipients.toShortString()));
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.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipients, true);
DatabaseFactory.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipient, true);
return null;
}
}.execute();

View File

@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.util.VerifySpan;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -57,7 +58,7 @@ import org.whispersystems.libsignal.IdentityKey;
* @author Moxie Marlinspike
*
*/
public class WebRtcCallScreen extends FrameLayout implements Recipient.RecipientModifiedListener {
public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedListener {
private static final String TAG = WebRtcCallScreen.class.getSimpleName();

View File

@ -11,12 +11,12 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.RecipientsFormatter;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.ViewUtil;
public class ContactSelectionListItem extends LinearLayout implements Recipients.RecipientsModifiedListener {
public class ContactSelectionListItem extends LinearLayout implements RecipientModifiedListener {
private AvatarImageView contactPhotoImage;
private TextView numberView;
@ -24,9 +24,9 @@ public class ContactSelectionListItem extends LinearLayout implements Recipients
private TextView labelView;
private CheckBox checkBox;
private long id;
private String number;
private Recipients recipients;
private long id;
private String number;
private Recipient recipient;
public ContactSelectionListItem(Context context) {
super(context);
@ -53,24 +53,22 @@ public class ContactSelectionListItem extends LinearLayout implements Recipients
this.number = number;
if (type == ContactsDatabase.NEW_TYPE) {
this.recipients = null;
this.recipient = null;
this.contactPhotoImage.setAvatar(RecipientFactory.getRecipientFor(getContext(), Address.UNKNOWN, true), false);
} else if (!TextUtils.isEmpty(number)) {
Address address = Address.fromExternal(getContext(), number);
this.recipients = RecipientFactory.getRecipientsFor(getContext(), new Address[] {address}, true);
this.recipient = RecipientFactory.getRecipientFor(getContext(), address, true);
if (this.recipients.getPrimaryRecipient() != null &&
this.recipients.getPrimaryRecipient().getName() != null)
{
name = this.recipients.getPrimaryRecipient().getName();
if (this.recipient.getName() != null) {
name = this.recipient.getName();
}
this.recipients.addListener(this);
this.recipient.addListener(this);
}
this.nameView.setTextColor(color);
this.numberView.setTextColor(color);
this.contactPhotoImage.setAvatar(recipients, false);
this.contactPhotoImage.setAvatar(recipient, false);
setText(type, name, number, label);
@ -83,9 +81,9 @@ public class ContactSelectionListItem extends LinearLayout implements Recipients
}
public void unbind() {
if (recipients != null) {
recipients.removeListener(this);
recipients = null;
if (recipient != null) {
recipient.removeListener(this);
recipient = null;
}
}
@ -117,13 +115,13 @@ public class ContactSelectionListItem extends LinearLayout implements Recipients
}
@Override
public void onModified(final Recipients recipients) {
if (this.recipients == recipients) {
public void onModified(final Recipient recipient) {
if (this.recipient == recipient) {
this.contactPhotoImage.post(new Runnable() {
@Override
public void run() {
contactPhotoImage.setAvatar(recipients, false);
nameView.setText(recipients.toShortString());
contactPhotoImage.setAvatar(recipient, false);
nameView.setText(recipient.toShortString());
}
});
}

View File

@ -29,8 +29,8 @@ import android.util.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.DirectoryHelper.UserCapabilities.Capability;
import org.thoughtcrime.securesms.util.NumberUtil;
@ -103,12 +103,10 @@ public class ContactsCursorLoader extends CursorLoader {
ContactsDatabase.LABEL_COLUMN,
ContactsDatabase.CONTACT_TYPE_COLUMN});
while (cursor.moveToNext()) {
final String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
final Recipients recipients = RecipientFactory.getRecipientsFor(getContext(), new Address[]{Address.fromExternal(getContext(), number)}, true);
final String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
final Recipient recipient = RecipientFactory.getRecipientFor(getContext(), Address.fromExternal(getContext(), number), true);
if (DirectoryHelper.getUserCapabilities(getContext(), recipients)
.getTextCapability() != Capability.SUPPORTED)
{
if (DirectoryHelper.getUserCapabilities(getContext(), recipient).getTextCapability() != Capability.SUPPORTED) {
matrix.addRow(new Object[]{cursor.getLong(cursor.getColumnIndexOrThrow(ContactsDatabase.ID_COLUMN)),
cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NAME_COLUMN)),
number,

View File

@ -30,16 +30,12 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.widget.MultiAutoCompleteTextView;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.RecipientsFormatter;
import java.util.ArrayList;
@ -205,10 +201,10 @@ public class RecipientsEditor extends AppCompatMultiAutoCompleteTextView {
return s;
}
public void populate(Recipients list) {
public void populate(List<Recipient> list) {
SpannableStringBuilder sb = new SpannableStringBuilder();
for (Recipient c : list.getRecipientsList()) {
for (Recipient c : list) {
if (sb.length() != 0) {
sb.append(", ");
}

View File

@ -96,20 +96,14 @@ public class Address implements Parcelable, Comparable<Address> {
return Util.join(escapedAddresses, delimiter + "");
}
public static Address[] fromParcelable(Parcelable[] parcelables) {
Address[] addresses = new Address[parcelables.length];
for (int i=0;i<parcelables.length;i++) {
addresses[i] = (Address)parcelables[i];
}
return addresses;
}
public boolean isGroup() {
return GroupUtil.isEncodedGroup(address);
}
public boolean isMmsGroup() {
return GroupUtil.isMmsGroup(address);
}
public boolean isEmail() {
return NumberUtil.isValidEmail(address);
}
@ -204,9 +198,9 @@ public class Address implements Parcelable, Comparable<Address> {
}
public String format(@Nullable String number) {
if (number == null) return "Unknown";
if (number.startsWith("__textsecure_group__!")) return number;
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
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+]", "");

View File

@ -28,8 +28,6 @@ import android.text.TextUtils;
import android.util.Log;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
@ -41,10 +39,10 @@ import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.DelimiterUtil;
import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@ -56,12 +54,12 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DatabaseFactory {
@ -102,7 +100,8 @@ public class DatabaseFactory {
private static final int INTRODUCED_IDENTITY_TIMESTAMP = 35;
private static final int SANIFY_ATTACHMENT_DOWNLOAD = 36;
private static final int NO_MORE_CANONICAL_ADDRESS_DATABASE = 37;
private static final int DATABASE_VERSION = 37;
private static final int NO_MORE_RECIPIENTS_PLURAL = 38;
private static final int DATABASE_VERSION = 38;
private static final String DATABASE_NAME = "messages.db";
private static final Object lock = new Object();
@ -117,7 +116,6 @@ public class DatabaseFactory {
private final AttachmentDatabase attachments;
private final MediaDatabase media;
private final ThreadDatabase thread;
private final MmsAddressDatabase mmsAddress;
private final MmsSmsDatabase mmsSmsDatabase;
private final IdentityDatabase identityDatabase;
private final DraftDatabase draftDatabase;
@ -163,10 +161,6 @@ public class DatabaseFactory {
return getInstance(context).media;
}
public static MmsAddressDatabase getMmsAddressDatabase(Context context) {
return getInstance(context).mmsAddress;
}
public static IdentityDatabase getIdentityDatabase(Context context) {
return getInstance(context).identityDatabase;
}
@ -199,7 +193,6 @@ public class DatabaseFactory {
this.attachments = new AttachmentDatabase(context, databaseHelper);
this.media = new MediaDatabase(context, databaseHelper);
this.thread = new ThreadDatabase(context, databaseHelper);
this.mmsAddress = new MmsAddressDatabase(context, databaseHelper);
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
this.draftDatabase = new DraftDatabase(context, databaseHelper);
@ -218,7 +211,6 @@ public class DatabaseFactory {
this.mms.reset(databaseHelper);
this.attachments.reset(databaseHelper);
this.thread.reset(databaseHelper);
this.mmsAddress.reset(databaseHelper);
this.mmsSmsDatabase.reset(databaseHelper);
this.identityDatabase.reset(databaseHelper);
this.draftDatabase.reset(databaseHelper);
@ -533,7 +525,6 @@ public class DatabaseFactory {
db.execSQL(MmsDatabase.CREATE_TABLE);
db.execSQL(AttachmentDatabase.CREATE_TABLE);
db.execSQL(ThreadDatabase.CREATE_TABLE);
db.execSQL(MmsAddressDatabase.CREATE_TABLE);
db.execSQL(IdentityDatabase.CREATE_TABLE);
db.execSQL(DraftDatabase.CREATE_TABLE);
db.execSQL(PushDatabase.CREATE_TABLE);
@ -544,7 +535,6 @@ public class DatabaseFactory {
executeStatements(db, MmsDatabase.CREATE_INDEXS);
executeStatements(db, AttachmentDatabase.CREATE_INDEXS);
executeStatements(db, ThreadDatabase.CREATE_INDEXS);
executeStatements(db, MmsAddressDatabase.CREATE_INDEXS);
executeStatements(db, DraftDatabase.CREATE_INDEXS);
executeStatements(db, GroupDatabase.CREATE_INDEXS);
}
@ -1209,6 +1199,80 @@ public class DatabaseFactory {
}
if (oldVersion < NO_MORE_RECIPIENTS_PLURAL) {
db.execSQL("ALTER TABLE groups ADD COLUMN mms INTEGER DEFAULT 0");
Cursor cursor = db.query("thread", new String[] {"_id", "recipient_ids"}, null, null, null, null, null);
while (cursor != null && cursor.moveToNext()) {
long threadId = cursor.getLong(0);
String addressListString = cursor.getString(1);
String[] addressList = DelimiterUtil.split(addressListString, ' ');
if (addressList.length == 1) {
ContentValues contentValues = new ContentValues();
contentValues.put("recipient_ids", DelimiterUtil.unescape(addressListString, ' '));
db.update("thread", contentValues, "_id = ?", new String[] {String.valueOf(threadId)});
} else {
byte[] groupId = new byte[16];
List<String> members = new LinkedList<>();
new SecureRandom().nextBytes(groupId);
for (String address : addressList) {
members.add(DelimiterUtil.escape(DelimiterUtil.unescape(address, ' '), ','));
}
String encodedGroupId = "__signal_mms_group__!" + Hex.toStringCondensed(groupId);
ContentValues groupValues = new ContentValues();
ContentValues threadValues = new ContentValues();
groupValues.put("group_id", encodedGroupId);
groupValues.put("members", Util.join(members, ","));
groupValues.put("mms", 1);
threadValues.put("recipient_ids", encodedGroupId);
db.insert("groups", null, groupValues);
db.update("thread", threadValues, "_id = ?", new String[] {String.valueOf(threadId)});
db.update("recipient_preferences", threadValues, "recipient_ids = ?", new String[] {addressListString});
}
}
if (cursor != null) cursor.close();
cursor = db.query("recipient_preferences", new String[] {"_id", "recipient_ids"}, null, null, null, null, null);
while (cursor != null && cursor.moveToNext()) {
long id = cursor.getLong(0);
String addressListString = cursor.getString(1);
String[] addressList = DelimiterUtil.split(addressListString, ' ');
if (addressList.length == 1) {
ContentValues contentValues = new ContentValues();
contentValues.put("recipient_ids", DelimiterUtil.unescape(addressListString, ' '));
db.update("recipient_preferences", contentValues, "_id = ?", new String[] {String.valueOf(id)});
} else {
Log.w(TAG, "Found preferences for MMS thread that appears to be gone: " + addressListString);
db.delete("recipient_preferences", "_id = ?", new String[] {String.valueOf(id)});
}
}
if (cursor != null) cursor.close();
cursor = db.rawQuery("SELECT mms._id, thread.recipient_ids FROM mms, thread WHERE mms.address IS NULL AND mms.thread_id = thread._id", null);
while (cursor != null && cursor.moveToNext()) {
long id = cursor.getLong(0);
ContentValues contentValues = new ContentValues(1);
contentValues.put("address", cursor.getString(1));
db.update("mms", contentValues, "_id = ?", new String[] {String.valueOf(id)});
}
if (cursor != null) cursor.close();
}
db.setTransactionSuccessful();
db.endTransaction();
}

View File

@ -14,7 +14,6 @@ import android.support.annotation.Nullable;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.Util;
@ -23,6 +22,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@ -45,6 +45,7 @@ public class GroupDatabase extends Database {
private static final String AVATAR_DIGEST = "avatar_digest";
private static final String TIMESTAMP = "timestamp";
private static final String ACTIVE = "active";
private static final String MMS = "mms";
public static final String CREATE_TABLE =
"CREATE TABLE " + TABLE_NAME +
@ -59,7 +60,8 @@ public class GroupDatabase extends Database {
AVATAR_RELAY + " TEXT, " +
TIMESTAMP + " INTEGER, " +
ACTIVE + " INTEGER DEFAULT 1, " +
AVATAR_DIGEST + " BLOB);";
AVATAR_DIGEST + " BLOB, " +
MMS + " INTEGER DEFAULT 0);";
public static final String[] CREATE_INDEXS = {
"CREATE UNIQUE INDEX IF NOT EXISTS group_id_index ON " + TABLE_NAME + " (" + GROUP_ID + ");",
@ -69,10 +71,10 @@ public class GroupDatabase extends Database {
super(context, databaseHelper);
}
public @Nullable GroupRecord getGroup(byte[] groupId) {
public @Nullable GroupRecord getGroup(String groupId) {
@SuppressLint("Recycle")
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(groupId)},
new String[] {groupId},
null, null, null);
Reader reader = new Reader(cursor);
@ -82,7 +84,7 @@ public class GroupDatabase extends Database {
return record;
}
public boolean isUnknownGroup(byte[] groupId) {
public boolean isUnknownGroup(String groupId) {
return getGroup(groupId) == null;
}
@ -94,12 +96,32 @@ public class GroupDatabase extends Database {
return new Reader(cursor);
}
public String getOrCreateGroupForMembers(List<Address> 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"},
null, null, null);
try {
if (cursor != null && cursor.moveToNext()) {
return cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
} else {
String groupId = GroupUtil.getEncodedId(allocateGroupId(), mms);
create(groupId, null, members, null, null);
return groupId;
}
} finally {
if (cursor != null) cursor.close();
}
}
public Reader getGroups() {
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, null, null, null, null, null);
return new Reader(cursor);
}
public @NonNull Recipients getGroupMembers(byte[] groupId, boolean includeSelf) {
public @NonNull List<Recipient> getGroupMembers(String groupId, boolean includeSelf) {
List<Address> members = getCurrentMembers(groupId);
List<Recipient> recipients = new LinkedList<>();
@ -110,14 +132,16 @@ public class GroupDatabase extends Database {
recipients.add(RecipientFactory.getRecipientFor(context, member, false));
}
return RecipientFactory.getRecipientsFor(context, recipients, false);
return recipients;
}
public void create(byte[] groupId, String title, List<Address> members,
SignalServiceAttachmentPointer avatar, String relay)
public void create(@NonNull String groupId, @Nullable String title, @NonNull List<Address> members,
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay)
{
Collections.sort(members);
ContentValues contentValues = new ContentValues();
contentValues.put(GROUP_ID, GroupUtil.getEncodedId(groupId));
contentValues.put(GROUP_ID, groupId);
contentValues.put(TITLE, title);
contentValues.put(MEMBERS, Address.toSerializedList(members, ','));
@ -131,13 +155,14 @@ public class GroupDatabase extends Database {
contentValues.put(AVATAR_RELAY, relay);
contentValues.put(TIMESTAMP, System.currentTimeMillis());
contentValues.put(ACTIVE, 1);
contentValues.put(MMS, GroupUtil.isMmsGroup(groupId));
databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
RecipientFactory.clearCache(context);
notifyConversationListListeners();
}
public void update(byte[] groupId, String title, SignalServiceAttachmentPointer avatar) {
public void update(String groupId, String title, SignalServiceAttachmentPointer avatar) {
ContentValues contentValues = new ContentValues();
if (title != null) contentValues.put(TITLE, title);
@ -150,65 +175,67 @@ public class GroupDatabase extends Database {
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,
GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(groupId)});
new String[] {groupId});
RecipientFactory.clearCache(context);
notifyDatabaseListeners();
notifyConversationListListeners();
}
public void updateTitle(byte[] groupId, String title) {
public void updateTitle(String groupId, String title) {
ContentValues contentValues = new ContentValues();
contentValues.put(TITLE, title);
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(groupId)});
new String[] {groupId});
RecipientFactory.clearCache(context);
notifyDatabaseListeners();
}
public void updateAvatar(byte[] groupId, Bitmap avatar) {
public void updateAvatar(String groupId, Bitmap avatar) {
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
}
public void updateAvatar(byte[] groupId, byte[] avatar) {
public void updateAvatar(String groupId, byte[] avatar) {
ContentValues contentValues = new ContentValues();
contentValues.put(AVATAR, avatar);
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(groupId)});
new String[] {groupId});
RecipientFactory.clearCache(context);
notifyDatabaseListeners();
}
public void updateMembers(byte[] id, List<Address> members) {
public void updateMembers(String groupId, List<Address> members) {
Collections.sort(members);
ContentValues contents = new ContentValues();
contents.put(MEMBERS, Address.toSerializedList(members, ','));
contents.put(ACTIVE, 1);
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(id)});
new String[] {groupId});
}
public void remove(byte[] id, Address source) {
List<Address> currentMembers = getCurrentMembers(id);
public void remove(String groupId, Address source) {
List<Address> currentMembers = getCurrentMembers(groupId);
currentMembers.remove(source);
ContentValues contents = new ContentValues();
contents.put(MEMBERS, Address.toSerializedList(currentMembers, ','));
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(id)});
new String[] {groupId});
}
private List<Address> getCurrentMembers(byte[] id) {
private List<Address> getCurrentMembers(String groupId) {
Cursor cursor = null;
try {
cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {MEMBERS},
GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(id)},
new String[] {groupId},
null, null, null);
if (cursor != null && cursor.moveToFirst()) {
@ -223,16 +250,16 @@ public class GroupDatabase extends Database {
}
}
public boolean isActive(byte[] id) {
GroupRecord record = getGroup(id);
public boolean isActive(String groupId) {
GroupRecord record = getGroup(groupId);
return record != null && record.isActive();
}
public void setActive(byte[] id, boolean active) {
public void setActive(String groupId, boolean active) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ACTIVE, active ? 1 : 0);
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {GroupUtil.getEncodedId(id)});
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {groupId});
}
@ -273,7 +300,8 @@ public class GroupDatabase extends Database {
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_CONTENT_TYPE)),
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_RELAY)),
cursor.getInt(cursor.getColumnIndexOrThrow(ACTIVE)) == 1,
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_DIGEST)));
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_DIGEST)),
cursor.getInt(cursor.getColumnIndexOrThrow(MMS)) == 1);
}
public void close() {
@ -294,10 +322,11 @@ public class GroupDatabase extends Database {
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,
long avatarId, byte[] avatarKey, String avatarContentType,
String relay, boolean active, byte[] avatarDigest)
String relay, boolean active, byte[] avatarDigest, boolean mms)
{
this.id = id;
this.title = title;
@ -309,6 +338,7 @@ public class GroupDatabase extends Database {
this.avatarContentType = avatarContentType;
this.relay = relay;
this.active = active;
this.mms = mms;
}
public byte[] getId() {
@ -358,5 +388,9 @@ public class GroupDatabase extends Database {
public boolean isActive() {
return active;
}
public boolean isMms() {
return mms;
}
}
}

View File

@ -1,150 +0,0 @@
/**
* Copyright (C) 2011 Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import com.google.android.mms.pdu_alt.PduHeaders;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.util.LinkedList;
import java.util.List;
public class MmsAddressDatabase extends Database {
private static final String TAG = MmsAddressDatabase.class.getSimpleName();
private static final String TABLE_NAME = "mms_addresses";
private static final String ID = "_id";
private static final String MMS_ID = "mms_id";
private static final String TYPE = "type";
private static final String ADDRESS = "address";
private static final String ADDRESS_CHARSET = "address_charset";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
MMS_ID + " INTEGER, " + TYPE + " INTEGER, " + ADDRESS + " TEXT, " +
ADDRESS_CHARSET + " INTEGER);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS mms_addresses_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
};
public MmsAddressDatabase(Context context, SQLiteOpenHelper databaseHelper) {
super(context, databaseHelper);
}
private void insertAddress(long messageId, int type, @NonNull Address value) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(MMS_ID, messageId);
contentValues.put(TYPE, type);
contentValues.put(ADDRESS, value.serialize());
contentValues.put(ADDRESS_CHARSET, "UTF-8");
database.insert(TABLE_NAME, null, contentValues);
}
private void insertAddress(long messageId, int type, @NonNull List<Address> addresses) {
for (Address address : addresses) {
insertAddress(messageId, type, address);
}
}
public void insertAddressesForId(long messageId, MmsAddresses addresses) {
if (addresses.getFrom() != null) {
insertAddress(messageId, PduHeaders.FROM, addresses.getFrom());
}
insertAddress(messageId, PduHeaders.TO, addresses.getTo());
insertAddress(messageId, PduHeaders.CC, addresses.getCc());
insertAddress(messageId, PduHeaders.BCC, addresses.getBcc());
}
public MmsAddresses getAddressesForId(long messageId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = null;
Address from = null;
List<Address> to = new LinkedList<>();
List<Address> cc = new LinkedList<>();
List<Address> bcc = new LinkedList<>();
try {
cursor = database.query(TABLE_NAME, null, MMS_ID + " = ?", new String[] {messageId+""}, null, null, null);
while (cursor != null && cursor.moveToNext()) {
long type = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE));
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
if (type == PduHeaders.FROM) from = address;
if (type == PduHeaders.TO) to.add(address);
if (type == PduHeaders.CC) cc.add(address);
if (type == PduHeaders.BCC) bcc.add(address);
}
} finally {
if (cursor != null)
cursor.close();
}
return new MmsAddresses(from, to, cc, bcc);
}
public List<Address> getAddressesListForId(long messageId) {
List<Address> results = new LinkedList<>();
MmsAddresses addresses = getAddressesForId(messageId);
if (addresses.getFrom() != null) {
results.add(addresses.getFrom());
}
results.addAll(addresses.getTo());
results.addAll(addresses.getCc());
results.addAll(addresses.getBcc());
return results;
}
public Recipients getRecipientsForId(long messageId) {
List<Address> addresses = getAddressesListForId(messageId);
List<Recipient> results = new LinkedList<>();
for (Address address : addresses) {
if (!PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.equals(address.serialize())) {
results.add(RecipientFactory.getRecipientFor(context, address, false));
}
}
return RecipientFactory.getRecipientsFor(context, results, false);
}
public void deleteAddressesForId(long messageId) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
database.delete(TABLE_NAME, MMS_ID + " = ?", new String[] {messageId+""});
}
public void deleteAllAddresses() {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
database.delete(TABLE_NAME, null, null);
}
}

View File

@ -1,56 +0,0 @@
package org.thoughtcrime.securesms.database;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.LinkedList;
import java.util.List;
public class MmsAddresses {
private final @Nullable Address from;
private final @NonNull List<Address> to;
private final @NonNull List<Address> cc;
private final @NonNull List<Address> bcc;
public MmsAddresses(@Nullable Address from, @NonNull List<Address> to,
@NonNull List<Address> cc, @NonNull List<Address> bcc)
{
this.from = from;
this.to = to;
this.cc = cc;
this.bcc = bcc;
}
@NonNull
public List<Address> getTo() {
return to;
}
@NonNull
public List<Address> getCc() {
return cc;
}
@NonNull
public List<Address> getBcc() {
return bcc;
}
@Nullable
public Address getFrom() {
return from;
}
public static MmsAddresses forTo(@NonNull List<Address> to) {
return new MmsAddresses(null, to, new LinkedList<Address>(), new LinkedList<Address>());
}
public static MmsAddresses forBcc(@NonNull List<Address> bcc) {
return new MmsAddresses(null, new LinkedList<Address>(), new LinkedList<Address>(), bcc);
}
public static MmsAddresses forFrom(@NonNull Address from) {
return new MmsAddresses(from, new LinkedList<Address>(), new LinkedList<Address>(), new LinkedList<Address>());
}
}

View File

@ -30,7 +30,6 @@ import android.util.Pair;
import com.google.android.mms.pdu_alt.NotificationInd;
import com.google.android.mms.pdu_alt.PduHeaders;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
@ -57,12 +56,10 @@ import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobManager;
import org.whispersystems.libsignal.InvalidMessageException;
@ -195,34 +192,30 @@ public class MmsDatabase extends MessagingDatabase {
}
public void incrementDeliveryReceiptCount(SyncMessageId messageId) {
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
SQLiteDatabase database = databaseHelper.getWritableDatabase();
Cursor cursor = null;
boolean found = false;
SQLiteDatabase database = databaseHelper.getWritableDatabase();
Cursor cursor = null;
boolean found = false;
try {
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
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);
while (cursor.moveToNext()) {
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
List<Address> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
Address ourAddress = messageId.getAddress();
for (Address theirAddress : addresses) {
Address ourAddress = messageId.getAddress();
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
found = true;
found = true;
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
new String[] {String.valueOf(id)});
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
new String[] {String.valueOf(id)});
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
notifyConversationListeners(threadId);
}
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
notifyConversationListeners(threadId);
}
}
}
@ -257,66 +250,20 @@ public class MmsDatabase extends MessagingDatabase {
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
if (retrieved.getGroupId() != null) {
Recipients groupRecipients = RecipientFactory.getRecipientsFor(context, new Address[] {retrieved.getGroupId()}, true);
Recipient groupRecipients = RecipientFactory.getRecipientFor(context, retrieved.getGroupId(), true);
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
}
String localNumber;
Set<Address> group = new HashSet<>();
if (retrieved.getAddresses().getFrom() == null) {
throw new MmsException("FROM value in PduHeaders did not exist.");
}
group.add(retrieved.getAddresses().getFrom());
if (TextSecurePreferences.isPushRegistered(context)) {
localNumber = TextSecurePreferences.getLocalNumber(context);
} else {
localNumber = ServiceUtil.getTelephonyManager(context).getLine1Number();
Recipient sender = RecipientFactory.getRecipientFor(context, retrieved.getFrom(), true);
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(sender);
}
for (Address cc : retrieved.getAddresses().getCc()) {
PhoneNumberUtil.MatchType match;
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, cc.serialize());
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
{
group.add(cc);
}
}
if (retrieved.getAddresses().getTo().size() > 1) {
for (Address to : retrieved.getAddresses().getTo()) {
PhoneNumberUtil.MatchType match;
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, to.serialize());
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
{
group.add(to);
}
}
}
Recipients recipients = RecipientFactory.getRecipientsFor(context, group.toArray(new Address[0]), false);
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
}
private long getThreadIdFor(@NonNull NotificationInd notification) {
String fromString = notification.getFrom() != null && notification.getFrom().getTextString() != null
? Util.toIsoString(notification.getFrom().getTextString())
: "";
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, fromString)}, false);
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromExternal(context, fromString), false);
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
}
private Cursor rawQuery(@NonNull String where, @Nullable String[] arguments) {
@ -489,39 +436,35 @@ public class MmsDatabase extends MessagingDatabase {
}
public List<Pair<Long, Long>> setTimestampRead(SyncMessageId messageId, long expireStarted) {
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
SQLiteDatabase database = databaseHelper.getWritableDatabase();
List<Pair<Long, Long>> expiring = new LinkedList<>();
Cursor cursor = null;
try {
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN}, 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, ADDRESS}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
while (cursor.moveToNext()) {
List<Address> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
Address ourAddress = messageId.getAddress();
for (Address theirAddress : addresses) {
Address ourAddress = messageId.getAddress();
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
ContentValues values = new ContentValues();
values.put(READ, 1);
ContentValues values = new ContentValues();
values.put(READ, 1);
if (expiresIn > 0) {
values.put(EXPIRE_STARTED, expireStarted);
expiring.add(new Pair<>(id, expiresIn));
}
database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)});
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
notifyConversationListeners(threadId);
if (expiresIn > 0) {
values.put(EXPIRE_STARTED, expireStarted);
expiring.add(new Pair<>(id, expiresIn));
}
database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)});
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
notifyConversationListeners(threadId);
}
}
} finally {
@ -592,7 +535,6 @@ public class MmsDatabase extends MessagingDatabase {
public OutgoingMediaMessage getOutgoingMessage(MasterSecret masterSecret, long messageId)
throws MmsException, NoSuchMessageException
{
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
Cursor cursor = null;
@ -600,31 +542,27 @@ public class MmsDatabase extends MessagingDatabase {
cursor = rawQuery(RAW_ID_WHERE, new String[] {String.valueOf(messageId)});
if (cursor != null && cursor.moveToNext()) {
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(masterSecret, messageId));
MmsAddresses addresses = addr.getAddressesForId(messageId);
List<Address> destinations = new LinkedList<>();
String body = getDecryptedBody(masterSecret, messageText, outboxType);
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(masterSecret, messageId));
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
String body = getDecryptedBody(masterSecret, messageText, outboxType);
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
int distributionType = DatabaseFactory.getThreadDatabase(context).getDistributionType(threadId);
destinations.addAll(addresses.getBcc());
destinations.addAll(addresses.getCc());
destinations.addAll(addresses.getTo());
Recipients recipients = RecipientFactory.getRecipientsFor(context, destinations.toArray(new Address[0]), false);
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(address), false);
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
return new OutgoingGroupMediaMessage(recipients, body, attachments, timestamp, 0);
return new OutgoingGroupMediaMessage(recipient, body, attachments, timestamp, 0);
} else if (Types.isExpirationTimerUpdate(outboxType)) {
return new OutgoingExpirationUpdateMessage(recipients, timestamp, expiresIn);
return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
}
OutgoingMediaMessage message = new OutgoingMediaMessage(recipients, body, attachments, timestamp, subscriptionId, expiresIn,
!addresses.getBcc().isEmpty() ? ThreadDatabase.DistributionTypes.BROADCAST :
ThreadDatabase.DistributionTypes.DEFAULT);
OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, distributionType);
if (Types.isSecureType(outboxType)) {
return new OutgoingSecureMediaMessage(message);
}
@ -645,7 +583,7 @@ public class MmsDatabase extends MessagingDatabase {
try {
OutgoingMediaMessage request = getOutgoingMessage(masterSecret, messageId);
ContentValues contentValues = new ContentValues();
contentValues.put(ADDRESS, request.getRecipients().getPrimaryRecipient().getAddress().serialize());
contentValues.put(ADDRESS, request.getRecipient().getAddress().serialize());
contentValues.put(DATE_SENT, request.getSentTimeMillis());
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT | Types.ENCRYPTION_SYMMETRIC_BIT);
contentValues.put(THREAD_ID, getThreadIdForMessage(messageId));
@ -674,7 +612,6 @@ public class MmsDatabase extends MessagingDatabase {
}
return insertMediaMessage(new MasterSecretUnion(masterSecret),
MmsAddresses.forTo(request.getRecipients().getAddressesList()),
request.getBody(),
attachments,
contentValues,
@ -703,7 +640,7 @@ public class MmsDatabase extends MessagingDatabase {
ContentValues contentValues = new ContentValues();
contentValues.put(DATE_SENT, retrieved.getSentTimeMillis());
contentValues.put(ADDRESS, retrieved.getAddresses().getFrom().serialize());
contentValues.put(ADDRESS, retrieved.getFrom().serialize());
contentValues.put(MESSAGE_BOX, mailbox);
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
@ -725,9 +662,7 @@ public class MmsDatabase extends MessagingDatabase {
return Optional.absent();
}
long messageId = insertMediaMessage(masterSecret, retrieved.getAddresses(),
retrieved.getBody(), retrieved.getAttachments(),
contentValues, null);
long messageId = insertMediaMessage(masterSecret, retrieved.getBody(), retrieved.getAttachments(), contentValues, null);
if (!Types.isExpirationTimerUpdate(mailbox)) {
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
@ -789,8 +724,7 @@ public class MmsDatabase extends MessagingDatabase {
}
public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification, int subscriptionId) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
SQLiteDatabase db = databaseHelper.getWritableDatabase();
long threadId = getThreadIdFor(notification);
ContentValues contentValues = new ContentValues();
ContentValuesBuilder contentBuilder = new ContentValuesBuilder(contentValues);
@ -806,9 +740,7 @@ public class MmsDatabase extends MessagingDatabase {
contentBuilder.add(MESSAGE_TYPE, notification.getMessageType());
if (notification.getFrom() != null) {
contentBuilder.add(ADDRESS, notification.getFrom().getTextString());
} else {
contentBuilder.add(ADDRESS, null);
contentValues.put(ADDRESS, Address.fromExternal(context, Util.toIsoString(notification.getFrom().getTextString())).serialize());
}
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE);
@ -823,10 +755,6 @@ public class MmsDatabase extends MessagingDatabase {
long messageId = db.insert(TABLE_NAME, null, contentValues);
if (notification.getFrom() != null) {
addressDatabase.insertAddressesForId(messageId, MmsAddresses.forFrom(Address.fromExternal(context, Util.toIsoString(notification.getFrom().getTextString()))));
}
return new Pair<>(messageId, threadId);
}
@ -864,18 +792,6 @@ public class MmsDatabase extends MessagingDatabase {
type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
}
List<Address> recipientNumbers = message.getRecipients().getAddressesList();
MmsAddresses addresses;
if (!message.getRecipients().isSingleRecipient() &&
message.getDistributionType() == ThreadDatabase.DistributionTypes.BROADCAST)
{
addresses = MmsAddresses.forBcc(recipientNumbers);
} else {
addresses = MmsAddresses.forTo(recipientNumbers);
}
ContentValues contentValues = new ContentValues();
contentValues.put(DATE_SENT, message.getSentTimeMillis());
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
@ -886,15 +802,10 @@ public class MmsDatabase extends MessagingDatabase {
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
contentValues.put(EXPIRES_IN, message.getExpiresIn());
contentValues.put(ADDRESS, message.getRecipient().getAddress().serialize());
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(message.getSentTimeMillis(), message.getRecipient().getAddress()));
if (message.getRecipients().isSingleRecipient()) {
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(message.getSentTimeMillis(), message.getRecipients().getPrimaryRecipient().getAddress()));
}
contentValues.remove(ADDRESS);
long messageId = insertMediaMessage(masterSecret, addresses, message.getBody(),
message.getAttachments(), contentValues, insertListener);
long messageId = insertMediaMessage(masterSecret, message.getBody(), message.getAttachments(), contentValues, insertListener);
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
jobManager.add(new TrimThreadJob(context, threadId));
@ -928,7 +839,6 @@ public class MmsDatabase extends MessagingDatabase {
}
private long insertMediaMessage(@NonNull MasterSecretUnion masterSecret,
@NonNull MmsAddresses addresses,
@Nullable String body,
@NonNull List<Attachment> attachments,
@NonNull ContentValues contentValues,
@ -937,7 +847,6 @@ public class MmsDatabase extends MessagingDatabase {
{
SQLiteDatabase db = databaseHelper.getWritableDatabase();
AttachmentDatabase partsDatabase = DatabaseFactory.getAttachmentDatabase(context);
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
if (Types.isSymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX)) ||
Types.isAsymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX)))
@ -953,7 +862,6 @@ public class MmsDatabase extends MessagingDatabase {
try {
long messageId = db.insert(TABLE_NAME, null, contentValues);
addressDatabase.insertAddressesForId(messageId, addresses);
partsDatabase.insertAttachmentsForMessage(masterSecret, messageId, attachments);
db.setTransactionSuccessful();
@ -972,10 +880,8 @@ public class MmsDatabase extends MessagingDatabase {
public boolean delete(long messageId) {
long threadId = getThreadIdForMessage(messageId);
MmsAddressDatabase addrDatabase = DatabaseFactory.getMmsAddressDatabase(context);
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
attachmentDatabase.deleteAttachmentsForMessage(messageId);
addrDatabase.deleteAddressesForId(messageId);
SQLiteDatabase database = databaseHelper.getWritableDatabase();
database.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
@ -993,7 +899,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 + " = ?",
new String[]{String.valueOf(message.getSentTimeMillis()), message.getAddresses().getFrom().serialize(), String.valueOf(threadId)},
new String[]{String.valueOf(message.getSentTimeMillis()), message.getFrom().serialize(), String.valueOf(threadId)},
null, null, null, "1");
try {
@ -1058,7 +964,6 @@ public class MmsDatabase extends MessagingDatabase {
public void deleteAllThreads() {
DatabaseFactory.getAttachmentDatabase(context).deleteAllAttachments();
DatabaseFactory.getMmsAddressDatabase(context).deleteAllAddresses();
SQLiteDatabase database = databaseHelper.getWritableDatabase();
database.delete(TABLE_NAME, null, null);
@ -1139,8 +1044,7 @@ public class MmsDatabase extends MessagingDatabase {
public MessageRecord getCurrent() {
SlideDeck slideDeck = new SlideDeck(context, message.getAttachments());
return new MediaMmsMessageRecord(context, id, message.getRecipients(),
message.getRecipients().getPrimaryRecipient(),
return new MediaMmsMessageRecord(context, id, message.getRecipient(), message.getRecipient(),
1, System.currentTimeMillis(), System.currentTimeMillis(),
0, threadId, new DisplayRecord.Body(message.getBody(), true),
slideDeck, slideDeck.getSlides().size(),
@ -1192,7 +1096,7 @@ public class MmsDatabase extends MessagingDatabase {
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
Recipients recipients = getRecipientsFor(address);
Recipient recipient = getRecipientFor(address);
String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.CONTENT_LOCATION));
String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.TRANSACTION_ID));
@ -1214,7 +1118,7 @@ public class MmsDatabase extends MessagingDatabase {
SlideDeck slideDeck = new SlideDeck(context, new MmsNotificationAttachment(status, messageSize));
return new NotificationMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
return new NotificationMmsMessageRecord(context, id, recipient, recipient,
addressDeviceId, dateSent, dateReceived, receiptCount, threadId,
contentLocationBytes, messageSize, expiry, status,
transactionIdBytes, mailbox, subscriptionId, slideDeck);
@ -1237,18 +1141,18 @@ public class MmsDatabase extends MessagingDatabase {
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
Recipients recipients = getRecipientsFor(address);
Recipient recipient = getRecipientFor(address);
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
List<NetworkFailure> networkFailures = getFailures(networkDocument);
SlideDeck slideDeck = getSlideDeck(cursor);
return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
return new MediaMmsMessageRecord(context, id, recipient, recipient,
addressDeviceId, dateSent, dateReceived, receiptCount,
threadId, body, slideDeck, partCount, box, mismatches,
networkFailures, subscriptionId, expiresIn, expireStarted);
}
private Recipients getRecipientsFor(String serialized) {
private Recipient getRecipientFor(String serialized) {
Address address;
if (TextUtils.isEmpty(serialized) || "insert-address-token".equals(serialized)) {
@ -1257,7 +1161,7 @@ public class MmsDatabase extends MessagingDatabase {
address = Address.fromSerialized(serialized);
}
return RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
return RecipientFactory.getRecipientFor(context, address, true);
}
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {

View File

@ -8,8 +8,8 @@ import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
@ -34,8 +34,8 @@ public class PlaintextBackupImporter {
XmlBackup.XmlBackupItem item;
while ((item = backup.getNext()) != null) {
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, item.getAddress())}, false);
long threadId = threads.getThreadIdFor(recipients);
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromExternal(context, item.getAddress()), false);
long threadId = threads.getThreadIdFor(recipient);
SQLiteStatement statement = db.createInsertStatement(transaction);
if (item.getAddress() == null || item.getAddress().equals("null"))

View File

@ -12,13 +12,10 @@ import android.util.Log;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.Arrays;
import java.util.List;
public class RecipientPreferenceDatabase extends Database {
private static final String TAG = RecipientPreferenceDatabase.class.getSimpleName();
@ -26,7 +23,7 @@ public class RecipientPreferenceDatabase extends Database {
private static final String TABLE_NAME = "recipient_preferences";
private static final String ID = "_id";
private static final String ADDRESSES = "recipient_ids";
private static final String ADDRESS = "recipient_ids";
private static final String BLOCK = "block";
private static final String NOTIFICATION = "notification";
private static final String VIBRATE = "vibrate";
@ -57,7 +54,7 @@ public class RecipientPreferenceDatabase extends Database {
public static final String CREATE_TABLE =
"CREATE TABLE " + TABLE_NAME +
" (" + ID + " INTEGER PRIMARY KEY, " +
ADDRESSES + " TEXT UNIQUE, " +
ADDRESS + " TEXT UNIQUE, " +
BLOCK + " INTEGER DEFAULT 0," +
NOTIFICATION + " TEXT DEFAULT NULL, " +
VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
@ -74,7 +71,7 @@ public class RecipientPreferenceDatabase extends Database {
public Cursor getBlocked() {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESSES}, BLOCK + " = 1",
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS}, BLOCK + " = 1",
null, null, null, null, null);
cursor.setNotificationUri(context.getContentResolver(), Uri.parse(RECIPIENT_PREFERENCES_URI));
@ -85,14 +82,13 @@ public class RecipientPreferenceDatabase extends Database {
return new BlockedReader(context, cursor);
}
public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull Address[] addresses) {
public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull Address address) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = null;
try {
cursor = database.query(TABLE_NAME, null, ADDRESSES + " = ?",
new String[] {Address.toSerializedList(Arrays.asList(addresses), ' ')},
null, null, null);
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null);
if (cursor != null && cursor.moveToNext()) {
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
@ -128,69 +124,68 @@ public class RecipientPreferenceDatabase extends Database {
}
}
public void setColor(Recipients recipients, MaterialColor color) {
public void setColor(Recipient recipient, MaterialColor color) {
ContentValues values = new ContentValues();
values.put(COLOR, color.serialize());
updateOrInsert(recipients, values);
updateOrInsert(recipient, values);
}
public void setDefaultSubscriptionId(@NonNull Recipients recipients, int defaultSubscriptionId) {
public void setDefaultSubscriptionId(@NonNull Recipient recipient, int defaultSubscriptionId) {
ContentValues values = new ContentValues();
values.put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId);
updateOrInsert(recipients, values);
EventBus.getDefault().post(new RecipientPreferenceEvent(recipients));
updateOrInsert(recipient, values);
EventBus.getDefault().post(new RecipientPreferenceEvent(recipient));
}
public void setBlocked(Recipients recipients, boolean blocked) {
public void setBlocked(Recipient recipient, boolean blocked) {
ContentValues values = new ContentValues();
values.put(BLOCK, blocked ? 1 : 0);
updateOrInsert(recipients, values);
updateOrInsert(recipient, values);
}
public void setRingtone(Recipients recipients, @Nullable Uri notification) {
public void setRingtone(Recipient recipient, @Nullable Uri notification) {
ContentValues values = new ContentValues();
values.put(NOTIFICATION, notification == null ? null : notification.toString());
updateOrInsert(recipients, values);
updateOrInsert(recipient, values);
}
public void setVibrate(Recipients recipients, @NonNull VibrateState enabled) {
public void setVibrate(Recipient recipient, @NonNull VibrateState enabled) {
ContentValues values = new ContentValues();
values.put(VIBRATE, enabled.getId());
updateOrInsert(recipients, values);
updateOrInsert(recipient, values);
}
public void setMuted(Recipients recipients, long until) {
public void setMuted(Recipient recipient, long until) {
Log.w(TAG, "Setting muted until: " + until);
ContentValues values = new ContentValues();
values.put(MUTE_UNTIL, until);
updateOrInsert(recipients, values);
updateOrInsert(recipient, values);
}
public void setSeenInviteReminder(Recipients recipients, boolean seen) {
public void setSeenInviteReminder(Recipient recipient, boolean seen) {
ContentValues values = new ContentValues(1);
values.put(SEEN_INVITE_REMINDER, seen ? 1 : 0);
updateOrInsert(recipients, values);
updateOrInsert(recipient, values);
}
public void setExpireMessages(Recipients recipients, int expiration) {
recipients.setExpireMessages(expiration);
public void setExpireMessages(Recipient recipient, int expiration) {
recipient.setExpireMessages(expiration);
ContentValues values = new ContentValues(1);
values.put(EXPIRE_MESSAGES, expiration);
updateOrInsert(recipients, values);
updateOrInsert(recipient, values);
}
private void updateOrInsert(Recipients recipients, ContentValues contentValues) {
private void updateOrInsert(Recipient recipient, ContentValues contentValues) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
database.beginTransaction();
List<Address> addresses = recipients.getAddressesList();
String serializedAddresses = Address.toSerializedList(addresses, ' ');
int updated = database.update(TABLE_NAME, contentValues, ADDRESSES + " = ?", new String[]{serializedAddresses});
int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ?",
new String[] {recipient.getAddress().serialize()});
if (updated < 1) {
contentValues.put(ADDRESSES, serializedAddresses);
contentValues.put(ADDRESS, recipient.getAddress().serialize());
database.insert(TABLE_NAME, null, contentValues);
}
@ -271,14 +266,12 @@ public class RecipientPreferenceDatabase extends Database {
this.cursor = cursor;
}
public @NonNull Recipients getCurrent() {
String serialized = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESSES));
List<Address> addressList = Address.fromSerializedList(serialized, ' ');
return RecipientFactory.getRecipientsFor(context, addressList.toArray(new Address[0]), false);
public @NonNull Recipient getCurrent() {
String serialized = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
return RecipientFactory.getRecipientFor(context, Address.fromSerialized(serialized), false);
}
public @Nullable Recipients getNext() {
public @Nullable Recipient getNext() {
if (!cursor.moveToNext()) {
return null;
}
@ -289,14 +282,14 @@ public class RecipientPreferenceDatabase extends Database {
public static class RecipientPreferenceEvent {
private final Recipients recipients;
private final Recipient recipient;
RecipientPreferenceEvent(Recipients recipients) {
this.recipients = recipients;
public RecipientPreferenceEvent(Recipient recipients) {
this.recipient = recipients;
}
public Recipients getRecipients() {
return recipients;
public Recipient getRecipient() {
return recipient;
}
}
}

View File

@ -34,8 +34,8 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
@ -457,8 +457,8 @@ public class SmsDatabase extends MessagingDatabase {
}
private @NonNull Pair<Long, Long> insertCallLog(@NonNull Address address, long type, boolean unread) {
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
Recipient recipient = RecipientFactory.getRecipientFor(context, address, true);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
ContentValues values = new ContentValues(6);
values.put(ADDRESS, address.serialize());
@ -506,14 +506,14 @@ 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;
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getSender()}, true);
Recipient recipient = RecipientFactory.getRecipientFor(context, message.getSender(), true);
Recipients groupRecipients;
Recipient groupRecipient;
if (message.getGroupId() == null) {
groupRecipients = null;
groupRecipient = null;
} else {
groupRecipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getGroupId()}, true);
groupRecipient = RecipientFactory.getRecipientFor(context, message.getGroupId(), true);
}
boolean unread = (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
@ -522,8 +522,8 @@ public class SmsDatabase extends MessagingDatabase {
long threadId;
if (groupRecipients == null) threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
if (groupRecipient == null) threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
ContentValues values = new ContentValues(6);
values.put(ADDRESS, message.getSender().serialize());
@ -560,7 +560,7 @@ public class SmsDatabase extends MessagingDatabase {
}
if (message.getSubscriptionId() != -1) {
DatabaseFactory.getRecipientPreferenceDatabase(context).setDefaultSubscriptionId(recipients, message.getSubscriptionId());
DatabaseFactory.getRecipientPreferenceDatabase(context).setDefaultSubscriptionId(recipient, message.getSubscriptionId());
}
notifyConversationListeners(threadId);
@ -589,7 +589,7 @@ 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.getRecipients().getPrimaryRecipient().getAddress();
Address address = message.getRecipient().getAddress();
ContentValues contentValues = new ContentValues(6);
contentValues.put(ADDRESS, address.serialize());
@ -783,7 +783,7 @@ public class SmsDatabase extends MessagingDatabase {
public MessageRecord getCurrent() {
return new SmsMessageRecord(context, id, new DisplayRecord.Body(message.getMessageBody(), true),
message.getRecipients(), message.getRecipients().getPrimaryRecipient(),
message.getRecipient(), message.getRecipient(),
1, System.currentTimeMillis(), System.currentTimeMillis(),
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
@ -828,21 +828,17 @@ public class SmsDatabase extends MessagingDatabase {
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
Recipients recipients = getRecipientsFor(address);
Recipient recipient = RecipientFactory.getRecipientFor(context, address, true);
DisplayRecord.Body body = getBody(cursor);
return new SmsMessageRecord(context, messageId, body, recipients,
recipients.getPrimaryRecipient(),
return new SmsMessageRecord(context, messageId, body, recipient,
recipient,
addressDeviceId,
dateSent, dateReceived, receiptCount, type,
threadId, status, mismatches, subscriptionId,
expiresIn, expireStarted);
}
private Recipients getRecipientsFor(Address address) {
return RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
}
private List<IdentityKeyMismatch> getMismatches(String document) {
try {
if (!TextUtils.isEmpty(document)) {

View File

@ -22,16 +22,19 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteStatement;
import android.net.Uri;
import android.text.TextUtils;
import android.support.annotation.Nullable;
import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
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;
public class SmsMigrator {
@ -140,21 +143,21 @@ public class SmsMigrator {
}
}
private static Recipients getOurRecipients(Context context, String theirRecipients) {
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
List<Address> addressList = new LinkedList<>();
private static @Nullable Set<Recipient> getOurRecipients(Context context, String theirRecipients) {
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
Set<Recipient> recipientList = new HashSet<>();
while (tokenizer.hasMoreTokens()) {
String theirRecipientId = tokenizer.nextToken();
String address = getTheirCanonicalAddress(context, theirRecipientId);
if (address != null) {
addressList.add(Address.fromExternal(context, address));
recipientList.add(RecipientFactory.getRecipientFor(context, Address.fromExternal(context, address), true));
}
}
if (addressList.isEmpty()) return null;
else return RecipientFactory.getRecipientsFor(context, addressList.toArray(new Address[0]), true);
if (recipientList.isEmpty()) return null;
else return recipientList;
}
private static String encrypt(MasterSecret masterSecret, String body)
@ -221,16 +224,30 @@ public class SmsMigrator {
cursor = context.getContentResolver().query(threadListUri, null, null, null, "date ASC");
while (cursor != null && cursor.moveToNext()) {
long theirThreadId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
String theirRecipients = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
Recipients ourRecipients = getOurRecipients(context, theirRecipients);
ProgressDescription progress = new ProgressDescription(cursor.getCount(), cursor.getPosition(), 100, 0);
long theirThreadId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
String theirRecipients = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
Set<Recipient> ourRecipients = getOurRecipients(context, theirRecipients);
ProgressDescription progress = new ProgressDescription(cursor.getCount(), cursor.getPosition(), 100, 0);
if (ourRecipients != null) {
long ourThreadId = threadDatabase.getThreadIdFor(ourRecipients);
migrateConversation(context, masterSecret,
listener, progress,
theirThreadId, ourThreadId);
if (ourRecipients.size() == 1) {
long ourThreadId = threadDatabase.getThreadIdFor(ourRecipients.iterator().next());
migrateConversation(context, masterSecret, listener, progress, theirThreadId, ourThreadId);
} else if (ourRecipients.size() > 1) {
ourRecipients.add(RecipientFactory.getRecipientFor(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), true));
List<Address> memberAddresses = new LinkedList<>();
for (Recipient recipient : ourRecipients) {
memberAddresses.add(recipient.getAddress());
}
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, true);
Recipient ourGroupRecipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(ourGroupId), true);
long ourThreadId = threadDatabase.getThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
migrateConversation(context, masterSecret, listener, progress, theirThreadId, ourThreadId);
}
}
progress.incrementPrimaryComplete();

View File

@ -36,13 +36,12 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.DelimiterUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.InvalidMessageException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@ -55,7 +54,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 ADDRESSES = "recipient_ids";
public static final String ADDRESS = "recipient_ids";
public static final String SNIPPET = "snippet";
private static final String SNIPPET_CHARSET = "snippet_cs";
public static final String READ = "read";
@ -71,7 +70,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, " + ADDRESSES + " TEXT, " + SNIPPET + " TEXT, " +
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESS + " TEXT, " + 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, " +
@ -80,7 +79,7 @@ public class ThreadDatabase extends Database {
LAST_SEEN + " INTEGER DEFAULT 0);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESSES + ");",
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESS + ");",
"CREATE INDEX IF NOT EXISTS archived_count_index ON " + TABLE_NAME + " (" + ARCHIVED + ", " + MESSAGE_COUNT + ");",
};
@ -88,14 +87,14 @@ public class ThreadDatabase extends Database {
super(context, databaseHelper);
}
private long createThreadForRecipients(Address[] addresses, int recipientCount, int distributionType) {
private long createThreadForRecipient(Address address, boolean group, int distributionType) {
ContentValues contentValues = new ContentValues(4);
long date = System.currentTimeMillis();
contentValues.put(DATE, date - date % 1000);
contentValues.put(ADDRESSES, Address.toSerializedList(Arrays.asList(addresses), ' '));
contentValues.put(ADDRESS, address.serialize());
if (recipientCount > 1)
if (group)
contentValues.put(TYPE, distributionType);
contentValues.put(MESSAGE_COUNT, 0);
@ -272,6 +271,22 @@ public class ThreadDatabase extends Database {
notifyConversationListListeners();
}
public int getDistributionType(long threadId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, new String[]{TYPE}, ID_WHERE, new String[]{String.valueOf(threadId)}, null, null, null);
try {
if (cursor != null && cursor.moveToNext()) {
return cursor.getInt(cursor.getColumnIndexOrThrow(TYPE));
}
return DistributionTypes.DEFAULT;
} finally {
if (cursor != null) cursor.close();
}
}
public Cursor getFilteredConversationList(List<Address> filter) {
if (filter == null || filter.size() == 0)
return null;
@ -281,11 +296,11 @@ public class ThreadDatabase extends Database {
List<Cursor> cursors = new LinkedList<>();
for (List<Address> addresses : partitionedAddresses) {
String selection = ADDRESSES + " = ?";
String selection = ADDRESS + " = ?";
String[] selectionArgs = new String[addresses.size()];
for (int i=0;i<addresses.size()-1;i++)
selection += (" OR " + ADDRESSES + " = ?");
selection += (" OR " + ADDRESS + " = ?");
int i= 0;
for (Address address : addresses) {
@ -410,12 +425,11 @@ public class ThreadDatabase extends Database {
deleteAllThreads();
}
public long getThreadIdIfExistsFor(Recipients recipients) {
List<Address> addresses = Arrays.asList(recipients.getAddresses());
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String where = ADDRESSES + " = ?";
String[] recipientsArg = new String[]{Address.toSerializedList(addresses, ' ')};
Cursor cursor = null;
public long getThreadIdIfExistsFor(Recipient recipient) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String where = ADDRESS + " = ?";
String[] recipientsArg = new String[] {recipient.getAddress().serialize()};
Cursor cursor = null;
try {
cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null);
@ -430,15 +444,14 @@ public class ThreadDatabase extends Database {
}
}
public long getThreadIdFor(Recipients recipients) {
return getThreadIdFor(recipients, DistributionTypes.DEFAULT);
public long getThreadIdFor(Recipient recipient) {
return getThreadIdFor(recipient, DistributionTypes.DEFAULT);
}
public long getThreadIdFor(Recipients recipients, int distributionType) {
Address[] addresses = recipients.getAddresses();
public long getThreadIdFor(Recipient recipient, int distributionType) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String where = ADDRESSES + " = ?";
String[] recipientsArg = new String[]{Address.toSerializedList(Arrays.asList(addresses), ' ')};
String where = ADDRESS + " = ?";
String[] recipientsArg = new String[]{recipient.getAddress().serialize()};
Cursor cursor = null;
try {
@ -447,7 +460,7 @@ public class ThreadDatabase extends Database {
if (cursor != null && cursor.moveToFirst()) {
return cursor.getLong(cursor.getColumnIndexOrThrow(ID));
} else {
return createThreadForRecipients(addresses, recipients.getRecipientsList().size(), distributionType);
return createThreadForRecipient(recipient.getAddress(), recipient.isGroupRecipient(), distributionType);
}
} finally {
if (cursor != null)
@ -455,7 +468,7 @@ public class ThreadDatabase extends Database {
}
}
public @Nullable Recipients getRecipientsForThreadId(long threadId) {
public @Nullable Recipient getRecipientForThreadId(long threadId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = null;
@ -463,8 +476,8 @@ public class ThreadDatabase extends Database {
cursor = db.query(TABLE_NAME, null, ID + " = ?", new String[] {threadId+""}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
List<Address> addresses = Address.fromSerializedList(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESSES)), ' ');
return RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), false);
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
return RecipientFactory.getRecipientFor(context, address, false);
}
} finally {
if (cursor != null)
@ -561,9 +574,9 @@ public class ThreadDatabase extends Database {
}
public ThreadRecord getCurrent() {
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
List<Address> addresses = Address.fromSerializedList(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESSES)), ' ');
Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), true);
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESS)));
Recipient recipient = RecipientFactory.getRecipientFor(context, address, true);
DisplayRecord.Body body = getPlaintextBody(cursor);
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
@ -578,7 +591,7 @@ public class ThreadDatabase extends Database {
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
Uri snippetUri = getSnippetUri(cursor);
return new ThreadRecord(context, body, snippetUri, recipients, date, count, read == 1,
return new ThreadRecord(context, body, snippetUri, recipient, date, count, read == 1,
threadId, receiptCount, status, type, distributionType, archived,
expiresIn, lastSeen);
}

View File

@ -42,7 +42,7 @@ public class ConversationListLoader extends AbstractCursorLoader {
if (archivedCount > 0) {
MatrixCursor switchToArchiveCursor = new MatrixCursor(new String[] {
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
ThreadDatabase.ADDRESSES, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
ThreadDatabase.ADDRESS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.RECEIPT_COUNT,
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN}, 1);

View File

@ -21,7 +21,7 @@ import android.text.SpannableString;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
/**
* The base class for all message record models. Encapsulates basic data
@ -36,7 +36,7 @@ public abstract class DisplayRecord {
protected final Context context;
protected final long type;
private final Recipients recipients;
private final Recipient recipient;
private final long dateSent;
private final long dateReceived;
private final long threadId;
@ -44,12 +44,12 @@ public abstract class DisplayRecord {
private final int deliveryStatus;
private final int receiptCount;
public DisplayRecord(Context context, Body body, Recipients recipients, long dateSent,
public DisplayRecord(Context context, Body body, Recipient recipient, long dateSent,
long dateReceived, long threadId, int deliveryStatus, int receiptCount, long type)
{
this.context = context.getApplicationContext();
this.threadId = threadId;
this.recipients = recipients;
this.recipient = recipient;
this.dateSent = dateSent;
this.dateReceived = dateReceived;
this.type = type;
@ -81,8 +81,8 @@ public abstract class DisplayRecord {
public abstract SpannableString getDisplayBody();
public Recipients getRecipients() {
return recipients;
public Recipient getRecipient() {
return recipient;
}
public long getDateSent() {

View File

@ -27,7 +27,6 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.util.List;
@ -45,7 +44,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
private final Context context;
private final int partCount;
public MediaMmsMessageRecord(Context context, long id, Recipients recipients,
public MediaMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
Recipient individualRecipient, int recipientDeviceId,
long dateSent, long dateReceived, int receiptCount,
long threadId, Body body,
@ -55,7 +54,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
List<NetworkFailure> failures, int subscriptionId,
long expiresIn, long expireStarted)
{
super(context, id, body, recipients, individualRecipient, recipientDeviceId, dateSent,
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox, mismatches, failures,
subscriptionId, expiresIn, expireStarted, slideDeck);

View File

@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
@ -55,7 +54,7 @@ public abstract class MessageRecord extends DisplayRecord {
private final long expiresIn;
private final long expireStarted;
MessageRecord(Context context, long id, Body body, Recipients recipients,
MessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
Recipient individualRecipient, int recipientDeviceId,
long dateSent, long dateReceived, long threadId,
int deliveryStatus, int receiptCount, long type,
@ -63,7 +62,7 @@ public abstract class MessageRecord extends DisplayRecord {
List<NetworkFailure> networkFailures,
int subscriptionId, long expiresIn, long expireStarted)
{
super(context, body, recipients, dateSent, dateReceived, threadId, deliveryStatus, receiptCount,
super(context, body, conversationRecipient, dateSent, dateReceived, threadId, deliveryStatus, receiptCount,
type);
this.id = id;
this.individualRecipient = individualRecipient;

View File

@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.util.List;
@ -17,14 +16,14 @@ public abstract class MmsMessageRecord extends MessageRecord {
private final @NonNull SlideDeck slideDeck;
MmsMessageRecord(Context context, long id, Body body, Recipients recipients,
MmsMessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
Recipient individualRecipient, int recipientDeviceId, long dateSent,
long dateReceived, long threadId, int deliveryStatus, int receiptCount,
long type, List<IdentityKeyMismatch> mismatches,
List<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
long expireStarted, @NonNull SlideDeck slideDeck)
{
super(context, id, body, recipients, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, receiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted);
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, receiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted);
this.slideDeck = slideDeck;
}

View File

@ -20,13 +20,12 @@ import android.content.Context;
import android.text.SpannableString;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.util.LinkedList;
@ -46,14 +45,14 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
private final int status;
private final byte[] transactionId;
public NotificationMmsMessageRecord(Context context, long id, Recipients recipients,
public NotificationMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
Recipient individualRecipient, int recipientDeviceId,
long dateSent, long dateReceived, int receiptCount,
long threadId, byte[] contentLocation, long messageSize,
long expiry, int status, byte[] transactionId, long mailbox,
int subscriptionId, SlideDeck slideDeck)
{
super(context, id, new Body("", true), recipients, individualRecipient, recipientDeviceId,
super(context, id, new Body("", true), conversationRecipient, individualRecipient, recipientDeviceId,
dateSent, dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox,
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), subscriptionId,
0, 0, slideDeck);

View File

@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.util.LinkedList;
import java.util.List;
@ -41,7 +40,7 @@ import java.util.List;
public class SmsMessageRecord extends MessageRecord {
public SmsMessageRecord(Context context, long id,
Body body, Recipients recipients,
Body body, Recipient recipient,
Recipient individualRecipient,
int recipientDeviceId,
long dateSent, long dateReceived,
@ -50,7 +49,7 @@ public class SmsMessageRecord extends MessageRecord {
int status, List<IdentityKeyMismatch> mismatches,
int subscriptionId, long expiresIn, long expireStarted)
{
super(context, id, body, recipients, individualRecipient, recipientDeviceId,
super(context, id, body, recipient, individualRecipient, recipientDeviceId,
dateSent, dateReceived, threadId, status, receiptCount, type,
mismatches, new LinkedList<NetworkFailure>(), subscriptionId,
expiresIn, expireStarted);

View File

@ -28,7 +28,7 @@ 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.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.ExpirationUtil;
/**
@ -49,11 +49,11 @@ public class ThreadRecord extends DisplayRecord {
private final long lastSeen;
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
@NonNull Recipients recipients, long date, long count, boolean read,
@NonNull Recipient recipient, long date, long count, boolean read,
long threadId, int receiptCount, int status, long snippetType,
int distributionType, boolean archived, long expiresIn, long lastSeen)
{
super(context, body, recipients, date, date, threadId, status, receiptCount, snippetType);
super(context, body, recipient, date, date, threadId, status, receiptCount, snippetType);
this.context = context.getApplicationContext();
this.snippetUri = snippetUri;
this.count = count;
@ -98,13 +98,13 @@ public class ThreadRecord extends DisplayRecord {
} else if (SmsDatabase.Types.isMissedCall(type)) {
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_missed_call));
} else if (SmsDatabase.Types.isJoinedType(type)) {
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal, getRecipients().getPrimaryRecipient().toShortString()));
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal, getRecipient().toShortString()));
} else if (SmsDatabase.Types.isExpirationTimerUpdate(type)) {
String time = ExpirationUtil.getExpirationDisplayValue(context, (int) (getExpiresIn() / 1000));
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time));
} else if (SmsDatabase.Types.isIdentityUpdate(type)) {
if (getRecipients().isGroupRecipient()) 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, getRecipients().getPrimaryRecipient().toShortString()));
if (getRecipient().isGroupRecipient()) 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));
} else if (SmsDatabase.Types.isIdentityDefault(type)) {

View File

@ -15,19 +15,21 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.providers.SingleUseBlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.util.guava.Optional;
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.HashSet;
import java.util.LinkedList;
@ -40,23 +42,93 @@ public class GroupManager {
@NonNull MasterSecret masterSecret,
@NonNull Set<Recipient> members,
@Nullable Bitmap avatar,
@Nullable String name)
throws InvalidNumberException
@Nullable String name,
boolean mms)
{
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final byte[] groupId = groupDatabase.allocateGroupId();
final Set<Address> memberAddresses = getMemberAddresses(context, members);
final String groupId = GroupUtil.getEncodedId(groupDatabase.allocateGroupId(), mms);
final Set<Address> memberAddresses = getMemberAddresses(members);
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null);
groupDatabase.updateAvatar(groupId, avatarBytes);
return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes);
if (!mms) {
groupDatabase.updateAvatar(groupId, avatarBytes);
return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes);
} else {
Recipient groupRecipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(groupId), true);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
return new GroupActionResult(groupRecipient, threadId);
}
}
private static Set<Address> getMemberAddresses(Context context, Collection<Recipient> recipients)
public static GroupActionResult updateGroup(@NonNull Context context,
@NonNull MasterSecret masterSecret,
@NonNull String groupId,
@NonNull Set<Recipient> members,
@Nullable Bitmap avatar,
@Nullable String name)
throws InvalidNumberException
{
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final Set<Address> memberAddresses = getMemberAddresses(members);
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
groupDatabase.updateMembers(groupId, new LinkedList<>(memberAddresses));
groupDatabase.updateTitle(groupId, name);
groupDatabase.updateAvatar(groupId, avatarBytes);
if (!GroupUtil.isMmsGroup(groupId)) {
return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes);
} else {
Recipient groupRecipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(groupId), true);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
return new GroupActionResult(groupRecipient, threadId);
}
}
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
@NonNull MasterSecret masterSecret,
@NonNull String groupId,
@NonNull Set<Address> members,
@Nullable String groupName,
@Nullable byte[] avatar)
{
try {
Attachment avatarAttachment = null;
Address groupAddress = Address.fromSerialized(groupId);
Recipient groupRecipient = RecipientFactory.getRecipientFor(context, groupAddress, false);
List<String> numbers = new LinkedList<>();
for (Address member : members) {
numbers.add(member.serialize());
}
GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedId(groupId)))
.setType(GroupContext.Type.UPDATE)
.addAllMembers(numbers);
if (groupName != null) groupContextBuilder.setName(groupName);
GroupContext groupContext = groupContextBuilder.build();
if (avatar != null) {
Uri avatarUri = SingleUseBlobProvider.getInstance().createUri(avatar);
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false);
}
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0);
long threadId = MessageSender.send(context, masterSecret, outgoingMessage, -1, false, null);
return new GroupActionResult(groupRecipient, threadId);
} catch (IOException e) {
throw new AssertionError(e);
}
}
private static Set<Address> getMemberAddresses(Collection<Recipient> recipients) {
final Set<Address> results = new HashSet<>();
for (Recipient recipient : recipients) {
results.add(recipient.getAddress());
@ -65,71 +137,16 @@ public class GroupManager {
return results;
}
public static GroupActionResult updateGroup(@NonNull Context context,
@NonNull MasterSecret masterSecret,
@NonNull byte[] groupId,
@NonNull Set<Recipient> members,
@Nullable Bitmap avatar,
@Nullable String name)
throws InvalidNumberException
{
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final Set<Address> memberAddresses = getMemberAddresses(context, members);
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
groupDatabase.updateMembers(groupId, new LinkedList<>(memberAddresses));
groupDatabase.updateTitle(groupId, name);
groupDatabase.updateAvatar(groupId, avatarBytes);
return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes);
}
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
@NonNull MasterSecret masterSecret,
@NonNull byte[] groupId,
@NonNull Set<Address> members,
@Nullable String groupName,
@Nullable byte[] avatar)
{
Attachment avatarAttachment = null;
Address groupAddress = Address.fromSerialized(GroupUtil.getEncodedId(groupId));
Recipients groupRecipient = RecipientFactory.getRecipientsFor(context, new Address[]{groupAddress}, false);
List<String> numbers = new LinkedList<>();
for (Address member : members) {
numbers.add(member.serialize());
}
GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
.setId(ByteString.copyFrom(groupId))
.setType(GroupContext.Type.UPDATE)
.addAllMembers(numbers);
if (groupName != null) groupContextBuilder.setName(groupName);
GroupContext groupContext = groupContextBuilder.build();
if (avatar != null) {
Uri avatarUri = SingleUseBlobProvider.getInstance().createUri(avatar);
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false);
}
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0);
long threadId = MessageSender.send(context, masterSecret, outgoingMessage, -1, false, null);
return new GroupActionResult(groupRecipient, threadId);
}
public static class GroupActionResult {
private Recipients groupRecipient;
private long threadId;
private Recipient groupRecipient;
private long threadId;
public GroupActionResult(Recipients groupRecipient, long threadId) {
public GroupActionResult(Recipient groupRecipient, long threadId) {
this.groupRecipient = groupRecipient;
this.threadId = threadId;
}
public Recipients getGroupRecipient() {
public Recipient getGroupRecipient() {
return groupRecipient;
}

View File

@ -21,8 +21,8 @@ import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
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.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.util.Base64;
@ -60,7 +60,7 @@ public class GroupMessageProcessor {
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
SignalServiceGroup group = message.getGroupInfo().get();
byte[] id = group.getGroupId();
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
GroupRecord record = database.getGroup(id);
if (record != null && group.getType() == Type.UPDATE) {
@ -84,7 +84,7 @@ public class GroupMessageProcessor {
boolean outgoing)
{
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
byte[] id = group.getGroupId();
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
GroupContext.Builder builder = createGroupContext(group);
builder.setType(GroupContext.Type.UPDATE);
@ -113,7 +113,7 @@ public class GroupMessageProcessor {
{
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
byte[] id = group.getGroupId();
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
Set<Address> recordMembers = new HashSet<>(groupRecord.getMembers());
Set<Address> messageMembers = new HashSet<>();
@ -185,7 +185,7 @@ public class GroupMessageProcessor {
boolean outgoing)
{
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
byte[] id = group.getGroupId();
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
List<Address> members = record.getMembers();
GroupContext.Builder builder = createGroupContext(group);
@ -217,10 +217,10 @@ public class GroupMessageProcessor {
try {
if (outgoing) {
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
Address addres = Address.fromExternal(context, GroupUtil.getEncodedId(group.getGroupId()));
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {addres}, false);
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipients, storage, null, envelope.getTimestamp(), 0);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
Address addres = Address.fromExternal(context, GroupUtil.getEncodedId(group.getGroupId(), false));
Recipient recipient = RecipientFactory.getRecipientFor(context, addres, false);
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, envelope.getTimestamp(), 0);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
long messageId = mmsDatabase.insertMessageOutbox(masterSecret, outgoingMessage, threadId, false, null);
mmsDatabase.markAsSent(messageId, true);

View File

@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.Hex;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
@ -54,8 +55,9 @@ public class AvatarDownloadJob extends MasterSecretJob implements InjectableType
@Override
public void onRun(MasterSecret masterSecret) throws IOException {
String encodeId = GroupUtil.getEncodedId(groupId, false);
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
GroupDatabase.GroupRecord record = database.getGroup(groupId);
GroupDatabase.GroupRecord record = database.getGroup(encodeId);
File attachment = null;
try {
@ -82,7 +84,7 @@ public class AvatarDownloadJob extends MasterSecretJob implements InjectableType
InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE);
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key), 500, 500);
database.updateAvatar(groupId, avatar);
database.updateAvatar(encodeId, avatar);
inputStream.close();
}
} catch (BitmapDecodingException | NonSuccessfulResponseCodeException | InvalidMessageException e) {

View File

@ -8,10 +8,9 @@ import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.SecurityEvent;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
@ -20,7 +19,7 @@ import java.io.IOException;
public class DirectoryRefreshJob extends ContextJob {
@Nullable private transient Recipients recipients;
@Nullable private transient Recipient recipient;
@Nullable private transient MasterSecret masterSecret;
public DirectoryRefreshJob(@NonNull Context context) {
@ -29,14 +28,14 @@ public class DirectoryRefreshJob extends ContextJob {
public DirectoryRefreshJob(@NonNull Context context,
@Nullable MasterSecret masterSecret,
@Nullable Recipients recipients)
@Nullable Recipient recipient)
{
super(context, JobParameters.newBuilder()
.withGroupId(DirectoryRefreshJob.class.getSimpleName())
.withRequirement(new NetworkRequirement(context))
.create());
this.recipients = recipients;
this.recipient = recipient;
this.masterSecret = masterSecret;
}
@ -51,10 +50,10 @@ public class DirectoryRefreshJob extends ContextJob {
try {
wakeLock.acquire();
if (recipients == null) {
if (recipient == null) {
DirectoryHelper.refreshDirectory(context, KeyCachingService.getMasterSecret(context));
} else {
DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients);
DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipient);
}
SecurityEvent.broadcastSecurityUpdateEvent(context);
} finally {

View File

@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.UriAttachment;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
@ -28,6 +29,7 @@ import org.thoughtcrime.securesms.mms.PartParser;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.providers.SingleUseBlobProvider;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
@ -39,8 +41,10 @@ import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class MmsDownloadJob extends MasterSecretJob {
@ -88,6 +92,10 @@ public class MmsDownloadJob extends MasterSecretJob {
throw new MmsException("Notification content location was null.");
}
if (!TextSecurePreferences.isPushRegistered(context)) {
throw new MmsException("Not registered");
}
database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_CONNECTING);
String contentLocation = notification.get().getContentLocation();
@ -161,28 +169,33 @@ public class MmsDownloadJob extends MasterSecretJob {
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
SingleUseBlobProvider provider = SingleUseBlobProvider.getInstance();
String from = null;
List<String> to = new LinkedList<>();
List<String> cc = new LinkedList<>();
Optional<Address> group = Optional.absent();
Set<Address> members = new HashSet<>();
String body = null;
List<Attachment> attachments = new LinkedList<>();
Address from;
if (retrieved.getFrom() != null) {
from = Util.toIsoString(retrieved.getFrom().getTextString());
from = Address.fromExternal(context, Util.toIsoString(retrieved.getFrom().getTextString()));
} else {
from = Address.UNKNOWN;
}
if (retrieved.getTo() != null) {
for (EncodedStringValue toValue : retrieved.getTo()) {
to.add(Util.toIsoString(toValue.getTextString()));
members.add(Address.fromExternal(context, Util.toIsoString(toValue.getTextString())));
}
}
if (retrieved.getCc() != null) {
for (EncodedStringValue ccValue : retrieved.getCc()) {
cc.add(Util.toIsoString(ccValue.getTextString()));
members.add(Address.fromExternal(context, Util.toIsoString(ccValue.getTextString())));
}
}
members.add(Address.fromExternal(context, TextSecurePreferences.getLocalNumber(context)));
if (retrieved.getBody() != null) {
body = PartParser.getMessageText(retrieved.getBody());
PduBody media = PartParser.getSupportedMediaParts(retrieved.getBody());
@ -203,9 +216,11 @@ public class MmsDownloadJob extends MasterSecretJob {
}
}
if (members.size() > 1) {
group = Optional.of(Address.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), true)));
}
IncomingMediaMessage message = new IncomingMediaMessage(context, from, to, cc, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
Optional<InsertResult> insertResult = database.insertMessageInbox(new MasterSecretUnion(masterSecret),
message, contentLocation, threadId);

View File

@ -13,8 +13,8 @@ import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
@ -86,7 +86,7 @@ public class MmsReceiveJob extends ContextJob {
private boolean isBlocked(GenericPdu pdu) {
if (pdu.getFrom() != null && pdu.getFrom().getTextString() != null) {
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, Util.toIsoString(pdu.getFrom().getTextString()))}, false);
Recipient recipients = RecipientFactory.getRecipientFor(context, Address.fromExternal(context, Util.toIsoString(pdu.getFrom().getTextString())), false);
return recipients.isBlocked();
}

View File

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
import org.thoughtcrime.securesms.mms.MediaConstraints;
@ -33,11 +34,12 @@ import org.thoughtcrime.securesms.mms.MmsSendResult;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients;
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.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
@ -171,16 +173,28 @@ public class MmsSendJob extends SendJob {
{
SendReq req = new SendReq();
String lineNumber = Utils.getMyPhoneNumber(context);
Address[] numbers = message.getRecipients().getAddresses();
Address destination = message.getRecipient().getAddress();
MediaConstraints mediaConstraints = MediaConstraints.getMmsMediaConstraints(message.getSubscriptionId());
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
if (!TextUtils.isEmpty(lineNumber)) {
req.setFrom(new EncodedStringValue(lineNumber));
} else {
req.setFrom(new EncodedStringValue(TextSecurePreferences.getLocalNumber(context)));
}
for (Address recipient : numbers) {
req.addTo(new EncodedStringValue(recipient.serialize()));
if (destination.isMmsGroup()) {
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(destination.toGroupString(), false);
for (Recipient member : members) {
if (message.getDistributionType() == ThreadDatabase.DistributionTypes.BROADCAST) {
req.addBcc(new EncodedStringValue(member.getAddress().serialize()));
} else {
req.addTo(new EncodedStringValue(member.getAddress().serialize()));
}
}
} else {
req.addTo(new EncodedStringValue(destination.serialize()));
}
req.setDate(System.currentTimeMillis() / 1000);
@ -266,11 +280,11 @@ public class MmsSendJob extends SendJob {
}
private void notifyMediaMessageDeliveryFailed(Context context, long messageId) {
long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId);
long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
if (recipients != null) {
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
if (recipient != null) {
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
}
}
}

View File

@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.BlockedRe
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
@ -50,11 +50,11 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
BlockedReader reader = database.readerForBlocked(database.getBlocked());
List<String> blocked = new LinkedList<>();
Recipients recipients;
Recipient recipient;
while ((recipients = reader.getNext()) != null) {
if (recipients.isSingleRecipient() && !recipients.isGroupRecipient()) {
blocked.add(recipients.getPrimaryRecipient().getAddress().serialize());
while ((recipient = reader.getNext()) != null) {
if (!recipient.isGroupRecipient()) {
blocked.add(recipient.getAddress().serialize());
}
}

View File

@ -34,8 +34,8 @@ import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
@ -80,7 +80,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptM
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -162,7 +161,7 @@ public class PushDecryptJob extends ContextJob {
else if (message.getAttachments().isPresent()) handleMediaMessage(masterSecret, envelope, message, smsMessageId);
else handleTextMessage(masterSecret, envelope, message, smsMessageId);
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(message.getGroupInfo().get().getGroupId())) {
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) {
handleUnknownGroupMessage(envelope, message.getGroupInfo().get());
}
} else if (content.getSyncMessage().isPresent()) {
@ -322,15 +321,15 @@ public class PushDecryptJob extends ContextJob {
@NonNull Optional<Long> smsMessageId)
{
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
Recipients recipients = getSyncMessageDestination(message);
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipients, "", -1);
Recipient recipient = getSyncMessageDestination(message);
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipient, "", -1);
OutgoingEndSessionMessage outgoingEndSessionMessage = new OutgoingEndSessionMessage(outgoingTextMessage);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
if (recipients.isSingleRecipient() && !recipients.isGroupRecipient()) {
if (!recipient.isGroupRecipient()) {
SessionStore sessionStore = new TextSecureSessionStore(context);
sessionStore.deleteAllSessions(recipients.getPrimaryRecipient().getAddress().toPhoneString());
sessionStore.deleteAllSessions(recipient.getAddress().toPhoneString());
SecurityEvent.broadcastSecurityUpdateEvent(context);
@ -373,11 +372,9 @@ public class PushDecryptJob extends ContextJob {
throws MmsException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
String localNumber = TextSecurePreferences.getLocalNumber(context);
Recipients recipients = getMessageDestination(envelope, message);
Recipient recipient = getMessageDestination(envelope, message);
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret,
Address.fromExternal(context, envelope.getSource()),
Address.fromSerialized(localNumber),
message.getTimestamp(), -1,
message.getExpiresInSeconds() * 1000, true,
Optional.fromNullable(envelope.getRelay()),
@ -388,7 +385,7 @@ public class PushDecryptJob extends ContextJob {
database.insertSecureDecryptedMessageInbox(masterSecret, mediaMessage, -1);
DatabaseFactory.getRecipientPreferenceDatabase(context).setExpireMessages(recipients, message.getExpiresInSeconds());
DatabaseFactory.getRecipientPreferenceDatabase(context).setExpireMessages(recipient, message.getExpiresInSeconds());
if (smsMessageId.isPresent()) {
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
@ -423,7 +420,7 @@ public class PushDecryptJob extends ContextJob {
threadId = handleSynchronizeSentTextMessage(masterSecret, message, smsMessageId);
}
if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(message.getMessage().getGroupInfo().get().getGroupId())) {
if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false))) {
handleUnknownGroupMessage(envelope, message.getMessage().getGroupInfo().get());
}
@ -490,11 +487,9 @@ public class PushDecryptJob extends ContextJob {
throws MmsException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
String localNumber = TextSecurePreferences.getLocalNumber(context);
Recipients recipients = getMessageDestination(envelope, message);
Recipient recipient = getMessageDestination(envelope, message);
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret,
Address.fromExternal(context, envelope.getSource()),
Address.fromSerialized(localNumber),
message.getTimestamp(), -1,
message.getExpiresInSeconds() * 1000, false,
Optional.fromNullable(envelope.getRelay()),
@ -502,7 +497,7 @@ public class PushDecryptJob extends ContextJob {
message.getGroupInfo(),
message.getAttachments());
if (message.getExpiresInSeconds() != recipients.getExpireMessages()) {
if (message.getExpiresInSeconds() != recipient.getExpireMessages()) {
handleExpirationUpdate(masterSecret, envelope, message, Optional.<Long>absent());
}
@ -537,18 +532,18 @@ public class PushDecryptJob extends ContextJob {
throws MmsException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
Recipients recipients = getSyncMessageDestination(message);
Recipient recipient = getSyncMessageDestination(message);
OutgoingExpirationUpdateMessage expirationUpdateMessage = new OutgoingExpirationUpdateMessage(recipients,
OutgoingExpirationUpdateMessage expirationUpdateMessage = new OutgoingExpirationUpdateMessage(recipient,
message.getTimestamp(),
message.getMessage().getExpiresInSeconds() * 1000);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
long messageId = database.insertMessageOutbox(masterSecret, expirationUpdateMessage, threadId, false, null);
database.markAsSent(messageId, true);
DatabaseFactory.getRecipientPreferenceDatabase(context).setExpireMessages(recipients, message.getMessage().getExpiresInSeconds());
DatabaseFactory.getRecipientPreferenceDatabase(context).setExpireMessages(recipient, message.getMessage().getExpiresInSeconds());
if (smsMessageId.isPresent()) {
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
@ -563,7 +558,7 @@ public class PushDecryptJob extends ContextJob {
throws MmsException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
Recipients recipients = getSyncMessageDestination(message);
Recipient recipients = getSyncMessageDestination(message);
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipients, message.getMessage().getBody().orNull(),
PointerAttachment.forPointers(masterSecret, message.getMessage().getAttachments()),
message.getTimestamp(), -1,
@ -611,9 +606,9 @@ public class PushDecryptJob extends ContextJob {
{
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
String body = message.getBody().isPresent() ? message.getBody().get() : "";
Recipients recipients = getMessageDestination(envelope, message);
Recipient recipient = getMessageDestination(envelope, message);
if (message.getExpiresInSeconds() != recipients.getExpireMessages()) {
if (message.getExpiresInSeconds() != recipient.getExpireMessages()) {
handleExpirationUpdate(masterSecret, envelope, message, Optional.<Long>absent());
}
@ -648,16 +643,16 @@ public class PushDecryptJob extends ContextJob {
throws MmsException
{
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
Recipients recipients = getSyncMessageDestination(message);
Recipient recipient = getSyncMessageDestination(message);
String body = message.getMessage().getBody().or("");
long expiresInMillis = message.getMessage().getExpiresInSeconds() * 1000;
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipients, body, expiresInMillis, -1);
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipient, body, expiresInMillis, -1);
if (recipients.getExpireMessages() != message.getMessage().getExpiresInSeconds()) {
if (recipient.getExpireMessages() != message.getMessage().getExpiresInSeconds()) {
handleSynchronizeSentExpirationUpdate(masterSecret, message, Optional.<Long>absent());
}
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
long messageId = database.insertMessageOutbox(masterSecret, threadId, outgoingTextMessage, false, message.getTimestamp(), null);
database.markAsSent(messageId, true);
@ -810,19 +805,19 @@ public class PushDecryptJob extends ContextJob {
return database.insertMessageInbox(textMessage);
}
private Recipients getSyncMessageDestination(SentTranscriptMessage message) {
private Recipient getSyncMessageDestination(SentTranscriptMessage message) {
if (message.getMessage().getGroupInfo().isPresent()) {
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId()))}, false);
return RecipientFactory.getRecipientFor(context, Address.fromExternal(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false)), false);
} else {
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, message.getDestination().get())}, false);
return RecipientFactory.getRecipientFor(context, Address.fromExternal(context, message.getDestination().get()), false);
}
}
private Recipients getMessageDestination(SignalServiceEnvelope envelope, SignalServiceDataMessage message) {
private Recipient getMessageDestination(SignalServiceEnvelope envelope, SignalServiceDataMessage message) {
if (message.getGroupInfo().isPresent()) {
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId()))}, false);
return RecipientFactory.getRecipientFor(context, Address.fromExternal(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false)), false);
} else {
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, envelope.getSource())}, false);
return RecipientFactory.getRecipientFor(context, Address.fromExternal(context, envelope.getSource()), false);
}
}
}

View File

@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.whispersystems.jobqueue.JobParameters;
@ -138,8 +137,8 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
EncapsulatedExceptions, UndeliverableMessageException
{
SignalServiceMessageSender messageSender = messageSenderFactory.create();
byte[] groupId = GroupUtil.getDecodedId(message.getRecipients().getPrimaryRecipient().getAddress().toGroupString());
Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
String groupId = message.getRecipient().getAddress().toGroupString();
List<Recipient> recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments);
@ -154,12 +153,12 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
GroupContext groupContext = groupMessage.getGroupContext();
SignalServiceAttachment avatar = attachmentStreams.isEmpty() ? null : attachmentStreams.get(0);
SignalServiceGroup.Type type = groupMessage.isGroupQuit() ? SignalServiceGroup.Type.QUIT : SignalServiceGroup.Type.UPDATE;
SignalServiceGroup group = new SignalServiceGroup(type, groupId, groupContext.getName(), groupContext.getMembersList(), avatar);
SignalServiceGroup group = new SignalServiceGroup(type, GroupUtil.getDecodedId(groupId), groupContext.getName(), groupContext.getMembersList(), avatar);
SignalServiceDataMessage groupDataMessage = new SignalServiceDataMessage(message.getSentTimeMillis(), group, null, null);
messageSender.sendMessage(addresses, groupDataMessage);
} else {
SignalServiceGroup group = new SignalServiceGroup(groupId);
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedId(groupId));
SignalServiceDataMessage groupMessage = new SignalServiceDataMessage(message.getSentTimeMillis(), group,
attachmentStreams, message.getBody(), false,
(int)(message.getExpiresIn() / 1000),
@ -175,10 +174,10 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
return addresses;
}
private List<SignalServiceAddress> getPushAddresses(Recipients recipients) {
private List<SignalServiceAddress> getPushAddresses(List<Recipient> recipients) {
List<SignalServiceAddress> addresses = new LinkedList<>();
for (Recipient recipient : recipients.getRecipientsList()) {
for (Recipient recipient : recipients) {
addresses.add(getPushAddress(recipient.getAddress()));
}

View File

@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
@ -59,7 +60,7 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType {
public void onRun() throws IOException, UntrustedIdentityException {
SignalServiceMessageSender messageSender = messageSenderFactory.create();
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
GroupRecord record = groupDatabase.getGroup(groupId);
GroupRecord record = groupDatabase.getGroup(GroupUtil.getEncodedId(groupId, false));
SignalServiceAttachment avatar = null;
if (record == null) {

View File

@ -102,14 +102,14 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
throws RetryLaterException, InsecureFallbackApprovalException, UntrustedIdentityException,
UndeliverableMessageException
{
if (message.getRecipients() == null || message.getRecipients().getPrimaryRecipient() == null) {
if (message.getRecipient() == null) {
throw new UndeliverableMessageException("No destination address.");
}
SignalServiceMessageSender messageSender = messageSenderFactory.create();
try {
SignalServiceAddress address = getPushAddress(message.getRecipients().getPrimaryRecipient().getAddress());
SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress());
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments);

View File

@ -9,8 +9,8 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.database.NotInDirectoryException;
import org.thoughtcrime.securesms.database.TextSecureDirectory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.whispersystems.jobqueue.JobManager;
import org.whispersystems.jobqueue.JobParameters;
@ -35,8 +35,8 @@ public abstract class PushReceivedJob extends ContextJob {
directory.setNumber(contactTokenDetails, true);
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {source}, false);
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, KeyCachingService.getMasterSecret(context), recipients));
Recipient recipient = RecipientFactory.getRecipientFor(context, source, false);
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, KeyCachingService.getMasterSecret(context), recipient));
}
if (envelope.isReceipt()) {
@ -49,7 +49,7 @@ public abstract class PushReceivedJob extends ContextJob {
}
private void handleMessage(SignalServiceEnvelope envelope, Address source, boolean sendExplicitReceipt) {
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {source}, false);
Recipient recipients = RecipientFactory.getRecipientFor(context, source, false);
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
if (!recipients.isBlocked()) {

View File

@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
@ -95,11 +95,11 @@ public abstract class PushSendJob extends SendJob {
}
protected void notifyMediaMessageDeliveryFailed(Context context, long messageId) {
long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId);
long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
if (threadId != -1 && recipients != null) {
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
if (threadId != -1 && recipient != null) {
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
}
}

View File

@ -12,7 +12,7 @@ import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
import org.thoughtcrime.securesms.transport.RetryLaterException;
@ -66,7 +66,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
} catch (InsecureFallbackApprovalException e) {
Log.w(TAG, e);
database.markAsPendingInsecureSmsFallback(record.getId());
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipients(), record.getThreadId());
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context));
} catch (UntrustedIdentityException e) {
Log.w(TAG, e);
@ -87,11 +87,11 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
public void onCanceled() {
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId);
Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId);
long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId);
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
if (threadId != -1 && recipients != null) {
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
if (threadId != -1 && recipient != null) {
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
}
}

View File

@ -9,10 +9,8 @@ import android.util.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.MessageRetrievalService;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.libsignal.IdentityKey;
@ -24,6 +22,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceProfile;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.io.IOException;
import java.util.List;
import javax.inject.Inject;
@ -33,14 +32,14 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
@Inject transient SignalServiceMessageReceiver receiver;
private final Recipients recipients;
private final Recipient recipient;
public RetrieveProfileJob(Context context, Recipients recipients) {
public RetrieveProfileJob(Context context, Recipient recipient) {
super(context, JobParameters.newBuilder()
.withRetryCount(3)
.create());
this.recipients = recipients;
this.recipient = recipient;
}
@Override
@ -49,10 +48,8 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
@Override
public void onRun() throws IOException, InvalidKeyException {
try {
for (Recipient recipient : recipients) {
if (recipient.isGroupRecipient()) handleGroupRecipient(recipient);
else handleIndividualRecipient(recipient);
}
if (recipient.isGroupRecipient()) handleGroupRecipient(recipient);
else handleIndividualRecipient(recipient);
} catch (InvalidNumberException e) {
Log.w(TAG, e);
}
@ -93,8 +90,7 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
private void handleGroupRecipient(Recipient group)
throws IOException, InvalidKeyException, InvalidNumberException
{
byte[] groupId = GroupUtil.getDecodedId(group.getAddress().toGroupString());
Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
List<Recipient> recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(group.getAddress().toGroupString(), false);
for (Recipient recipient : recipients) {
handleIndividualRecipient(recipient);

View File

@ -9,13 +9,12 @@ import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.whispersystems.jobqueue.JobParameters;
@ -86,8 +85,8 @@ public class SmsReceiveJob extends ContextJob {
private boolean isBlocked(IncomingTextMessage message) {
if (message.getSender() != null) {
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getSender()}, false);
return recipients.isBlocked();
Recipient recipient = RecipientFactory.getRecipientFor(context, message.getSender(), false);
return recipient.isBlocked();
}
return false;

View File

@ -13,13 +13,12 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.jobs.requirements.NetworkOrServiceRequirement;
import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirement;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.SmsDeliveryListener;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.util.NumberUtil;
@ -54,7 +53,7 @@ public class SmsSendJob extends SendJob {
} catch (UndeliverableMessageException ude) {
Log.w(TAG, ude);
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(record.getId());
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipients(), record.getThreadId());
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
}
}
@ -66,11 +65,11 @@ public class SmsSendJob extends SendJob {
@Override
public void onCanceled() {
Log.w(TAG, "onCanceled()");
long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId);
Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId);
long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId);
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
}
private void deliver(SmsMessageRecord message)

View File

@ -86,7 +86,7 @@ public class SmsSentJob extends MasterSecretJob {
break;
default:
database.markAsSentFailed(messageId);
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipients(), record.getThreadId());
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
}
} catch (NoSuchMessageException e) {
Log.w(TAG, e);

View File

@ -1,12 +1,9 @@
package org.thoughtcrime.securesms.mms;
import android.content.Context;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.PointerAttachment;
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.MmsAddresses;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
@ -18,46 +15,39 @@ import java.util.List;
public class IncomingMediaMessage {
private final Address from;
private final String body;
private final Address groupId;
private final String body;
private final boolean push;
private final long sentTimeMillis;
private final int subscriptionId;
private final long expiresIn;
private final boolean expirationUpdate;
private final List<Address> to = new LinkedList<>();
private final List<Address> cc = new LinkedList<>();
private final List<Attachment> attachments = new LinkedList<>();
public IncomingMediaMessage(Context context, String from, List<String> to, List<String> cc,
String body, long sentTimeMillis,
List<Attachment> attachments, int subscriptionId,
long expiresIn, boolean expirationUpdate)
public IncomingMediaMessage(Address from,
Optional<Address> groupId,
String body,
long sentTimeMillis,
List<Attachment> attachments,
int subscriptionId,
long expiresIn,
boolean expirationUpdate)
{
this.from = Address.fromExternal(context, from);
this.from = from;
this.groupId = groupId.orNull();
this.sentTimeMillis = sentTimeMillis;
this.body = body;
this.groupId = null;
this.push = false;
this.subscriptionId = subscriptionId;
this.expiresIn = expiresIn;
this.expirationUpdate = expirationUpdate;
for (String destination : to) {
this.to.add(Address.fromExternal(context, destination));
}
for (String destination : cc) {
this.cc.add(Address.fromExternal(context, destination));
}
this.attachments.addAll(attachments);
}
public IncomingMediaMessage(MasterSecretUnion masterSecret,
Address from,
Address to,
long sentTimeMillis,
int subscriptionId,
long expiresIn,
@ -75,10 +65,9 @@ public class IncomingMediaMessage {
this.expiresIn = expiresIn;
this.expirationUpdate = expirationUpdate;
if (group.isPresent()) this.groupId = Address.fromSerialized(GroupUtil.getEncodedId(group.get().getGroupId()));
if (group.isPresent()) this.groupId = Address.fromSerialized(GroupUtil.getEncodedId(group.get().getGroupId(), false));
else this.groupId = null;
this.to.add(to);
this.attachments.addAll(PointerAttachment.forPointers(masterSecret, attachments));
}
@ -90,14 +79,14 @@ public class IncomingMediaMessage {
return body;
}
public MmsAddresses getAddresses() {
return new MmsAddresses(from, to, cc, new LinkedList<Address>());
}
public List<Attachment> getAttachments() {
return attachments;
}
public Address getFrom() {
return from;
}
public Address getGroupId() {
return groupId;
}
@ -119,6 +108,6 @@ public class IncomingMediaMessage {
}
public boolean isGroupMessage() {
return groupId != null || to.size() > 1 || cc.size() > 0;
return groupId != null;
}
}

View File

@ -2,14 +2,14 @@ package org.thoughtcrime.securesms.mms;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.LinkedList;
public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage {
public OutgoingExpirationUpdateMessage(Recipients recipients, long sentTimeMillis, long expiresIn) {
super(recipients, "", new LinkedList<Attachment>(), sentTimeMillis,
public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) {
super(recipient, "", new LinkedList<Attachment>(), sentTimeMillis,
ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn);
}

View File

@ -5,7 +5,7 @@ import android.support.annotation.Nullable;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
@ -17,26 +17,26 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
private final GroupContext group;
public OutgoingGroupMediaMessage(@NonNull Recipients recipients,
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
@NonNull String encodedGroupContext,
@NonNull List<Attachment> avatar,
long sentTimeMillis,
long expiresIn)
throws IOException
{
super(recipients, encodedGroupContext, avatar, sentTimeMillis,
super(recipient, encodedGroupContext, avatar, sentTimeMillis,
ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn);
this.group = GroupContext.parseFrom(Base64.decode(encodedGroupContext));
}
public OutgoingGroupMediaMessage(@NonNull Recipients recipients,
public OutgoingGroupMediaMessage(@NonNull Recipient recipient,
@NonNull GroupContext group,
@Nullable final Attachment avatar,
long sentTimeMillis,
long expireIn)
{
super(recipients, Base64.encodeBytes(group.toByteArray()),
super(recipient, Base64.encodeBytes(group.toByteArray()),
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
System.currentTimeMillis(),
ThreadDatabase.DistributionTypes.CONVERSATION, expireIn);

View File

@ -3,13 +3,13 @@ package org.thoughtcrime.securesms.mms;
import android.text.TextUtils;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.List;
public class OutgoingMediaMessage {
private final Recipients recipients;
private final Recipient recipient;
protected final String body;
protected final List<Attachment> attachments;
private final long sentTimeMillis;
@ -17,12 +17,12 @@ public class OutgoingMediaMessage {
private final int subscriptionId;
private final long expiresIn;
public OutgoingMediaMessage(Recipients recipients, String message,
public OutgoingMediaMessage(Recipient recipient, String message,
List<Attachment> attachments, long sentTimeMillis,
int subscriptionId, long expiresIn,
int distributionType)
{
this.recipients = recipients;
this.recipient = recipient;
this.body = message;
this.sentTimeMillis = sentTimeMillis;
this.distributionType = distributionType;
@ -31,9 +31,9 @@ public class OutgoingMediaMessage {
this.expiresIn = expiresIn;
}
public OutgoingMediaMessage(Recipients recipients, SlideDeck slideDeck, String message, long sentTimeMillis, int subscriptionId, long expiresIn, int distributionType)
public OutgoingMediaMessage(Recipient recipient, SlideDeck slideDeck, String message, long sentTimeMillis, int subscriptionId, long expiresIn, int distributionType)
{
this(recipients,
this(recipient,
buildMessage(slideDeck, message),
slideDeck.asAttachments(),
sentTimeMillis, subscriptionId,
@ -41,7 +41,7 @@ public class OutgoingMediaMessage {
}
public OutgoingMediaMessage(OutgoingMediaMessage that) {
this.recipients = that.getRecipients();
this.recipient = that.getRecipient();
this.body = that.body;
this.distributionType = that.distributionType;
this.attachments = that.attachments;
@ -50,8 +50,8 @@ public class OutgoingMediaMessage {
this.expiresIn = that.expiresIn;
}
public Recipients getRecipients() {
return recipients;
public Recipient getRecipient() {
return recipient;
}
public String getBody() {

View File

@ -1,19 +1,19 @@
package org.thoughtcrime.securesms.mms;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.List;
public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
public OutgoingSecureMediaMessage(Recipients recipients, String body,
public OutgoingSecureMediaMessage(Recipient recipient, String body,
List<Attachment> attachments,
long sentTimeMillis,
int distributionType,
long expiresIn)
{
super(recipients, body, attachments, sentTimeMillis, -1, expiresIn, distributionType);
super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, distributionType);
}
public OutgoingSecureMediaMessage(OutgoingMediaMessage base) {

View File

@ -31,8 +31,8 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.whispersystems.libsignal.logging.Log;
@ -48,7 +48,7 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
public static final String TAG = AndroidAutoReplyReceiver.class.getSimpleName();
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.ANDROID_AUTO_REPLY";
public static final String ADDRESSES_EXTRA = "car_addresses";
public static final String ADDRESS_EXTRA = "car_address";
public static final String VOICE_REPLY_KEY = "car_voice_reply_key";
public static final String THREAD_ID_EXTRA = "car_reply_thread_id";
@ -62,10 +62,10 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
if (remoteInput == null) return;
final Address[] addresses = Address.fromParcelable(intent.getParcelableArrayExtra(ADDRESSES_EXTRA));
final Address address = intent.getParcelableExtra(ADDRESS_EXTRA);
final long threadId = intent.getLongExtra(THREAD_ID_EXTRA, -1);
final CharSequence responseText = getMessageText(intent);
final Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses, false);
final Recipient recipient = RecipientFactory.getRecipientFor(context, address, false);
if (responseText != null) {
new AsyncTask<Void, Void, Void>() {
@ -74,17 +74,17 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
long replyThreadId;
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(addresses);
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(address);
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
if (recipients.isGroupRecipient()) {
if (recipient.isGroupRecipient()) {
Log.w("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message");
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
replyThreadId = MessageSender.send(context, masterSecret, reply, threadId, false, null);
} else {
Log.w("AndroidAutoReplyReceiver", "Sending regular message ");
OutgoingTextMessage reply = new OutgoingTextMessage(recipients, responseText.toString(), expiresIn, subscriptionId);
OutgoingTextMessage reply = new OutgoingTextMessage(recipient, responseText.toString(), expiresIn, subscriptionId);
replyThreadId = MessageSender.send(context, masterSecret, reply, threadId, false, null);
}

View File

@ -49,7 +49,6 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.MessageRetrievalService;
import org.thoughtcrime.securesms.util.ServiceUtil;
@ -102,12 +101,12 @@ public class MessageNotifier {
lastDesktopActivityTimestamp = timestamp;
}
public static void notifyMessageDeliveryFailed(Context context, Recipients recipients, long threadId) {
public static void notifyMessageDeliveryFailed(Context context, Recipient recipient, long threadId) {
if (visibleThread == threadId) {
sendInThreadNotification(context, recipients);
sendInThreadNotification(context, recipient);
} else {
Intent intent = new Intent(context, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.setData((Uri.parse("custom://" + System.currentTimeMillis())));
@ -213,8 +212,8 @@ public class MessageNotifier {
boolean isVisible = visibleThread == threadId;
ThreadDatabase threads = DatabaseFactory.getThreadDatabase(context);
Recipients recipients = DatabaseFactory.getThreadDatabase(context)
.getRecipientsForThreadId(threadId);
Recipient recipients = DatabaseFactory.getThreadDatabase(context)
.getRecipientForThreadId(threadId);
if (isVisible) {
List<MarkedMessageInfo> messageIds = threads.setRead(threadId, false);
@ -228,7 +227,7 @@ public class MessageNotifier {
}
if (isVisible) {
sendInThreadNotification(context, threads.getRecipientsForThreadId(threadId));
sendInThreadNotification(context, threads.getRecipientForThreadId(threadId));
} else {
updateNotification(context, masterSecret, signal, 0);
}
@ -299,13 +298,13 @@ public class MessageNotifier {
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, masterSecret, TextSecurePreferences.getNotificationPrivacy(context));
List<NotificationItem> notifications = notificationState.getNotifications();
Recipients recipients = notifications.get(0).getRecipients();
Recipient recipient = notifications.get(0).getRecipient();
int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0));
builder.setThread(notifications.get(0).getRecipients());
builder.setThread(notifications.get(0).getRecipient());
builder.setMessageCount(notificationState.getMessageCount());
builder.setPrimaryMessageBody(recipients, notifications.get(0).getIndividualRecipient(),
builder.setPrimaryMessageBody(recipient, notifications.get(0).getIndividualRecipient(),
notifications.get(0).getText(), notifications.get(0).getSlideDeck());
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
builder.setGroup(NOTIFICATION_GROUP);
@ -316,17 +315,17 @@ public class MessageNotifier {
builder.addActions(masterSecret,
notificationState.getMarkAsReadIntent(context, notificationId),
notificationState.getQuickReplyIntent(context, notifications.get(0).getRecipients()),
notificationState.getRemoteReplyIntent(context, notifications.get(0).getRecipients()));
notificationState.getQuickReplyIntent(context, notifications.get(0).getRecipient()),
notificationState.getRemoteReplyIntent(context, notifications.get(0).getRecipient()));
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, notifications.get(0).getRecipients()),
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, notifications.get(0).getRecipient()),
notificationState.getAndroidAutoHeardIntent(context, notificationId), notifications.get(0).getTimestamp());
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
while(iterator.hasPrevious()) {
NotificationItem item = iterator.previous();
builder.addMessageBody(item.getRecipients(), item.getIndividualRecipient(), item.getText());
builder.addMessageBody(item.getRecipient(), item.getIndividualRecipient(), item.getText());
}
if (signal) {
@ -375,14 +374,14 @@ public class MessageNotifier {
NotificationManagerCompat.from(context).notify(SUMMARY_NOTIFICATION_ID, builder.build());
}
private static void sendInThreadNotification(Context context, Recipients recipients) {
private static void sendInThreadNotification(Context context, Recipient recipient) {
if (!TextSecurePreferences.isInThreadNotifications(context) ||
ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
{
return;
}
Uri uri = recipients != null ? recipients.getRingtone() : null;
Uri uri = recipient != null ? recipient.getRingtone() : null;
if (uri == null) {
String ringtone = TextSecurePreferences.getNotificationRingtone(context);
@ -435,19 +434,19 @@ public class MessageNotifier {
else reader = DatabaseFactory.getMmsSmsDatabase(context).readerFor(cursor, masterSecret);
while ((record = reader.getNext()) != null) {
long id = record.getId();
boolean mms = record.isMms() || record.isMmsNotification();
Recipient recipient = record.getIndividualRecipient();
Recipients recipients = record.getRecipients();
long threadId = record.getThreadId();
CharSequence body = record.getDisplayBody();
Recipients threadRecipients = null;
SlideDeck slideDeck = null;
long timestamp = record.getTimestamp();
long id = record.getId();
boolean mms = record.isMms() || record.isMmsNotification();
Recipient recipient = record.getIndividualRecipient();
Recipient conversationRecipient = record.getRecipient();
long threadId = record.getThreadId();
CharSequence body = record.getDisplayBody();
Recipient threadRecipients = null;
SlideDeck slideDeck = null;
long timestamp = record.getTimestamp();
if (threadId != -1) {
threadRecipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId);
threadRecipients = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
}
if (SmsDatabase.Types.isDecryptInProgressType(record.getType()) || !record.getBody().isPlaintext()) {
@ -463,7 +462,7 @@ public class MessageNotifier {
}
if (threadRecipients == null || !threadRecipients.isMuted()) {
notificationState.addNotification(new NotificationItem(id, mms, recipient, recipients, threadRecipients, threadId, body, timestamp, slideDeck));
notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck));
}
}

View File

@ -11,15 +11,14 @@ import android.support.v4.app.TaskStackBuilder;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
public class NotificationItem {
private final long id;
private final boolean mms;
private final @NonNull Recipients recipients;
private final @NonNull Recipient conversationRecipient;
private final @NonNull Recipient individualRecipient;
private final @Nullable Recipients threadRecipients;
private final @Nullable Recipient threadRecipient;
private final long threadId;
private final @Nullable CharSequence text;
private final long timestamp;
@ -27,24 +26,24 @@ public class NotificationItem {
public NotificationItem(long id, boolean mms,
@NonNull Recipient individualRecipient,
@NonNull Recipients recipients,
@Nullable Recipients threadRecipients,
@NonNull Recipient conversationRecipient,
@Nullable Recipient threadRecipient,
long threadId, @Nullable CharSequence text, long timestamp,
@Nullable SlideDeck slideDeck)
{
this.id = id;
this.mms = mms;
this.individualRecipient = individualRecipient;
this.recipients = recipients;
this.threadRecipients = threadRecipients;
this.text = text;
this.threadId = threadId;
this.timestamp = timestamp;
this.slideDeck = slideDeck;
this.id = id;
this.mms = mms;
this.individualRecipient = individualRecipient;
this.conversationRecipient = conversationRecipient;
this.threadRecipient = threadRecipient;
this.text = text;
this.threadId = threadId;
this.timestamp = timestamp;
this.slideDeck = slideDeck;
}
public @NonNull Recipients getRecipients() {
return threadRecipients == null ? recipients : threadRecipients;
public @NonNull Recipient getRecipient() {
return threadRecipient == null ? conversationRecipient : threadRecipient;
}
public @NonNull Recipient getIndividualRecipient() {
@ -69,8 +68,8 @@ public class NotificationItem {
public PendingIntent getPendingIntent(Context context) {
Intent intent = new Intent(context, ConversationActivity.class);
Recipients notifyRecipients = threadRecipients != null ? threadRecipients : recipients;
if (notifyRecipients != null) intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, notifyRecipients.getAddresses());
Recipient notifyRecipients = threadRecipient != null ? threadRecipient : conversationRecipient;
if (notifyRecipients != null) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, notifyRecipients.getAddress());
intent.putExtra("thread_id", threadId);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));

View File

@ -11,7 +11,7 @@ import android.util.Log;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.ConversationPopupActivity;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@ -45,10 +45,10 @@ public class NotificationState {
public @Nullable Uri getRingtone() {
if (!notifications.isEmpty()) {
Recipients recipients = notifications.getFirst().getRecipients();
Recipient recipient = notifications.getFirst().getRecipient();
if (recipients != null) {
return recipients.getRingtone();
if (recipient != null) {
return recipient.getRingtone();
}
}
@ -57,10 +57,10 @@ public class NotificationState {
public VibrateState getVibrate() {
if (!notifications.isEmpty()) {
Recipients recipients = notifications.getFirst().getRecipients();
Recipient recipient = notifications.getFirst().getRecipient();
if (recipients != null) {
return recipients.getVibrate();
if (recipient != null) {
return recipient.getVibrate();
}
}
@ -115,26 +115,26 @@ public class NotificationState {
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public PendingIntent getRemoteReplyIntent(Context context, Recipients recipients) {
public PendingIntent getRemoteReplyIntent(Context context, Recipient recipient) {
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications!");
Intent intent = new Intent(RemoteReplyReceiver.REPLY_ACTION);
intent.setClass(context, RemoteReplyReceiver.class);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
intent.putExtra(RemoteReplyReceiver.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(RemoteReplyReceiver.ADDRESS_EXTRA, recipient.getAddress());
intent.setPackage(context.getPackageName());
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public PendingIntent getAndroidAutoReplyIntent(Context context, Recipients recipients) {
public PendingIntent getAndroidAutoReplyIntent(Context context, Recipient recipient) {
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications!");
Intent intent = new Intent(AndroidAutoReplyReceiver.REPLY_ACTION);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setClass(context, AndroidAutoReplyReceiver.class);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
intent.putExtra(AndroidAutoReplyReceiver.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(AndroidAutoReplyReceiver.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(AndroidAutoReplyReceiver.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
intent.setPackage(context.getPackageName());
@ -160,11 +160,11 @@ public class NotificationState {
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public PendingIntent getQuickReplyIntent(Context context, Recipients recipients) {
public PendingIntent getQuickReplyIntent(Context context, Recipient recipient) {
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications! " + threads.size());
Intent intent = new Intent(context, ConversationPopupActivity.class);
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));

View File

@ -31,8 +31,8 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.whispersystems.libsignal.util.guava.Optional;
@ -45,9 +45,9 @@ import java.util.List;
*/
public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
public static final String TAG = RemoteReplyReceiver.class.getSimpleName();
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY";
public static final String ADDRESSES_EXTRA = "addresses";
public static final String TAG = RemoteReplyReceiver.class.getSimpleName();
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY";
public static final String ADDRESS_EXTRA = "address";
@Override
protected void onReceive(final Context context, Intent intent,
@ -59,7 +59,7 @@ public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
if (remoteInput == null) return;
final Address[] addresses = Address.fromParcelable(intent.getParcelableArrayExtra(ADDRESSES_EXTRA));
final Address address = intent.getParcelableExtra(ADDRESS_EXTRA);
final CharSequence responseText = remoteInput.getCharSequence(MessageNotifier.EXTRA_REMOTE_REPLY);
if (masterSecret != null && responseText != null) {
@ -68,16 +68,16 @@ public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
protected Void doInBackground(Void... params) {
long threadId;
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(addresses);
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(address);
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
Recipient recipient = RecipientFactory.getRecipientFor(context, address, false);
Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses, false);
if (recipients.isGroupRecipient()) {
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
if (recipient.isGroupRecipient()) {
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
threadId = MessageSender.send(context, masterSecret, reply, -1, false, null);
} else {
OutgoingTextMessage reply = new OutgoingTextMessage(recipients, responseText.toString(), expiresIn, subscriptionId);
OutgoingTextMessage reply = new OutgoingTextMessage(recipient, responseText.toString(), expiresIn, subscriptionId);
threadId = MessageSender.send(context, masterSecret, reply, -1, false, null);
}

View File

@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.preferences.NotificationPrivacyPreference;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@ -57,16 +56,16 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
setCategory(NotificationCompat.CATEGORY_MESSAGE);
}
public void setThread(@NonNull Recipients recipients) {
public void setThread(@NonNull Recipient recipient) {
if (privacy.isDisplayContact()) {
setContentTitle(recipients.toShortString());
setContentTitle(recipient.toShortString());
if (recipients.isSingleRecipient() && recipients.getPrimaryRecipient().getContactUri() != null) {
addPerson(recipients.getPrimaryRecipient().getContactUri().toString());
if (recipient.getContactUri() != null) {
addPerson(recipient.getContactUri().toString());
}
setLargeIcon(recipients.getContactPhoto()
.asDrawable(context, recipients.getColor()
setLargeIcon(recipient.getContactPhoto()
.asDrawable(context, recipient.getColor()
.toConversationColor(context)));
} else {
setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal));
@ -80,14 +79,14 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
setNumber(messageCount);
}
public void setPrimaryMessageBody(@NonNull Recipients threadRecipients,
public void setPrimaryMessageBody(@NonNull Recipient threadRecipients,
@NonNull Recipient individualRecipient,
@NonNull CharSequence message,
@Nullable SlideDeck slideDeck)
{
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
if (privacy.isDisplayContact() && (threadRecipients.isGroupRecipient() || !threadRecipients.isSingleRecipient())) {
if (privacy.isDisplayContact() && threadRecipients.isGroupRecipient()) {
stringBuilder.append(Util.getBoldedString(individualRecipient.toShortString() + ": "));
}
@ -162,13 +161,13 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
}
}
public void addMessageBody(@NonNull Recipients threadRecipients,
public void addMessageBody(@NonNull Recipient threadRecipient,
@NonNull Recipient individualRecipient,
@Nullable CharSequence messageBody)
{
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
if (privacy.isDisplayContact() && (threadRecipients.isGroupRecipient() || !threadRecipients.isSingleRecipient())) {
if (privacy.isDisplayContact() && threadRecipient.isGroupRecipient()) {
stringBuilder.append(Util.getBoldedString(individualRecipient.toShortString() + ": "));
}

View File

@ -7,14 +7,15 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.Util;
public class BlockedContactListItem extends RelativeLayout implements Recipients.RecipientsModifiedListener {
public class BlockedContactListItem extends RelativeLayout implements RecipientModifiedListener {
private AvatarImageView contactPhotoImage;
private TextView nameView;
private Recipients recipients;
private Recipient recipient;
public BlockedContactListItem(Context context) {
super(context);
@ -35,15 +36,15 @@ public class BlockedContactListItem extends RelativeLayout implements Recipients
this.nameView = (TextView) findViewById(R.id.name);
}
public void set(Recipients recipients) {
this.recipients = recipients;
public void set(Recipient recipients) {
this.recipient = recipients;
onModified(recipients);
recipients.addListener(this);
}
@Override
public void onModified(final Recipients recipients) {
public void onModified(final Recipient recipients) {
final AvatarImageView contactPhotoImage = this.contactPhotoImage;
final TextView nameView = this.nameView;
@ -56,7 +57,7 @@ public class BlockedContactListItem extends RelativeLayout implements Recipients
});
}
public Recipients getRecipients() {
return recipients;
public Recipient getRecipient() {
return recipient;
}
}

View File

@ -1,27 +1,14 @@
package org.thoughtcrime.securesms.providers;
import android.content.ContentUris;
import android.content.Context;
import android.content.UriMatcher;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.util.Log;
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.EncryptingPartOutputStream;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.Util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

View File

@ -26,31 +26,41 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.Util;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException;
public class Recipient {
public class Recipient implements RecipientModifiedListener {
private final static String TAG = Recipient.class.getSimpleName();
private final Set<RecipientModifiedListener> listeners = Collections.newSetFromMap(new WeakHashMap<RecipientModifiedListener, Boolean>());
private final @NonNull Address address;
private final @NonNull List<Recipient> participants = new LinkedList<>();
private @Nullable String name;
private @Nullable String customLabel;
private boolean stale;
private boolean resolving;
private boolean stale;
private boolean resolving;
private ContactPhoto contactPhoto;
private Uri contactUri;
private Uri ringtone = null;
private long mutedUntil = 0;
private boolean blocked = false;
private VibrateState vibrate = VibrateState.DEFAULT;
private int expireMessages = 0;
@Nullable private MaterialColor color;
@ -64,11 +74,16 @@ public class Recipient {
this.resolving = true;
if (stale != null) {
this.name = stale.name;
this.contactUri = stale.contactUri;
this.contactPhoto = stale.contactPhoto;
this.color = stale.color;
this.customLabel = stale.customLabel;
this.name = stale.name;
this.contactUri = stale.contactUri;
this.contactPhoto = stale.contactPhoto;
this.color = stale.color;
this.customLabel = stale.customLabel;
this.ringtone = stale.ringtone;
this.mutedUntil = stale.mutedUntil;
this.blocked = stale.blocked;
this.vibrate = stale.vibrate;
this.expireMessages = stale.expireMessages;
}
future.addListener(new FutureTaskListener<RecipientDetails>() {
@ -76,12 +91,22 @@ public class Recipient {
public void onSuccess(RecipientDetails result) {
if (result != null) {
synchronized (Recipient.this) {
Recipient.this.name = result.name;
Recipient.this.contactUri = result.contactUri;
Recipient.this.contactPhoto = result.avatar;
Recipient.this.color = result.color;
Recipient.this.customLabel = result.customLabel;
Recipient.this.resolving = false;
Recipient.this.name = result.name;
Recipient.this.contactUri = result.contactUri;
Recipient.this.contactPhoto = result.avatar;
Recipient.this.color = result.color;
Recipient.this.customLabel = result.customLabel;
Recipient.this.ringtone = result.ringtone;
Recipient.this.mutedUntil = result.mutedUntil;
Recipient.this.blocked = result.blocked;
Recipient.this.vibrate = result.vibrateState;
Recipient.this.expireMessages = result.expireMessages;
Recipient.this.participants.addAll(result.participants);
Recipient.this.resolving = false;
if (!listeners.isEmpty()) {
for (Recipient recipient : participants) recipient.addListener(Recipient.this);
}
}
notifyListeners();
@ -95,14 +120,20 @@ public class Recipient {
});
}
Recipient(Address address, RecipientDetails details) {
this.address = address;
this.contactUri = details.contactUri;
this.name = details.name;
this.contactPhoto = details.avatar;
this.color = details.color;
Recipient(@NonNull Address address, @NonNull RecipientDetails details) {
this.address = address;
this.contactUri = details.contactUri;
this.name = details.name;
this.contactPhoto = details.avatar;
this.color = details.color;
this.customLabel = details.customLabel;
this.ringtone = details.ringtone;
this.mutedUntil = details.mutedUntil;
this.blocked = details.blocked;
this.vibrate = details.vibrateState;
this.expireMessages = details.expireMessages;
this.participants.addAll(details.participants);
this.resolving = false;
this.customLabel = details.customLabel;
}
public synchronized @Nullable Uri getContactUri() {
@ -110,13 +141,24 @@ public class Recipient {
}
public synchronized @Nullable String getName() {
if (this.name == null && isMmsGroupRecipient()) {
List<String> names = new LinkedList<>();
for (Recipient recipient : participants) {
names.add(recipient.toShortString());
}
return Util.join(names, ", ");
}
return this.name;
}
public synchronized @NonNull MaterialColor getColor() {
if (color != null) return color;
else if (name != null) return ContactColors.generateFor(name);
else return ContactColors.UNKNOWN_COLOR;
if (isGroupRecipient()) return MaterialColor.GROUP;
else if (color != null) return color;
else if (name != null) return ContactColors.generateFor(name);
else return ContactColors.UNKNOWN_COLOR;
}
public void setColor(@NonNull MaterialColor color) {
@ -139,22 +181,101 @@ public class Recipient {
return address.isGroup();
}
public boolean isMmsGroupRecipient() {
return address.isMmsGroup();
}
public boolean isPushGroupRecipient() {
return address.isGroup() && !address.isMmsGroup();
}
public List<Recipient> getParticipants() {
return participants;
}
public synchronized void addListener(RecipientModifiedListener listener) {
if (listeners.isEmpty()) {
for (Recipient recipient : participants) recipient.addListener(this);
}
listeners.add(listener);
}
public synchronized void removeListener(RecipientModifiedListener listener) {
listeners.remove(listener);
if (listeners.isEmpty()) {
for (Recipient recipient : participants) recipient.removeListener(this);
}
}
public synchronized String toShortString() {
return (name == null ? address.serialize() : name);
return (getName() == null ? address.serialize() : getName());
}
public synchronized @NonNull ContactPhoto getContactPhoto() {
return contactPhoto;
}
public synchronized @Nullable Uri getRingtone() {
return ringtone;
}
public void setRingtone(Uri ringtone) {
synchronized (this) {
this.ringtone = ringtone;
}
notifyListeners();
}
public synchronized boolean isMuted() {
return System.currentTimeMillis() <= mutedUntil;
}
public void setMuted(long mutedUntil) {
synchronized (this) {
this.mutedUntil = mutedUntil;
}
notifyListeners();
}
public synchronized boolean isBlocked() {
return blocked;
}
public void setBlocked(boolean blocked) {
synchronized (this) {
this.blocked = blocked;
}
notifyListeners();
}
public synchronized VibrateState getVibrate() {
return vibrate;
}
public void setVibrate(VibrateState vibrate) {
synchronized (this) {
this.vibrate = vibrate;
}
notifyListeners();
}
public synchronized int getExpireMessages() {
return expireMessages;
}
public void setExpireMessages(int expireMessages) {
synchronized (this) {
this.expireMessages = expireMessages;
}
notifyListeners();
}
@Override
public boolean equals(Object o) {
@ -182,8 +303,9 @@ public class Recipient {
listener.onModified(this);
}
public interface RecipientModifiedListener {
public void onModified(Recipient recipient);
@Override
public void onModified(Recipient recipient) {
notifyListeners();
}
boolean isStale() {

View File

@ -22,37 +22,12 @@ import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.database.Address;
import java.util.Collection;
public class RecipientFactory {
public static final String RECIPIENT_CLEAR_ACTION = "org.thoughtcrime.securesms.database.RecipientFactory.CLEAR";
private static final RecipientProvider provider = new RecipientProvider();
public static @NonNull Recipients getRecipientsFor(Context context, Collection<Recipient> recipients, boolean asynchronous) {
Address[] addresses= new Address[recipients.size()];
int i = 0;
for (Recipient recipient : recipients) {
addresses[i++] = recipient.getAddress();
}
return provider.getRecipients(context, addresses, asynchronous);
}
public static Recipients getRecipientsFor(Context context, Recipient recipient, boolean asynchronous) {
Address[] addresses = new Address[1];
addresses[0] = recipient.getAddress();
return provider.getRecipients(context, addresses, asynchronous);
}
public static @NonNull Recipients getRecipientsFor(@NonNull Context context, @NonNull Address[] addresses, boolean asynchronous) {
if (addresses == null || addresses.length == 0) throw new AssertionError(addresses);
return provider.getRecipients(context, addresses, asynchronous);
}
public static @NonNull Recipient getRecipientFor(@NonNull Context context, @NonNull Address address, boolean asynchronous) {
if (address == null) throw new AssertionError(address);
return provider.getRecipient(context, address, asynchronous);

View File

@ -0,0 +1,6 @@
package org.thoughtcrime.securesms.recipients;
public interface RecipientModifiedListener {
public void onModified(Recipient recipient);
}

View File

@ -28,21 +28,18 @@ import android.util.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
import org.thoughtcrime.securesms.util.LRUCache;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -55,7 +52,6 @@ class RecipientProvider {
private static final String TAG = RecipientProvider.class.getSimpleName();
private static final RecipientCache recipientCache = new RecipientCache();
private static final RecipientsCache recipientsCache = new RecipientsCache();
private static final ExecutorService asyncRecipientResolver = Util.newSingleThreadedLifoExecutor();
private static final String[] CALLER_ID_PROJECTION = new String[] {
@ -69,7 +65,7 @@ class RecipientProvider {
private static final Map<String, RecipientDetails> STATIC_DETAILS = new HashMap<String, RecipientDetails>() {{
put("262966", new RecipientDetails("Amazon", null, null,
ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_amazon),
ContactColors.UNKNOWN_COLOR));
null, null));
}};
@NonNull Recipient getRecipient(Context context, Address address, boolean asynchronous) {
@ -81,35 +77,15 @@ class RecipientProvider {
if (asynchronous) {
cachedRecipient = new Recipient(address, cachedRecipient, getRecipientDetailsAsync(context, address));
} else {
cachedRecipient = new Recipient(address, getRecipientDetailsSync(context, address));
cachedRecipient = new Recipient(address, getRecipientDetailsSync(context, address, false));
}
recipientCache.set(address, cachedRecipient);
return cachedRecipient;
}
@NonNull Recipients getRecipients(Context context, Address[] recipientAddresses, boolean asynchronous) {
Recipients cachedRecipients = recipientsCache.get(new RecipientAddresses(recipientAddresses));
if (cachedRecipients != null && !cachedRecipients.isStale() && (asynchronous || !cachedRecipients.isResolving())) {
return cachedRecipients;
}
List<Recipient> recipientList = new LinkedList<>();
for (Address address : recipientAddresses) {
recipientList.add(getRecipient(context, address, asynchronous));
}
if (asynchronous) cachedRecipients = new Recipients(recipientList, cachedRecipients, getRecipientsPreferencesAsync(context, recipientAddresses));
else cachedRecipients = new Recipients(recipientList, getRecipientsPreferencesSync(context, recipientAddresses));
recipientsCache.set(new RecipientAddresses(recipientAddresses), cachedRecipients);
return cachedRecipients;
}
void clearCache() {
recipientCache.reset();
recipientsCache.reset();
}
private @NonNull ListenableFutureTask<RecipientDetails> getRecipientDetailsAsync(final Context context, final @NonNull Address address)
@ -117,7 +93,7 @@ class RecipientProvider {
Callable<RecipientDetails> task = new Callable<RecipientDetails>() {
@Override
public RecipientDetails call() throws Exception {
return getRecipientDetailsSync(context, address);
return getRecipientDetailsSync(context, address, true);
}
};
@ -126,14 +102,13 @@ class RecipientProvider {
return future;
}
private @NonNull RecipientDetails getRecipientDetailsSync(Context context, @NonNull Address address) {
if (address.isGroup()) return getGroupRecipientDetails(context, address);
private @NonNull RecipientDetails getRecipientDetailsSync(Context context, @NonNull Address address, boolean nestedAsynchronous) {
if (address.isGroup()) return getGroupRecipientDetails(context, address, nestedAsynchronous);
else return getIndividualRecipientDetails(context, address);
}
private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, @NonNull Address address) {
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(new Address[]{address});
MaterialColor color = preferences.isPresent() ? preferences.get().getColor() : null;
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(address);
if (address.isPhone() && !TextUtils.isEmpty(address.toPhoneString())) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address.toPhoneString()));
@ -149,7 +124,7 @@ class RecipientProvider {
Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""),
name);
return new RecipientDetails(cursor.getString(0), cursor.getString(4), contactUri, contactPhoto, color);
return new RecipientDetails(cursor.getString(0), cursor.getString(4), contactUri, contactPhoto, preferences.orNull(), null);
} else {
Log.w(TAG, "resultNumber is null");
}
@ -161,84 +136,61 @@ class RecipientProvider {
}
if (STATIC_DETAILS.containsKey(address.serialize())) return STATIC_DETAILS.get(address.serialize());
else return new RecipientDetails(null, null, null, ContactPhotoFactory.getDefaultContactPhoto(null), color);
else return new RecipientDetails(null, null, null, ContactPhotoFactory.getDefaultContactPhoto(null), preferences.orNull(), null);
}
private @NonNull RecipientDetails getGroupRecipientDetails(Context context, Address groupId) {
try {
GroupDatabase.GroupRecord record = DatabaseFactory.getGroupDatabase(context)
.getGroup(GroupUtil.getDecodedId(groupId.toGroupString()));
private @NonNull RecipientDetails getGroupRecipientDetails(Context context, Address groupId, boolean asynchronous) {
GroupDatabase.GroupRecord record = DatabaseFactory.getGroupDatabase(context).getGroup(groupId.toGroupString());
if (record != null) {
ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(record.getAvatar());
String title = record.getTitle();
if (record != null) {
ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(record.getAvatar());
String title = record.getTitle();
List<Address> memberAddresses = record.getMembers();
List<Recipient> members = new LinkedList<>();
if (title == null) {
title = context.getString(R.string.RecipientProvider_unnamed_group);;
}
return new RecipientDetails(title, null, null, contactPhoto, null);
for (Address memberAddress : memberAddresses) {
members.add(getRecipient(context, memberAddress, asynchronous));
}
return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
} catch (IOException e) {
Log.w("RecipientProvider", e);
return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
if (!groupId.isMmsGroup() && title == null) {
title = context.getString(R.string.RecipientProvider_unnamed_group);;
}
return new RecipientDetails(title, null, null, contactPhoto, null, members);
}
return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null, null);
}
private @Nullable RecipientsPreferences getRecipientsPreferencesSync(Context context, Address[] addresses) {
return DatabaseFactory.getRecipientPreferenceDatabase(context)
.getRecipientsPreferences(addresses)
.orNull();
}
private ListenableFutureTask<RecipientsPreferences> getRecipientsPreferencesAsync(final Context context, final Address[] addresses) {
ListenableFutureTask<RecipientsPreferences> task = new ListenableFutureTask<>(new Callable<RecipientsPreferences>() {
@Override
public RecipientsPreferences call() throws Exception {
return getRecipientsPreferencesSync(context, addresses);
}
});
asyncRecipientResolver.execute(task);
return task;
}
public static class RecipientDetails {
@Nullable public final String name;
@Nullable public final String customLabel;
@NonNull public final ContactPhoto avatar;
@Nullable public final Uri contactUri;
@Nullable public final MaterialColor color;
static class RecipientDetails {
@Nullable public final String name;
@Nullable public final String customLabel;
@NonNull public final ContactPhoto avatar;
@Nullable public final Uri contactUri;
@Nullable public final MaterialColor color;
@Nullable public final Uri ringtone;
public final long mutedUntil;
@Nullable public final VibrateState vibrateState;
public final boolean blocked;
public final int expireMessages;
@NonNull public final List<Recipient> participants;
public RecipientDetails(@Nullable String name, @Nullable String customLabel,
@Nullable Uri contactUri, @NonNull ContactPhoto avatar,
@Nullable MaterialColor color)
@Nullable RecipientsPreferences preferences,
@Nullable List<Recipient> participants)
{
this.name = name;
this.customLabel = customLabel;
this.avatar = avatar;
this.contactUri = contactUri;
this.color = color;
}
}
private static class RecipientAddresses {
private final Address[] addresses;
private RecipientAddresses(Address[] addresses) {
this.addresses = addresses;
}
public boolean equals(Object other) {
if (other == null || !(other instanceof RecipientAddresses)) return false;
return Arrays.equals(this.addresses, ((RecipientAddresses) other).addresses);
}
public int hashCode() {
return Arrays.hashCode(addresses);
this.name = name;
this.customLabel = customLabel;
this.avatar = avatar;
this.contactUri = contactUri;
this.color = preferences != null ? preferences.getColor() : null;
this.ringtone = preferences != null ? preferences.getRingtone() : null;
this.mutedUntil = preferences != null ? preferences.getMuteUntil() : 0;
this.vibrateState = preferences != null ? preferences.getVibrateState() : null;
this.blocked = preferences != null && preferences.isBlocked();
this.expireMessages = preferences != null ? preferences.getExpireMessages() : 0;
this.participants = participants == null ? new LinkedList<Recipient>() : participants;
}
}
@ -262,26 +214,4 @@ class RecipientProvider {
}
private static class RecipientsCache {
private final Map<RecipientAddresses,Recipients> cache = new LRUCache<>(1000);
public synchronized Recipients get(RecipientAddresses addresses) {
return cache.get(addresses);
}
public synchronized void set(RecipientAddresses addresses, Recipients recipients) {
cache.put(addresses, recipients);
}
public synchronized void reset() {
for (Recipients recipients : cache.values()) {
recipients.setStale();
}
}
}
}

View File

@ -1,321 +0,0 @@
/**
* Copyright (C) 2015 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.recipients;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException;
public class Recipients implements Iterable<Recipient>, RecipientModifiedListener {
private static final String TAG = Recipients.class.getSimpleName();
private final Set<RecipientsModifiedListener> listeners = Collections.newSetFromMap(new WeakHashMap<RecipientsModifiedListener, Boolean>());
private final List<Recipient> recipients;
private Uri ringtone = null;
private long mutedUntil = 0;
private boolean blocked = false;
private VibrateState vibrate = VibrateState.DEFAULT;
private int expireMessages = 0;
private boolean stale = false;
Recipients() {
this(new LinkedList<Recipient>(), null);
}
Recipients(List<Recipient> recipients, @Nullable RecipientsPreferences preferences) {
this.recipients = recipients;
if (preferences != null) {
ringtone = preferences.getRingtone();
mutedUntil = preferences.getMuteUntil();
vibrate = preferences.getVibrateState();
blocked = preferences.isBlocked();
expireMessages = preferences.getExpireMessages();
}
}
Recipients(@NonNull List<Recipient> recipients,
@Nullable Recipients stale,
@NonNull ListenableFutureTask<RecipientsPreferences> preferences)
{
this.recipients = recipients;
if (stale != null) {
ringtone = stale.ringtone;
mutedUntil = stale.mutedUntil;
vibrate = stale.vibrate;
blocked = stale.blocked;
expireMessages = stale.expireMessages;
}
preferences.addListener(new FutureTaskListener<RecipientsPreferences>() {
@Override
public void onSuccess(RecipientsPreferences result) {
if (result != null) {
Set<RecipientsModifiedListener> localListeners;
synchronized (Recipients.this) {
ringtone = result.getRingtone();
mutedUntil = result.getMuteUntil();
vibrate = result.getVibrateState();
blocked = result.isBlocked();
expireMessages = result.getExpireMessages();
localListeners = new HashSet<>(listeners);
}
for (RecipientsModifiedListener listener : localListeners) {
listener.onModified(Recipients.this);
}
}
}
@Override
public void onFailure(ExecutionException error) {
Log.w(TAG, error);
}
});
}
public synchronized @Nullable Uri getRingtone() {
return ringtone;
}
public void setRingtone(Uri ringtone) {
synchronized (this) {
this.ringtone = ringtone;
}
notifyListeners();
}
public synchronized boolean isMuted() {
return System.currentTimeMillis() <= mutedUntil;
}
public void setMuted(long mutedUntil) {
synchronized (this) {
this.mutedUntil = mutedUntil;
}
notifyListeners();
}
public synchronized boolean isBlocked() {
return blocked;
}
public void setBlocked(boolean blocked) {
synchronized (this) {
this.blocked = blocked;
}
notifyListeners();
}
public synchronized VibrateState getVibrate() {
return vibrate;
}
public void setVibrate(VibrateState vibrate) {
synchronized (this) {
this.vibrate = vibrate;
}
notifyListeners();
}
public @NonNull ContactPhoto getContactPhoto() {
if (recipients.size() == 1) return recipients.get(0).getContactPhoto();
else return ContactPhotoFactory.getDefaultGroupPhoto();
}
public synchronized @NonNull MaterialColor getColor() {
if (!isSingleRecipient() || isGroupRecipient()) return MaterialColor.GROUP;
else if (isEmpty()) return ContactColors.UNKNOWN_COLOR;
else return recipients.get(0).getColor();
}
public synchronized void setColor(@NonNull MaterialColor color) {
if (!isSingleRecipient() || isGroupRecipient()) throw new AssertionError("Groups don't have colors!");
else if (!isEmpty()) recipients.get(0).setColor(color);
}
public synchronized int getExpireMessages() {
return expireMessages;
}
public void setExpireMessages(int expireMessages) {
synchronized (this) {
this.expireMessages = expireMessages;
}
notifyListeners();
}
public synchronized void addListener(RecipientsModifiedListener listener) {
if (listeners.isEmpty()) {
for (Recipient recipient : recipients) {
recipient.addListener(this);
}
}
listeners.add(listener);
}
public synchronized void removeListener(RecipientsModifiedListener listener) {
listeners.remove(listener);
if (listeners.isEmpty()) {
for (Recipient recipient : recipients) {
recipient.removeListener(this);
}
}
}
public boolean isEmailRecipient() {
for (Recipient recipient : recipients) {
if (recipient.getAddress().isEmail()) {
return true;
}
}
return false;
}
public boolean isGroupRecipient() {
return isSingleRecipient() && recipients.get(0).getAddress().isGroup();
}
public boolean isEmpty() {
return this.recipients.isEmpty();
}
public boolean isSingleRecipient() {
return this.recipients.size() == 1;
}
public @Nullable Recipient getPrimaryRecipient() {
if (!isEmpty())
return this.recipients.get(0);
else
return null;
}
public List<Recipient> getRecipientsList() {
return this.recipients;
}
public Address[] getAddresses() {
Address[] addresses = new Address[recipients.size()];
for (int i=0;i<recipients.size();i++) {
addresses[i] = recipients.get(i).getAddress();
}
Arrays.sort(addresses);
return addresses;
}
public List<Address> getAddressesList() {
List<Address> results = new LinkedList<>();
Collections.addAll(results, getAddresses());
return results;
}
public String toShortString() {
String fromString = "";
for (int i=0;i<recipients.size();i++) {
fromString += recipients.get(i).toShortString();
if (i != recipients.size() -1 )
fromString += ", ";
}
return fromString;
}
@Override
public Iterator<Recipient> iterator() {
return recipients.iterator();
}
@Override
public void onModified(Recipient recipient) {
notifyListeners();
}
private void notifyListeners() {
Set<RecipientsModifiedListener> localListeners;
synchronized (this) {
localListeners = new HashSet<>(listeners);
}
for (RecipientsModifiedListener listener : localListeners) {
listener.onModified(this);
}
}
boolean isStale() {
return stale;
}
void setStale() {
this.stale = true;
}
boolean isResolving() {
for (Recipient recipient : recipients) {
if (recipient.isResolving()) return true;
}
return false;
}
public interface RecipientsModifiedListener {
public void onModified(Recipients recipient);
}
}

View File

@ -20,8 +20,8 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.BitmapUtil;
import java.util.LinkedList;
@ -49,17 +49,17 @@ public class DirectShareService extends ChooserTargetService {
ThreadRecord record;
while ((record = reader.getNext()) != null && results.size() < 10) {
Recipients recipients = RecipientFactory.getRecipientsFor(this, record.getRecipients().getAddresses(), false);
String name = recipients.toShortString();
Drawable drawable = recipients.getContactPhoto().asDrawable(this, recipients.getColor().toConversationColor(this));
Bitmap avatar = BitmapUtil.createFromDrawable(drawable, 500, 500);
Recipient recipient = RecipientFactory.getRecipientFor(this, record.getRecipient().getAddress(), false);
String name = recipient.toShortString();
Drawable drawable = recipient.getContactPhoto().asDrawable(this, recipient.getColor().toConversationColor(this));
Bitmap avatar = BitmapUtil.createFromDrawable(drawable, 500, 500);
Parcel parcel = Parcel.obtain();
parcel.writeTypedArray(recipients.getAddresses(), 0);
parcel.writeParcelable(recipient.getAddress(), 0);
Bundle bundle = new Bundle();
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId());
bundle.putByteArray(ShareActivity.EXTRA_ADDRESSES_MARSHALLED, parcel.marshall());
bundle.putByteArray(ShareActivity.EXTRA_ADDRESS_MARSHALLED, parcel.marshall());
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType());
bundle.setClassLoader(getClassLoader());

View File

@ -12,11 +12,8 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.Rfc5724Uri;
@ -49,31 +46,20 @@ public class QuickResponseService extends MasterSecretIntentService {
try {
Rfc5724Uri uri = new Rfc5724Uri(intent.getDataString());
String content = intent.getStringExtra(Intent.EXTRA_TEXT);
String numbers = uri.getPath();
String number = uri.getPath();
if (numbers.contains("%")){
numbers = URLDecoder.decode(numbers);
if (number.contains("%")){
number = URLDecoder.decode(number);
}
String[] numbersArray = numbers.split(",");
Address[] addresses = new Address[numbersArray.length];
for (int i=0;i<numbersArray.length;i++) {
addresses[i] = Address.fromExternal(this, numbersArray[i]);
}
Recipients recipients = RecipientFactory.getRecipientsFor(this, addresses, false);
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(this).getRecipientsPreferences(recipients.getAddresses());
Address address = Address.fromExternal(this, number);
Recipient recipient = RecipientFactory.getRecipientFor(this, address, false);
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(this).getRecipientsPreferences(recipient.getAddress());
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
if (!TextUtils.isEmpty(content)) {
if (recipients.isSingleRecipient()) {
MessageSender.send(this, masterSecret, new OutgoingTextMessage(recipients, content, expiresIn, subscriptionId), -1, false, null);
} else {
MessageSender.send(this, masterSecret, new OutgoingMediaMessage(recipients, new SlideDeck(), content, System.currentTimeMillis(),
subscriptionId, expiresIn, ThreadDatabase.DistributionTypes.DEFAULT), -1, false, null);
}
MessageSender.send(this, masterSecret, new OutgoingTextMessage(recipient, content, expiresIn, subscriptionId), -1, false, null);
}
} catch (URISyntaxException e) {
Toast.makeText(this, R.string.QuickResponseService_problem_sending_message, Toast.LENGTH_LONG).show();

View File

@ -75,7 +75,7 @@ public class IncomingTextMessage implements Parcelable {
this.expiresInMillis = expiresInMillis;
if (group.isPresent()) {
this.groupId = Address.fromSerialized(GroupUtil.getEncodedId(group.get().getGroupId()));
this.groupId = Address.fromSerialized(GroupUtil.getEncodedId(group.get().getGroupId(), false));
} else {
this.groupId = null;
}

View File

@ -40,7 +40,7 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.push.AccountManagerFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@ -63,13 +63,13 @@ public class MessageSender {
final SmsDatabase.InsertListener insertListener)
{
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
Recipients recipients = message.getRecipients();
Recipient recipient = message.getRecipient();
boolean keyExchange = message.isKeyExchange();
long allocatedThreadId;
if (threadId == -1) {
allocatedThreadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
allocatedThreadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
} else {
allocatedThreadId = threadId;
}
@ -77,7 +77,7 @@ public class MessageSender {
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), allocatedThreadId,
message, forceSms, System.currentTimeMillis(), insertListener);
sendTextMessage(context, recipients, forceSms, keyExchange, messageId, message.getExpiresIn());
sendTextMessage(context, recipient, forceSms, keyExchange, messageId, message.getExpiresIn());
return allocatedThreadId;
}
@ -96,15 +96,15 @@ public class MessageSender {
long allocatedThreadId;
if (threadId == -1) {
allocatedThreadId = threadDatabase.getThreadIdFor(message.getRecipients(), message.getDistributionType());
allocatedThreadId = threadDatabase.getThreadIdFor(message.getRecipient(), message.getDistributionType());
} else {
allocatedThreadId = threadId;
}
Recipients recipients = message.getRecipients();
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), message, allocatedThreadId, forceSms, insertListener);
Recipient recipient = message.getRecipient();
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), message, allocatedThreadId, forceSms, insertListener);
sendMediaMessage(context, masterSecret, recipients, forceSms, messageId, message.getExpiresIn());
sendMediaMessage(context, masterSecret, recipient, forceSms, messageId, message.getExpiresIn());
return allocatedThreadId;
} catch (MmsException e) {
@ -113,11 +113,9 @@ public class MessageSender {
}
}
public static void resendGroupMessage(Context context, MasterSecret masterSecret, MessageRecord messageRecord, Address filterAddress) {
public static void resendGroupMessage(Context context, MessageRecord messageRecord, Address filterAddress) {
if (!messageRecord.isMms()) throw new AssertionError("Not Group");
Recipients recipients = DatabaseFactory.getMmsAddressDatabase(context).getRecipientsForId(messageRecord.getId());
sendGroupPush(context, recipients, messageRecord.getId(), filterAddress);
sendGroupPush(context, messageRecord.getRecipient(), messageRecord.getId(), filterAddress);
}
public static void resend(Context context, MasterSecret masterSecret, MessageRecord messageRecord) {
@ -126,13 +124,12 @@ public class MessageSender {
boolean forceSms = messageRecord.isForcedSms();
boolean keyExchange = messageRecord.isKeyExchange();
long expiresIn = messageRecord.getExpiresIn();
Recipient recipient = messageRecord.getRecipient();
if (messageRecord.isMms()) {
Recipients recipients = DatabaseFactory.getMmsAddressDatabase(context).getRecipientsForId(messageId);
sendMediaMessage(context, masterSecret, recipients, forceSms, messageId, expiresIn);
sendMediaMessage(context, masterSecret, recipient, forceSms, messageId, expiresIn);
} else {
Recipients recipients = messageRecord.getRecipients();
sendTextMessage(context, recipients, forceSms, keyExchange, messageId, expiresIn);
sendTextMessage(context, recipient, forceSms, keyExchange, messageId, expiresIn);
}
} catch (MmsException e) {
Log.w(TAG, e);
@ -140,31 +137,31 @@ public class MessageSender {
}
private static void sendMediaMessage(Context context, MasterSecret masterSecret,
Recipients recipients, boolean forceSms,
Recipient recipient, boolean forceSms,
long messageId, long expiresIn)
throws MmsException
{
if (!forceSms && isSelfSend(context, recipients)) {
if (!forceSms && isSelfSend(context, recipient)) {
sendMediaSelf(context, masterSecret, messageId, expiresIn);
} else if (isGroupPushSend(recipients)) {
sendGroupPush(context, recipients, messageId, null);
} else if (!forceSms && isPushMediaSend(context, recipients)) {
sendMediaPush(context, recipients, messageId);
} else if (isGroupPushSend(recipient)) {
sendGroupPush(context, recipient, messageId, null);
} else if (!forceSms && isPushMediaSend(context, recipient)) {
sendMediaPush(context, recipient, messageId);
} else {
sendMms(context, messageId);
}
}
private static void sendTextMessage(Context context, Recipients recipients,
private static void sendTextMessage(Context context, Recipient recipient,
boolean forceSms, boolean keyExchange,
long messageId, long expiresIn)
{
if (!forceSms && isSelfSend(context, recipients)) {
if (!forceSms && isSelfSend(context, recipient)) {
sendTextSelf(context, messageId, expiresIn);
} else if (!forceSms && isPushTextSend(context, recipients, keyExchange)) {
sendTextPush(context, recipients, messageId);
} else if (!forceSms && isPushTextSend(context, recipient, keyExchange)) {
sendTextPush(context, recipient, messageId);
} else {
sendSms(context, recipients, messageId);
sendSms(context, recipient, messageId);
}
}
@ -200,24 +197,24 @@ public class MessageSender {
}
}
private static void sendTextPush(Context context, Recipients recipients, long messageId) {
private static void sendTextPush(Context context, Recipient recipient, long messageId) {
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
jobManager.add(new PushTextSendJob(context, messageId, recipients.getPrimaryRecipient().getAddress()));
jobManager.add(new PushTextSendJob(context, messageId, recipient.getAddress()));
}
private static void sendMediaPush(Context context, Recipients recipients, long messageId) {
private static void sendMediaPush(Context context, Recipient recipient, long messageId) {
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
jobManager.add(new PushMediaSendJob(context, messageId, recipients.getPrimaryRecipient().getAddress()));
jobManager.add(new PushMediaSendJob(context, messageId, recipient.getAddress()));
}
private static void sendGroupPush(Context context, Recipients recipients, long messageId, Address filterAddress) {
private static void sendGroupPush(Context context, Recipient recipient, long messageId, Address filterAddress) {
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
jobManager.add(new PushGroupSendJob(context, messageId, recipients.getPrimaryRecipient().getAddress(), filterAddress));
jobManager.add(new PushGroupSendJob(context, messageId, recipient.getAddress(), filterAddress));
}
private static void sendSms(Context context, Recipients recipients, long messageId) {
private static void sendSms(Context context, Recipient recipient, long messageId) {
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
jobManager.add(new SmsSendJob(context, messageId, recipients.getPrimaryRecipient().getName()));
jobManager.add(new SmsSendJob(context, messageId, recipient.getName()));
}
private static void sendMms(Context context, long messageId) {
@ -225,7 +222,7 @@ public class MessageSender {
jobManager.add(new MmsSendJob(context, messageId));
}
private static boolean isPushTextSend(Context context, Recipients recipients, boolean keyExchange) {
private static boolean isPushTextSend(Context context, Recipient recipient, boolean keyExchange) {
if (!TextSecurePreferences.isPushRegistered(context)) {
return false;
}
@ -234,39 +231,36 @@ public class MessageSender {
return false;
}
return isPushDestination(context, recipients.getPrimaryRecipient().getAddress());
return isPushDestination(context, recipient.getAddress());
}
private static boolean isPushMediaSend(Context context, Recipients recipients) {
private static boolean isPushMediaSend(Context context, Recipient recipient) {
if (!TextSecurePreferences.isPushRegistered(context)) {
return false;
}
if (recipients.getRecipientsList().size() > 1) {
if (recipient.isGroupRecipient()) {
return false;
}
return isPushDestination(context, recipients.getPrimaryRecipient().getAddress());
return isPushDestination(context, recipient.getAddress());
}
private static boolean isGroupPushSend(Recipients recipients) {
return recipients.getPrimaryRecipient().getAddress().isGroup();
private static boolean isGroupPushSend(Recipient recipient) {
return recipient.getAddress().isGroup() &&
!recipient.getAddress().isMmsGroup();
}
private static boolean isSelfSend(Context context, Recipients recipients) {
private static boolean isSelfSend(Context context, Recipient recipient) {
if (!TextSecurePreferences.isPushRegistered(context)) {
return false;
}
if (!recipients.isSingleRecipient()) {
if (recipient.isGroupRecipient()) {
return false;
}
if (recipients.isGroupRecipient()) {
return false;
}
return Util.isOwnNumber(context, recipients.getPrimaryRecipient().getAddress());
return Util.isOwnNumber(context, recipient.getAddress());
}
private static boolean isPushDestination(Context context, Address destination) {

View File

@ -1,11 +1,11 @@
package org.thoughtcrime.securesms.sms;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
public class OutgoingEncryptedMessage extends OutgoingTextMessage {
public OutgoingEncryptedMessage(Recipients recipients, String body, long expiresIn) {
super(recipients, body, expiresIn, -1);
public OutgoingEncryptedMessage(Recipient recipient, String body, long expiresIn) {
super(recipient, body, expiresIn, -1);
}
private OutgoingEncryptedMessage(OutgoingEncryptedMessage base, String body) {

View File

@ -1,16 +1,16 @@
package org.thoughtcrime.securesms.sms;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.recipients.Recipient;
public class OutgoingIdentityDefaultMessage extends OutgoingTextMessage {
public OutgoingIdentityDefaultMessage(Recipients recipients) {
this(recipients, "");
public OutgoingIdentityDefaultMessage(Recipient recipient) {
this(recipient, "");
}
private OutgoingIdentityDefaultMessage(Recipients recipients, String body) {
super(recipients, body, -1);
private OutgoingIdentityDefaultMessage(Recipient recipient, String body) {
super(recipient, body, -1);
}
@Override
@ -19,6 +19,6 @@ public class OutgoingIdentityDefaultMessage extends OutgoingTextMessage {
}
public OutgoingTextMessage withBody(String body) {
return new OutgoingIdentityDefaultMessage(getRecipients());
return new OutgoingIdentityDefaultMessage(getRecipient());
}
}

Some files were not shown because too many files have changed in this diff Show More