diff --git a/src/org/thoughtcrime/securesms/BindableConversationItem.java b/src/org/thoughtcrime/securesms/BindableConversationItem.java index 2be2e707164..9a9b64254fb 100644 --- a/src/org/thoughtcrime/securesms/BindableConversationItem.java +++ b/src/org/thoughtcrime/securesms/BindableConversationItem.java @@ -4,7 +4,7 @@ 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 @@ void bind(@NonNull MasterSecret masterSecret, @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 9096f823d98..b83f91cec74 100644 --- a/src/org/thoughtcrime/securesms/BlockedContactsActivity.java +++ b/src/org/thoughtcrime/securesms/BlockedContactsActivity.java @@ -20,13 +20,11 @@ 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 void onLoaderReset(Loader loader) { @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 View newView(Context context, Cursor cursor, ViewGroup parent) { @Override public void bindView(View view, Context context, Cursor cursor) { - String addressesConcat = cursor.getString(1); - List
addresses = Address.fromSerializedList(addressesConcat, ' '); - - Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), true); + String address = cursor.getString(1); + Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(address), 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 c33a6c4ff5d..90a46f7dabb 100644 --- a/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java +++ b/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java @@ -14,7 +14,6 @@ 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.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 @@ private void processPendingMessageRecords(long threadId, IdentityKeyMismatch mis 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 543b8d0096d..12ffff669ea 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -132,8 +132,7 @@ 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 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 @@ 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 @@ protected void onResume() { 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 void onConfigurationChanged(Configuration newConfig) { @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 void onActivityResult(final int reqCode, int resultCode, Intent data) { 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 void onActivityResult(final int reqCode, int resultCode, Intent data) { } 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 boolean onPrepareOptionsMenu(Menu menu) { 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 void onClick(View v) { 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 boolean onOptionsItemSelected(MenuItem item) { 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 @@ private void handleSelectMessageExpiration() { 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 @@ private void handleMuteNotifications() { 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 @@ private void handleConversationSettings() { } 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 @@ private void handleUnblock() { .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 @@ private void handleInviteLink() { 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 void onClick(DialogInterface dialog, int which) { 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 @@ protected void onPostExecute(Long result) { 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 @@ private void handleLeavePushGroup() { 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 void onClick(DialogInterface dialog, int which) { 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 @@ private void handleDial(final Recipient recipient) { } 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 @@ private void handleSecurityChange(boolean isSecureText, boolean isDefaultSms) { 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 @@ private ListenableFuture initializeSecurity(final boolean currentSecure 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 @@ protected void onPostExecute(boolean[] result) { future.set(true); onSecurityUpdated(); } - }.execute(recipients); + }.execute(recipient); return future; } @@ -1050,7 +1049,7 @@ private void onSecurityUpdated() { } private void updateRecipientPreferences() { - new RecipientPreferencesTask().execute(recipients); + new RecipientPreferencesTask().execute(recipient); } protected void updateInviteReminder(boolean seenInvite) { @@ -1059,11 +1058,9 @@ protected void updateInviteReminder(boolean seenInvite) { 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 @@ protected void onPostExecute(Boolean isMmsEnabled) { 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]; - - if (recipients.isGroupRecipient()) { - recipients = DatabaseFactory.getGroupDatabase(ConversationActivity.this) - .getGroupMembers(GroupUtil.getDecodedId(recipients.getPrimaryRecipient().getAddress().toGroupString()), false); - } + protected @NonNull Pair doInBackground(Recipient... params) { + IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this); + IdentityRecordList identityRecordList = new IdentityRecordList(); + List recipients = new LinkedList<>(); + + if (params[0].isGroupRecipient()) { + recipients.addAll(DatabaseFactory.getGroupDatabase(ConversationActivity.this) + .getGroupMembers(params[0].getAddress().toGroupString(), false)); + } else { + recipients.add(params[0]); + } - for (Address recipientAddress : recipients.getAddresses()) { - Log.w(TAG, "Loading identity for: " + recipientAddress); - identityRecordList.add(identityDatabase.getIdentity(recipientAddress)); - } + for (Recipient recipient : recipients) { + Log.w(TAG, "Loading identity for: " + recipient.getAddress()); + identityRecordList.add(identityDatabase.getIdentity(recipient.getAddress())); + } - String message = null; + 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 (identityRecordList.isUnverified()) { + message = IdentityUtil.getUnverifiedBannerDescription(ConversationActivity.this, identityRecordList.getUnverifiedRecipients(ConversationActivity.this)); } + + return new Pair<>(identityRecordList, message); } @Override @@ -1149,7 +1144,7 @@ protected void onPostExecute(@NonNull Pair result) { future.set(true); } - }.execute(recipients); + }.execute(recipient); return future; } @@ -1212,7 +1207,7 @@ public void onChange(TransportOption newTransport, boolean manuallySelected) { @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 @@ protected void initializeActionBar() { } 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 @@ private void initializeResources() { conversationContainer.setClipToPadding(true); } - recipients.addListener(this); + recipient.addListener(this); } private void initializeProfiles() { @@ -1281,18 +1276,18 @@ private void initializeProfiles() { 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 void run() { @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 void onReceive(Context context, Intent intent) { @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 @@ private Drafts getDraftsForCurrentState() { 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 @@ protected Long doInBackground(Long... params) { 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 @@ private void setActionBarColor(MaterialColor color) { 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 @@ private void calculateCharactersRemaining() { } 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 @@ protected void sendComplete(long threadId) { fragment.setLastSeen(0); if (refreshFragment) { - fragment.reload(recipients, threadId); + fragment.reload(recipient, threadId); MessageNotifier.setVisibleThread(threadId); } @@ -1602,26 +1588,26 @@ protected void sendComplete(long threadId) { 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 @@ private ListenableFuture sendMediaMessage(final boolean forceSms, String b { 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 @@ private void sendTextMessage(final boolean forceSms, final long expiresIn, final 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 @@ private void recordSubscriptionIdPreference(final Optional subscription @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 void onSuccess(final @NonNull Pair result) { 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 void onAttachmentChanged() { 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 fa163789bd8..ef67b21c82f 100644 --- a/src/org/thoughtcrime/securesms/ConversationAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationAdapter.java @@ -41,7 +41,7 @@ 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 interface ItemClickListener { 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 ConversationAdapter(@NonNull Context context, @NonNull Locale locale, @Nullable ItemClickListener clickListener, @Nullable Cursor cursor, - @NonNull Recipients recipients) + @NonNull Recipient recipient) { super(context, cursor); @@ -166,7 +166,7 @@ public ConversationAdapter(@NonNull Context context, 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 void changeCursor(Cursor cursor) { @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 5ca0167171f..f2f9c1bef23 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.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 void reloadList() { } 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 @@ private void initializeResources() { } 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 @@ private MessageRecord getSelectedMessageRecord() { 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 @@ private void handleDisplayDetails(MessageRecord message) { 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 dd5902bb754..c57621c6b1e 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -70,7 +70,7 @@ 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 @@ */ 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 void bind(@NonNull MasterSecret masterSecret, @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 @@ private void setBubbleState(MessageRecord messageRecord, Recipient recipient) { } 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 void run() { 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 void onClick(View v) { 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 fe137faa115..377405983b8 100644 --- a/src/org/thoughtcrime/securesms/ConversationListActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java @@ -37,8 +37,8 @@ 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 boolean onOptionsItemSelected(MenuItem item) { } @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 726c523dcb1..8c3dd8e3bcb 100644 --- a/src/org/thoughtcrime/securesms/ConversationListAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationListAdapter.java @@ -78,13 +78,8 @@ public BindableConversationListItem getItem() { @Override public long getItemId(@NonNull Cursor cursor) { ThreadRecord record = getThreadRecord(cursor); - StringBuilder builder = new StringBuilder("" + record.getThreadId()); - for (Address address : record.getRecipients().getAddresses()) { - builder.append("::").append(address.serialize()); - } - - return Conversions.byteArrayToLong(digest.digest(builder.toString().getBytes())); + return Conversions.byteArrayToLong(digest.digest(record.getRecipient().getAddress().serialize().getBytes())); } public ConversationListAdapter(@NonNull Context context, diff --git a/src/org/thoughtcrime/securesms/ConversationListArchiveActivity.java b/src/org/thoughtcrime/securesms/ConversationListArchiveActivity.java index 67ed29eaca2..62982a3c041 100644 --- a/src/org/thoughtcrime/securesms/ConversationListArchiveActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationListArchiveActivity.java @@ -6,7 +6,7 @@ import android.view.MenuItem; import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; @@ -54,9 +54,9 @@ public boolean onOptionsItemSelected(MenuItem item) { } @Override - public void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeenTime) { + public void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeenTime) { Intent intent = new Intent(this, ConversationActivity.class); - intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses()); + intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress()); intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId); intent.putExtra(ConversationActivity.IS_ARCHIVED_EXTRA, true); intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType); diff --git a/src/org/thoughtcrime/securesms/ConversationListFragment.java b/src/org/thoughtcrime/securesms/ConversationListFragment.java index c3d728b03c3..15e09985152 100644 --- a/src/org/thoughtcrime/securesms/ConversationListFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationListFragment.java @@ -69,7 +69,7 @@ import org.thoughtcrime.securesms.database.loaders.ConversationListLoader; import org.thoughtcrime.securesms.notifications.MarkReadReceiver; import org.thoughtcrime.securesms.notifications.MessageNotifier; -import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask; @@ -309,8 +309,8 @@ private void handleSelectAllThreads() { getListAdapter().getBatchSelections().size())); } - private void handleCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeen) { - ((ConversationSelectedListener)getActivity()).onCreateConversation(threadId, recipients, distributionType, lastSeen); + private void handleCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen) { + ((ConversationSelectedListener)getActivity()).onCreateConversation(threadId, recipient, distributionType, lastSeen); } @Override @@ -331,7 +331,7 @@ public void onLoaderReset(Loader arg0) { @Override public void onItemClick(ConversationListItem item) { if (actionMode == null) { - handleCreateConversation(item.getThreadId(), item.getRecipients(), + handleCreateConversation(item.getThreadId(), item.getRecipient(), item.getDistributionType(), item.getLastSeen()); } else { ConversationListAdapter adapter = (ConversationListAdapter)list.getAdapter(); @@ -363,7 +363,7 @@ public void onSwitchToArchive() { } public interface ConversationSelectedListener { - void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeen); + void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen); void onSwitchToArchive(); } diff --git a/src/org/thoughtcrime/securesms/ConversationListItem.java b/src/org/thoughtcrime/securesms/ConversationListItem.java index 141d94099ae..091bc1e2e97 100644 --- a/src/org/thoughtcrime/securesms/ConversationListItem.java +++ b/src/org/thoughtcrime/securesms/ConversationListItem.java @@ -31,14 +31,15 @@ import android.widget.RelativeLayout; import android.widget.TextView; +import org.thoughtcrime.securesms.components.AlertView; import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.DeliveryStatusView; -import org.thoughtcrime.securesms.components.AlertView; import org.thoughtcrime.securesms.components.FromTextView; import org.thoughtcrime.securesms.components.ThumbnailView; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.ThreadRecord; -import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.ResUtil; import org.thoughtcrime.securesms.util.ViewUtil; @@ -56,7 +57,7 @@ */ public class ConversationListItem extends RelativeLayout - implements Recipients.RecipientsModifiedListener, + implements RecipientModifiedListener, BindableConversationListItem, Unbindable { private final static String TAG = ConversationListItem.class.getSimpleName(); @@ -65,7 +66,7 @@ public class ConversationListItem extends RelativeLayout private final static Typeface LIGHT_TYPEFACE = Typeface.create("sans-serif-light", Typeface.NORMAL); private Set selectedThreads; - private Recipients recipients; + private Recipient recipient; private long threadId; private TextView subjectView; private FromTextView fromView; @@ -116,14 +117,14 @@ public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord threa @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 void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord threa 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 @@ private void setBackground(ThreadRecord thread) { } @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 8e1164719eb..56cf4b2a3f1 100644 --- a/src/org/thoughtcrime/securesms/ConversationPopupActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationPopupActivity.java @@ -84,7 +84,7 @@ public boolean onOptionsItemSelected(MenuItem item) { 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 86a35278bae..ce7740a163e 100644 --- a/src/org/thoughtcrime/securesms/ConversationTitleView.java +++ b/src/org/thoughtcrime/securesms/ConversationTitleView.java @@ -10,7 +10,6 @@ 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 void onFinishInflate() { 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 @@ private void setRecipientTitle(Recipient recipient) { 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 ab5e8a6a26b..32ef9ea068d 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.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.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 void bind(@NonNull MasterSecret masterSecret, @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 @@ private void setEndSessionRecord(MessageRecord messageRecord) { 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 82e29e05381..2dea4f85f53 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -62,11 +62,9 @@ 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.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 void onClick(View view) { 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 void onRecipientDeleted(Recipient recipient) { } @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 @@ private void handleGroupCreate() { 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 @@ private void handleGroupUpdate() { 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 void onClick(View v) { } } - 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<>(); + + 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(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(); - } + protected void onPostExecute(GroupActionResult result) { + activity.handleOpenConversation(result.getThreadId(), result.getGroupRecipient()); } @Override @@ -427,11 +419,7 @@ public CreateSignalGroupTask(GroupCreateActivity activity, MasterSecret masterSe @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 @@ protected void onPostExecute(Optional result) { } 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 @@ protected void onPostExecute(Optional result) { 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 @@ protected void onPostExecute(List results) { } } - private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask> { + private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask> { private GroupCreateActivity activity; public FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) { @@ -552,12 +540,12 @@ public FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) { } @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 @@ private void setAvatar(T model, Bitmap bitmap) { } 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 8c90e3981a9..acf675aecdc 100644 --- a/src/org/thoughtcrime/securesms/GroupMembersDialog.java +++ b/src/org/thoughtcrime/securesms/GroupMembersDialog.java @@ -7,48 +7,36 @@ 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 void onPostExecute(Recipients members) { } public void display() { - if (recipients.isGroupRecipient()) execute(); - else onPostExecute(recipients); + execute(); } private static class GroupMembersOnClickListener implements DialogInterface.OnClickListener { @@ -107,8 +94,8 @@ private class GroupMembers { 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 d0b4beded52..b3fb4e262af 100644 --- a/src/org/thoughtcrime/securesms/InviteActivity.java +++ b/src/org/thoughtcrime/securesms/InviteActivity.java @@ -30,8 +30,8 @@ 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 @@ protected Void doInBackground(String... numbers) { 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 a7b6e7623c7..f58fb7b70d9 100644 --- a/src/org/thoughtcrime/securesms/MediaOverviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaOverviewActivity.java @@ -24,7 +24,6 @@ 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.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 @@ 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 void onResume() { } 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 @@ private void initializeResources() { 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 be35e09c7eb..820684e24c7 100644 --- a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java @@ -37,7 +37,7 @@ 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 b518ab9f0df..ea6e6a74988 100644 --- a/src/org/thoughtcrime/securesms/MessageDetailsActivity.java +++ b/src/org/thoughtcrime/securesms/MessageDetailsActivity.java @@ -47,26 +47,25 @@ 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 @@ protected void onDestroy() { 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 @@ private void setActionBarColor(MaterialColor color) { } @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 void run() { }); } - 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 @@ private void updateRecipients(MessageRecord messageRecord, Recipients recipients } 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 boolean onOptionsItemSelected(MenuItem item) { return false; } - private class MessageRecipientAsyncTask extends AsyncTask { + private class MessageRecipientAsyncTask extends AsyncTask> { private WeakReference weakContext; private MessageRecord messageRecord; @@ -335,41 +334,27 @@ protected Context getContext() { } @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 void onPostExecute(Recipients recipients) { 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 a0e39aa0e74..e38afa28d64 100644 --- a/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java +++ b/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java @@ -10,22 +10,22 @@ 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 MessageDetailsRecipientAdapter(Context context, MasterSecret masterSecret @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 View getView(int position, View convertView, ViewGroup parent) { 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 8d2d5715d71..3c8a23c91ee 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.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 @@ * @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 MessageRecipientListItem(Context context, AttributeSet attrs) { @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 void run() { } 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 ResendAsyncTask(MasterSecret masterSecret, MessageRecord record, NetworkF @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 2d43a2631d4..e2025962c04 100644 --- a/src/org/thoughtcrime/securesms/NewConversationActivity.java +++ b/src/org/thoughtcrime/securesms/NewConversationActivity.java @@ -28,8 +28,8 @@ 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 void onCreate(Bundle bundle, @NonNull MasterSecret masterSecret) { @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 849891afb7e..1459e53f8aa 100644 --- a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java +++ b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java @@ -41,8 +41,9 @@ 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 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 void onPreCreate() { 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 @@ private void initializeReceivers() { 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 void onReceive(Context context, Intent intent) { 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 void onCreate(Bundle icicle) { @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 void onReceive(Context context, Intent intent) { 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 @@ private void setSummaries(Recipients recipients) { 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 @@ private void setSummaries(Recipients recipients) { } } - 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 @@ private void setSummaries(Recipients recipients) { 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 void onFailure(ExecutionException e) { } @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 boolean onPreferenceChange(Preference preference, Object newValue) { 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 boolean onPreferenceChange(Preference preference, Object newValue) { 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 @@ private class ColorChangeListener implements Preference.OnPreferenceChangeListen 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 @@ protected Void doInBackground(Void... params) { 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 @@ private void handleMute() { 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 @@ private IdentityClickedListener(IdentityRecord identityKey) { @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 boolean onPreferenceClick(Preference preference) { 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 @@ private void handleBlock() { .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 @@ private void handleUnblock() { .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 @@ protected Void doInBackground(Void... params) { 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 29466bd2ded..c740b58e380 100644 --- a/src/org/thoughtcrime/securesms/ShareActivity.java +++ b/src/org/thoughtcrime/securesms/ShareActivity.java @@ -39,7 +39,7 @@ 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 @@ private void handleNewConversation() { } @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 @@ private void handleResolvedMedia(Intent intent, boolean animate) { 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 9a0a7b14720..3405037feff 100644 --- a/src/org/thoughtcrime/securesms/ShareFragment.java +++ b/src/org/thoughtcrime/securesms/ShareFragment.java @@ -28,10 +28,9 @@ 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 void onListItemClick(ListView l, View v, int position, long id) { if (v instanceof ShareListItem) { ShareListItem headerView = (ShareListItem) v; - handleCreateConversation(headerView.getThreadId(), headerView.getRecipients(), + handleCreateConversation(headerView.getThreadId(), headerView.getRecipient(), headerView.getDistributionType()); } } @@ -84,8 +83,8 @@ private void initializeListAdapter() { 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 void onLoaderReset(Loader arg0) { } 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 716aa1ff40a..00777cc7a86 100644 --- a/src/org/thoughtcrime/securesms/ShareListItem.java +++ b/src/org/thoughtcrime/securesms/ShareListItem.java @@ -25,7 +25,8 @@ 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 @@ * @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 ShareListItem(Context context, AttributeSet attrs) { @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 @@ private void setBackground() { drawables.recycle(); } - public Recipients getRecipients() { - return recipients; + public Recipient getRecipient() { + return recipient; } public long getThreadId() { @@ -101,12 +103,12 @@ public int getDistributionType() { } @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 68fbcbd010a..cda84287023 100644 --- a/src/org/thoughtcrime/securesms/SmsSendtoActivity.java +++ b/src/org/thoughtcrime/securesms/SmsSendtoActivity.java @@ -12,8 +12,8 @@ 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 @@ private Intent getNextIntent(Intent original) { 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 f367d57518e..a36a5e63b85 100644 --- a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java @@ -74,6 +74,7 @@ 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 @@ * * @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 @@ private void setActionBarNotificationBarColor(MaterialColor color) { } } - 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 230b5351346..9c772994553 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.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 AvatarImageView(Context context, AttributeSet attrs) { } } - 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 fc99e4e0250..804fc736a8e 100644 --- a/src/org/thoughtcrime/securesms/components/FromTextView.java +++ b/src/org/thoughtcrime/securesms/components/FromTextView.java @@ -11,8 +11,6 @@ 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 FromTextView(Context context, AttributeSet attrs) { } 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 void setText(Recipients recipients, boolean read) { 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 c49c16d3208..38c4e4cb97a 100644 --- a/src/org/thoughtcrime/securesms/components/PushRecipientsPanel.java +++ b/src/org/thoughtcrime/securesms/components/PushRecipientsPanel.java @@ -19,7 +19,6 @@ 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.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 @@ * * @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 PushRecipientsPanel(Context context, AttributeSet attrs, int defStyle) { 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 @@ private void initialize() { } 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 @@ private void initRecipientsEditor() { @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 @@ private String parseBracketedNumber(String recipient) { } @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 48c0a0dde9a..dbfb8f0493b 100644 --- a/src/org/thoughtcrime/securesms/components/reminder/InviteReminder.java +++ b/src/org/thoughtcrime/securesms/components/reminder/InviteReminder.java @@ -8,22 +8,22 @@ 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 5de9769da79..ec96a21c654 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.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 @@ * @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 34ab6014de8..b55df22a443 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java @@ -11,12 +11,12 @@ 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 void set(long id, int type, String name, String number, String label, int 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 void setChecked(boolean selected) { } public void unbind() { - if (recipients != null) { - recipients.removeListener(this); - recipients = null; + if (recipient != null) { + recipient.removeListener(this); + recipient = null; } } @@ -117,13 +115,13 @@ public String getNumber() { } @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 59a5f8ada4c..3329c87220c 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java @@ -29,8 +29,8 @@ 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 Cursor loadInBackground() { 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 23c6c39f505..7c77dd89480 100644 --- a/src/org/thoughtcrime/securesms/contacts/RecipientsEditor.java +++ b/src/org/thoughtcrime/securesms/contacts/RecipientsEditor.java @@ -30,16 +30,12 @@ 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 static CharSequence contactToToken(Recipient c) { 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 6104c9e5baa..a14ea3a6b8e 100644 --- a/src/org/thoughtcrime/securesms/database/Address.java +++ b/src/org/thoughtcrime/securesms/database/Address.java @@ -96,20 +96,14 @@ public static Address fromExternal(@NonNull Context context, @Nullable String ex return Util.join(escapedAddresses, delimiter + ""); } - public static Address[] fromParcelable(Parcelable[] parcelables) { - Address[] addresses = new Address[parcelables.length]; - - for (int i=0;i 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 4a44a96850d..e4b6f4a6908 100644 --- a/src/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/src/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -14,7 +14,6 @@ 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 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 GroupDatabase(Context context, SQLiteOpenHelper databaseHelper) { 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 GroupDatabase(Context context, SQLiteOpenHelper databaseHelper) { return record; } - public boolean isUnknownGroup(byte[] groupId) { + public boolean isUnknownGroup(String groupId) { return getGroup(groupId) == null; } @@ -94,12 +96,32 @@ public Reader getGroupsFilteredByTitle(String constraint) { 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 Reader getGroups() { 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 void create(byte[] groupId, String title, List
members, 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 void update(byte[] groupId, String title, SignalServiceAttachmentPointer 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 @@ private List
getCurrentMembers(byte[] id) { } } - 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 Reader(Cursor cursor) { 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 static class GroupRecord { 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 GroupRecord(String id, String title, String members, byte[] avatar, this.avatarContentType = avatarContentType; this.relay = relay; this.active = active; + this.mms = mms; } public byte[] getId() { @@ -358,5 +388,9 @@ public String getRelay() { 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 d31deed4dde..00000000000 --- 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 21302a222b4..00000000000 --- 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 248ae23aaf4..6df470108da 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -30,7 +30,6 @@ 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.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 void removeFailure(long messageId, NetworkFailure failure) { } 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))); - - for (Address theirAddress : addresses) { - Address ourAddress = messageId.getAddress(); + Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))); + 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 long getThreadIdForMessage(long id) { 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(); - } - - 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); - } - - } + Recipient sender = RecipientFactory.getRecipientFor(context, retrieved.getFrom(), true); + return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(sender); } - - 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 List setMessagesRead(long threadId) { } 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))); - - for (Address theirAddress : addresses) { - Address ourAddress = messageId.getAddress(); + Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))); + 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)); - } + 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)}); + database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)}); - DatabaseFactory.getThreadDatabase(context).updateReadState(threadId); - DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId); - notifyConversationListeners(threadId); - } + DatabaseFactory.getThreadDatabase(context).updateReadState(threadId); + DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId); + notifyConversationListeners(threadId); } } } finally { @@ -592,7 +535,6 @@ public Optional getNotification(long messageId) { 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 OutgoingMediaMessage getOutgoingMessage(MasterSecret masterSecret, long m 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); - - destinations.addAll(addresses.getBcc()); - destinations.addAll(addresses.getCc()); - destinations.addAll(addresses.getTo()); - - Recipients recipients = RecipientFactory.getRecipientsFor(context, destinations.toArray(new Address[0]), false); + 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); + + 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 long copyMessageInbox(MasterSecret masterSecret, long messageId) throws M 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 long copyMessageInbox(MasterSecret masterSecret, long messageId) throws M } return insertMediaMessage(new MasterSecretUnion(masterSecret), - MmsAddresses.forTo(request.getRecipients().getAddressesList()), request.getBody(), attachments, contentValues, @@ -703,7 +640,7 @@ private Optional insertMessageInbox(MasterSecretUnion masterSecret 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 @@ private Optional insertMessageInbox(MasterSecretUnion masterSecret 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 Optional insertSecureDecryptedMessageInbox(MasterSecretUnio } 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 Pair insertMessageInbox(@NonNull NotificationInd notification 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 Pair insertMessageInbox(@NonNull NotificationInd notification 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 long insertMessageOutbox(@NonNull MasterSecretUnion masterSecret, 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 long insertMessageOutbox(@NonNull MasterSecretUnion masterSecret, 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 @@ private String getEncryptedBody(MasterSecretUnion masterSecret, String body) { } private long insertMediaMessage(@NonNull MasterSecretUnion masterSecret, - @NonNull MmsAddresses addresses, @Nullable String body, @NonNull List attachments, @NonNull ContentValues contentValues, @@ -937,7 +847,6 @@ private long insertMediaMessage(@NonNull MasterSecretUnion masterSecret, { 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 @@ private long insertMediaMessage(@NonNull MasterSecretUnion masterSecret, try { long messageId = db.insert(TABLE_NAME, null, contentValues); - addressDatabase.insertAddressesForId(messageId, addresses); partsDatabase.insertAttachmentsForMessage(masterSecret, messageId, attachments); db.setTransactionSuccessful(); @@ -972,10 +880,8 @@ private long insertMediaMessage(@NonNull MasterSecretUnion masterSecret, 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 void deleteThread(long threadId) { 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 @@ private boolean isDuplicate(IncomingMediaMessage message, long threadId) { 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 OutgoingMessageReader(OutgoingMediaMessage message, long threadId) { 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 @@ private NotificationMmsMessageRecord getNotificationMmsMessageRecord(Cursor curs 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 @@ private NotificationMmsMessageRecord getNotificationMmsMessageRecord(Cursor curs 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 @@ private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) { 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 @@ private Recipients getRecipientsFor(String serialized) { 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 f48bcde277f..92bb9fb478d 100644 --- a/src/org/thoughtcrime/securesms/database/PlaintextBackupImporter.java +++ b/src/org/thoughtcrime/securesms/database/PlaintextBackupImporter.java @@ -8,8 +8,8 @@ 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 static void importPlaintextFromSd(Context context, MasterSecret masterSec 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 2734f024f22..558e5e8d19a 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java @@ -12,13 +12,10 @@ 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 static VibrateState fromId(int id) { 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 RecipientPreferenceDatabase(Context context, SQLiteOpenHelper databaseHel 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 BlockedReader readerForBlocked(Cursor cursor) { 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 Optional getRecipientsPreferences(@NonNull Address } } - 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 static class BlockedReader { 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 static class BlockedReader { 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 5b31b59da2e..5defe8f1547 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.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 Pair copyMessageInbox(long messageId) { } 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 @@ protected Optional insertMessageInbox(IncomingTextMessage message, 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 @@ protected Optional insertMessageInbox(IncomingTextMessage message, 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 @@ protected Optional insertMessageInbox(IncomingTextMessage message, } if (message.getSubscriptionId() != -1) { - DatabaseFactory.getRecipientPreferenceDatabase(context).setDefaultSubscriptionId(recipients, message.getSubscriptionId()); + DatabaseFactory.getRecipientPreferenceDatabase(context).setDefaultSubscriptionId(recipient, message.getSubscriptionId()); } notifyConversationListeners(threadId); @@ -589,7 +589,7 @@ protected long insertMessageOutbox(long threadId, OutgoingTextMessage message, 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 OutgoingMessageReader(OutgoingTextMessage message, long threadId) { 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 SmsMessageRecord getCurrent() { 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 1a253d3a7b4..15c6b40b3e9 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.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 @@ private static String getTheirCanonicalAddress(Context context, String theirReci } } - 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 static void migrateDatabase(Context context, 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 8fcea43a4c6..5758e5004a0 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.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 ThreadDatabase(Context context, SQLiteOpenHelper databaseHelper) { 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 void setDistributionType(long threadId, int distributionType) { 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 Cursor getFilteredConversationList(List
filter) { 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 long getThreadIdIfExistsFor(Recipients recipients) { } } - 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 long getThreadIdFor(Recipients recipients, int distributionType) { 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 long getThreadIdFor(Recipients recipients, int distributionType) { } } - public @Nullable Recipients getRecipientsForThreadId(long threadId) { + public @Nullable Recipient getRecipientForThreadId(long threadId) { SQLiteDatabase db = databaseHelper.getReadableDatabase(); Cursor cursor = null; @@ -463,8 +476,8 @@ public long getThreadIdFor(Recipients recipients, int distributionType) { 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 ThreadRecord getNext() { } 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 ThreadRecord getCurrent() { 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 4ffe26a39d9..30b29ce76cc 100644 --- a/src/org/thoughtcrime/securesms/database/loaders/ConversationListLoader.java +++ b/src/org/thoughtcrime/securesms/database/loaders/ConversationListLoader.java @@ -42,7 +42,7 @@ private Cursor getUnarchivedConversationList() { 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 f480033a105..803fc6104d6 100644 --- a/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -21,7 +21,7 @@ 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 boolean isOutgoing() { 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 dead6bfa0ba..4b126753cea 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.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 MediaMmsMessageRecord(Context context, long id, Recipients recipients, 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 ff269e04d0f..8906c9297f0 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.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 ebde8209b03..5c16f6022cd 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.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 13e5d9f353e..8a63c1cf0b2 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.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 2a8ab4a3b84..e92ceef6010 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.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 @@ 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 SmsMessageRecord(Context context, long id, 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 e165ebdb886..aac177c28c9 100644 --- a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -28,7 +28,7 @@ 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 SpannableString getDisplayBody() { } 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 73740ec4454..af06662774e 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.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,41 +42,37 @@ 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); - } - private static Set
getMemberAddresses(Context context, Collection recipients) - throws InvalidNumberException - { - final Set
results = new HashSet<>(); - for (Recipient recipient : recipients) { - results.add(recipient.getAddress()); + 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); } - - return results; } public static GroupActionResult updateGroup(@NonNull Context context, @NonNull MasterSecret masterSecret, - @NonNull byte[] groupId, + @NonNull String 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 Set
memberAddresses = getMemberAddresses(members); final byte[] avatarBytes = BitmapUtil.toByteArray(avatar); memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context))); @@ -82,54 +80,73 @@ public static GroupActionResult updateGroup(@NonNull Context context, groupDatabase.updateTitle(groupId, name); groupDatabase.updateAvatar(groupId, avatarBytes); - return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, 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 byte[] groupId, + @NonNull String 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()); + 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); } + } - 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); + private static Set
getMemberAddresses(Collection recipients) { + final Set
results = new HashSet<>(); + for (Recipient recipient : recipients) { + results.add(recipient.getAddress()); } - 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); + return results; } 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 f48c2708bdc..c3529dc0ba8 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.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 @@ private static Long handleGroupLeave(@NonNull Context context, 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 @@ private static Long handleGroupLeave(@NonNull Context context, 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 c511108dc2a..9e9b8bc8394 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.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 void onAdded() {} @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 void onRun(MasterSecret masterSecret) throws IOException { 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 a7939573ddb..3c2221b7e3f 100644 --- a/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java +++ b/src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java @@ -8,10 +8,9 @@ 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 @@ 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 DirectoryRefreshJob(@NonNull Context context) { 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 void onRun() throws IOException { 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 34d933edd25..b5255531da7 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.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.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 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 void onRun(MasterSecret masterSecret) { 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 @@ private void storeRetrievedMms(MasterSecret masterSecret, String contentLocation { 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 @@ private void storeRetrievedMms(MasterSecret masterSecret, String contentLocation } } + 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 1411299be13..5cbb700954f 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.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 boolean onShouldRetry(Exception exception) { 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 24a356ec40a..10b1153805b 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.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.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 @@ private SendReq constructSendPdu(MasterSecret masterSecret, OutgoingMediaMessage { 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 @@ private long getPartSize(PduPart part) { } 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 67ac8e40364..3f358eb6cf3 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.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 void onRun(MasterSecret masterSecret) 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 4fe5f9a6a22..2672f2c590b 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.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.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 @@ private void handleMessage(MasterSecretUnion masterSecret, SignalServiceEnvelope 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 @@ private long handleSynchronizeSentEndSessionMessage(@NonNull MasterSecretUnion @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 @@ private void handleExpirationUpdate(@NonNull MasterSecretUnion masterSecret, 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 @@ private void handleExpirationUpdate(@NonNull MasterSecretUnion masterSecret, 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 @@ private void handleSynchronizeSentMessage(@NonNull MasterSecretUnion masterSecre 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 @@ private void handleMediaMessage(@NonNull MasterSecretUnion masterSecret, 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 @@ private void handleMediaMessage(@NonNull MasterSecretUnion masterSecret, message.getGroupInfo(), message.getAttachments()); - if (message.getExpiresInSeconds() != recipients.getExpireMessages()) { + if (message.getExpiresInSeconds() != recipient.getExpireMessages()) { handleExpirationUpdate(masterSecret, envelope, message, Optional.absent()); } @@ -537,18 +532,18 @@ private long handleSynchronizeSentExpirationUpdate(@NonNull MasterSecretUnion ma 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 @@ private long handleSynchronizeSentMediaMessage(@NonNull MasterSecretUnion master 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 @@ private void handleTextMessage(@NonNull MasterSecretUnion masterSecret, { 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 @@ private long handleSynchronizeSentTextMessage(@NonNull MasterSecretUnion masterS 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 @@ private Optional insertPlaceholder(@NonNull SignalServiceEnvelope 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 ce57af90a8f..5fbb4b30c9f 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.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 @@ private void deliver(MasterSecret masterSecret, OutgoingMediaMessage message, @N 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 @@ private void deliver(MasterSecret masterSecret, OutgoingMediaMessage message, @N 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 @@ private List getPushAddresses(Address address) { 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 30d30703dee..3a2e9ef1ad7 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.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 void onAdded() {} 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 9c538b1f14f..f9cfa11117e 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -102,14 +102,14 @@ private void deliver(MasterSecret masterSecret, OutgoingMediaMessage message) 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 ecf8fc638fa..3af1212491a 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.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 void handle(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) 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 void handle(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) } 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 060f19bb413..f17baceba6f 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.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 void onAttachmentProgress(long total, long progress) { } 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 402033edc50..27c099f663d 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.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 void onPushSend(MasterSecret masterSecret) throws NoSuchMessageException, } 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 boolean onShouldRetryThrowable(Exception exception) { 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 1ba656681a2..9212656a33c 100644 --- a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java @@ -9,10 +9,8 @@ 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.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 void onAdded() {} @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 @@ private void handleIndividualRecipient(Recipient recipient) 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 9959fb9896d..2e019c602ca 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java @@ -9,13 +9,12 @@ 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 boolean onShouldRetry(Exception exception) { 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 944ff9a8647..45f2b25578a 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.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 void onSend(MasterSecret masterSecret) throws NoSuchMessageException { } 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 boolean onShouldRetryThrowable(Exception throwable) { @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 5d2c7ebb383..f7067335cac 100644 --- a/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java +++ b/src/org/thoughtcrime/securesms/jobs/SmsSentJob.java @@ -86,7 +86,7 @@ private void handleSentResult(MasterSecret masterSecret, long messageId, int res 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 9eae8996837..1d5a02b525f 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 @@ 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 IncomingMediaMessage(MasterSecretUnion masterSecret, 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 String getBody() { 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 long getExpiresIn() { } 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 1dbe3363930..a104793424b 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java @@ -2,14 +2,14 @@ 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 de49a0e066e..6cf0e2572c9 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java @@ -5,7 +5,7 @@ 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 8376e0204ad..865bf866d68 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java @@ -3,13 +3,13 @@ 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 OutgoingMediaMessage(Recipients recipients, String message, 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 OutgoingMediaMessage(Recipients recipients, SlideDeck slideDeck, String m } 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 OutgoingMediaMessage(OutgoingMediaMessage that) { 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 f93a124d11c..2956b1e4679 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 92d0b08464c..0666d8bf22a 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.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 @@ protected void onReceive(final Context context, Intent intent, 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 @@ protected Void doInBackground(Void... params) { 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 a5006449d77..ee8d4df59e7 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.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 static void setLastDesktopActivityTimestamp(long timestamp) { 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 static void updateNotification(@NonNull Context context, 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 static void updateNotification(@NonNull Context context, } if (isVisible) { - sendInThreadNotification(context, threads.getRecipientsForThreadId(threadId)); + sendInThreadNotification(context, threads.getRecipientForThreadId(threadId)); } else { updateNotification(context, masterSecret, signal, 0); } @@ -299,13 +298,13 @@ private static void sendSingleThreadNotification(@NonNull Context context, 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 @@ private static void sendSingleThreadNotification(@NonNull Context context, 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 @@ private static void sendMultipleThreadNotification(@NonNull Context context, 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 @@ private static NotificationState constructNotificationState(@NonNull Context co 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 @@ private static NotificationState constructNotificationState(@NonNull Context co } 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 423d56132e8..ea1ef661c75 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationItem.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationItem.java @@ -11,15 +11,14 @@ 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 long getThreadId() { 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 9f55d4d7a5f..28ba3e3ccc3 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationState.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationState.java @@ -11,7 +11,7 @@ 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 void addNotification(NotificationItem item) { 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 void addNotification(NotificationItem item) { 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 PendingIntent getMarkAsReadIntent(Context context, int notificationId) { 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 PendingIntent getAndroidAutoHeardIntent(Context context, int notification 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 8bc28a24c15..8372551690a 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.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 @@ */ 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 @@ protected void onReceive(final Context context, Intent intent, 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 @@ protected void onReceive(final Context context, Intent intent, 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 5218966d333..6d0d7eead45 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.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 SingleRecipientNotificationBuilder(@NonNull Context context, 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 void setMessageCount(int messageCount) { 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 void addActions(@Nullable MasterSecret masterSecret, } } - 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 92798e19590..8a9e7a4d73d 100644 --- a/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java +++ b/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java @@ -7,14 +7,15 @@ 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 void onFinishInflate() { 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 void run() { }); } - 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 08d1d054f5a..736c4ec0c5a 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 5b0e64ec521..d78c7eb6753 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.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 void onFailure(ExecutionException error) { }); } - 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 void onFailure(ExecutionException error) { } 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 boolean isGroupRecipient() { 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 @@ private void notifyListeners() { 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 bf83a286076..f7da7c17109 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java @@ -22,37 +22,12 @@ 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 00000000000..d6e0955c3f9 --- /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 f3d52ca32fb..f8b3209f0f2 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -28,21 +28,18 @@ 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 @@ void clearCache() { Callable task = new Callable() { @Override public RecipientDetails call() throws Exception { - return getRecipientDetailsSync(context, address); + return getRecipientDetailsSync(context, address, true); } }; @@ -126,14 +102,13 @@ public RecipientDetails call() throws Exception { 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 @@ public RecipientDetails call() throws Exception { 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 @@ public RecipientDetails call() throws Exception { } 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 (title == null) { - title = context.getString(R.string.RecipientProvider_unnamed_group);; - } + if (record != null) { + ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(record.getAvatar()); + String title = record.getTitle(); + List
memberAddresses = record.getMembers(); + List members = new LinkedList<>(); - 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); - } - } - - 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); + if (!groupId.isMmsGroup() && title == null) { + title = context.getString(R.string.RecipientProvider_unnamed_group);; } - }); - asyncRecipientResolver.execute(task); + return new RecipientDetails(title, null, null, contactPhoto, null, members); + } - return task; + return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null, null); } - 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 @@ public synchronized void reset() { } - 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 7d83c95ebaf..00000000000 --- 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 48ac80d34ff..1d9b55e2020 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.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 List onGetChooserTargets(ComponentName targetActivityName, 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 28197bb76b3..9b8d0d5ecff 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.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 @@ protected void onHandleIntent(Intent intent, @Nullable MasterSecret masterSecret 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 ff392eb497f..570a48aa7b0 100644 --- a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java @@ -75,7 +75,7 @@ public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestam 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 a29384161be..4d0fe5decfb 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.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 static long send(final Context context, 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 static long send(final Context context, 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 static long send(final Context context, 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 static long send(final Context context, } } - 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 static void resend(Context context, MasterSecret masterSecret, MessageRec 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 static void resend(Context context, MasterSecret masterSecret, MessageRec } 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 @@ private static void sendMediaSelf(Context context, MasterSecret masterSecret, } } - 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 @@ private static void sendMms(Context context, long messageId) { 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 @@ private static boolean isPushTextSend(Context context, Recipients recipients, bo 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()) { - return false; - } - - if (recipients.isGroupRecipient()) { + if (recipient.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 042facf703b..9f2bfcb87d5 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 24890032ce6..30bc27a27ca 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 boolean isIdentityDefault() { } 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 310fbc00357..23d83334c1b 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 boolean isIdentityVerified() { @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 5a39e155b25..557814c89f8 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 760e1d9710d..440b0afaa63 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 String getMessageBody() { return message; } - public Recipients getRecipients() { - return recipients; + public Recipient getRecipient() { + return recipient; } public boolean isKeyExchange() { @@ -70,13 +70,13 @@ public boolean isIdentityDefault() { 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 c413b27fc48..56de76eeee8 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.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 static void refreshDirectory(@NonNull Context context, @Nullable MasterSe 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 static UserCapabilities refreshDirectoryFor(@NonNull Context context, } 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 static UserCapabilities refreshDirectoryFor(@NonNull Context context, 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 ba971b793ef..0e1bf176894 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.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 @@ 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 static byte[] getDecodedId(String groupId) throws IOException { } 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 static class GroupDescription { @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 GroupDescription(@NonNull Context context, @Nullable GroupContext groupCo 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 String toString(Recipient sender) { 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 String toString(Recipient sender) { 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