diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index a3ad115f05..4364a41fda 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -833,11 +833,12 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi } private boolean isSingleConversation() { - return getRecipients() != null && getRecipients().isSingleRecipient(); + return getRecipients() != null && getRecipients().isSingleRecipient() && !getRecipients().isGroupRecipient(); } private boolean isGroupConversation() { - return getRecipients() != null && !getRecipients().isSingleRecipient(); + return getRecipients() != null && + (!getRecipients().isSingleRecipient() || getRecipients().isGroupRecipient()); } private Recipients getRecipients() { diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index e065b78aa9..d36266c863 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -31,6 +31,7 @@ import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.media.MediaScannerConnection; import android.net.Uri; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.Message; @@ -60,6 +61,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.Emoji; +import org.whispersystems.textsecure.push.PushMessageProtos; import org.whispersystems.textsecure.util.FutureTaskListener; import org.whispersystems.textsecure.util.ListenableFutureTask; @@ -69,6 +71,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext; + /** * A view that displays an individual conversation item within a conversation * thread. Used by ComposeMessageActivity's ListActivity via a ConversationAdapter. @@ -175,8 +179,25 @@ public class ConversationItem extends LinearLayout { /// MessageRecord Attribute Parsers private void setBodyText(MessageRecord messageRecord) { - bodyText.setText(Emoji.getInstance(context).emojify(messageRecord.getDisplayBody(), Emoji.EMOJI_LARGE), - TextView.BufferType.SPANNABLE); + switch (messageRecord.getGroupAction()) { + case GroupContext.Type.QUIT_VALUE: + bodyText.setText(messageRecord.getIndividualRecipient().toShortString() + " has left the group."); + return; + case GroupContext.Type.ADD_VALUE: + case GroupContext.Type.CREATE_VALUE: + bodyText.setText(messageRecord.getGroupActionArguments() + " have joined the group."); + return; + case GroupContext.Type.MODIFY_VALUE: + bodyText.setText(messageRecord.getIndividualRecipient() + " has updated the group."); + return; + } + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + bodyText.setText(Emoji.getInstance(context).emojify(messageRecord.getDisplayBody(), Emoji.EMOJI_LARGE), + TextView.BufferType.SPANNABLE); + } else { + bodyText.setText(messageRecord.getDisplayBody()); + } } private void setContactPhoto(MessageRecord messageRecord) { diff --git a/src/org/thoughtcrime/securesms/ConversationListItem.java b/src/org/thoughtcrime/securesms/ConversationListItem.java index ee9755ed3f..916fcedd3f 100644 --- a/src/org/thoughtcrime/securesms/ConversationListItem.java +++ b/src/org/thoughtcrime/securesms/ConversationListItem.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Typeface; import android.net.Uri; +import android.os.Build; import android.os.Handler; import android.provider.Contacts.Intents; import android.provider.ContactsContract.QuickContact; @@ -102,9 +103,14 @@ public class ConversationListItem extends RelativeLayout this.recipients.addListener(this); this.fromView.setText(formatFrom(recipients, count, read)); - this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(), - Emoji.EMOJI_SMALL), - TextView.BufferType.SPANNABLE); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(), + Emoji.EMOJI_SMALL), + TextView.BufferType.SPANNABLE); + } else { + this.subjectView.setText(thread.getDisplayBody()); + } if (thread.getDate() > 0) this.dateView.setText(DateUtils.getBetterRelativeTimeSpanString(getContext(), thread.getDate())); diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index 9e16a2eac1..ec88fad683 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -30,6 +30,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.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.transport.PushTransport; import org.thoughtcrime.securesms.util.ActionBarUtil; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -366,6 +367,8 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv byte[] groupId = groupDatabase.allocateGroupId(); AttachmentPointer avatarPointer = null; + memberE164Numbers.add(TextSecurePreferences.getLocalNumber(this)); + GroupContext.Builder builder = GroupContext.newBuilder() .setId(ByteString.copyFrom(groupId)) .setType(GroupContext.Type.CREATE) @@ -389,9 +392,23 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv groupDatabase.updateAvatar(groupId, avatar); } - long threadId = threadDatabase.getThreadIdForGroup(GroupUtil.getEncodedId(groupId)); + try { + String groupRecipientId = GroupUtil.getEncodedId(groupId); + Recipient groupRecipient = RecipientFactory.getRecipientsFromString(this, groupRecipientId, false).getPrimaryRecipient(); + OutgoingTextMessage outgoing = new OutgoingTextMessage(groupRecipient, GroupContext.Type.ADD_VALUE, org.whispersystems.textsecure.util.Util.join(memberE164Numbers, ",")); + long threadId = threadDatabase.getThreadIdFor(new Recipients(groupRecipient)); + List messageIds = DatabaseFactory.getEncryptingSmsDatabase(this) + .insertMessageOutbox(masterSecret, threadId, outgoing); - return new Pair>(threadId, failures); + for (long messageId : messageIds) { + DatabaseFactory.getEncryptingSmsDatabase(this).markAsSent(messageId); + } + + + return new Pair>(threadId, failures); + } catch (RecipientFormattingException e) { + throw new AssertionError(e); + } } private long handleCreateMmsGroup(Set members) { diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index 7de9b696b6..f750f71c5d 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -647,6 +647,10 @@ public class DatabaseFactory { db.execSQL("ALTER TABLE push ADD COLUMN device_id INTEGER DEFAULT 1;"); db.execSQL("ALTER TABLE sms ADD COLUMN address_device_id INTEGER DEFAULT 1;"); db.execSQL("ALTER TABLE mms ADD COLUMN address_device_id INTEGER DEFAULT 1;"); + db.execSQL("ALTER TABLE sms ADD COLUMN group_action INTEGER DEFAULT -1;"); + db.execSQL("ALTER TABLE mms ADD COLUMN group_action_arguments TEXT;"); + db.execSQL("ALTER TABLE thread ADD COLUMN group_action INTEGER DEFAULT -1;"); + db.execSQL("ALTER TABLE thread ADD COLUMN group_action_arguments TEXT;"); } db.setTransactionSuccessful(); diff --git a/src/org/thoughtcrime/securesms/database/GroupDatabase.java b/src/org/thoughtcrime/securesms/database/GroupDatabase.java index 9a21e6f76d..b10e15437d 100644 --- a/src/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/src/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.GroupUtil; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Util; @@ -90,11 +91,20 @@ public class GroupDatabase extends Database { List members, AttachmentPointer avatar, String relay) { + List filteredMembers = new LinkedList(); + String localNumber = TextSecurePreferences.getLocalNumber(context); + + for (String member : members) { + if (!member.equals(localNumber)) { + filteredMembers.add(member); + } + } + ContentValues contentValues = new ContentValues(); contentValues.put(GROUP_ID, GroupUtil.getEncodedId(groupId)); contentValues.put(OWNER, owner); contentValues.put(TITLE, title); - contentValues.put(MEMBERS, Util.join(members, ",")); + contentValues.put(MEMBERS, Util.join(filteredMembers, ",")); if (avatar != null) { contentValues.put(AVATAR_ID, avatar.getId()); @@ -147,7 +157,7 @@ public class GroupDatabase extends Database { contents.put(MEMBERS, Util.join(concatenatedMembers, ",")); databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", - new String[] {Hex.toString(id)}); + new String[] {GroupUtil.getEncodedId(id)}); } } } @@ -160,7 +170,7 @@ public class GroupDatabase extends Database { contents.put(MEMBERS, Util.join(currentMembers, ",")); databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", - new String[]{Hex.toString(id)}); + new String[]{GroupUtil.getEncodedId(id)}); } private List getCurrentMembers(byte[] id) { @@ -168,7 +178,8 @@ public class GroupDatabase extends Database { try { cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {MEMBERS}, - GROUP_ID + " = ?", new String[] {Hex.toString(id)}, + GROUP_ID + " = ?", + new String[] {GroupUtil.getEncodedId(id)}, null, null, null); if (cursor != null && cursor.moveToFirst()) { diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 70e81a4f8a..d47f26d076 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -116,7 +116,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns { STATUS + " INTEGER, " + TRANSACTION_ID + " TEXT, " + RETRIEVE_STATUS + " INTEGER, " + RETRIEVE_TEXT + " TEXT, " + RETRIEVE_TEXT_CS + " INTEGER, " + READ_STATUS + " INTEGER, " + CONTENT_CLASS + " INTEGER, " + RESPONSE_TEXT + " TEXT, " + DELIVERY_TIME + " INTEGER, " + - DELIVERY_REPORT + " INTEGER);"; + DELIVERY_REPORT + " INTEGER, " + GROUP_ACTION + " INTEGER DEFAULT -1, " + GROUP_ACTION_ARGUMENTS + " TEXT);"; public static final String[] CREATE_INDEXS = { "CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");", @@ -181,7 +181,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns { private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException { if (retrieved.getGroupId() != null) { - return DatabaseFactory.getThreadDatabase(context).getThreadIdForGroup(retrieved.getGroupId()); + Recipients groupRecipients = RecipientFactory.getRecipientsFromString(context, retrieved.getGroupId(), true); + return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients); } try { @@ -399,6 +400,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns { contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED); contentValues.put(DATE_RECEIVED, System.currentTimeMillis() / 1000); contentValues.put(READ, unread ? 0 : 1); + contentValues.put(GROUP_ACTION, retrieved.getGroupAction()); + contentValues.put(GROUP_ACTION_ARGUMENTS, retrieved.getGroupActionArguments()); if (!contentValues.containsKey(DATE_SENT)) { contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED)); @@ -797,6 +800,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns { long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_SIZE)); long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRY)); int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.STATUS)); + int groupAction = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.GROUP_ACTION)); + String groupActionArgs = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.GROUP_ACTION_ARGUMENTS)); byte[]contentLocationBytes = null; byte[]transactionIdBytes = null; @@ -811,7 +816,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns { return new NotificationMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(), addressDeviceId, dateSent, dateReceived, threadId, contentLocationBytes, messageSize, expiry, status, - transactionIdBytes, mailbox); + transactionIdBytes, mailbox, groupAction, groupActionArgs); } private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) { @@ -822,6 +827,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns { long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID)); String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS)); int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID)); + int groupAction = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.GROUP_ACTION)); + String groupActionArgs = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.GROUP_ACTION_ARGUMENTS)); DisplayRecord.Body body = getBody(cursor); int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT)); Recipients recipients = getRecipientsFor(address); @@ -830,7 +837,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns { return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(), addressDeviceId, dateSent, dateReceived, threadId, body, - slideDeck, partCount, box); + slideDeck, partCount, box, groupAction, groupActionArgs); } private Recipients getRecipientsFor(String address) { diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 99edd838d7..d8955ec617 100644 --- a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -10,7 +10,8 @@ public interface MmsSmsColumns { public static final String BODY = "body"; public static final String ADDRESS = "address"; public static final String ADDRESS_DEVICE_ID = "address_device_id"; - + public static final String GROUP_ACTION = "group_action"; + public static final String GROUP_ACTION_ARGUMENTS = "group_action_arguments"; public static class Types { protected static final long TOTAL_MASK = 0xFFFFFFFF; diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java index f9666decd1..16abce63ba 100644 --- a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java @@ -49,7 +49,8 @@ public class MmsSmsDatabase extends Database { SmsDatabase.STATUS, MmsDatabase.PART_COUNT, MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID, MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, - MmsDatabase.STATUS, TRANSPORT}; + MmsDatabase.STATUS, MmsSmsColumns.GROUP_ACTION, + MmsSmsColumns.GROUP_ACTION_ARGUMENTS, TRANSPORT}; String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC"; @@ -71,7 +72,8 @@ public class MmsSmsDatabase extends Database { SmsDatabase.STATUS, MmsDatabase.PART_COUNT, MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID, MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, - MmsDatabase.STATUS, TRANSPORT}; + MmsDatabase.STATUS, MmsSmsColumns.GROUP_ACTION, + MmsSmsColumns.GROUP_ACTION_ARGUMENTS, TRANSPORT}; String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; String selection = MmsSmsColumns.THREAD_ID + " = " + threadId; @@ -89,7 +91,8 @@ public class MmsSmsDatabase extends Database { MmsDatabase.PART_COUNT, MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID, MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, - MmsDatabase.STATUS, TRANSPORT}; + MmsDatabase.STATUS, MmsSmsColumns.GROUP_ACTION, + MmsSmsColumns.GROUP_ACTION_ARGUMENTS, TRANSPORT}; String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC"; String selection = MmsSmsColumns.READ + " = 0"; @@ -112,6 +115,7 @@ public class MmsSmsDatabase extends Database { MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT, MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID, MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS, + MmsSmsColumns.GROUP_ACTION, MmsSmsColumns.GROUP_ACTION_ARGUMENTS, TRANSPORT}; String[] smsProjection = {SmsDatabase.DATE_SENT + " * 1 AS " + MmsSmsColumns.NORMALIZED_DATE_SENT, @@ -121,6 +125,7 @@ public class MmsSmsDatabase extends Database { MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT, MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID, MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS, + MmsSmsColumns.GROUP_ACTION, MmsSmsColumns.GROUP_ACTION_ARGUMENTS, TRANSPORT}; @@ -149,6 +154,8 @@ public class MmsSmsDatabase extends Database { mmsColumnsPresent.add(MmsDatabase.TRANSACTION_ID); mmsColumnsPresent.add(MmsDatabase.MESSAGE_SIZE); mmsColumnsPresent.add(MmsDatabase.EXPIRY); + mmsColumnsPresent.add(MmsSmsColumns.GROUP_ACTION); + mmsColumnsPresent.add(MmsSmsColumns.GROUP_ACTION_ARGUMENTS); mmsColumnsPresent.add(MmsDatabase.STATUS); Set smsColumnsPresent = new HashSet(); @@ -162,6 +169,8 @@ public class MmsSmsDatabase extends Database { smsColumnsPresent.add(SmsDatabase.SUBJECT); smsColumnsPresent.add(SmsDatabase.DATE_SENT); smsColumnsPresent.add(SmsDatabase.DATE_RECEIVED); + smsColumnsPresent.add(MmsSmsColumns.GROUP_ACTION); + smsColumnsPresent.add(MmsSmsColumns.GROUP_ACTION_ARGUMENTS); smsColumnsPresent.add(SmsDatabase.STATUS); String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 2, MMS_TRANSPORT, selection, null, null, null); diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index 5beacd9591..57bf11e593 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -26,7 +26,6 @@ import android.telephony.PhoneNumberUtils; import android.util.Log; import android.util.Pair; -import org.thoughtcrime.securesms.contacts.ContactPhotoFactory; import org.thoughtcrime.securesms.database.model.DisplayRecord; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.recipients.Recipient; @@ -66,7 +65,8 @@ public class SmsDatabase extends Database implements MmsSmsColumns { THREAD_ID + " INTEGER, " + ADDRESS + " TEXT, " + ADDRESS_DEVICE_ID + " INTEGER DEFAULT 1, " + PERSON + " INTEGER, " + DATE_RECEIVED + " INTEGER, " + DATE_SENT + " INTEGER, " + PROTOCOL + " INTEGER, " + READ + " INTEGER DEFAULT 0, " + STATUS + " INTEGER DEFAULT -1," + TYPE + " INTEGER, " + REPLY_PATH_PRESENT + " INTEGER, " + - SUBJECT + " TEXT, " + BODY + " TEXT, " + SERVICE_CENTER + " TEXT);"; + SUBJECT + " TEXT, " + BODY + " TEXT, " + SERVICE_CENTER + " TEXT, " + + GROUP_ACTION + " INTEGER DEFAULT -1, " + GROUP_ACTION_ARGUMENTS + " TEXT);"; public static final String[] CREATE_INDEXS = { "CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");", @@ -80,7 +80,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns { DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED, DATE_SENT + " AS " + NORMALIZED_DATE_SENT, PROTOCOL, READ, STATUS, TYPE, - REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER + REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, GROUP_ACTION, GROUP_ACTION_ARGUMENTS }; public SmsDatabase(Context context, SQLiteOpenHelper databaseHelper) { @@ -303,6 +303,8 @@ public class SmsDatabase extends Database implements MmsSmsColumns { values.put(BODY, message.getMessageBody()); values.put(TYPE, type); values.put(THREAD_ID, threadId); + values.put(GROUP_ACTION, message.getGroupAction()); + values.put(GROUP_ACTION_ARGUMENTS, message.getGroupActionArgument()); SQLiteDatabase db = databaseHelper.getWritableDatabase(); long messageId = db.insert(TABLE_NAME, null, values); @@ -338,6 +340,8 @@ public class SmsDatabase extends Database implements MmsSmsColumns { contentValues.put(DATE_SENT, date); contentValues.put(READ, 1); contentValues.put(TYPE, type); + contentValues.put(GROUP_ACTION, message.getGroupAction()); + contentValues.put(GROUP_ACTION_ARGUMENTS, message.getGroupActionArguments()); SQLiteDatabase db = databaseHelper.getWritableDatabase(); messageIds.add(db.insert(TABLE_NAME, ADDRESS, contentValues)); @@ -494,6 +498,8 @@ public class SmsDatabase extends Database implements MmsSmsColumns { long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_SENT)); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID)); int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS)); + int groupAction = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.GROUP_ACTION)); + String groupActionArgs = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.GROUP_ACTION_ARGUMENTS)); Recipients recipients = getRecipientsFor(address); DisplayRecord.Body body = getBody(cursor); @@ -501,7 +507,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns { recipients.getPrimaryRecipient(), addressDeviceId, dateSent, dateReceived, type, - threadId, status); + threadId, status, groupAction, groupActionArgs); } private Recipients getRecipientsFor(String address) { diff --git a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java index 0aa8842192..228179bb4d 100644 --- a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -53,13 +53,15 @@ public class ThreadDatabase extends Database { private static final String ERROR = "error"; private static final String HAS_ATTACHMENT = "has_attachment"; public static final String SNIPPET_TYPE = "snippet_type"; + private static final String GROUP_ACTION = "group_action"; + private static final String GROUP_ACTION_ARG = "group_action_arguments"; public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " + MESSAGE_COUNT + " INTEGER DEFAULT 0, " + RECIPIENT_IDS + " 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, " + - HAS_ATTACHMENT + " INTEGER DEFAULT 0);"; + SNIPPET_TYPE + " INTEGER DEFAULT 0, " + GROUP_ACTION + " INTEGER DEFAULT -1, " + + GROUP_ACTION_ARG + " TEXT, " + HAS_ATTACHMENT + " INTEGER DEFAULT 0);"; public static final String[] CREATE_INDEXS = { "CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + RECIPIENT_IDS + ");", @@ -99,17 +101,6 @@ public class ThreadDatabase extends Database { return sb.toString(); } - private long createThreadForGroup(String group) { - long date = System.currentTimeMillis(); - - ContentValues values = new ContentValues(); - values.put(DATE, date - date % 1000); - values.put(RECIPIENT_IDS, group); - values.put(MESSAGE_COUNT, 0); - - return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values); - } - private long createThreadForRecipients(String recipients, int recipientCount, int distributionType) { ContentValues contentValues = new ContentValues(4); long date = System.currentTimeMillis(); @@ -126,12 +117,16 @@ public class ThreadDatabase extends Database { return db.insert(TABLE_NAME, null, contentValues); } - private void updateThread(long threadId, long count, String body, long date, long type) { + private void updateThread(long threadId, long count, String body, long date, long type, + int groupAction, String groupActionArguments) + { ContentValues contentValues = new ContentValues(3); contentValues.put(DATE, date - date % 1000); contentValues.put(MESSAGE_COUNT, count); contentValues.put(SNIPPET, body); contentValues.put(SNIPPET_TYPE, type); + contentValues.put(GROUP_ACTION, groupAction); + contentValues.put(GROUP_ACTION_ARG, groupActionArguments); SQLiteDatabase db = databaseHelper.getWritableDatabase(); db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""}); @@ -358,26 +353,6 @@ public class ThreadDatabase extends Database { } } - public long getThreadIdForGroup(String groupId) { - SQLiteDatabase db = databaseHelper.getReadableDatabase(); - String where = RECIPIENT_IDS + " = ?"; - String[] recipientsArg = new String[] {groupId}; - Cursor cursor = null; - - try { - cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null); - - if (cursor != null && cursor.moveToFirst()) { - return cursor.getLong(cursor.getColumnIndexOrThrow(ID)); - } else { - return createThreadForGroup(groupId); - } - } finally { - if (cursor != null) - cursor.close(); - } - } - public Recipients getRecipientsForThreadId(long threadId) { SQLiteDatabase db = databaseHelper.getReadableDatabase(); Cursor cursor = null; @@ -414,7 +389,8 @@ public class ThreadDatabase extends Database { MessageRecord record = null; if (reader != null && (record = reader.getNext()) != null) { - updateThread(threadId, count, record.getBody().getBody(), record.getDateReceived(), record.getType()); + updateThread(threadId, count, record.getBody().getBody(), record.getDateReceived(), + record.getType(), record.getGroupAction(), record.getGroupActionArguments()); } else { deleteThread(threadId); } @@ -470,9 +446,12 @@ public class ThreadDatabase extends Database { long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ)); long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE)); int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE)); + int groupAction = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.GROUP_ACTION)); + String groupActionArg = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.GROUP_ACTION_ARG)); return new ThreadRecord(context, body, recipients, date, count, - read == 1, threadId, type, distributionType); + read == 1, threadId, type, distributionType, + groupAction, groupActionArg); } private DisplayRecord.Body getPlaintextBody(Cursor cursor) { diff --git a/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java index ef60bec8d3..dcec4f9549 100644 --- a/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -36,22 +36,26 @@ public abstract class DisplayRecord { protected final long type; private final Recipients recipients; - private final long dateSent; - private final long dateReceived; - private final long threadId; - private final Body body; -// private final String body; + private final long dateSent; + private final long dateReceived; + private final long threadId; + private final Body body; + private final int groupAction; + private final String groupActionArguments; public DisplayRecord(Context context, Body body, Recipients recipients, long dateSent, - long dateReceived, long threadId, long type) + long dateReceived, long threadId, long type, int groupAction, + String groupActionArguments) { - this.context = context.getApplicationContext(); - this.threadId = threadId; - this.recipients = recipients; - this.dateSent = dateSent; - this.dateReceived = dateReceived; - this.type = type; - this.body = body; + this.context = context.getApplicationContext(); + this.threadId = threadId; + this.recipients = recipients; + this.dateSent = dateSent; + this.dateReceived = dateReceived; + this.type = type; + this.body = body; + this.groupAction = groupAction; + this.groupActionArguments = groupActionArguments; } public Body getBody() { @@ -80,6 +84,14 @@ public abstract class DisplayRecord { return SmsDatabase.Types.isKeyExchangeType(type); } + public int getGroupAction() { + return groupAction; + } + + public String getGroupActionArguments() { + return groupActionArguments; + } + public static class Body { private final String body; private final boolean plaintext; diff --git a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java index 46fac48fbd..cf861437e0 100644 --- a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java @@ -44,10 +44,12 @@ public class MediaMmsMessageRecord extends MessageRecord { Recipient individualRecipient, int recipientDeviceId, long dateSent, long dateReceived, long threadId, Body body, ListenableFutureTask slideDeck, - int partCount, long mailbox) + int partCount, long mailbox, int groupAction, + String groupActionArguments) { super(context, id, body, recipients, individualRecipient, recipientDeviceId, - dateSent, dateReceived, threadId, DELIVERY_STATUS_NONE, mailbox); + dateSent, dateReceived, threadId, DELIVERY_STATUS_NONE, mailbox, + groupAction, groupActionArguments); this.context = context.getApplicationContext(); this.partCount = partCount; diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java index 724fa88939..98b57e9a5f 100644 --- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -53,9 +53,9 @@ public abstract class MessageRecord extends DisplayRecord { Recipient individualRecipient, int recipientDeviceId, long dateSent, long dateReceived, long threadId, int deliveryStatus, - long type) + long type, int groupAction, String groupActionArguments) { - super(context, body, recipients, dateSent, dateReceived, threadId, type); + super(context, body, recipients, dateSent, dateReceived, threadId, type, groupAction, groupActionArguments); this.id = id; this.individualRecipient = individualRecipient; this.recipientDeviceId = recipientDeviceId; diff --git a/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java index 7ebf70c75d..5d575e024f 100644 --- a/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java @@ -44,10 +44,11 @@ public class NotificationMmsMessageRecord extends MessageRecord { Recipient individualRecipient, int recipientDeviceId, long dateSent, long dateReceived, long threadId, byte[] contentLocation, long messageSize, long expiry, - int status, byte[] transactionId, long mailbox) + int status, byte[] transactionId, long mailbox, + int groupAction, String groupActionArguments) { super(context, id, new Body("", true), recipients, individualRecipient, recipientDeviceId, - dateSent, dateReceived, threadId, DELIVERY_STATUS_NONE, mailbox); + dateSent, dateReceived, threadId, DELIVERY_STATUS_NONE, mailbox, groupAction, groupActionArguments); this.contentLocation = contentLocation; this.messageSize = messageSize; diff --git a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java index e630507e96..3b7e35798d 100644 --- a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java @@ -41,10 +41,12 @@ public class SmsMessageRecord extends MessageRecord { int recipientDeviceId, long dateSent, long dateReceived, long type, long threadId, - int status) + int status, int groupAction, + String groupActionArguments) { super(context, id, body, recipients, individualRecipient, recipientDeviceId, - dateSent, dateReceived, threadId, getGenericDeliveryStatus(status), type); + dateSent, dateReceived, threadId, getGenericDeliveryStatus(status), type, + groupAction, groupActionArguments); } public long getType() { diff --git a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java index 1047c56b82..f6ef86bea4 100644 --- a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -24,8 +24,11 @@ import android.text.style.StyleSpan; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.recipients.Recipients; +import org.whispersystems.textsecure.push.PushMessageProtos; import org.whispersystems.textsecure.util.Util; +import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext; + /** * The message record model which represents thread heading messages. * @@ -41,9 +44,9 @@ public class ThreadRecord extends DisplayRecord { public ThreadRecord(Context context, Body body, Recipients recipients, long date, long count, boolean read, long threadId, long snippetType, - int distributionType) + int distributionType, int groupAction, String groupActionArg) { - super(context, body, recipients, date, date, threadId, snippetType); + super(context, body, recipients, date, date, threadId, snippetType, groupAction, groupActionArg); this.context = context.getApplicationContext(); this.count = count; this.read = read; @@ -54,6 +57,14 @@ public class ThreadRecord extends DisplayRecord { public SpannableString getDisplayBody() { if (SmsDatabase.Types.isDecryptInProgressType(type)) { return emphasisAdded(context.getString(R.string.MessageDisplayHelper_decrypting_please_wait)); + } else if (getGroupAction() == GroupContext.Type.ADD_VALUE || + getGroupAction() == GroupContext.Type.CREATE_VALUE) + { + return emphasisAdded("Added " + getGroupActionArguments()); + } else if (getGroupAction() == GroupContext.Type.QUIT_VALUE) { + return emphasisAdded(getRecipients().toShortString() + " left the group."); + } else if (getGroupAction() == GroupContext.Type.MODIFY_VALUE) { + return emphasisAdded(getRecipients().toShortString() + " modified the group."); } else if (isKeyExchange()) { return emphasisAdded(context.getString(R.string.ConversationListItem_key_exchange_message)); } else if (SmsDatabase.Types.isFailedDecryptType(type)) { diff --git a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java index 1fc0b2ea81..f1f458bb9b 100644 --- a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java @@ -20,11 +20,15 @@ public class IncomingMediaMessage { private final PduHeaders headers; private final PduBody body; private final String groupId; + private final int groupAction; + private final String groupActionArguments; public IncomingMediaMessage(RetrieveConf retreived) { - this.headers = retreived.getPduHeaders(); - this.body = retreived.getBody(); - this.groupId = null; + this.headers = retreived.getPduHeaders(); + this.body = retreived.getBody(); + this.groupId = null; + this.groupAction = -1; + this.groupActionArguments = null; } public IncomingMediaMessage(MasterSecret masterSecret, String localNumber, @@ -35,9 +39,13 @@ public class IncomingMediaMessage { this.body = new PduBody(); if (messageContent.hasGroup()) { - this.groupId = GroupUtil.getEncodedId(messageContent.getGroup().getId().toByteArray()); + this.groupId = GroupUtil.getEncodedId(messageContent.getGroup().getId().toByteArray()); + this.groupAction = messageContent.getGroup().getType().getNumber(); + this.groupActionArguments = GroupUtil.getActionArgument(messageContent.getGroup()); } else { - this.groupId = null; + this.groupId = null; + this.groupAction = -1; + this.groupActionArguments = null; } this.headers.setEncodedStringValue(new EncodedStringValue(message.getSource()), PduHeaders.FROM); @@ -90,4 +98,11 @@ public class IncomingMediaMessage { headers.getEncodedStringValues(PduHeaders.TO).length > 1); } + public int getGroupAction() { + return groupAction; + } + + public String getGroupActionArguments() { + return groupActionArguments; + } } diff --git a/src/org/thoughtcrime/securesms/push/GroupActionRecord.java b/src/org/thoughtcrime/securesms/push/GroupActionRecord.java deleted file mode 100644 index c3fd3f6f94..0000000000 --- a/src/org/thoughtcrime/securesms/push/GroupActionRecord.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.thoughtcrime.securesms.push; - -import org.thoughtcrime.securesms.recipients.Recipient; - -import java.util.Set; - -public class GroupActionRecord { - - private static final int CREATE_GROUP_TYPE = 1; - private static final int ADD_USERS_TYPE = 2; - private static final int LEAVE_GROUP_TYPE = 3; - - private final int type; - private final Set recipients; - private final byte[] groupId; - private final String groupName; - private final byte[] avatar; - - public GroupActionRecord(int type, byte[] groupId, String groupName, - byte[] avatar, Set recipients) - { - this.type = type; - this.groupId = groupId; - this.groupName = groupName; - this.avatar = avatar; - this.recipients = recipients; - } - - public boolean isCreateAction() { - return type== CREATE_GROUP_TYPE; - } - - public boolean isAddUsersAction() { - return type == ADD_USERS_TYPE; - } - - public boolean isLeaveAction() { - return type == LEAVE_GROUP_TYPE; - } - - - public Set getRecipients() { - return recipients; - } - - public byte[] getGroupId() { - return groupId; - } - - public String getGroupName() { - return groupName; - } - - public byte[] getAvatar() { - return avatar; - } -} diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index dddc9e9334..a63aa235d3 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -108,6 +108,10 @@ public class Recipient implements Parcelable, CanonicalRecipient { return this.contactUri; } + public synchronized void setContactPhoto(Bitmap bitmap) { + this.contactPhoto = bitmap; + } + public synchronized String getName() { return this.name; } @@ -149,6 +153,18 @@ public class Recipient implements Parcelable, CanonicalRecipient { listeners.remove(listener); } + public void notifyListeners() { + HashSet localListeners; + + synchronized (this) { + localListeners = (HashSet)listeners.clone(); + } + + for (RecipientModifiedListener listener : localListeners) { + listener.onModified(this); + } + } + public synchronized void writeToParcel(Parcel dest, int flags) { dest.writeString(number); dest.writeString(name); diff --git a/src/org/thoughtcrime/securesms/recipients/Recipients.java b/src/org/thoughtcrime/securesms/recipients/Recipients.java index 60857f9d70..3b87267af2 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipients.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipients.java @@ -18,6 +18,7 @@ package org.thoughtcrime.securesms.recipients; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; import android.util.Patterns; import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener; @@ -145,7 +146,10 @@ public class Recipients implements Parcelable { while (iterator.hasNext()) { String number = iterator.next().getNumber(); - if (scrub && number != null && !Patterns.EMAIL_ADDRESS.matcher(number).matches()) { + if (scrub && number != null && + !Patterns.EMAIL_ADDRESS.matcher(number).matches() && + !GroupUtil.isEncodedGroup(number)) + { number = number.replaceAll("[^0-9+]", ""); } diff --git a/src/org/thoughtcrime/securesms/service/AvatarDownloader.java b/src/org/thoughtcrime/securesms/service/AvatarDownloader.java index 8d5c30f7f5..8eedd3c7d7 100644 --- a/src/org/thoughtcrime/securesms/service/AvatarDownloader.java +++ b/src/org/thoughtcrime/securesms/service/AvatarDownloader.java @@ -9,8 +9,12 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.PartDatabase; import org.thoughtcrime.securesms.push.PushServiceSocketFactory; +import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.recipients.RecipientFactory; +import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; +import org.thoughtcrime.securesms.util.GroupUtil; import org.whispersystems.textsecure.crypto.AttachmentCipherInputStream; import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterSecret; @@ -55,7 +59,16 @@ public class AvatarDownloader { database.updateAvatar(groupId, avatar); - avatar.recycle(); + try { + Recipient groupRecipient = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(groupId), true) + .getPrimaryRecipient(); + groupRecipient.setContactPhoto(avatar); + groupRecipient.notifyListeners(); + } catch (RecipientFormattingException e) { + Log.w("AvatarDownloader", e); + } + +// avatar.recycle(); attachment.delete(); } } catch (IOException e) { diff --git a/src/org/thoughtcrime/securesms/service/PushReceiver.java b/src/org/thoughtcrime/securesms/service/PushReceiver.java index 307bd29b2e..58296e2ef1 100644 --- a/src/org/thoughtcrime/securesms/service/PushReceiver.java +++ b/src/org/thoughtcrime/securesms/service/PushReceiver.java @@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.sms.IncomingKeyExchangeMessage; import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.SmsTransportDetails; -import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.crypto.InvalidMessageException; @@ -35,7 +34,6 @@ import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.RecipientDevice; -import org.whispersystems.textsecure.util.Hex; import ws.com.google.android.mms.MmsException; @@ -220,7 +218,7 @@ public class PushReceiver { if (messageContent.getAttachmentsCount() > 0) { handleReceivedMediaMessage(masterSecret, message, messageContent, secure); - } else if (messageContent.hasBody()) { + } else { handleReceivedTextMessage(masterSecret, message, messageContent, secure); } } @@ -263,8 +261,7 @@ public class PushReceiver { boolean secure) { EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); - String groupId = messageContent.hasGroup() ? GroupUtil.getEncodedId(messageContent.getGroup().getId().toByteArray()) : null; - IncomingTextMessage textMessage = new IncomingTextMessage(message, "", groupId); + IncomingTextMessage textMessage = new IncomingTextMessage(message, "", messageContent.getGroup()); if (secure) { textMessage = new IncomingEncryptedMessage(textMessage, ""); diff --git a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java index 89027974f5..5c1ec29a5c 100644 --- a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java @@ -4,11 +4,14 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.SmsMessage; +import org.thoughtcrime.securesms.util.GroupUtil; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.storage.RecipientDevice; import java.util.List; +import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext; + public class IncomingTextMessage implements Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -32,6 +35,8 @@ public class IncomingTextMessage implements Parcelable { private final String pseudoSubject; private final long sentTimestampMillis; private final String groupId; + private final int groupAction; + private final String groupActionArgument; public IncomingTextMessage(SmsMessage message) { this.message = message.getDisplayMessageBody(); @@ -43,9 +48,11 @@ public class IncomingTextMessage implements Parcelable { this.pseudoSubject = message.getPseudoSubject(); this.sentTimestampMillis = message.getTimestampMillis(); this.groupId = null; + this.groupAction = -1; + this.groupActionArgument = null; } - public IncomingTextMessage(IncomingPushMessage message, String encodedBody, String groupId) { + public IncomingTextMessage(IncomingPushMessage message, String encodedBody, GroupContext group) { this.message = encodedBody; this.sender = message.getSource(); this.senderDeviceId = message.getSourceDevice(); @@ -54,7 +61,16 @@ public class IncomingTextMessage implements Parcelable { this.replyPathPresent = true; this.pseudoSubject = ""; this.sentTimestampMillis = message.getTimestampMillis(); - this.groupId = groupId; + + if (group != null) { + this.groupId = GroupUtil.getEncodedId(group.getId().toByteArray()); + this.groupAction = group.getType().getNumber(); + this.groupActionArgument = GroupUtil.getActionArgument(group); + } else { + this.groupId = null; + this.groupAction = -1; + this.groupActionArgument = null; + } } public IncomingTextMessage(Parcel in) { @@ -67,6 +83,8 @@ public class IncomingTextMessage implements Parcelable { this.pseudoSubject = in.readString(); this.sentTimestampMillis = in.readLong(); this.groupId = in.readString(); + this.groupAction = in.readInt(); + this.groupActionArgument = in.readString(); } public IncomingTextMessage(IncomingTextMessage base, String newBody) { @@ -79,6 +97,8 @@ public class IncomingTextMessage implements Parcelable { this.pseudoSubject = base.getPseudoSubject(); this.sentTimestampMillis = base.getSentTimestampMillis(); this.groupId = base.getGroupId(); + this.groupAction = base.getGroupAction(); + this.groupActionArgument = base.getGroupActionArgument(); } public IncomingTextMessage(List fragments) { @@ -97,6 +117,8 @@ public class IncomingTextMessage implements Parcelable { this.pseudoSubject = fragments.get(0).getPseudoSubject(); this.sentTimestampMillis = fragments.get(0).getSentTimestampMillis(); this.groupId = fragments.get(0).getGroupId(); + this.groupAction = fragments.get(0).getGroupAction(); + this.groupActionArgument = fragments.get(0).getGroupActionArgument(); } public long getSentTimestampMillis() { @@ -151,6 +173,14 @@ public class IncomingTextMessage implements Parcelable { return groupId; } + public int getGroupAction() { + return groupAction; + } + + public String getGroupActionArgument() { + return groupActionArgument; + } + @Override public int describeContents() { return 0; @@ -167,5 +197,7 @@ public class IncomingTextMessage implements Parcelable { out.writeString(pseudoSubject); out.writeLong(sentTimestampMillis); out.writeString(groupId); + out.writeInt(groupAction); + out.writeString(groupActionArgument); } } diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java index 5eac49e7d7..f71906a273 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java @@ -7,20 +7,33 @@ import org.thoughtcrime.securesms.recipients.Recipients; public class OutgoingTextMessage { private final Recipients recipients; - private String message; + private final String message; + private final int groupAction; + private final String groupActionArguments; public OutgoingTextMessage(Recipient recipient, String message) { this(new Recipients(recipient), message); } public OutgoingTextMessage(Recipients recipients, String message) { - this.recipients = recipients; - this.message = message; + this.recipients = recipients; + this.message = message; + this.groupAction = -1; + this.groupActionArguments = null; + } + + public OutgoingTextMessage(Recipient recipient, int groupAction, String groupActionArguments) { + this.recipients = new Recipients(recipient); + this.groupAction = groupAction; + this.groupActionArguments = groupActionArguments; + this.message = ""; } protected OutgoingTextMessage(OutgoingTextMessage base, String body) { - this.recipients = base.getRecipients(); - this.message = body; + this.recipients = base.getRecipients(); + this.groupAction = base.getGroupAction(); + this.groupActionArguments = base.getGroupActionArguments(); + this.message = body; } public String getMessageBody() { @@ -56,4 +69,12 @@ public class OutgoingTextMessage { public OutgoingTextMessage withBody(String body) { return new OutgoingTextMessage(this, body); } + + public int getGroupAction() { + return groupAction; + } + + public String getGroupActionArguments() { + return groupActionArguments; + } } diff --git a/src/org/thoughtcrime/securesms/util/GroupUtil.java b/src/org/thoughtcrime/securesms/util/GroupUtil.java index 843641c3a7..89a76cd4a4 100644 --- a/src/org/thoughtcrime/securesms/util/GroupUtil.java +++ b/src/org/thoughtcrime/securesms/util/GroupUtil.java @@ -4,6 +4,8 @@ import org.whispersystems.textsecure.util.Hex; import java.io.IOException; +import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext; + public class GroupUtil { private static final String ENCODED_GROUP_PREFIX = "__textsecure_group__!"; @@ -24,4 +26,15 @@ public class GroupUtil { return groupId.startsWith(ENCODED_GROUP_PREFIX); } + public static String getActionArgument(GroupContext group) { + if (group.getType().equals(GroupContext.Type.CREATE) || + group.getType().equals(GroupContext.Type.ADD)) + { + return org.whispersystems.textsecure.util.Util.join(group.getMembersList(), ","); + } else if (group.getType().equals(GroupContext.Type.MODIFY)) { + return group.getName(); + } + + return null; + } }