diff --git a/src/org/thoughtcrime/securesms/BindableConversationItem.java b/src/org/thoughtcrime/securesms/BindableConversationItem.java index 2be2e70716..9a9b64254f 100644 --- a/src/org/thoughtcrime/securesms/BindableConversationItem.java +++ b/src/org/thoughtcrime/securesms/BindableConversationItem.java @@ -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 batchSelected, - @NonNull Recipients recipients); + @NonNull Recipient recipients); MessageRecord getMessageRecord(); } diff --git a/src/org/thoughtcrime/securesms/BlockedContactsActivity.java b/src/org/thoughtcrime/securesms/BlockedContactsActivity.java index 9096f823d9..b83f91cec7 100644 --- a/src/org/thoughtcrime/securesms/BlockedContactsActivity.java +++ b/src/org/thoughtcrime/securesms/BlockedContactsActivity.java @@ -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
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); } } diff --git a/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java b/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java index c33a6c4ff5..90a46f7dab 100644 --- a/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java +++ b/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java @@ -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(), diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index 543b8d0096..12ffff669e 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -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() { @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() { @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() { @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() { @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() { @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() { + new AsyncTask() { @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 initializeIdentityRecords() { final SettableFuture future = new SettableFuture<>(); - new AsyncTask>() { + new AsyncTask>() { @Override - protected @NonNull Pair doInBackground(Recipients... params) { - try { - IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this); - IdentityRecordList identityRecordList = new IdentityRecordList(); - Recipients recipients = params[0]; + protected @NonNull Pair doInBackground(Recipient... params) { + IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this); + IdentityRecordList identityRecordList = new IdentityRecordList(); + List 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 saveDraft() { final SettableFuture 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 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> { + private class RecipientPreferencesTask extends AsyncTask> { @Override - protected Pair doInBackground(Recipients... recipients) { - if (recipients.length != 1 || recipients[0] == null) { + protected Pair doInBackground(Recipient... recipient) { + if (recipient.length != 1 || recipient[0] == null) { throw new AssertionError("task needs exactly one Recipients object"); } Optional 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 result) { - if (result.first == recipients) { + protected void onPostExecute(@NonNull Pair result) { + if (result.first == recipient) { updateInviteReminder(result.second != null && result.second.hasSeenInviteReminder()); updateDefaultSubscriptionId(result.second != null ? result.second.getDefaultSubscriptionId() : Optional.absent()); } diff --git a/src/org/thoughtcrime/securesms/ConversationAdapter.java b/src/org/thoughtcrime/securesms/ConversationAdapter.java index fa163789bd..ef67b21c82 100644 --- a/src/org/thoughtcrime/securesms/ConversationAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationAdapter.java @@ -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 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 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 @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 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 @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)); } diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java index 5ca0167171..f2f9c1bef2 100644 --- a/src/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationFragment.java @@ -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); } diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index dd5902bb75..c57621c6b1 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -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 batchSelected = new HashSet<>(); - private @Nullable Recipients conversationRecipients; + private @Nullable Recipient conversationRecipient; private @NonNull Stub mediaThumbnailStub; private @NonNull Stub audioViewStub; private @NonNull Stub documentViewStub; @@ -180,18 +180,18 @@ public class ConversationItem extends LinearLayout @NonNull MessageRecord messageRecord, @NonNull Locale locale, @NonNull Set 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(); diff --git a/src/org/thoughtcrime/securesms/ConversationListActivity.java b/src/org/thoughtcrime/securesms/ConversationListActivity.java index fe137faa11..377405983b 100644 --- a/src/org/thoughtcrime/securesms/ConversationListActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java @@ -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()); diff --git a/src/org/thoughtcrime/securesms/ConversationListAdapter.java b/src/org/thoughtcrime/securesms/ConversationListAdapter.java index 726c523dcb..8c3dd8e3bc 100644 --- a/src/org/thoughtcrime/securesms/ConversationListAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationListAdapter.java @@ -78,13 +78,8 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter 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 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); } }); } diff --git a/src/org/thoughtcrime/securesms/ConversationPopupActivity.java b/src/org/thoughtcrime/securesms/ConversationPopupActivity.java index 8e1164719e..56cf4b2a3f 100644 --- a/src/org/thoughtcrime/securesms/ConversationPopupActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationPopupActivity.java @@ -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) { diff --git a/src/org/thoughtcrime/securesms/ConversationTitleView.java b/src/org/thoughtcrime/securesms/ConversationTitleView.java index 86a35278ba..ce7740a163 100644 --- a/src/org/thoughtcrime/securesms/ConversationTitleView.java +++ b/src/org/thoughtcrime/securesms/ConversationTitleView.java @@ -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); - } - - - - - } diff --git a/src/org/thoughtcrime/securesms/ConversationUpdateItem.java b/src/org/thoughtcrime/securesms/ConversationUpdateItem.java index ab5e8a6a26..32ef9ea068 100644 --- a/src/org/thoughtcrime/securesms/ConversationUpdateItem.java +++ b/src/org/thoughtcrime/securesms/ConversationUpdateItem.java @@ -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 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() { diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index 82e29e0538..2dea4f85f5 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -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 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 { - private GroupCreateActivity activity; - private Set members; + private static class CreateMmsGroupTask extends AsyncTask { + private final GroupCreateActivity activity; + private final MasterSecret masterSecret; + private final Set members; - public CreateMmsGroupTask(GroupCreateActivity activity, Set members) { - this.activity = activity; - this.members = members; + public CreateMmsGroupTask(GroupCreateActivity activity, MasterSecret masterSecret, Set 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
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 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 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> { + private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask> { private GroupCreateActivity activity; public FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) { @@ -552,12 +540,12 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity } @Override - protected Optional doInBackground(byte[]... groupIds) { + protected Optional doInBackground(String... groupIds) { final GroupDatabase db = DatabaseFactory.getGroupDatabase(activity); - final Recipients recipients = db.getGroupMembers(groupIds[0], false); + final List recipients = db.getGroupMembers(groupIds[0], false); final GroupRecord group = db.getGroup(groupIds[0]); - final Set existingContacts = new HashSet<>(recipients.getRecipientsList().size()); - existingContacts.addAll(recipients.getRecipientsList()); + final Set 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 recipients; Bitmap avatarBmp; byte[] avatarBytes; String name; - public GroupData(byte[] id, Set recipients, Bitmap avatarBmp, byte[] avatarBytes, String name) { + public GroupData(String id, Set recipients, Bitmap avatarBmp, byte[] avatarBytes, String name) { this.id = id; this.recipients = recipients; this.avatarBmp = avatarBmp; diff --git a/src/org/thoughtcrime/securesms/GroupMembersDialog.java b/src/org/thoughtcrime/securesms/GroupMembersDialog.java index 8c90e3981a..acf675aecd 100644 --- a/src/org/thoughtcrime/securesms/GroupMembersDialog.java +++ b/src/org/thoughtcrime/securesms/GroupMembersDialog.java @@ -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 { +public class GroupMembersDialog extends AsyncTask> { 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(), true); - } + protected List doInBackground(Void... params) { + return DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), true); } @Override - public void onPostExecute(Recipients members) { + public void onPostExecute(List 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 { } 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 { private final LinkedList members = new LinkedList<>(); - public GroupMembers(Recipients recipients) { - for (Recipient recipient : recipients.getRecipientsList()) { + public GroupMembers(List recipients) { + for (Recipient recipient : recipients) { if (isLocalNumber(recipient)) { members.push(recipient); } else { diff --git a/src/org/thoughtcrime/securesms/InviteActivity.java b/src/org/thoughtcrime/securesms/InviteActivity.java index d0b4beded5..b3fb4e262a 100644 --- a/src/org/thoughtcrime/securesms/InviteActivity.java +++ b/src/org/thoughtcrime/securesms/InviteActivity.java @@ -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 preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipient.getAddress()); + int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1; - if (recipients.getPrimaryRecipient() != null) { - Optional 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; } diff --git a/src/org/thoughtcrime/securesms/MediaOverviewActivity.java b/src/org/thoughtcrime/securesms/MediaOverviewActivity.java index a7b6e7623c..f58fb7b70d 100644 --- a/src/org/thoughtcrime/securesms/MediaOverviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaOverviewActivity.java @@ -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 { 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(); } }); diff --git a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java index be35e09c7e..820684e24c 100644 --- a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java @@ -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; diff --git a/src/org/thoughtcrime/securesms/MessageDetailsActivity.java b/src/org/thoughtcrime/securesms/MessageDetailsActivity.java index b518ab9f0d..ea6e6a7498 100644 --- a/src/org/thoughtcrime/securesms/MessageDetailsActivity.java +++ b/src/org/thoughtcrime/securesms/MessageDetailsActivity.java @@ -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, Recipients.RecipientsModifiedListener { +public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks, 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 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(), recipients); + new HashSet(), 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 { + private class MessageRecipientAsyncTask extends AsyncTask> { private WeakReference weakContext; private MessageRecord messageRecord; @@ -335,41 +334,27 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity } @Override - public Recipients doInBackground(Void... voids) { + public List doInBackground(Void... voids) { Context context = getContext(); if (context == null) { Log.w(TAG, "associated context is destroyed, finishing early"); return null; } - Recipients recipients; + List 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(), false); - } + recipients.addAll(DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().getAddress().toGroupString(), false)); } return recipients; } @Override - public void onPostExecute(Recipients recipients) { + public void onPostExecute(List 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); diff --git a/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java b/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java index a0e39aa0e7..e38afa28d6 100644 --- a/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java +++ b/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java @@ -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 recipients; + private final boolean isPushGroup; public MessageDetailsRecipientAdapter(Context context, MasterSecret masterSecret, - MessageRecord record, Recipients recipients, + MessageRecord record, List 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; } diff --git a/src/org/thoughtcrime/securesms/MessageRecipientListItem.java b/src/org/thoughtcrime/securesms/MessageRecipientListItem.java index 8d2d5715d7..3c8a23c91e 100644 --- a/src/org/thoughtcrime/securesms/MessageRecipientListItem.java +++ b/src/org/thoughtcrime/securesms/MessageRecipientListItem.java @@ -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 { + 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; } diff --git a/src/org/thoughtcrime/securesms/NewConversationActivity.java b/src/org/thoughtcrime/securesms/NewConversationActivity.java index 2d43a2631d..e2025962c0 100644 --- a/src/org/thoughtcrime/securesms/NewConversationActivity.java +++ b/src/org/thoughtcrime/securesms/NewConversationActivity.java @@ -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); diff --git a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java index 849891afb7..1459e53f8a 100644 --- a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java +++ b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java @@ -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>() { + IdentityUtil.getRemoteIdentityKey(getActivity(), recipient).addListener(new ListenableFuture.Listener>() { @Override public void onSuccess(Optional 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() { @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() { @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() { @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() { @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() { @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() diff --git a/src/org/thoughtcrime/securesms/ShareActivity.java b/src/org/thoughtcrime/securesms/ShareActivity.java index 29466bd2de..c740b58e38 100644 --- a/src/org/thoughtcrime/securesms/ShareActivity.java +++ b/src/org/thoughtcrime/securesms/ShareActivity.java @@ -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); diff --git a/src/org/thoughtcrime/securesms/ShareFragment.java b/src/org/thoughtcrime/securesms/ShareFragment.java index 9a0a7b1472..3405037fef 100644 --- a/src/org/thoughtcrime/securesms/ShareFragment.java +++ b/src/org/thoughtcrime/securesms/ShareFragment.java @@ -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); } } diff --git a/src/org/thoughtcrime/securesms/ShareListItem.java b/src/org/thoughtcrime/securesms/ShareListItem.java index 716aa1ff40..00777cc7a8 100644 --- a/src/org/thoughtcrime/securesms/ShareListItem.java +++ b/src/org/thoughtcrime/securesms/ShareListItem.java @@ -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); } }); } diff --git a/src/org/thoughtcrime/securesms/SmsSendtoActivity.java b/src/org/thoughtcrime/securesms/SmsSendtoActivity.java index 68fbcbd010..cda8428702 100644 --- a/src/org/thoughtcrime/securesms/SmsSendtoActivity.java +++ b/src/org/thoughtcrime/securesms/SmsSendtoActivity.java @@ -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; } diff --git a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java index f367d57518..a36a5e63b8 100644 --- a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java @@ -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"; diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java index 230b535134..9c77299455 100644 --- a/src/org/thoughtcrime/securesms/components/AvatarImageView.java +++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java @@ -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()); diff --git a/src/org/thoughtcrime/securesms/components/FromTextView.java b/src/org/thoughtcrime/securesms/components/FromTextView.java index fc99e4e025..804fc736a8 100644 --- a/src/org/thoughtcrime/securesms/components/FromTextView.java +++ b/src/org/thoughtcrime/securesms/components/FromTextView.java @@ -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); } diff --git a/src/org/thoughtcrime/securesms/components/PushRecipientsPanel.java b/src/org/thoughtcrime/securesms/components/PushRecipientsPanel.java index c49c16d320..38c4e4cb97 100644 --- a/src/org/thoughtcrime/securesms/components/PushRecipientsPanel.java +++ b/src/org/thoughtcrime/securesms/components/PushRecipientsPanel.java @@ -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 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(), true); + this.recipientsText = (RecipientsEditor)findViewById(R.id.recipients_text); + + List 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
addresses = new LinkedList<>(); + private @NonNull List getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) { + StringTokenizer tokenizer = new StringTokenizer(rawText, ","); + List 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 recipients); } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/components/reminder/InviteReminder.java b/src/org/thoughtcrime/securesms/components/reminder/InviteReminder.java index 48c0a0dde9..dbfb8f0493 100644 --- a/src/org/thoughtcrime/securesms/components/reminder/InviteReminder.java +++ b/src/org/thoughtcrime/securesms/components/reminder/InviteReminder.java @@ -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() { @Override protected Void doInBackground(Void... params) { - DatabaseFactory.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipients, true); + DatabaseFactory.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipient, true); return null; } }.execute(); diff --git a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java index 5de9769da7..ec96a21c65 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java @@ -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(); diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java index 34ab6014de..b55df22a44 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java @@ -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()); } }); } diff --git a/src/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java b/src/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java index 59a5f8ada4..3329c87220 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java @@ -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, diff --git a/src/org/thoughtcrime/securesms/contacts/RecipientsEditor.java b/src/org/thoughtcrime/securesms/contacts/RecipientsEditor.java index 23c6c39f50..7c77dd8948 100644 --- a/src/org/thoughtcrime/securesms/contacts/RecipientsEditor.java +++ b/src/org/thoughtcrime/securesms/contacts/RecipientsEditor.java @@ -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 list) { SpannableStringBuilder sb = new SpannableStringBuilder(); - for (Recipient c : list.getRecipientsList()) { + for (Recipient c : list) { if (sb.length() != 0) { sb.append(", "); } diff --git a/src/org/thoughtcrime/securesms/database/Address.java b/src/org/thoughtcrime/securesms/database/Address.java index 6104c9e5ba..a14ea3a6b8 100644 --- a/src/org/thoughtcrime/securesms/database/Address.java +++ b/src/org/thoughtcrime/securesms/database/Address.java @@ -96,20 +96,14 @@ public class Address implements Parcelable, Comparable
{ return Util.join(escapedAddresses, delimiter + ""); } - public static Address[] fromParcelable(Parcelable[] parcelables) { - Address[] addresses = new Address[parcelables.length]; - - for (int i=0;i { } 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+]", ""); diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index 7acd5e5303..0a02af005d 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -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 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(); } diff --git a/src/org/thoughtcrime/securesms/database/GroupDatabase.java b/src/org/thoughtcrime/securesms/database/GroupDatabase.java index 4a44a96850..e4b6f4a690 100644 --- a/src/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/src/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -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
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 getGroupMembers(String groupId, boolean includeSelf) { List
members = getCurrentMembers(groupId); List 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
members, - SignalServiceAttachmentPointer avatar, String relay) + public void create(@NonNull String groupId, @Nullable String title, @NonNull List
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
members) { + public void updateMembers(String groupId, List
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
currentMembers = getCurrentMembers(id); + public void remove(String groupId, Address source) { + List
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
getCurrentMembers(byte[] id) { + private List
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; + } } } diff --git a/src/org/thoughtcrime/securesms/database/MmsAddressDatabase.java b/src/org/thoughtcrime/securesms/database/MmsAddressDatabase.java deleted file mode 100644 index d31deed4dd..0000000000 --- a/src/org/thoughtcrime/securesms/database/MmsAddressDatabase.java +++ /dev/null @@ -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 . - */ -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
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
to = new LinkedList<>(); - List
cc = new LinkedList<>(); - List
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
getAddressesListForId(long messageId) { - List
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
addresses = getAddressesListForId(messageId); - List 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); - } -} diff --git a/src/org/thoughtcrime/securesms/database/MmsAddresses.java b/src/org/thoughtcrime/securesms/database/MmsAddresses.java deleted file mode 100644 index 21302a222b..0000000000 --- a/src/org/thoughtcrime/securesms/database/MmsAddresses.java +++ /dev/null @@ -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
to; - private final @NonNull List
cc; - private final @NonNull List
bcc; - - public MmsAddresses(@Nullable Address from, @NonNull List
to, - @NonNull List
cc, @NonNull List
bcc) - { - this.from = from; - this.to = to; - this.cc = cc; - this.bcc = bcc; - } - - @NonNull - public List
getTo() { - return to; - } - - @NonNull - public List
getCc() { - return cc; - } - - @NonNull - public List
getBcc() { - return bcc; - } - - @Nullable - public Address getFrom() { - return from; - } - - public static MmsAddresses forTo(@NonNull List
to) { - return new MmsAddresses(null, to, new LinkedList
(), new LinkedList
()); - } - - public static MmsAddresses forBcc(@NonNull List
bcc) { - return new MmsAddresses(null, new LinkedList
(), new LinkedList
(), bcc); - } - - public static MmsAddresses forFrom(@NonNull Address from) { - return new MmsAddresses(from, new LinkedList
(), new LinkedList
(), new LinkedList
()); - } -} diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 248ae23aaf..6df470108d 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -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
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
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> setTimestampRead(SyncMessageId messageId, long expireStarted) { - MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context); SQLiteDatabase database = databaseHelper.getWritableDatabase(); List> 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
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 attachments = new LinkedList(attachmentDatabase.getAttachmentsForMessage(masterSecret, messageId)); - MmsAddresses addresses = addr.getAddressesForId(messageId); - List
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 attachments = new LinkedList(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 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
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 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 mismatches = getMismatchedIdentities(mismatchDocument); List 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 getMismatchedIdentities(String document) { diff --git a/src/org/thoughtcrime/securesms/database/PlaintextBackupImporter.java b/src/org/thoughtcrime/securesms/database/PlaintextBackupImporter.java index f48bcde277..92bb9fb478 100644 --- a/src/org/thoughtcrime/securesms/database/PlaintextBackupImporter.java +++ b/src/org/thoughtcrime/securesms/database/PlaintextBackupImporter.java @@ -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")) diff --git a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java index 2734f024f2..558e5e8d19 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java @@ -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 getRecipientsPreferences(@NonNull Address[] addresses) { + + public Optional 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
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
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; } } } diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index 5b31b59da2..5defe8f154 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -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 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(), @@ -828,21 +828,17 @@ public class SmsDatabase extends MessagingDatabase { long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED)); List 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 getMismatches(String document) { try { if (!TextUtils.isEmpty(document)) { diff --git a/src/org/thoughtcrime/securesms/database/SmsMigrator.java b/src/org/thoughtcrime/securesms/database/SmsMigrator.java index 1a253d3a7b..15c6b40b3e 100644 --- a/src/org/thoughtcrime/securesms/database/SmsMigrator.java +++ b/src/org/thoughtcrime/securesms/database/SmsMigrator.java @@ -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
addressList = new LinkedList<>(); + private static @Nullable Set getOurRecipients(Context context, String theirRecipients) { + StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " "); + Set 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 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
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(); diff --git a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java index 8fcea43a4c..5758e5004a 100644 --- a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -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
filter) { if (filter == null || filter.size() == 0) return null; @@ -281,11 +296,11 @@ public class ThreadDatabase extends Database { List cursors = new LinkedList<>(); for (List
addresses : partitionedAddresses) { - String selection = ADDRESSES + " = ?"; + String selection = ADDRESS + " = ?"; String[] selectionArgs = new String[addresses.size()]; for (int i=0;i 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
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
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); } diff --git a/src/org/thoughtcrime/securesms/database/loaders/ConversationListLoader.java b/src/org/thoughtcrime/securesms/database/loaders/ConversationListLoader.java index 4ffe26a39d..30b29ce76c 100644 --- a/src/org/thoughtcrime/securesms/database/loaders/ConversationListLoader.java +++ b/src/org/thoughtcrime/securesms/database/loaders/ConversationListLoader.java @@ -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); diff --git a/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java index f480033a10..803fc6104d 100644 --- a/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -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() { diff --git a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java index dead6bfa0b..4b126753ce 100644 --- a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java @@ -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 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); diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java index ff269e04d0..8906c9297f 100644 --- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -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 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; diff --git a/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java index ebde8209b0..5c16f6022c 100644 --- a/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java @@ -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 mismatches, List 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; } diff --git a/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java index 13e5d9f353..8a63c1cf0b 100644 --- a/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java @@ -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(), new LinkedList(), subscriptionId, 0, 0, slideDeck); diff --git a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java index 2a8ab4a3b8..e92ceef601 100644 --- a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java @@ -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 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(), subscriptionId, expiresIn, expireStarted); diff --git a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java index e165ebdb88..aac177c28c 100644 --- a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -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)) { diff --git a/src/org/thoughtcrime/securesms/groups/GroupManager.java b/src/org/thoughtcrime/securesms/groups/GroupManager.java index 73740ec445..af06662774 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupManager.java +++ b/src/org/thoughtcrime/securesms/groups/GroupManager.java @@ -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 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
memberAddresses = getMemberAddresses(context, members); + final String groupId = GroupUtil.getEncodedId(groupDatabase.allocateGroupId(), mms); + final Set
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
getMemberAddresses(Context context, Collection recipients) + public static GroupActionResult updateGroup(@NonNull Context context, + @NonNull MasterSecret masterSecret, + @NonNull String groupId, + @NonNull Set members, + @Nullable Bitmap avatar, + @Nullable String name) throws InvalidNumberException { + final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); + final Set
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
members, + @Nullable String groupName, + @Nullable byte[] avatar) + { + try { + Attachment avatarAttachment = null; + Address groupAddress = Address.fromSerialized(groupId); + Recipient groupRecipient = RecipientFactory.getRecipientFor(context, groupAddress, false); + + List 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
getMemberAddresses(Collection recipients) { final Set
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 members, - @Nullable Bitmap avatar, - @Nullable String name) - throws InvalidNumberException - { - final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); - final Set
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
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 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; } diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index f48c2708bd..c3529dc0ba 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -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
recordMembers = new HashSet<>(groupRecord.getMembers()); Set
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
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); diff --git a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java index c511108dc2..9e9b8bc839 100644 --- a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java @@ -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) { diff --git a/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java b/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java index a7939573dd..3c2221b7e3 100644 --- a/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java +++ b/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java @@ -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 { diff --git a/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java index 34d933edd2..b5255531da 100644 --- a/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java @@ -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 to = new LinkedList<>(); - List cc = new LinkedList<>(); + Optional
group = Optional.absent(); + Set
members = new HashSet<>(); String body = null; List 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 = database.insertMessageInbox(new MasterSecretUnion(masterSecret), message, contentLocation, threadId); diff --git a/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java index 1411299be1..5cbb700954 100644 --- a/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MmsReceiveJob.java @@ -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(); } diff --git a/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java b/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java index 24a356ec40..10b1153805 100644 --- a/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MmsSendJob.java @@ -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 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 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); } } } diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java index 67ac8e4036..3f358eb6cf 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java @@ -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 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()); } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 4fe5f9a6a2..2672f2c590 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -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 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.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.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.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); } } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index ce57af90a8..5fbb4b30c9 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -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 recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false); MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints(); List scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments()); List 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 getPushAddresses(Recipients recipients) { + private List getPushAddresses(List recipients) { List addresses = new LinkedList<>(); - for (Recipient recipient : recipients.getRecipientsList()) { + for (Recipient recipient : recipients) { addresses.add(getPushAddress(recipient.getAddress())); } diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java index 30d30703de..3a2e9ef1ad 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupUpdateJob.java @@ -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) { diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 9c538b1f14..f9cfa11117 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -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 scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments()); List attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments); diff --git a/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java b/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java index ecf8fc638f..3af1212491 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java @@ -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()) { diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index 060f19bb41..f17baceba6 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -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); } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 402033edc5..27c099f663 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -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); } } diff --git a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java index 1ba656681a..9212656a33 100644 --- a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java @@ -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 recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(group.getAddress().toGroupString(), false); for (Recipient recipient : recipients) { handleIndividualRecipient(recipient); diff --git a/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java index 9959fb9896..2e019c602c 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java @@ -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; diff --git a/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java b/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java index 944ff9a864..45f2b25578 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsSendJob.java @@ -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) diff --git a/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java b/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java index 5d2c7ebb38..f7067335ca 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java @@ -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); diff --git a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java index 9eae899683..1d5a02b525 100644 --- a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java @@ -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
to = new LinkedList<>(); - private final List
cc = new LinkedList<>(); private final List attachments = new LinkedList<>(); - public IncomingMediaMessage(Context context, String from, List to, List cc, - String body, long sentTimeMillis, - List attachments, int subscriptionId, - long expiresIn, boolean expirationUpdate) + public IncomingMediaMessage(Address from, + Optional
groupId, + String body, + long sentTimeMillis, + List 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
()); - } - public List 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; } } diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java index 1dbe336393..a104793424 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java @@ -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(), sentTimeMillis, + public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) { + super(recipient, "", new LinkedList(), sentTimeMillis, ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn); } diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java index de49a0e066..6cf0e2572c 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java @@ -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 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() {{if (avatar != null) add(avatar);}}, System.currentTimeMillis(), ThreadDatabase.DistributionTypes.CONVERSATION, expireIn); diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java index 8376e0204a..865bf866d6 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java @@ -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 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 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() { diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java index f93a124d11..2956b1e467 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java @@ -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 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) { diff --git a/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java b/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java index 92d0b08464..0666d8bf22 100644 --- a/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java +++ b/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java @@ -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() { @@ -74,17 +74,17 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver { long replyThreadId; - Optional preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(addresses); + Optional 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(), System.currentTimeMillis(), subscriptionId, expiresIn, 0); + OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList(), 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); } diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index a5006449d7..ee8d4df59e 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -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 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 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 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)); } } diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationItem.java b/src/org/thoughtcrime/securesms/notifications/NotificationItem.java index 423d56132e..ea1ef661c7 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationItem.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationItem.java @@ -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()))); diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationState.java b/src/org/thoughtcrime/securesms/notifications/NotificationState.java index 9f55d4d7a5..28ba3e3ccc 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationState.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationState.java @@ -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()))); diff --git a/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java b/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java index 8bc28a24c1..8372551690 100644 --- a/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java +++ b/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java @@ -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 preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(addresses); + Optional 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(), System.currentTimeMillis(), subscriptionId, expiresIn, 0); + if (recipient.isGroupRecipient()) { + OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList(), 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); } diff --git a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java index 5218966d33..6d0d7eead4 100644 --- a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java +++ b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java @@ -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() + ": ")); } diff --git a/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java b/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java index 92798e1959..8a9e7a4d73 100644 --- a/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java +++ b/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java @@ -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; } } diff --git a/src/org/thoughtcrime/securesms/providers/SingleUseBlobProvider.java b/src/org/thoughtcrime/securesms/providers/SingleUseBlobProvider.java index 08d1d054f5..736c4ec0c5 100644 --- a/src/org/thoughtcrime/securesms/providers/SingleUseBlobProvider.java +++ b/src/org/thoughtcrime/securesms/providers/SingleUseBlobProvider.java @@ -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; diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index 5b0e64ec52..d78c7eb675 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -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 listeners = Collections.newSetFromMap(new WeakHashMap()); private final @NonNull Address address; + private final @NonNull List 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() { @@ -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 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 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() { diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java b/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java index bf83a28607..f7da7c1710 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java @@ -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 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); diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientModifiedListener.java b/src/org/thoughtcrime/securesms/recipients/RecipientModifiedListener.java new file mode 100644 index 0000000000..d6e0955c3f --- /dev/null +++ b/src/org/thoughtcrime/securesms/recipients/RecipientModifiedListener.java @@ -0,0 +1,6 @@ +package org.thoughtcrime.securesms.recipients; + + +public interface RecipientModifiedListener { + public void onModified(Recipient recipient); +} diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index f3d52ca32f..f8b3209f0f 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -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 STATIC_DETAILS = new HashMap() {{ 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 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 getRecipientDetailsAsync(final Context context, final @NonNull Address address) @@ -117,7 +93,7 @@ class RecipientProvider { Callable task = new Callable() { @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 preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(new Address[]{address}); - MaterialColor color = preferences.isPresent() ? preferences.get().getColor() : null; + Optional 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
memberAddresses = record.getMembers(); + List 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 getRecipientsPreferencesAsync(final Context context, final Address[] addresses) { - ListenableFutureTask task = new ListenableFutureTask<>(new Callable() { - @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 participants; public RecipientDetails(@Nullable String name, @Nullable String customLabel, @Nullable Uri contactUri, @NonNull ContactPhoto avatar, - @Nullable MaterialColor color) + @Nullable RecipientsPreferences preferences, + @Nullable List 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() : participants; } } @@ -262,26 +214,4 @@ class RecipientProvider { } - private static class RecipientsCache { - - private final Map 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(); - } - } - - } - - - } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/recipients/Recipients.java b/src/org/thoughtcrime/securesms/recipients/Recipients.java deleted file mode 100644 index 7d83c95eba..0000000000 --- a/src/org/thoughtcrime/securesms/recipients/Recipients.java +++ /dev/null @@ -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 . - */ -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, RecipientModifiedListener { - - private static final String TAG = Recipients.class.getSimpleName(); - - private final Set listeners = Collections.newSetFromMap(new WeakHashMap()); - private final List 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(), null); - } - - Recipients(List 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 recipients, - @Nullable Recipients stale, - @NonNull ListenableFutureTask 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() { - @Override - public void onSuccess(RecipientsPreferences result) { - if (result != null) { - - Set 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 getRecipientsList() { - return this.recipients; - } - - public Address[] getAddresses() { - Address[] addresses = new Address[recipients.size()]; - for (int i=0;i getAddressesList() { - List
results = new LinkedList<>(); - Collections.addAll(results, getAddresses()); - - return results; - } - - public String toShortString() { - String fromString = ""; - - for (int i=0;i iterator() { - return recipients.iterator(); - } - - @Override - public void onModified(Recipient recipient) { - notifyListeners(); - } - - private void notifyListeners() { - Set 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); - } - -} diff --git a/src/org/thoughtcrime/securesms/service/DirectShareService.java b/src/org/thoughtcrime/securesms/service/DirectShareService.java index 48ac80d34f..1d9b55e202 100644 --- a/src/org/thoughtcrime/securesms/service/DirectShareService.java +++ b/src/org/thoughtcrime/securesms/service/DirectShareService.java @@ -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()); diff --git a/src/org/thoughtcrime/securesms/service/QuickResponseService.java b/src/org/thoughtcrime/securesms/service/QuickResponseService.java index 28197bb76b..9b8d0d5ecf 100644 --- a/src/org/thoughtcrime/securesms/service/QuickResponseService.java +++ b/src/org/thoughtcrime/securesms/service/QuickResponseService.java @@ -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 preferences = DatabaseFactory.getRecipientPreferenceDatabase(this).getRecipientsPreferences(recipients.getAddresses()); + Address address = Address.fromExternal(this, number); + Recipient recipient = RecipientFactory.getRecipientFor(this, address, false); + Optional 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(); diff --git a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java index ff392eb497..570a48aa7b 100644 --- a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java @@ -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; } diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index a29384161b..4d0fe5decf 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -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) { diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingEncryptedMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingEncryptedMessage.java index 042facf703..9f2bfcb87d 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingEncryptedMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingEncryptedMessage.java @@ -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) { diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingIdentityDefaultMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingIdentityDefaultMessage.java index 24890032ce..30bc27a27c 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingIdentityDefaultMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingIdentityDefaultMessage.java @@ -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()); } } diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingIdentityVerifiedMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingIdentityVerifiedMessage.java index 310fbc0035..23d83334c1 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingIdentityVerifiedMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingIdentityVerifiedMessage.java @@ -1,16 +1,16 @@ package org.thoughtcrime.securesms.sms; -import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.recipients.Recipient; public class OutgoingIdentityVerifiedMessage extends OutgoingTextMessage { - public OutgoingIdentityVerifiedMessage(Recipients recipients) { - this(recipients, ""); + public OutgoingIdentityVerifiedMessage(Recipient recipient) { + this(recipient, ""); } - private OutgoingIdentityVerifiedMessage(Recipients recipients, String body) { - super(recipients, body, -1); + private OutgoingIdentityVerifiedMessage(Recipient recipient, String body) { + super(recipient, body, -1); } @Override @@ -20,6 +20,6 @@ public class OutgoingIdentityVerifiedMessage extends OutgoingTextMessage { @Override public OutgoingTextMessage withBody(String body) { - return new OutgoingIdentityVerifiedMessage(getRecipients(), body); + return new OutgoingIdentityVerifiedMessage(getRecipient(), body); } } diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingKeyExchangeMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingKeyExchangeMessage.java index 5a39e155b2..557814c89f 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingKeyExchangeMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingKeyExchangeMessage.java @@ -1,11 +1,11 @@ package org.thoughtcrime.securesms.sms; -import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.recipients.Recipient; public class OutgoingKeyExchangeMessage extends OutgoingTextMessage { - public OutgoingKeyExchangeMessage(Recipients recipients, String message) { - super(recipients, message, -1); + public OutgoingKeyExchangeMessage(Recipient recipient, String message) { + super(recipient, message, -1); } private OutgoingKeyExchangeMessage(OutgoingKeyExchangeMessage base, String body) { diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java index 760e1d9710..440b0afaa6 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java @@ -1,28 +1,28 @@ package org.thoughtcrime.securesms.sms; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; -import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.recipients.Recipient; public class OutgoingTextMessage { - private final Recipients recipients; - private final String message; - private final int subscriptionId; - private final long expiresIn; + private final Recipient recipient; + private final String message; + private final int subscriptionId; + private final long expiresIn; - public OutgoingTextMessage(Recipients recipients, String message, int subscriptionId) { - this(recipients, message, 0, subscriptionId); + public OutgoingTextMessage(Recipient recipient, String message, int subscriptionId) { + this(recipient, message, 0, subscriptionId); } - public OutgoingTextMessage(Recipients recipients, String message, long expiresIn, int subscriptionId) { - this.recipients = recipients; + public OutgoingTextMessage(Recipient recipient, String message, long expiresIn, int subscriptionId) { + this.recipient = recipient; this.message = message; this.expiresIn = expiresIn; this.subscriptionId = subscriptionId; } protected OutgoingTextMessage(OutgoingTextMessage base, String body) { - this.recipients = base.getRecipients(); + this.recipient = base.getRecipient(); this.subscriptionId = base.getSubscriptionId(); this.expiresIn = base.getExpiresIn(); this.message = body; @@ -40,8 +40,8 @@ public class OutgoingTextMessage { return message; } - public Recipients getRecipients() { - return recipients; + public Recipient getRecipient() { + return recipient; } public boolean isKeyExchange() { @@ -70,13 +70,13 @@ public class OutgoingTextMessage { public static OutgoingTextMessage from(SmsMessageRecord record) { if (record.isSecure()) { - return new OutgoingEncryptedMessage(record.getRecipients(), record.getBody().getBody(), record.getExpiresIn()); + return new OutgoingEncryptedMessage(record.getRecipient(), record.getBody().getBody(), record.getExpiresIn()); } else if (record.isKeyExchange()) { - return new OutgoingKeyExchangeMessage(record.getRecipients(), record.getBody().getBody()); + return new OutgoingKeyExchangeMessage(record.getRecipient(), record.getBody().getBody()); } else if (record.isEndSession()) { - return new OutgoingEndSessionMessage(new OutgoingTextMessage(record.getRecipients(), record.getBody().getBody(), 0, -1)); + return new OutgoingEndSessionMessage(new OutgoingTextMessage(record.getRecipient(), record.getBody().getBody(), 0, -1)); } else { - return new OutgoingTextMessage(record.getRecipients(), record.getBody().getBody(), record.getExpiresIn(), record.getSubscriptionId()); + return new OutgoingTextMessage(record.getRecipient(), record.getBody().getBody(), record.getExpiresIn(), record.getSubscriptionId()); } } diff --git a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java index c413b27fc4..56de76eeee 100644 --- a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java +++ b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java @@ -24,7 +24,7 @@ import org.thoughtcrime.securesms.database.TextSecureDirectory; import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.push.AccountManagerFactory; -import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.sms.IncomingJoinedMessage; import org.thoughtcrime.securesms.util.DirectoryHelper.UserCapabilities.Capability; import org.whispersystems.libsignal.util.guava.Optional; @@ -123,12 +123,12 @@ public class DirectoryHelper { public static UserCapabilities refreshDirectoryFor(@NonNull Context context, @Nullable MasterSecret masterSecret, - @NonNull Recipients recipients) + @NonNull Recipient recipient) throws IOException { TextSecureDirectory directory = TextSecureDirectory.getInstance(context); SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context); - String number = recipients.getPrimaryRecipient().getAddress().serialize(); + String number = recipient.getAddress().serialize(); Optional details = accountManager.getContact(number); if (details.isPresent()) { @@ -156,10 +156,10 @@ public class DirectoryHelper { } public static @NonNull UserCapabilities getUserCapabilities(@NonNull Context context, - @Nullable Recipients recipients) + @Nullable Recipient recipient) { try { - if (recipients == null) { + if (recipient == null) { return UserCapabilities.UNSUPPORTED; } @@ -167,15 +167,15 @@ public class DirectoryHelper { return UserCapabilities.UNSUPPORTED; } - if (!recipients.isSingleRecipient()) { + if (recipient.isMmsGroupRecipient()) { return UserCapabilities.UNSUPPORTED; } - if (recipients.isGroupRecipient()) { + if (recipient.isPushGroupRecipient()) { return new UserCapabilities(Capability.SUPPORTED, Capability.UNSUPPORTED, Capability.UNSUPPORTED); } - final Address address = recipients.getPrimaryRecipient().getAddress(); + final Address address = recipient.getAddress(); boolean secureText = TextSecureDirectory.getInstance(context).isSecureTextSupported(address); diff --git a/src/org/thoughtcrime/securesms/util/GroupUtil.java b/src/org/thoughtcrime/securesms/util/GroupUtil.java index ba971b793e..0e1bf17689 100644 --- a/src/org/thoughtcrime/securesms/util/GroupUtil.java +++ b/src/org/thoughtcrime/securesms/util/GroupUtil.java @@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.R; 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.RecipientModifiedListener; import java.io.IOException; import java.util.LinkedList; @@ -19,11 +19,12 @@ import static org.whispersystems.signalservice.internal.push.SignalServiceProtos public class GroupUtil { - private static final String ENCODED_GROUP_PREFIX = "__textsecure_group__!"; + private static final String ENCODED_SIGNAL_GROUP_PREFIX = "__textsecure_group__!"; + private static final String ENCODED_MMS_GROUP_PREFIX = "__signal_mms_group__!"; private static final String TAG = GroupUtil.class.getSimpleName(); - public static String getEncodedId(byte[] groupId) { - return ENCODED_GROUP_PREFIX + Hex.toStringCondensed(groupId); + public static String getEncodedId(byte[] groupId, boolean mms) { + return mms ? ENCODED_MMS_GROUP_PREFIX : ENCODED_SIGNAL_GROUP_PREFIX + Hex.toStringCondensed(groupId); } public static byte[] getDecodedId(String groupId) throws IOException { @@ -35,7 +36,11 @@ public class GroupUtil { } public static boolean isEncodedGroup(@NonNull String groupId) { - return groupId.startsWith(ENCODED_GROUP_PREFIX); + return groupId.startsWith(ENCODED_SIGNAL_GROUP_PREFIX) || groupId.startsWith(ENCODED_MMS_GROUP_PREFIX); + } + + public static boolean isMmsGroup(@NonNull String groupId) { + return groupId.startsWith(ENCODED_MMS_GROUP_PREFIX); } public static @NonNull GroupDescription getDescription(@NonNull Context context, @Nullable String encodedGroup) { @@ -56,7 +61,7 @@ public class GroupUtil { @NonNull private final Context context; @Nullable private final GroupContext groupContext; - @Nullable private final Recipients members; + @Nullable private final List members; public GroupDescription(@NonNull Context context, @Nullable GroupContext groupContext) { this.context = context.getApplicationContext(); @@ -65,13 +70,11 @@ public class GroupUtil { if (groupContext == null || groupContext.getMembersList().isEmpty()) { this.members = null; } else { - List
adddresses = new LinkedList<>(); + this.members = new LinkedList<>(); for (String member : groupContext.getMembersList()) { - adddresses.add(Address.fromExternal(context, member)); + this.members.add(RecipientFactory.getRecipientFor(context, Address.fromExternal(context, member), true)); } - - this.members = RecipientFactory.getRecipientsFor(context, adddresses.toArray(new Address[0]), true); } } @@ -88,7 +91,7 @@ public class GroupUtil { if (members != null) { description.append("\n"); description.append(context.getResources().getQuantityString(R.plurals.GroupUtil_joined_the_group, - members.getRecipientsList().size(), members.toShortString())); + members.size(), toString(members))); } if (title != null && !title.trim().isEmpty()) { @@ -100,10 +103,25 @@ public class GroupUtil { return description.toString(); } - public void addListener(Recipients.RecipientsModifiedListener listener) { + public void addListener(RecipientModifiedListener listener) { if (this.members != null) { - this.members.addListener(listener); + for (Recipient member : this.members) { + member.addListener(listener); + } } } + + private String toString(List recipients) { + String result = ""; + + for (int i=0;i