From 5000957b99e13c5bbdc40c1b21d4f6a16a04f1d1 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Mon, 24 Feb 2014 00:19:54 -0800 Subject: [PATCH] Listen for group updates, fix group updates, and Recipient marshing --- .../securesms/ConversationActivity.java | 46 +++++++- .../securesms/ConversationFragment.java | 5 +- .../securesms/ConversationListActivity.java | 2 +- .../securesms/GroupCreateActivity.java | 50 ++++----- .../securesms/GroupMembersDialog.java | 2 +- .../securesms/RoutingActivity.java | 2 +- .../SingleContactSelectionActivity.java | 2 +- .../securesms/database/GroupDatabase.java | 103 ++++++------------ .../database/model/MessageRecord.java | 4 +- .../securesms/recipients/Recipients.java | 11 ++ .../securesms/service/GroupReceiver.java | 4 +- .../securesms/transport/PushTransport.java | 2 +- .../securesms/util/GroupUtil.java | 2 +- 13 files changed, 119 insertions(+), 116 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index 42083274a9..ebeaf41127 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -73,6 +73,8 @@ import org.thoughtcrime.securesms.mms.AttachmentTypeSelectorAdapter; import org.thoughtcrime.securesms.mms.MediaTooLargeException; import org.thoughtcrime.securesms.mms.MmsSendHelper; import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; +import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; +import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.notifications.MessageNotifier; @@ -85,8 +87,6 @@ import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage; import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage; -import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; -import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.ActionBarUtil; import org.thoughtcrime.securesms.util.BitmapDecodingException; @@ -116,6 +116,7 @@ import java.util.List; import ws.com.google.android.mms.MmsException; import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; +import static org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener; import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext; /** @@ -155,6 +156,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi private AttachmentTypeSelectorAdapter attachmentAdapter; private AttachmentManager attachmentManager; private BroadcastReceiver securityUpdateReceiver; + private BroadcastReceiver groupUpdateReceiver; private EmojiDrawer emojiDrawer; private EmojiToggle emojiToggle; @@ -218,6 +220,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi @Override protected void onDestroy() { unregisterReceiver(securityUpdateReceiver); + unregisterReceiver(groupUpdateReceiver); saveDraft(); MemoryCleaner.clean(masterSecret); super.onDestroy(); @@ -456,10 +459,10 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi initializeEnabledCheck(); } catch (IOException e) { Log.w(TAG, e); - Toast.makeText(ConversationActivity.this, "Error leaving group....", Toast.LENGTH_LONG); + Toast.makeText(ConversationActivity.this, "Error leaving group....", Toast.LENGTH_LONG).show(); } catch (MmsException e) { Log.w(TAG, e); - Toast.makeText(ConversationActivity.this, "Error leaving group...", Toast.LENGTH_LONG); + Toast.makeText(ConversationActivity.this, "Error leaving group...", Toast.LENGTH_LONG).show(); } } }); @@ -706,7 +709,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi private void initializeResources() { recipientsPanel = (RecipientsPanel)findViewById(R.id.recipients); - recipients = getIntent().getParcelableExtra(RECIPIENTS_EXTRA); + recipients = RecipientFactory.getRecipientsForIds(this, getIntent().getStringExtra(RECIPIENTS_EXTRA), true); threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT); @@ -739,6 +742,13 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi emojiDrawer.setComposeEditText(composeText); emojiToggle.setOnClickListener(new EmojiToggleListener()); + recipients.addListener(new RecipientModifiedListener() { + @Override + public void onModified(Recipient recipient) { + initializeTitleBar(); + } + }); + registerForContextMenu(sendButton); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { @@ -777,9 +787,30 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi } }; + groupUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.w("ConversationActivity", "Group update received..."); + if (recipients != null) { + String ids = recipients.toIdString(); + Log.w("ConversationActivity", "Looking up new recipients..."); + recipients = RecipientFactory.getRecipientsForIds(context, ids, true); + recipients.addListener(new RecipientModifiedListener() { + @Override + public void onModified(Recipient recipient) { + initializeTitleBar(); + } + }); + } + } + }; + registerReceiver(securityUpdateReceiver, new IntentFilter(KeyExchangeProcessor.SECURITY_UPDATE_EVENT), KeyCachingService.KEY_PERMISSION, null); + + registerReceiver(groupUpdateReceiver, + new IntentFilter(GroupDatabase.DATABASE_UPDATE_ACTION)); } @@ -959,7 +990,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi } private boolean isPushGroupConversation() { - return getRecipients().isGroupRecipient(); + return getRecipients() != null && getRecipients().isGroupRecipient(); } private boolean isPushDestination() { @@ -967,6 +998,9 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi if (!TextSecurePreferences.isPushRegistered(this)) return false; + if (getRecipients() == null) + return false; + if (isPushGroupConversation()) return true; diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java index 187f727a83..4c52c46596 100644 --- a/src/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationFragment.java @@ -20,6 +20,7 @@ import android.widget.CursorAdapter; import com.actionbarsherlock.app.SherlockListFragment; +import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.whispersystems.textsecure.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.loaders.ConversationLoader; @@ -183,9 +184,11 @@ public class ConversationFragment extends SherlockListFragment } private void initializeResources() { + String recipientIds = this.getActivity().getIntent().getStringExtra("recipients"); + this.masterSecret = (MasterSecret)this.getActivity().getIntent() .getParcelableExtra("master_secret"); - this.recipients = this.getActivity().getIntent().getParcelableExtra("recipients"); + this.recipients = RecipientFactory.getRecipientsForIds(getActivity(), recipientIds, true); this.threadId = this.getActivity().getIntent().getLongExtra("thread_id", -1); } diff --git a/src/org/thoughtcrime/securesms/ConversationListActivity.java b/src/org/thoughtcrime/securesms/ConversationListActivity.java index 194d6ca973..7cc4b7a366 100644 --- a/src/org/thoughtcrime/securesms/ConversationListActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java @@ -177,7 +177,7 @@ public class ConversationListActivity extends PassphraseRequiredSherlockFragment private void createConversation(long threadId, Recipients recipients, int distributionType) { Intent intent = new Intent(this, ConversationActivity.class); - intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients); + intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.toIdString()); intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId); intent.putExtra(ConversationActivity.MASTER_SECRET_EXTRA, masterSecret); intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType); diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index d7677350b1..b144097522 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -34,12 +34,12 @@ import org.thoughtcrime.securesms.contacts.RecipientsEditor; 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.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; import org.thoughtcrime.securesms.util.ActionBarUtil; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -341,18 +341,6 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv new UpdateWhisperGroupAsyncTask().execute(); } - private static List recipientsToNormalizedStrings(Collection recipients, String localNumber) { - final List e164numbers = new ArrayList(recipients.size()); - for (Recipient contact : recipients) { - try { - e164numbers.add(PhoneNumberFormatter.formatNumber(contact.getNumber(), localNumber)); - } catch (InvalidNumberException ine) { - Log.w(TAG, "Failed to format number for added group member.", ine); - } - } - return e164numbers; - } - private void enableWhisperGroupCreatingUi() { findViewById(R.id.group_details_layout).setVisibility(View.GONE); findViewById(R.id.creating_group_layout).setVisibility(View.VISIBLE); @@ -428,10 +416,11 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv { GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(this); byte[] groupId = groupDatabase.allocateGroupId(); - List memberE164Numbers = getE164Numbers(members); + Set memberE164Numbers = getE164Numbers(members); + + memberE164Numbers.add(TextSecurePreferences.getLocalNumber(this)); - groupDatabase.create(groupId, TextSecurePreferences.getLocalNumber(this), groupName, - memberE164Numbers, null, null); + groupDatabase.create(groupId, groupName, new LinkedList(memberE164Numbers), null, null); groupDatabase.updateAvatar(groupId, avatar); return handlePushOperation(groupId, groupName, avatar, memberE164Numbers); @@ -442,24 +431,21 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv throws InvalidNumberException, MmsException { GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(this); - List memberE164Numbers = getE164Numbers(members); + Set memberE164Numbers = getE164Numbers(members); + memberE164Numbers.add(TextSecurePreferences.getLocalNumber(this)); - GroupDatabase.GroupRecord record = groupDatabase.getGroup(groupId); - Set newMembers = new HashSet(memberE164Numbers); - newMembers.removeAll(record.getMembers()); - - groupDatabase.add(groupId, TextSecurePreferences.getLocalNumber(this), - new LinkedList(newMembers)); + for (String number : memberE164Numbers) + Log.w(TAG, "Updating: " + number); + groupDatabase.updateMembers(groupId, new LinkedList(memberE164Numbers)); groupDatabase.updateTitle(groupId, groupName); groupDatabase.updateAvatar(groupId, avatar); - return handlePushOperation(groupId, groupName, avatar, memberE164Numbers); } private Pair handlePushOperation(byte[] groupId, String groupName, byte[] avatar, - List e164numbers) + Set e164numbers) throws MmsException, InvalidNumberException { @@ -501,10 +487,10 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv return arrayList; } - private List getE164Numbers(Set recipients) + private Set getE164Numbers(Set recipients) throws InvalidNumberException { - List results = new LinkedList(); + Set results = new HashSet(); for (Recipient recipient : recipients) { results.add(Util.canonicalizeNumber(this, recipient.getNumber())); @@ -545,7 +531,7 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT); ArrayList selectedContactsList = setToArrayList(selectedContacts); - intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, new Recipients(selectedContactsList)); + intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, new Recipients(selectedContactsList).toIdString()); startActivity(intent); finish(); } else { @@ -573,7 +559,9 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv } final String name = (groupName.getText() != null) ? groupName.getText().toString() : null; try { - return handleUpdatePushGroup(groupId, name, avatarBytes, selectedContacts); + Set unionContacts = new HashSet(selectedContacts); + unionContacts.addAll(existingContacts); + return handleUpdatePushGroup(groupId, name, avatarBytes, unionContacts); } catch (MmsException e) { Log.w(TAG, e); return new Pair(RES_MMS_EXCEPTION, null); @@ -638,7 +626,7 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv intent.putExtra(ConversationActivity.MASTER_SECRET_EXTRA, masterSecret); intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId); intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT); - intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients); + intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.toIdString()); startActivity(intent); finish(); } else if (threadId == RES_BAD_NUMBER) { @@ -671,7 +659,7 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv @Override protected Boolean doInBackground(Void... voids) { final GroupDatabase db = DatabaseFactory.getGroupDatabase(GroupCreateActivity.this); - final Recipients recipients = db.getGroupMembers(groupId); + final Recipients recipients = db.getGroupMembers(groupId, false); if (recipients != null) { final List recipientList = recipients.getRecipientsList(); if (recipientList != null) { diff --git a/src/org/thoughtcrime/securesms/GroupMembersDialog.java b/src/org/thoughtcrime/securesms/GroupMembersDialog.java index 818ec9f1dd..dfc564a2d6 100644 --- a/src/org/thoughtcrime/securesms/GroupMembersDialog.java +++ b/src/org/thoughtcrime/securesms/GroupMembersDialog.java @@ -37,7 +37,7 @@ public class GroupMembersDialog extends AsyncTask { try { String groupId = recipients.getPrimaryRecipient().getNumber(); return DatabaseFactory.getGroupDatabase(context) - .getGroupMembers(GroupUtil.getDecodedId(groupId)); + .getGroupMembers(GroupUtil.getDecodedId(groupId), true); } catch (IOException e) { Log.w("ConverstionActivity", e); return new Recipients(new LinkedList()); diff --git a/src/org/thoughtcrime/securesms/RoutingActivity.java b/src/org/thoughtcrime/securesms/RoutingActivity.java index 8d03807af7..70e8ff8b72 100644 --- a/src/org/thoughtcrime/securesms/RoutingActivity.java +++ b/src/org/thoughtcrime/securesms/RoutingActivity.java @@ -135,7 +135,7 @@ public class RoutingActivity extends PassphraseRequiredSherlockActivity { private Intent getConversationIntent(ConversationParameters parameters) { Intent intent = new Intent(this, ConversationActivity.class); - intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, parameters.recipients); + intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, parameters.recipients != null ? parameters.recipients.toIdString() : ""); intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, parameters.thread); intent.putExtra(ConversationActivity.MASTER_SECRET_EXTRA, masterSecret); intent.putExtra(ConversationActivity.DRAFT_TEXT_EXTRA, parameters.draftText); diff --git a/src/org/thoughtcrime/securesms/SingleContactSelectionActivity.java b/src/org/thoughtcrime/securesms/SingleContactSelectionActivity.java index 18dfecd152..68e3e19199 100644 --- a/src/org/thoughtcrime/securesms/SingleContactSelectionActivity.java +++ b/src/org/thoughtcrime/securesms/SingleContactSelectionActivity.java @@ -113,7 +113,7 @@ public class SingleContactSelectionActivity extends PassphraseRequiredSherlockFr private void openNewConversation(Recipients recipients) { if (recipients != null) { Intent intent = new Intent(SingleContactSelectionActivity.this, ConversationActivity.class); - intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients); + intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.toIdString()); intent.putExtra(ConversationActivity.MASTER_SECRET_EXTRA, masterSecret); long existingThread = DatabaseFactory.getThreadDatabase(SingleContactSelectionActivity.this).getThreadIdIfExistsFor(recipients); intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread); diff --git a/src/org/thoughtcrime/securesms/database/GroupDatabase.java b/src/org/thoughtcrime/securesms/database/GroupDatabase.java index 89a32cf8e4..60ba09e7b6 100644 --- a/src/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/src/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.database; import android.content.ContentValues; import android.content.Context; +import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; @@ -24,10 +25,14 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.LinkedList; import java.util.List; +import java.util.Set; import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.AttachmentPointer; public class GroupDatabase extends Database { + + public static final String DATABASE_UPDATE_ACTION = "org.thoughtcrime.securesms.database.GroupDatabase.UPDATE"; + private static final String TAG = GroupDatabase.class.getSimpleName(); private static final String TABLE_NAME = "groups"; @@ -77,11 +82,15 @@ public class GroupDatabase extends Database { return record; } - public Recipients getGroupMembers(byte[] groupId) { - List members = getCurrentMembers(groupId); - List recipients = new LinkedList(); + public Recipients getGroupMembers(byte[] groupId, boolean includeSelf) { + String localNumber = TextSecurePreferences.getLocalNumber(context); + List members = getCurrentMembers(groupId); + List recipients = new LinkedList(); for (String member : members) { + if (!includeSelf && member.equals(localNumber)) + continue; + try { recipients.addAll(RecipientFactory.getRecipientsFromString(context, member, false) .getRecipientsList()); @@ -93,27 +102,13 @@ public class GroupDatabase extends Database { return new Recipients(recipients); } - public void create(byte[] groupId, String owner, String title, - List members, AttachmentPointer avatar, - String relay) + public void create(byte[] groupId, String title, List members, + AttachmentPointer avatar, String relay) { - List filteredMembers = new LinkedList(); - String localNumber = TextSecurePreferences.getLocalNumber(context); - - if (!localNumber.equals(owner)) { - filteredMembers.add(owner); - } - - for (String member : members) { - if (!member.equals(localNumber)) { - filteredMembers.add(member); - } - } - ContentValues contentValues = new ContentValues(); contentValues.put(GROUP_ID, GroupUtil.getEncodedId(groupId)); contentValues.put(TITLE, title); - contentValues.put(MEMBERS, Util.join(filteredMembers, ",")); + contentValues.put(MEMBERS, Util.join(members, ",")); if (avatar != null) { contentValues.put(AVATAR_ID, avatar.getId()); @@ -142,7 +137,8 @@ public class GroupDatabase extends Database { GROUP_ID + " = ?", new String[] {GroupUtil.getEncodedId(groupId)}); - if (title != null) updateGroupRecipientTitle(groupId, title); + RecipientFactory.clearCache(); + notifyDatabaseListeners(); } public void updateTitle(byte[] groupId, String title) { @@ -151,43 +147,32 @@ public class GroupDatabase extends Database { databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?", new String[] {GroupUtil.getEncodedId(groupId)}); - if (title != null) updateGroupRecipientTitle(groupId, title); + RecipientFactory.clearCache(); + notifyDatabaseListeners(); } public void updateAvatar(byte[] groupId, Bitmap avatar) { - updateAvatarInDatabase(groupId, BitmapUtil.toByteArray(avatar)); - updateGroupRecipientAvatar(groupId, avatar); + updateAvatar(groupId, BitmapUtil.toByteArray(avatar)); } public void updateAvatar(byte[] groupId, byte[] avatar) { - updateAvatarInDatabase(groupId, avatar); - updateGroupRecipientAvatar(groupId, BitmapFactory.decodeByteArray(avatar, 0, avatar.length)); - } - - private void updateAvatarInDatabase(byte[] groupId, byte[] avatar) { ContentValues contentValues = new ContentValues(); contentValues.put(AVATAR, avatar); databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?", new String[] {GroupUtil.getEncodedId(groupId)}); - } - - public void add(byte[] id, String source, List members) { - List currentMembers = getCurrentMembers(id); - for (String currentMember : currentMembers) { - if (currentMember.equals(source)) { - List concatenatedMembers = new LinkedList(currentMembers); - concatenatedMembers.addAll(members); + RecipientFactory.clearCache(); + notifyDatabaseListeners(); + } - ContentValues contents = new ContentValues(); - contents.put(MEMBERS, Util.join(concatenatedMembers, ",")); - contents.put(ACTIVE, 1); + public void updateMembers(byte[] id, List members) { + ContentValues contents = new ContentValues(); + contents.put(MEMBERS, Util.join(members, ",")); + contents.put(ACTIVE, 1); - databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", - new String[] {GroupUtil.getEncodedId(id)}); - } - } + databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", + new String[] {GroupUtil.getEncodedId(id)}); } public void remove(byte[] id, String source) { @@ -198,7 +183,7 @@ public class GroupDatabase extends Database { contents.put(MEMBERS, Util.join(currentMembers, ",")); databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", - new String[]{GroupUtil.getEncodedId(id)}); + new String[] {GroupUtil.getEncodedId(id)}); } private List getCurrentMembers(byte[] id) { @@ -244,6 +229,10 @@ public class GroupDatabase extends Database { } } + private void notifyDatabaseListeners() { + Intent intent = new Intent(DATABASE_UPDATE_ACTION); + context.sendBroadcast(intent); + } public static class Reader { @@ -342,28 +331,4 @@ public class GroupDatabase extends Database { return active; } } - - private Recipient getGroupRecipient(byte[] groupId) { - try { - return RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(groupId), true) - .getPrimaryRecipient(); - } catch (RecipientFormattingException e) { - Log.w(TAG, e); - return null; - } - } - - private void updateGroupRecipientTitle(byte[] groupId, String title) { - Recipient groupRecipient = getGroupRecipient(groupId); - Log.i(TAG, "updating group recipient title for recipient " + System.identityHashCode(groupRecipient)); - if (groupRecipient != null) groupRecipient.setName(title); - else Log.w(TAG, "Couldn't update group title because recipient couldn't be found."); - } - - private void updateGroupRecipientAvatar(byte[] groupId, Bitmap photo) { - Recipient groupRecipient = getGroupRecipient(groupId); - if (groupRecipient != null) groupRecipient.setContactPhoto(photo); - else Log.w(TAG, "Couldn't update group title because recipient couldn't be found."); - } - } diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java index 67f5973ea0..e2c1a0ca37 100644 --- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -84,7 +84,9 @@ public abstract class MessageRecord extends DisplayRecord { @Override public SpannableString getDisplayBody() { - if (isGroupUpdate()) { + if (isGroupUpdate() && isOutgoing()) { + return emphasisAdded("Updated the group."); + } else if (isGroupUpdate()) { return emphasisAdded(GroupUtil.getDescription(getBody().getBody())); } else if (isGroupQuit() && isOutgoing()) { return emphasisAdded("You have left the group."); diff --git a/src/org/thoughtcrime/securesms/recipients/Recipients.java b/src/org/thoughtcrime/securesms/recipients/Recipients.java index 025b6d917e..de0d60dfee 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipients.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipients.java @@ -23,6 +23,7 @@ import android.util.Patterns; import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.NumberUtil; +import org.whispersystems.textsecure.util.Util; import java.util.ArrayList; import java.util.Iterator; @@ -137,6 +138,16 @@ public class Recipients implements Parcelable { return this.recipients; } + public String toIdString() { + List ids = new LinkedList(); + + for (Recipient recipient : recipients) { + ids.add(String.valueOf(recipient.getRecipientId())); + } + + return Util.join(ids, " "); + } + public String[] toNumberStringArray(boolean scrub) { String[] recipientsArray = new String[recipients.size()]; Iterator iterator = recipients.iterator(); diff --git a/src/org/thoughtcrime/securesms/service/GroupReceiver.java b/src/org/thoughtcrime/securesms/service/GroupReceiver.java index 4f8d9c9fe8..0cc6cfc2ea 100644 --- a/src/org/thoughtcrime/securesms/service/GroupReceiver.java +++ b/src/org/thoughtcrime/securesms/service/GroupReceiver.java @@ -71,7 +71,7 @@ public class GroupReceiver { GroupDatabase database = DatabaseFactory.getGroupDatabase(context); byte[] id = group.getId().toByteArray(); - database.create(id, message.getSource(), group.getName(), group.getMembersList(), + database.create(id, group.getName(), group.getMembersList(), group.getAvatar(), message.getRelay()); storeMessage(masterSecret, message, group); @@ -98,7 +98,7 @@ public class GroupReceiver { if (addedMembers.size() > 0) { Set unionMembers = new HashSet(recordMembers); unionMembers.addAll(messageMembers); - database.add(id, message.getSource(), new LinkedList(unionMembers)); + database.updateMembers(id, new LinkedList(unionMembers)); group = group.toBuilder().clearMembers().addAllMembers(addedMembers).build(); } else { diff --git a/src/org/thoughtcrime/securesms/transport/PushTransport.java b/src/org/thoughtcrime/securesms/transport/PushTransport.java index 414ddcc2c7..f7e41251f8 100644 --- a/src/org/thoughtcrime/securesms/transport/PushTransport.java +++ b/src/org/thoughtcrime/securesms/transport/PushTransport.java @@ -115,7 +115,7 @@ public class PushTransport extends BaseTransport { if (GroupUtil.isEncodedGroup(destination)) { recipients = DatabaseFactory.getGroupDatabase(context) - .getGroupMembers(GroupUtil.getDecodedId(destination)); + .getGroupMembers(GroupUtil.getDecodedId(destination), false); } else { recipients = RecipientFactory.getRecipientsFromString(context, destination, false); } diff --git a/src/org/thoughtcrime/securesms/util/GroupUtil.java b/src/org/thoughtcrime/securesms/util/GroupUtil.java index cca3513048..7a37e44dee 100644 --- a/src/org/thoughtcrime/securesms/util/GroupUtil.java +++ b/src/org/thoughtcrime/securesms/util/GroupUtil.java @@ -50,7 +50,7 @@ public class GroupUtil { } if (title != null && !title.trim().isEmpty()) { - description += " Updated title to '" + title + "'."; + description += " Title is now '" + title + "'."; } return description;