GroupId class.
This commit is contained in:
parent
a73a73e42c
commit
a860315587
43 changed files with 519 additions and 365 deletions
|
@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
|
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
@ -208,7 +209,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeExistingGroup() {
|
private void initializeExistingGroup() {
|
||||||
final String groupId = getIntent().getStringExtra(GROUP_ID_EXTRA);
|
final GroupId groupId = GroupId.parseNullable(getIntent().getStringExtra(GROUP_ID_EXTRA));
|
||||||
|
|
||||||
if (groupId != null) {
|
if (groupId != null) {
|
||||||
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, groupId);
|
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, groupId);
|
||||||
|
@ -361,7 +362,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||||
}
|
}
|
||||||
memberAddresses.add(Recipient.self().getId());
|
memberAddresses.add(Recipient.self().getId());
|
||||||
|
|
||||||
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true);
|
GroupId groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true);
|
||||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(activity).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(activity).getOrInsertFromGroupId(groupId);
|
||||||
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
|
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||||
|
@ -443,9 +444,9 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class UpdateSignalGroupTask extends SignalGroupTask {
|
private static class UpdateSignalGroupTask extends SignalGroupTask {
|
||||||
private String groupId;
|
private final GroupId groupId;
|
||||||
|
|
||||||
public UpdateSignalGroupTask(GroupCreateActivity activity, String groupId,
|
public UpdateSignalGroupTask(GroupCreateActivity activity, GroupId groupId,
|
||||||
Bitmap avatar, String name, Set<Recipient> members)
|
Bitmap avatar, String name, Set<Recipient> members)
|
||||||
{
|
{
|
||||||
super(activity, avatar, name, members);
|
super(activity, avatar, name, members);
|
||||||
|
@ -467,7 +468,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||||
if (!activity.isFinishing()) {
|
if (!activity.isFinishing()) {
|
||||||
Intent intent = activity.getIntent();
|
Intent intent = activity.getIntent();
|
||||||
intent.putExtra(GROUP_THREAD_EXTRA, result.get().getThreadId());
|
intent.putExtra(GROUP_THREAD_EXTRA, result.get().getThreadId());
|
||||||
intent.putExtra(GROUP_ID_EXTRA, result.get().getGroupRecipient().requireGroupId());
|
intent.putExtra(GROUP_ID_EXTRA, result.get().getGroupRecipient().requireGroupId().toString());
|
||||||
activity.setResult(RESULT_OK, intent);
|
activity.setResult(RESULT_OK, intent);
|
||||||
activity.finish();
|
activity.finish();
|
||||||
}
|
}
|
||||||
|
@ -534,7 +535,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask<String,Void,Optional<GroupData>> {
|
private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask<GroupId, Void, Optional<GroupData>> {
|
||||||
private GroupCreateActivity activity;
|
private GroupCreateActivity activity;
|
||||||
|
|
||||||
public FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) {
|
public FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) {
|
||||||
|
@ -545,7 +546,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Optional<GroupData> doInBackground(String... groupIds) {
|
protected Optional<GroupData> doInBackground(GroupId... groupIds) {
|
||||||
final GroupDatabase db = DatabaseFactory.getGroupDatabase(activity);
|
final GroupDatabase db = DatabaseFactory.getGroupDatabase(activity);
|
||||||
final List<Recipient> recipients = db.getGroupMembers(groupIds[0], false);
|
final List<Recipient> recipients = db.getGroupMembers(groupIds[0], false);
|
||||||
final Optional<GroupRecord> group = db.getGroup(groupIds[0]);
|
final Optional<GroupRecord> group = db.getGroup(groupIds[0]);
|
||||||
|
@ -593,13 +594,13 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GroupData {
|
private static class GroupData {
|
||||||
String id;
|
GroupId id;
|
||||||
Set<Recipient> recipients;
|
Set<Recipient> recipients;
|
||||||
Bitmap avatarBmp;
|
Bitmap avatarBmp;
|
||||||
byte[] avatarBytes;
|
byte[] avatarBytes;
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
public GroupData(String id, Set<Recipient> recipients, Bitmap avatarBmp, byte[] avatarBytes, String name) {
|
GroupData(GroupId id, Set<Recipient> recipients, Bitmap avatarBmp, byte[] avatarBytes, String name) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.recipients = recipients;
|
this.recipients = recipients;
|
||||||
this.avatarBmp = avatarBmp;
|
this.avatarBmp = avatarBmp;
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class ContactAccessor {
|
||||||
reader = DatabaseFactory.getGroupDatabase(context).getGroupsFilteredByTitle(constraint, true);
|
reader = DatabaseFactory.getGroupDatabase(context).getGroupsFilteredByTitle(constraint, true);
|
||||||
|
|
||||||
while ((record = reader.getNext()) != null) {
|
while ((record = reader.getNext()) != null) {
|
||||||
numberList.add(record.getEncodedId());
|
numberList.add(record.getId().toString());
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (reader != null)
|
if (reader != null)
|
||||||
|
|
|
@ -2,24 +2,24 @@ package org.thoughtcrime.securesms.contacts;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||||
import org.thoughtcrime.securesms.components.FromTextView;
|
import org.thoughtcrime.securesms.components.FromTextView;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientF
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private void setText(@Nullable Recipient recipient, int type, String name, String number, String label) {
|
private void setText(@Nullable Recipient recipient, int type, String name, String number, String label) {
|
||||||
if (number == null || number.isEmpty() || GroupUtil.isEncodedGroup(number)) {
|
if (number == null || number.isEmpty() || GroupId.isEncodedGroup(number)) {
|
||||||
this.nameView.setEnabled(false);
|
this.nameView.setEnabled(false);
|
||||||
this.numberView.setText("");
|
this.numberView.setText("");
|
||||||
this.labelView.setVisibility(View.GONE);
|
this.labelView.setVisibility(View.GONE);
|
||||||
|
|
|
@ -22,10 +22,11 @@ import android.database.Cursor;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.database.MergeCursor;
|
import android.database.MergeCursor;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.loader.content.CursorLoader;
|
import androidx.loader.content.CursorLoader;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
@ -35,8 +36,8 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.UsernameUtil;
|
import org.thoughtcrime.securesms.util.UsernameUtil;
|
||||||
|
@ -226,7 +227,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
||||||
ThreadRecord threadRecord;
|
ThreadRecord threadRecord;
|
||||||
while ((threadRecord = reader.getNext()) != null) {
|
while ((threadRecord = reader.getNext()) != null) {
|
||||||
Recipient recipient = threadRecord.getRecipient();
|
Recipient recipient = threadRecord.getRecipient();
|
||||||
String stringId = recipient.isGroup() ? recipient.requireGroupId() : recipient.getE164().or(recipient.getEmail()).or("");
|
String stringId = recipient.isGroup() ? recipient.requireGroupId().toString() : recipient.getE164().or(recipient.getEmail()).or("");
|
||||||
|
|
||||||
recentConversations.addRow(new Object[] { recipient.getId().serialize(),
|
recentConversations.addRow(new Object[] { recipient.getId().serialize(),
|
||||||
recipient.toShortString(getContext()),
|
recipient.toShortString(getContext()),
|
||||||
|
@ -265,7 +266,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
groupContacts.addRow(new Object[] { groupRecord.getRecipientId().serialize(),
|
groupContacts.addRow(new Object[] { groupRecord.getRecipientId().serialize(),
|
||||||
groupRecord.getTitle(),
|
groupRecord.getTitle(),
|
||||||
groupRecord.getEncodedId(),
|
groupRecord.getId(),
|
||||||
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
||||||
"",
|
"",
|
||||||
ContactRepository.NORMAL_TYPE });
|
ContactRepository.NORMAL_TYPE });
|
||||||
|
|
|
@ -3,11 +3,13 @@ package org.thoughtcrime.securesms.contacts.avatars;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.util.Conversions;
|
import org.thoughtcrime.securesms.util.Conversions;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
|
@ -16,12 +18,12 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
public class GroupRecordContactPhoto implements ContactPhoto {
|
public final class GroupRecordContactPhoto implements ContactPhoto {
|
||||||
|
|
||||||
private final String groupId;
|
private final GroupId groupId;
|
||||||
private final long avatarId;
|
private final long avatarId;
|
||||||
|
|
||||||
public GroupRecordContactPhoto(@NonNull String groupId, long avatarId) {
|
public GroupRecordContactPhoto(@NonNull GroupId groupId, long avatarId) {
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.avatarId = avatarId;
|
this.avatarId = avatarId;
|
||||||
}
|
}
|
||||||
|
@ -50,13 +52,13 @@ public class GroupRecordContactPhoto implements ContactPhoto {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
|
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
|
||||||
messageDigest.update(groupId.getBytes());
|
messageDigest.update(groupId.toString().getBytes());
|
||||||
messageDigest.update(Conversions.longToByteArray(avatarId));
|
messageDigest.update(Conversions.longToByteArray(avatarId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null || !(other instanceof GroupRecordContactPhoto)) return false;
|
if (!(other instanceof GroupRecordContactPhoto)) return false;
|
||||||
|
|
||||||
GroupRecordContactPhoto that = (GroupRecordContactPhoto)other;
|
GroupRecordContactPhoto that = (GroupRecordContactPhoto)other;
|
||||||
return this.groupId.equals(that.groupId) && this.avatarId == that.avatarId;
|
return this.groupId.equals(that.groupId) && this.avatarId == that.avatarId;
|
||||||
|
|
|
@ -1140,7 +1140,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||||
|
|
||||||
private void handleEditPushGroup() {
|
private void handleEditPushGroup() {
|
||||||
Intent intent = new Intent(ConversationActivity.this, GroupCreateActivity.class);
|
Intent intent = new Intent(ConversationActivity.this, GroupCreateActivity.class);
|
||||||
intent.putExtra(GroupCreateActivity.GROUP_ID_EXTRA, recipient.get().requireGroupId());
|
intent.putExtra(GroupCreateActivity.GROUP_ID_EXTRA, recipient.get().requireGroupId().toString());
|
||||||
startActivityForResult(intent, GROUP_EDIT);
|
startActivityForResult(intent, GROUP_EDIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,25 +6,25 @@ import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
import net.sqlcipher.database.SQLiteDatabase;
|
import net.sqlcipher.database.SQLiteDatabase;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -95,9 +95,9 @@ public class GroupDatabase extends Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<GroupRecord> getGroup(String groupId) {
|
public Optional<GroupRecord> getGroup(@NonNull GroupId groupId) {
|
||||||
try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, GROUP_ID + " = ?",
|
try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, GROUP_ID + " = ?",
|
||||||
new String[] {groupId},
|
new String[] {groupId.toString()},
|
||||||
null, null, null))
|
null, null, null))
|
||||||
{
|
{
|
||||||
if (cursor != null && cursor.moveToNext()) {
|
if (cursor != null && cursor.moveToNext()) {
|
||||||
|
@ -113,7 +113,7 @@ public class GroupDatabase extends Database {
|
||||||
return Optional.fromNullable(reader.getCurrent());
|
return Optional.fromNullable(reader.getCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUnknownGroup(String groupId) {
|
public boolean isUnknownGroup(@NonNull GroupId groupId) {
|
||||||
Optional<GroupRecord> group = getGroup(groupId);
|
Optional<GroupRecord> group = getGroup(groupId);
|
||||||
|
|
||||||
if (!group.isPresent()) {
|
if (!group.isPresent()) {
|
||||||
|
@ -143,7 +143,7 @@ public class GroupDatabase extends Database {
|
||||||
return new Reader(cursor);
|
return new Reader(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOrCreateGroupForMembers(List<RecipientId> members, boolean mms) {
|
public GroupId getOrCreateGroupForMembers(List<RecipientId> members, boolean mms) {
|
||||||
Collections.sort(members);
|
Collections.sort(members);
|
||||||
|
|
||||||
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {GROUP_ID},
|
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {GROUP_ID},
|
||||||
|
@ -152,9 +152,9 @@ public class GroupDatabase extends Database {
|
||||||
null, null, null);
|
null, null, null);
|
||||||
try {
|
try {
|
||||||
if (cursor != null && cursor.moveToNext()) {
|
if (cursor != null && cursor.moveToNext()) {
|
||||||
return cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
|
return GroupId.parse(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID)));
|
||||||
} else {
|
} else {
|
||||||
String groupId = GroupUtil.getEncodedId(allocateGroupId(), mms);
|
GroupId groupId = allocateGroupId(mms);
|
||||||
create(groupId, null, members, null, null);
|
create(groupId, null, members, null, null);
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ public class GroupDatabase extends Database {
|
||||||
return new Reader(cursor);
|
return new Reader(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull List<Recipient> getGroupMembers(String groupId, boolean includeSelf) {
|
public @NonNull List<Recipient> getGroupMembers(@NonNull GroupId groupId, boolean includeSelf) {
|
||||||
List<RecipientId> members = getCurrentMembers(groupId);
|
List<RecipientId> members = getCurrentMembers(groupId);
|
||||||
List<Recipient> recipients = new LinkedList<>();
|
List<Recipient> recipients = new LinkedList<>();
|
||||||
|
|
||||||
|
@ -212,14 +212,14 @@ public class GroupDatabase extends Database {
|
||||||
return recipients;
|
return recipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void create(@NonNull String groupId, @Nullable String title, @NonNull List<RecipientId> members,
|
public void create(@NonNull GroupId groupId, @Nullable String title, @NonNull List<RecipientId> members,
|
||||||
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay)
|
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay)
|
||||||
{
|
{
|
||||||
Collections.sort(members);
|
Collections.sort(members);
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(RECIPIENT_ID, DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId).serialize());
|
contentValues.put(RECIPIENT_ID, DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId).serialize());
|
||||||
contentValues.put(GROUP_ID, groupId);
|
contentValues.put(GROUP_ID, groupId.toString());
|
||||||
contentValues.put(TITLE, title);
|
contentValues.put(TITLE, title);
|
||||||
contentValues.put(MEMBERS, RecipientId.toSerializedList(members));
|
contentValues.put(MEMBERS, RecipientId.toSerializedList(members));
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ public class GroupDatabase extends Database {
|
||||||
contentValues.put(AVATAR_RELAY, relay);
|
contentValues.put(AVATAR_RELAY, relay);
|
||||||
contentValues.put(TIMESTAMP, System.currentTimeMillis());
|
contentValues.put(TIMESTAMP, System.currentTimeMillis());
|
||||||
contentValues.put(ACTIVE, 1);
|
contentValues.put(ACTIVE, 1);
|
||||||
contentValues.put(MMS, GroupUtil.isMmsGroup(groupId));
|
contentValues.put(MMS, groupId.isMmsGroup());
|
||||||
|
|
||||||
databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
|
databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ public class GroupDatabase extends Database {
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(String groupId, String title, SignalServiceAttachmentPointer avatar) {
|
public void update(@NonNull GroupId groupId, String title, SignalServiceAttachmentPointer avatar) {
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
if (title != null) contentValues.put(TITLE, title);
|
if (title != null) contentValues.put(TITLE, title);
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ public class GroupDatabase extends Database {
|
||||||
|
|
||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,
|
||||||
GROUP_ID + " = ?",
|
GROUP_ID + " = ?",
|
||||||
new String[] {groupId});
|
new String[] {groupId.toString()});
|
||||||
|
|
||||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
Recipient.live(groupRecipient).refresh();
|
Recipient.live(groupRecipient).refresh();
|
||||||
|
@ -264,21 +264,21 @@ public class GroupDatabase extends Database {
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateTitle(String groupId, String title) {
|
public void updateTitle(@NonNull GroupId groupId, String title) {
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(TITLE, title);
|
contentValues.put(TITLE, title);
|
||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
||||||
new String[] {groupId});
|
new String[] {groupId.toString()});
|
||||||
|
|
||||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
Recipient.live(groupRecipient).refresh();
|
Recipient.live(groupRecipient).refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAvatar(String groupId, Bitmap avatar) {
|
public void updateAvatar(@NonNull GroupId groupId, @Nullable Bitmap avatar) {
|
||||||
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
|
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAvatar(String groupId, byte[] avatar) {
|
public void updateAvatar(@NonNull GroupId groupId, @Nullable byte[] avatar) {
|
||||||
long avatarId;
|
long avatarId;
|
||||||
|
|
||||||
if (avatar != null) avatarId = Math.abs(new SecureRandom().nextLong());
|
if (avatar != null) avatarId = Math.abs(new SecureRandom().nextLong());
|
||||||
|
@ -290,13 +290,13 @@ public class GroupDatabase extends Database {
|
||||||
contentValues.put(AVATAR_ID, avatarId);
|
contentValues.put(AVATAR_ID, avatarId);
|
||||||
|
|
||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
||||||
new String[] {groupId});
|
new String[] {groupId.toString()});
|
||||||
|
|
||||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
Recipient.live(groupRecipient).refresh();
|
Recipient.live(groupRecipient).refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMembers(String groupId, List<RecipientId> members) {
|
public void updateMembers(@NonNull GroupId groupId, List<RecipientId> members) {
|
||||||
Collections.sort(members);
|
Collections.sort(members);
|
||||||
|
|
||||||
ContentValues contents = new ContentValues();
|
ContentValues contents = new ContentValues();
|
||||||
|
@ -304,13 +304,13 @@ public class GroupDatabase extends Database {
|
||||||
contents.put(ACTIVE, 1);
|
contents.put(ACTIVE, 1);
|
||||||
|
|
||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
||||||
new String[] {groupId});
|
new String[] {groupId.toString()});
|
||||||
|
|
||||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
Recipient.live(groupRecipient).refresh();
|
Recipient.live(groupRecipient).refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(String groupId, RecipientId source) {
|
public void remove(@NonNull GroupId groupId, RecipientId source) {
|
||||||
List<RecipientId> currentMembers = getCurrentMembers(groupId);
|
List<RecipientId> currentMembers = getCurrentMembers(groupId);
|
||||||
currentMembers.remove(source);
|
currentMembers.remove(source);
|
||||||
|
|
||||||
|
@ -318,19 +318,19 @@ public class GroupDatabase extends Database {
|
||||||
contents.put(MEMBERS, RecipientId.toSerializedList(currentMembers));
|
contents.put(MEMBERS, RecipientId.toSerializedList(currentMembers));
|
||||||
|
|
||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
||||||
new String[] {groupId});
|
new String[] {groupId.toString()});
|
||||||
|
|
||||||
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
Recipient.live(groupRecipient).refresh();
|
Recipient.live(groupRecipient).refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<RecipientId> getCurrentMembers(String groupId) {
|
private List<RecipientId> getCurrentMembers(@NonNull GroupId groupId) {
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {MEMBERS},
|
cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {MEMBERS},
|
||||||
GROUP_ID + " = ?",
|
GROUP_ID + " = ?",
|
||||||
new String[] {groupId},
|
new String[] {groupId.toString()},
|
||||||
null, null, null);
|
null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
@ -345,23 +345,22 @@ public class GroupDatabase extends Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive(String groupId) {
|
public boolean isActive(@NonNull GroupId groupId) {
|
||||||
Optional<GroupRecord> record = getGroup(groupId);
|
Optional<GroupRecord> record = getGroup(groupId);
|
||||||
return record.isPresent() && record.get().isActive();
|
return record.isPresent() && record.get().isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setActive(String groupId, boolean active) {
|
public void setActive(@NonNull GroupId groupId, boolean active) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(ACTIVE, active ? 1 : 0);
|
values.put(ACTIVE, active ? 1 : 0);
|
||||||
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {groupId});
|
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {groupId.toString()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GroupId allocateGroupId(boolean mms) {
|
||||||
public byte[] allocateGroupId() {
|
|
||||||
byte[] groupId = new byte[16];
|
byte[] groupId = new byte[16];
|
||||||
new SecureRandom().nextBytes(groupId);
|
new SecureRandom().nextBytes(groupId);
|
||||||
return groupId;
|
return mms ? GroupId.mms(groupId) : GroupId.v1(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Reader implements Closeable {
|
public static class Reader implements Closeable {
|
||||||
|
@ -385,7 +384,7 @@ public class GroupDatabase extends Database {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GroupRecord(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID)),
|
return new GroupRecord(GroupId.parse(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID))),
|
||||||
RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(TITLE)),
|
cursor.getString(cursor.getColumnIndexOrThrow(TITLE)),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)),
|
cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)),
|
||||||
|
@ -408,7 +407,7 @@ public class GroupDatabase extends Database {
|
||||||
|
|
||||||
public static class GroupRecord {
|
public static class GroupRecord {
|
||||||
|
|
||||||
private final String id;
|
private final GroupId id;
|
||||||
private final RecipientId recipientId;
|
private final RecipientId recipientId;
|
||||||
private final String title;
|
private final String title;
|
||||||
private final List<RecipientId> members;
|
private final List<RecipientId> members;
|
||||||
|
@ -421,7 +420,7 @@ public class GroupDatabase extends Database {
|
||||||
private final boolean active;
|
private final boolean active;
|
||||||
private final boolean mms;
|
private final boolean mms;
|
||||||
|
|
||||||
public GroupRecord(String id, @NonNull RecipientId recipientId, String title, String members, byte[] avatar,
|
public GroupRecord(@NonNull GroupId id, @NonNull RecipientId recipientId, String title, String members, byte[] avatar,
|
||||||
long avatarId, byte[] avatarKey, String avatarContentType,
|
long avatarId, byte[] avatarKey, String avatarContentType,
|
||||||
String relay, boolean active, byte[] avatarDigest, boolean mms)
|
String relay, boolean active, byte[] avatarDigest, boolean mms)
|
||||||
{
|
{
|
||||||
|
@ -441,22 +440,14 @@ public class GroupDatabase extends Database {
|
||||||
else this.members = new LinkedList<>();
|
else this.members = new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getId() {
|
public GroupId getId() {
|
||||||
try {
|
return id;
|
||||||
return GroupUtil.getDecodedId(id);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new AssertionError(ioe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull RecipientId getRecipientId() {
|
public @NonNull RecipientId getRecipientId() {
|
||||||
return recipientId;
|
return recipientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEncodedId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,22 +17,20 @@ import net.sqlcipher.database.SQLiteDatabase;
|
||||||
import org.signal.zkgroup.profiles.ProfileKey;
|
import org.signal.zkgroup.profiles.ProfileKey;
|
||||||
import org.signal.zkgroup.profiles.ProfileKeyCredential;
|
import org.signal.zkgroup.profiles.ProfileKeyCredential;
|
||||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper.RecordUpdate;
|
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncModels;
|
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobs.StorageSyncJob;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
|
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||||
|
import org.thoughtcrime.securesms.storage.StorageSyncHelper.RecordUpdate;
|
||||||
|
import org.thoughtcrime.securesms.storage.StorageSyncModels;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.InvalidKeyException;
|
import org.whispersystems.libsignal.InvalidKeyException;
|
||||||
|
@ -352,13 +350,13 @@ public class RecipientDatabase extends Database {
|
||||||
return getOrInsertByColumn(EMAIL, email).recipientId;
|
return getOrInsertByColumn(EMAIL, email).recipientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull RecipientId getOrInsertFromGroupId(@NonNull String groupId) {
|
public @NonNull RecipientId getOrInsertFromGroupId(@NonNull GroupId groupId) {
|
||||||
GetOrInsertResult result = getOrInsertByColumn(GROUP_ID, groupId);
|
GetOrInsertResult result = getOrInsertByColumn(GROUP_ID, groupId.toString());
|
||||||
|
|
||||||
if (result.neededInsert) {
|
if (result.neededInsert) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
|
||||||
if (GroupUtil.isMmsGroup(groupId)) {
|
if (groupId.isMmsGroup()) {
|
||||||
values.put(GROUP_TYPE, GroupType.MMS.getId());
|
values.put(GROUP_TYPE, GroupType.MMS.getId());
|
||||||
} else {
|
} else {
|
||||||
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
||||||
|
@ -563,7 +561,7 @@ public class RecipientDatabase extends Database {
|
||||||
for (SignalGroupV1Record insert : groupV1Inserts) {
|
for (SignalGroupV1Record insert : groupV1Inserts) {
|
||||||
db.insertOrThrow(TABLE_NAME, null, getValuesForStorageGroupV1(insert));
|
db.insertOrThrow(TABLE_NAME, null, getValuesForStorageGroupV1(insert));
|
||||||
|
|
||||||
Recipient recipient = Recipient.externalGroup(context, GroupUtil.getEncodedId(insert.getGroupId(), false));
|
Recipient recipient = Recipient.externalGroup(context, GroupId.v1(insert.getGroupId()));
|
||||||
|
|
||||||
threadDatabase.setArchived(recipient.getId(), insert.isArchived());
|
threadDatabase.setArchived(recipient.getId(), insert.isArchived());
|
||||||
recipient.live().refresh();
|
recipient.live().refresh();
|
||||||
|
@ -577,7 +575,7 @@ public class RecipientDatabase extends Database {
|
||||||
throw new AssertionError("Had an update, but it didn't match any rows!");
|
throw new AssertionError("Had an update, but it didn't match any rows!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Recipient recipient = Recipient.externalGroup(context, GroupUtil.getEncodedId(update.getOld().getGroupId(), false));
|
Recipient recipient = Recipient.externalGroup(context, GroupId.v1(update.getOld().getGroupId()));
|
||||||
|
|
||||||
threadDatabase.setArchived(recipient.getId(), update.getNew().isArchived());
|
threadDatabase.setArchived(recipient.getId(), update.getNew().isArchived());
|
||||||
recipient.live().refresh();
|
recipient.live().refresh();
|
||||||
|
@ -672,7 +670,7 @@ public class RecipientDatabase extends Database {
|
||||||
|
|
||||||
private static @NonNull ContentValues getValuesForStorageGroupV1(@NonNull SignalGroupV1Record groupV1) {
|
private static @NonNull ContentValues getValuesForStorageGroupV1(@NonNull SignalGroupV1Record groupV1) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(GROUP_ID, GroupUtil.getEncodedId(groupV1.getGroupId(), false));
|
values.put(GROUP_ID, GroupId.v1(groupV1.getGroupId()).toString());
|
||||||
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
|
||||||
values.put(PROFILE_SHARING, groupV1.isProfileSharingEnabled() ? "1" : "0");
|
values.put(PROFILE_SHARING, groupV1.isProfileSharingEnabled() ? "1" : "0");
|
||||||
values.put(BLOCKED, groupV1.isBlocked() ? "1" : "0");
|
values.put(BLOCKED, groupV1.isBlocked() ? "1" : "0");
|
||||||
|
@ -729,13 +727,13 @@ public class RecipientDatabase extends Database {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull RecipientSettings getRecipientSettings(@NonNull Cursor cursor) {
|
private static @NonNull RecipientSettings getRecipientSettings(@NonNull Cursor cursor) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||||
UUID uuid = UuidUtil.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(UUID)));
|
UUID uuid = UuidUtil.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(UUID)));
|
||||||
String username = cursor.getString(cursor.getColumnIndexOrThrow(USERNAME));
|
String username = cursor.getString(cursor.getColumnIndexOrThrow(USERNAME));
|
||||||
String e164 = cursor.getString(cursor.getColumnIndexOrThrow(PHONE));
|
String e164 = cursor.getString(cursor.getColumnIndexOrThrow(PHONE));
|
||||||
String email = cursor.getString(cursor.getColumnIndexOrThrow(EMAIL));
|
String email = cursor.getString(cursor.getColumnIndexOrThrow(EMAIL));
|
||||||
String groupId = cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
|
GroupId groupId = GroupId.parseNullable(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID)));
|
||||||
int groupType = cursor.getInt(cursor.getColumnIndexOrThrow(GROUP_TYPE));
|
int groupType = cursor.getInt(cursor.getColumnIndexOrThrow(GROUP_TYPE));
|
||||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKED)) == 1;
|
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKED)) == 1;
|
||||||
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE_RINGTONE));
|
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE_RINGTONE));
|
||||||
|
@ -1408,10 +1406,10 @@ public class RecipientDatabase extends Database {
|
||||||
db.update(TABLE_NAME, setBlocked, UUID + " = ?", new String[] { uuid });
|
db.update(TABLE_NAME, setBlocked, UUID + " = ?", new String[] { uuid });
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> groupIdStrings = Stream.of(groupIds).map(g -> GroupUtil.getEncodedId(g, false)).toList();
|
List<GroupId> groupIdStrings = Stream.of(groupIds).map(GroupId::v1).toList();
|
||||||
|
|
||||||
for (String groupId : groupIdStrings) {
|
for (GroupId groupId : groupIdStrings) {
|
||||||
db.update(TABLE_NAME, setBlocked, GROUP_ID + " = ?", new String[] { groupId });
|
db.update(TABLE_NAME, setBlocked, GROUP_ID + " = ?", new String[] { groupId.toString() });
|
||||||
}
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
|
@ -1637,7 +1635,7 @@ public class RecipientDatabase extends Database {
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String e164;
|
private final String e164;
|
||||||
private final String email;
|
private final String email;
|
||||||
private final String groupId;
|
private final GroupId groupId;
|
||||||
private final GroupType groupType;
|
private final GroupType groupType;
|
||||||
private final boolean blocked;
|
private final boolean blocked;
|
||||||
private final long muteUntil;
|
private final long muteUntil;
|
||||||
|
@ -1673,7 +1671,7 @@ public class RecipientDatabase extends Database {
|
||||||
@Nullable String username,
|
@Nullable String username,
|
||||||
@Nullable String e164,
|
@Nullable String e164,
|
||||||
@Nullable String email,
|
@Nullable String email,
|
||||||
@Nullable String groupId,
|
@Nullable GroupId groupId,
|
||||||
@NonNull GroupType groupType,
|
@NonNull GroupType groupType,
|
||||||
boolean blocked,
|
boolean blocked,
|
||||||
long muteUntil,
|
long muteUntil,
|
||||||
|
@ -1761,7 +1759,7 @@ public class RecipientDatabase extends Database {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable String getGroupId() {
|
public @Nullable GroupId getGroupId() {
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
@ -27,6 +28,7 @@ import com.annimon.stream.Stream;
|
||||||
import net.sqlcipher.database.SQLiteDatabase;
|
import net.sqlcipher.database.SQLiteDatabase;
|
||||||
import net.sqlcipher.database.SQLiteStatement;
|
import net.sqlcipher.database.SQLiteStatement;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
|
@ -231,7 +233,7 @@ public class SmsMigrator {
|
||||||
|
|
||||||
List<RecipientId> recipientIds = Stream.of(ourRecipients).map(Recipient::getId).toList();
|
List<RecipientId> recipientIds = Stream.of(ourRecipients).map(Recipient::getId).toList();
|
||||||
|
|
||||||
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(recipientIds, true);
|
GroupId ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(recipientIds, true);
|
||||||
RecipientId ourGroupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(ourGroupId);
|
RecipientId ourGroupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(ourGroupId);
|
||||||
Recipient ourGroupRecipient = Recipient.resolved(ourGroupRecipientId);
|
Recipient ourGroupRecipient = Recipient.resolved(ourGroupRecipientId);
|
||||||
long ourThreadId = threadDatabase.getThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
long ourThreadId = threadDatabase.getThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||||
|
|
|
@ -10,9 +10,9 @@ import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.google.i18n.phonenumbers.NumberParseException;
|
import com.google.i18n.phonenumbers.NumberParseException;
|
||||||
|
@ -35,13 +35,14 @@ import org.thoughtcrime.securesms.database.PushDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.migrations.LegacyMigrationJob;
|
import org.thoughtcrime.securesms.migrations.LegacyMigrationJob;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
|
@ -1274,7 +1275,7 @@ public class ClassicOpenHelper extends SQLiteOpenHelper {
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
String address = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(address) && !GroupUtil.isEncodedGroup(address) && !NumberUtil.isValidEmail(address)) {
|
if (!TextUtils.isEmpty(address) && !GroupId.isEncodedGroup(address) && !NumberUtil.isValidEmail(address)) {
|
||||||
Uri lookup = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address));
|
Uri lookup = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address));
|
||||||
|
|
||||||
try (Cursor contactCursor = context.getContentResolver().query(lookup, new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME,
|
try (Cursor contactCursor = context.getContentResolver().query(lookup, new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME,
|
||||||
|
|
|
@ -9,10 +9,10 @@ import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import net.sqlcipher.database.SQLiteDatabase;
|
import net.sqlcipher.database.SQLiteDatabase;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -153,7 +153,7 @@ public class RecipientIdMigrationHelper {
|
||||||
try (Cursor cursor = db.query("recipient_preferences", null, null, null, null, null, null)) {
|
try (Cursor cursor = db.query("recipient_preferences", null, null, null, null, null, null)) {
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
String address = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||||
boolean isGroup = GroupUtil.isEncodedGroup(address);
|
boolean isGroup = GroupId.isEncodedGroup(address);
|
||||||
boolean isEmail = !isGroup && NumberUtil.isValidEmail(address);
|
boolean isEmail = !isGroup && NumberUtil.isValidEmail(address);
|
||||||
boolean isPhone = !isGroup && !isEmail;
|
boolean isPhone = !isGroup && !isEmail;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ import net.sqlcipher.database.SQLiteDatabase;
|
||||||
import net.sqlcipher.database.SQLiteDatabaseHook;
|
import net.sqlcipher.database.SQLiteDatabaseHook;
|
||||||
import net.sqlcipher.database.SQLiteOpenHelper;
|
import net.sqlcipher.database.SQLiteOpenHelper;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
|
||||||
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||||
|
@ -44,13 +43,14 @@ import org.thoughtcrime.securesms.database.StickerDatabase;
|
||||||
import org.thoughtcrime.securesms.database.StorageKeyDatabase;
|
import org.thoughtcrime.securesms.database.StorageKeyDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
|
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
@ -349,7 +349,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||||
String displayName = NotificationChannels.getChannelDisplayNameFor(context, systemName, profileName, null, address);
|
String displayName = NotificationChannels.getChannelDisplayNameFor(context, systemName, profileName, null, address);
|
||||||
boolean vibrateEnabled = vibrateState == 0 ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == 1;
|
boolean vibrateEnabled = vibrateState == 0 ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == 1;
|
||||||
|
|
||||||
if (GroupUtil.isEncodedGroup(address)) {
|
if (GroupId.isEncodedGroup(address)) {
|
||||||
try(Cursor groupCursor = db.rawQuery("SELECT title FROM groups WHERE group_id = ?", new String[] { address })) {
|
try(Cursor groupCursor = db.rawQuery("SELECT title FROM groups WHERE group_id = ?", new String[] { address })) {
|
||||||
if (groupCursor != null && groupCursor.moveToFirst()) {
|
if (groupCursor != null && groupCursor.moveToFirst()) {
|
||||||
String title = groupCursor.getString(groupCursor.getColumnIndexOrThrow("title"));
|
String title = groupCursor.getString(groupCursor.getColumnIndexOrThrow("title"));
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
package org.thoughtcrime.securesms.groups;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public final class GroupId {
|
||||||
|
|
||||||
|
private static final String ENCODED_SIGNAL_GROUP_PREFIX = "__textsecure_group__!";
|
||||||
|
private static final String ENCODED_MMS_GROUP_PREFIX = "__signal_mms_group__!";
|
||||||
|
|
||||||
|
private final String encodedId;
|
||||||
|
|
||||||
|
private GroupId(@NonNull String encodedId) {
|
||||||
|
this.encodedId = encodedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull GroupId v1(byte[] gv1GroupIdBytes) {
|
||||||
|
return new GroupId(ENCODED_SIGNAL_GROUP_PREFIX + Hex.toStringCondensed(gv1GroupIdBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull GroupId mms(byte[] mmsGroupIdBytes) {
|
||||||
|
return new GroupId(ENCODED_MMS_GROUP_PREFIX + Hex.toStringCondensed(mmsGroupIdBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull GroupId parse(@NonNull String encodedGroupId) {
|
||||||
|
try {
|
||||||
|
if (!isEncodedGroup(encodedGroupId)) {
|
||||||
|
throw new IOException("Invalid encoding");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bytes = extractDecodedId(encodedGroupId);
|
||||||
|
return isMmsGroup(encodedGroupId) ? mms(bytes) : v1(bytes);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable GroupId parseNullable(@Nullable String encodedGroupId) {
|
||||||
|
if (encodedGroupId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse(encodedGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEncodedGroup(@NonNull String groupId) {
|
||||||
|
return groupId.startsWith(ENCODED_SIGNAL_GROUP_PREFIX) || groupId.startsWith(ENCODED_MMS_GROUP_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] extractDecodedId(@NonNull String encodedGroupId) throws IOException {
|
||||||
|
return Hex.fromStringCondensed(encodedGroupId.split("!", 2)[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMmsGroup(@NonNull String groupId) {
|
||||||
|
return groupId.startsWith(ENCODED_MMS_GROUP_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getDecodedId() {
|
||||||
|
try {
|
||||||
|
return extractDecodedId(encodedId);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMmsGroup() {
|
||||||
|
return isMmsGroup(encodedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object obj) {
|
||||||
|
if (obj instanceof GroupId) {
|
||||||
|
return ((GroupId) obj).encodedId.equals(encodedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return encodedId.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return encodedId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ public final class GroupManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GroupActionResult updateGroup(@NonNull Context context,
|
public static GroupActionResult updateGroup(@NonNull Context context,
|
||||||
@NonNull String groupId,
|
@NonNull GroupId groupId,
|
||||||
@NonNull Set<Recipient> members,
|
@NonNull Set<Recipient> members,
|
||||||
@Nullable Bitmap avatar,
|
@Nullable Bitmap avatar,
|
||||||
@Nullable String name)
|
@Nullable String name)
|
||||||
|
@ -51,7 +51,7 @@ public final class GroupManager {
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static boolean leaveGroup(@NonNull Context context, @NonNull Recipient groupRecipient) {
|
public static boolean leaveGroup(@NonNull Context context, @NonNull Recipient groupRecipient) {
|
||||||
String groupId = groupRecipient.requireGroupId();
|
GroupId groupId = groupRecipient.requireGroupId();
|
||||||
|
|
||||||
return V1GroupManager.leaveGroup(context, groupId, groupRecipient);
|
return V1GroupManager.leaveGroup(context, groupId, groupRecipient);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||||
|
@ -63,7 +62,7 @@ public class GroupMessageProcessor {
|
||||||
|
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
SignalServiceGroup group = message.getGroupInfo().get();
|
SignalServiceGroup group = message.getGroupInfo().get();
|
||||||
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
|
GroupId id = GroupId.v1(group.getGroupId());
|
||||||
Optional<GroupRecord> record = database.getGroup(id);
|
Optional<GroupRecord> record = database.getGroup(id);
|
||||||
|
|
||||||
if (record.isPresent() && group.getType() == Type.UPDATE) {
|
if (record.isPresent() && group.getType() == Type.UPDATE) {
|
||||||
|
@ -73,7 +72,7 @@ public class GroupMessageProcessor {
|
||||||
} else if (record.isPresent() && group.getType() == Type.QUIT) {
|
} else if (record.isPresent() && group.getType() == Type.QUIT) {
|
||||||
return handleGroupLeave(context, content, group, record.get(), outgoing);
|
return handleGroupLeave(context, content, group, record.get(), outgoing);
|
||||||
} else if (record.isPresent() && group.getType() == Type.REQUEST_INFO) {
|
} else if (record.isPresent() && group.getType() == Type.REQUEST_INFO) {
|
||||||
return handleGroupInfoRequest(context, content, group, record.get());
|
return handleGroupInfoRequest(context, content, record.get());
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Received unknown type, ignoring...");
|
Log.w(TAG, "Received unknown type, ignoring...");
|
||||||
return null;
|
return null;
|
||||||
|
@ -86,7 +85,7 @@ public class GroupMessageProcessor {
|
||||||
boolean outgoing)
|
boolean outgoing)
|
||||||
{
|
{
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
|
GroupId id = GroupId.v1(group.getGroupId());
|
||||||
GroupContext.Builder builder = createGroupContext(group);
|
GroupContext.Builder builder = createGroupContext(group);
|
||||||
builder.setType(GroupContext.Type.UPDATE);
|
builder.setType(GroupContext.Type.UPDATE);
|
||||||
|
|
||||||
|
@ -106,7 +105,7 @@ public class GroupMessageProcessor {
|
||||||
|
|
||||||
if (FeatureFlags.messageRequests() && (sender.isSystemContact() || sender.isProfileSharing())) {
|
if (FeatureFlags.messageRequests() && (sender.isSystemContact() || sender.isProfileSharing())) {
|
||||||
Log.i(TAG, "Auto-enabling profile sharing because 'adder' is trusted. contact: " + sender.isSystemContact() + ", profileSharing: " + sender.isProfileSharing());
|
Log.i(TAG, "Auto-enabling profile sharing because 'adder' is trusted. contact: " + sender.isSystemContact() + ", profileSharing: " + sender.isProfileSharing());
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.external(context, id).getId(), true);
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.externalGroup(context, id).getId(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||||
|
@ -120,7 +119,7 @@ public class GroupMessageProcessor {
|
||||||
{
|
{
|
||||||
|
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
|
GroupId id = GroupId.v1(group.getGroupId());
|
||||||
|
|
||||||
Set<RecipientId> recordMembers = new HashSet<>(groupRecord.getMembers());
|
Set<RecipientId> recordMembers = new HashSet<>(groupRecord.getMembers());
|
||||||
Set<RecipientId> messageMembers = new HashSet<>();
|
Set<RecipientId> messageMembers = new HashSet<>();
|
||||||
|
@ -178,13 +177,12 @@ public class GroupMessageProcessor {
|
||||||
|
|
||||||
private static Long handleGroupInfoRequest(@NonNull Context context,
|
private static Long handleGroupInfoRequest(@NonNull Context context,
|
||||||
@NonNull SignalServiceContent content,
|
@NonNull SignalServiceContent content,
|
||||||
@NonNull SignalServiceGroup group,
|
|
||||||
@NonNull GroupRecord record)
|
@NonNull GroupRecord record)
|
||||||
{
|
{
|
||||||
Recipient sender = Recipient.externalPush(context, content.getSender());
|
Recipient sender = Recipient.externalPush(context, content.getSender());
|
||||||
|
|
||||||
if (record.getMembers().contains(sender.getId())) {
|
if (record.getMembers().contains(sender.getId())) {
|
||||||
ApplicationDependencies.getJobManager().add(new PushGroupUpdateJob(sender.getId(), group.getGroupId()));
|
ApplicationDependencies.getJobManager().add(new PushGroupUpdateJob(sender.getId(), record.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -197,7 +195,7 @@ public class GroupMessageProcessor {
|
||||||
boolean outgoing)
|
boolean outgoing)
|
||||||
{
|
{
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
String id = GroupUtil.getEncodedId(group.getGroupId(), false);
|
GroupId id = GroupId.v1(group.getGroupId());
|
||||||
List<RecipientId> members = record.getMembers();
|
List<RecipientId> members = record.getMembers();
|
||||||
|
|
||||||
GroupContext.Builder builder = createGroupContext(group);
|
GroupContext.Builder builder = createGroupContext(group);
|
||||||
|
@ -222,13 +220,13 @@ public class GroupMessageProcessor {
|
||||||
{
|
{
|
||||||
if (group.getAvatar().isPresent()) {
|
if (group.getAvatar().isPresent()) {
|
||||||
ApplicationDependencies.getJobManager()
|
ApplicationDependencies.getJobManager()
|
||||||
.add(new AvatarDownloadJob(group.getGroupId()));
|
.add(new AvatarDownloadJob(GroupId.v1(group.getGroupId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (outgoing) {
|
if (outgoing) {
|
||||||
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||||
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupUtil.getEncodedId(group.getGroupId(), false));
|
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupId.v1(group.getGroupId()));
|
||||||
Recipient recipient = Recipient.resolved(recipientId);
|
Recipient recipient = Recipient.resolved(recipientId);
|
||||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, false, null, Collections.emptyList(), Collections.emptyList());
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, false, null, Collections.emptyList(), Collections.emptyList());
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||||
|
@ -240,7 +238,7 @@ public class GroupMessageProcessor {
|
||||||
} else {
|
} else {
|
||||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||||
String body = Base64.encodeBytes(storage.toByteArray());
|
String body = Base64.encodeBytes(storage.toByteArray());
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalPush(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(GroupUtil.getEncodedId(group.getGroupId(), false)), 0, content.isNeedsReceipt());
|
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalPush(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(GroupId.v1(group.getGroupId())), 0, content.isNeedsReceipt());
|
||||||
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
||||||
|
|
||||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.groups;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
@ -11,7 +12,6 @@ import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
||||||
import org.thoughtcrime.securesms.blurhash.BlurHash;
|
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
|
@ -28,12 +28,10 @@ import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -49,7 +47,7 @@ final class V1GroupManager {
|
||||||
{
|
{
|
||||||
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
||||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
final String groupId = GroupUtil.getEncodedId(groupDatabase.allocateGroupId(), mms);
|
final GroupId groupId = GroupDatabase.allocateGroupId(mms);
|
||||||
final RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
final RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
final Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
final Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||||
|
|
||||||
|
@ -67,7 +65,7 @@ final class V1GroupManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
static GroupActionResult updateGroup(@NonNull Context context,
|
static GroupActionResult updateGroup(@NonNull Context context,
|
||||||
@NonNull String groupId,
|
@NonNull GroupId groupId,
|
||||||
@NonNull Set<RecipientId> memberAddresses,
|
@NonNull Set<RecipientId> memberAddresses,
|
||||||
@Nullable Bitmap avatar,
|
@Nullable Bitmap avatar,
|
||||||
@Nullable String name)
|
@Nullable String name)
|
||||||
|
@ -81,7 +79,7 @@ final class V1GroupManager {
|
||||||
groupDatabase.updateTitle(groupId, name);
|
groupDatabase.updateTitle(groupId, name);
|
||||||
groupDatabase.updateAvatar(groupId, avatarBytes);
|
groupDatabase.updateAvatar(groupId, avatarBytes);
|
||||||
|
|
||||||
if (!GroupUtil.isMmsGroup(groupId)) {
|
if (!groupId.isMmsGroup()) {
|
||||||
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes);
|
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes);
|
||||||
} else {
|
} else {
|
||||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
|
@ -92,48 +90,44 @@ final class V1GroupManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
||||||
@NonNull String groupId,
|
@NonNull GroupId groupId,
|
||||||
@NonNull Set<RecipientId> members,
|
@NonNull Set<RecipientId> members,
|
||||||
@Nullable String groupName,
|
@Nullable String groupName,
|
||||||
@Nullable byte[] avatar)
|
@Nullable byte[] avatar)
|
||||||
{
|
{
|
||||||
try {
|
Attachment avatarAttachment = null;
|
||||||
Attachment avatarAttachment = null;
|
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||||
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
|
||||||
|
|
||||||
List<GroupContext.Member> uuidMembers = new LinkedList<>();
|
List<GroupContext.Member> uuidMembers = new LinkedList<>();
|
||||||
List<String> e164Members = new LinkedList<>();
|
List<String> e164Members = new LinkedList<>();
|
||||||
|
|
||||||
for (RecipientId member : members) {
|
for (RecipientId member : members) {
|
||||||
Recipient recipient = Recipient.resolved(member);
|
Recipient recipient = Recipient.resolved(member);
|
||||||
uuidMembers.add(GroupMessageProcessor.createMember(RecipientUtil.toSignalServiceAddress(context, recipient)));
|
uuidMembers.add(GroupMessageProcessor.createMember(RecipientUtil.toSignalServiceAddress(context, recipient)));
|
||||||
}
|
|
||||||
|
|
||||||
GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
|
|
||||||
.setId(ByteString.copyFrom(GroupUtil.getDecodedId(groupId)))
|
|
||||||
.setType(GroupContext.Type.UPDATE)
|
|
||||||
.addAllMembersE164(e164Members)
|
|
||||||
.addAllMembers(uuidMembers);
|
|
||||||
if (groupName != null) groupContextBuilder.setName(groupName);
|
|
||||||
GroupContext groupContext = groupContextBuilder.build();
|
|
||||||
|
|
||||||
if (avatar != null) {
|
|
||||||
Uri avatarUri = BlobProvider.getInstance().forData(avatar).createForSingleUseInMemory();
|
|
||||||
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false, null, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList());
|
|
||||||
long threadId = MessageSender.send(context, 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.getDecodedId()))
|
||||||
|
.setType(GroupContext.Type.UPDATE)
|
||||||
|
.addAllMembersE164(e164Members)
|
||||||
|
.addAllMembers(uuidMembers);
|
||||||
|
if (groupName != null) groupContextBuilder.setName(groupName);
|
||||||
|
GroupContext groupContext = groupContextBuilder.build();
|
||||||
|
|
||||||
|
if (avatar != null) {
|
||||||
|
Uri avatarUri = BlobProvider.getInstance().forData(avatar).createForSingleUseInMemory();
|
||||||
|
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList());
|
||||||
|
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
|
||||||
|
|
||||||
|
return new GroupActionResult(groupRecipient, threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
static boolean leaveGroup(@NonNull Context context, @NonNull String groupId, @NonNull Recipient groupRecipient) {
|
static boolean leaveGroup(@NonNull Context context, @NonNull GroupId groupId, @NonNull Recipient groupRecipient) {
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, groupRecipient);
|
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, groupRecipient);
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package org.thoughtcrime.securesms.jobs;
|
package org.thoughtcrime.securesms.jobs;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
|
@ -14,7 +16,6 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
|
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
|
||||||
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
@ -36,9 +37,9 @@ public class AvatarDownloadJob extends BaseJob {
|
||||||
|
|
||||||
private static final String KEY_GROUP_ID = "group_id";
|
private static final String KEY_GROUP_ID = "group_id";
|
||||||
|
|
||||||
private byte[] groupId;
|
private @NonNull GroupId groupId;
|
||||||
|
|
||||||
public AvatarDownloadJob(@NonNull byte[] groupId) {
|
public AvatarDownloadJob(@NonNull GroupId groupId) {
|
||||||
this(new Job.Parameters.Builder()
|
this(new Job.Parameters.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setMaxAttempts(10)
|
.setMaxAttempts(10)
|
||||||
|
@ -46,14 +47,14 @@ public class AvatarDownloadJob extends BaseJob {
|
||||||
groupId);
|
groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AvatarDownloadJob(@NonNull Job.Parameters parameters, @NonNull byte[] groupId) {
|
private AvatarDownloadJob(@NonNull Job.Parameters parameters, @NonNull GroupId groupId) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putString(KEY_GROUP_ID, GroupUtil.getEncodedId(groupId, false)).build();
|
return new Data.Builder().putString(KEY_GROUP_ID, groupId.toString()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,9 +64,8 @@ public class AvatarDownloadJob extends BaseJob {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException {
|
public void onRun() throws IOException {
|
||||||
String encodeId = GroupUtil.getEncodedId(groupId, false);
|
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
Optional<GroupRecord> record = database.getGroup(encodeId);
|
Optional<GroupRecord> record = database.getGroup(groupId);
|
||||||
File attachment = null;
|
File attachment = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -93,7 +93,7 @@ public class AvatarDownloadJob extends BaseJob {
|
||||||
InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE);
|
InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE);
|
||||||
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
|
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
|
||||||
|
|
||||||
database.updateAvatar(encodeId, avatar);
|
database.updateAvatar(groupId, avatar);
|
||||||
inputStream.close();
|
inputStream.close();
|
||||||
}
|
}
|
||||||
} catch (BitmapDecodingException | NonSuccessfulResponseCodeException | InvalidMessageException e) {
|
} catch (BitmapDecodingException | NonSuccessfulResponseCodeException | InvalidMessageException e) {
|
||||||
|
@ -116,11 +116,7 @@ public class AvatarDownloadJob extends BaseJob {
|
||||||
public static final class Factory implements Job.Factory<AvatarDownloadJob> {
|
public static final class Factory implements Job.Factory<AvatarDownloadJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull AvatarDownloadJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
public @NonNull AvatarDownloadJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||||
try {
|
return new AvatarDownloadJob(parameters, GroupId.parse(data.getString(KEY_GROUP_ID)));
|
||||||
return new AvatarDownloadJob(parameters, GroupUtil.getDecodedId(data.getString(KEY_GROUP_ID)));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,12 @@ package org.thoughtcrime.securesms.jobs;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.WorkerThread;
|
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
|
@ -18,7 +18,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
|
@ -27,8 +26,6 @@ import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -54,7 +51,7 @@ public class LeaveGroupJob extends BaseJob {
|
||||||
private static final String KEY_MEMBERS = "members";
|
private static final String KEY_MEMBERS = "members";
|
||||||
private static final String KEY_RECIPIENTS = "recipients";
|
private static final String KEY_RECIPIENTS = "recipients";
|
||||||
|
|
||||||
private final byte[] groupId;
|
private final GroupId groupId;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final List<RecipientId> members;
|
private final List<RecipientId> members;
|
||||||
private final List<RecipientId> recipients;
|
private final List<RecipientId> recipients;
|
||||||
|
@ -63,7 +60,7 @@ public class LeaveGroupJob extends BaseJob {
|
||||||
List<RecipientId> members = Stream.of(group.resolve().getParticipants()).map(Recipient::getId).toList();
|
List<RecipientId> members = Stream.of(group.resolve().getParticipants()).map(Recipient::getId).toList();
|
||||||
members.remove(Recipient.self().getId());
|
members.remove(Recipient.self().getId());
|
||||||
|
|
||||||
return new LeaveGroupJob(GroupUtil.getDecodedIdOrThrow(group.getGroupId().get()),
|
return new LeaveGroupJob(group.getGroupId().get(),
|
||||||
group.resolve().getDisplayName(ApplicationDependencies.getApplication()),
|
group.resolve().getDisplayName(ApplicationDependencies.getApplication()),
|
||||||
members,
|
members,
|
||||||
members,
|
members,
|
||||||
|
@ -75,7 +72,7 @@ public class LeaveGroupJob extends BaseJob {
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LeaveGroupJob(@NonNull byte[] groupId,
|
private LeaveGroupJob(@NonNull GroupId groupId,
|
||||||
@NonNull String name,
|
@NonNull String name,
|
||||||
@NonNull List<RecipientId> members,
|
@NonNull List<RecipientId> members,
|
||||||
@NonNull List<RecipientId> recipients,
|
@NonNull List<RecipientId> recipients,
|
||||||
|
@ -90,7 +87,7 @@ public class LeaveGroupJob extends BaseJob {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putString(KEY_GROUP_ID, Base64.encodeBytes(groupId))
|
return new Data.Builder().putString(KEY_GROUP_ID, Base64.encodeBytes(groupId.getDecodedId()))
|
||||||
.putString(KEY_GROUP_NAME, name)
|
.putString(KEY_GROUP_NAME, name)
|
||||||
.putString(KEY_MEMBERS, RecipientId.toSerializedList(members))
|
.putString(KEY_MEMBERS, RecipientId.toSerializedList(members))
|
||||||
.putString(KEY_RECIPIENTS, RecipientId.toSerializedList(recipients))
|
.putString(KEY_RECIPIENTS, RecipientId.toSerializedList(recipients))
|
||||||
|
@ -128,7 +125,7 @@ public class LeaveGroupJob extends BaseJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull List<Recipient> deliver(@NonNull Context context,
|
private static @NonNull List<Recipient> deliver(@NonNull Context context,
|
||||||
@NonNull byte[] groupId,
|
@NonNull GroupId groupId,
|
||||||
@NonNull String name,
|
@NonNull String name,
|
||||||
@NonNull List<RecipientId> members,
|
@NonNull List<RecipientId> members,
|
||||||
@NonNull List<RecipientId> destinations)
|
@NonNull List<RecipientId> destinations)
|
||||||
|
@ -138,7 +135,7 @@ public class LeaveGroupJob extends BaseJob {
|
||||||
List<SignalServiceAddress> addresses = Stream.of(destinations).map(Recipient::resolved).map(t -> RecipientUtil.toSignalServiceAddress(context, t)).toList();
|
List<SignalServiceAddress> addresses = Stream.of(destinations).map(Recipient::resolved).map(t -> RecipientUtil.toSignalServiceAddress(context, t)).toList();
|
||||||
List<SignalServiceAddress> memberAddresses = Stream.of(members).map(Recipient::resolved).map(t -> RecipientUtil.toSignalServiceAddress(context, t)).toList();
|
List<SignalServiceAddress> memberAddresses = Stream.of(members).map(Recipient::resolved).map(t -> RecipientUtil.toSignalServiceAddress(context, t)).toList();
|
||||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(destinations).map(Recipient::resolved).map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient)).toList();
|
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(destinations).map(Recipient::resolved).map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient)).toList();
|
||||||
SignalServiceGroup serviceGroup = new SignalServiceGroup(SignalServiceGroup.Type.QUIT, groupId, name, memberAddresses, null);
|
SignalServiceGroup serviceGroup = new SignalServiceGroup(SignalServiceGroup.Type.QUIT, groupId.getDecodedId(), name, memberAddresses, null);
|
||||||
SignalServiceDataMessage.Builder dataMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage.Builder dataMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(System.currentTimeMillis())
|
.withTimestamp(System.currentTimeMillis())
|
||||||
.asGroupMessage(serviceGroup);
|
.asGroupMessage(serviceGroup);
|
||||||
|
@ -169,7 +166,7 @@ public class LeaveGroupJob extends BaseJob {
|
||||||
public static class Factory implements Job.Factory<LeaveGroupJob> {
|
public static class Factory implements Job.Factory<LeaveGroupJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull LeaveGroupJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
public @NonNull LeaveGroupJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||||
return new LeaveGroupJob(Base64.decodeOrThrow(data.getString(KEY_GROUP_ID)),
|
return new LeaveGroupJob(GroupId.v1(Base64.decodeOrThrow(data.getString(KEY_GROUP_ID))),
|
||||||
data.getString(KEY_GROUP_NAME),
|
data.getString(KEY_GROUP_NAME),
|
||||||
RecipientId.fromSerializedList(data.getString(KEY_MEMBERS)),
|
RecipientId.fromSerializedList(data.getString(KEY_MEMBERS)),
|
||||||
RecipientId.fromSerializedList(data.getString(KEY_RECIPIENTS)),
|
RecipientId.fromSerializedList(data.getString(KEY_RECIPIENTS)),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.thoughtcrime.securesms.jobs;
|
package org.thoughtcrime.securesms.jobs;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
@ -177,11 +179,11 @@ public class MmsDownloadJob extends BaseJob {
|
||||||
int subscriptionId, @Nullable RecipientId notificationFrom)
|
int subscriptionId, @Nullable RecipientId notificationFrom)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
Optional<String> group = Optional.absent();
|
Optional<GroupId> group = Optional.absent();
|
||||||
Set<RecipientId> members = new HashSet<>();
|
Set<RecipientId> members = new HashSet<>();
|
||||||
String body = null;
|
String body = null;
|
||||||
List<Attachment> attachments = new LinkedList<>();
|
List<Attachment> attachments = new LinkedList<>();
|
||||||
|
|
||||||
RecipientId from = null;
|
RecipientId from = null;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
|
@ -76,7 +75,7 @@ public class MultiDeviceBlockedUpdateJob extends BaseJob {
|
||||||
|
|
||||||
while ((recipient = reader.getNext()) != null) {
|
while ((recipient = reader.getNext()) != null) {
|
||||||
if (recipient.isPushGroup()) {
|
if (recipient.isPushGroup()) {
|
||||||
blockedGroups.add(GroupUtil.getDecodedId(recipient.requireGroupId()));
|
blockedGroups.add(recipient.requireGroupId().getDecodedId());
|
||||||
} else if (recipient.hasServiceIdentifier()) {
|
} else if (recipient.hasServiceIdentifier()) {
|
||||||
blockedIndividuals.add(RecipientUtil.toSignalServiceAddress(context, recipient));
|
blockedIndividuals.add(RecipientUtil.toSignalServiceAddress(context, recipient));
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
|
@ -92,13 +91,13 @@ public class MultiDeviceGroupUpdateJob extends BaseJob {
|
||||||
members.add(RecipientUtil.toSignalServiceAddress(context, Recipient.resolved(member)));
|
members.add(RecipientUtil.toSignalServiceAddress(context, Recipient.resolved(member)));
|
||||||
}
|
}
|
||||||
|
|
||||||
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupUtil.getEncodedId(record.getId(), record.isMms()));
|
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(record.getId());
|
||||||
Recipient recipient = Recipient.resolved(recipientId);
|
Recipient recipient = Recipient.resolved(recipientId);
|
||||||
Optional<Integer> expirationTimer = recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent();
|
Optional<Integer> expirationTimer = recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent();
|
||||||
Map<RecipientId, Integer> inboxPositions = DatabaseFactory.getThreadDatabase(context).getInboxPositions();
|
Map<RecipientId, Integer> inboxPositions = DatabaseFactory.getThreadDatabase(context).getInboxPositions();
|
||||||
Set<RecipientId> archived = DatabaseFactory.getThreadDatabase(context).getArchivedRecipients();
|
Set<RecipientId> archived = DatabaseFactory.getThreadDatabase(context).getArchivedRecipients();
|
||||||
|
|
||||||
out.write(new DeviceGroup(record.getId(),
|
out.write(new DeviceGroup(record.getId().getDecodedId(),
|
||||||
Optional.fromNullable(record.getTitle()),
|
Optional.fromNullable(record.getTitle()),
|
||||||
members,
|
members,
|
||||||
getAvatar(record.getAvatar()),
|
getAvatar(record.getAvatar()),
|
||||||
|
|
|
@ -8,18 +8,13 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.kbs.MasterKey;
|
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.KeysMessage;
|
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.MessageRequestResponseMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.MessageRequestResponseMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
@ -100,7 +95,7 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob {
|
||||||
MessageRequestResponseMessage response;
|
MessageRequestResponseMessage response;
|
||||||
|
|
||||||
if (recipient.isGroup()) {
|
if (recipient.isGroup()) {
|
||||||
response = MessageRequestResponseMessage.forGroup(GroupUtil.getDecodedId(recipient.getGroupId().get()), localToRemoteType(type));
|
response = MessageRequestResponseMessage.forGroup(recipient.getGroupId().get().getDecodedId(), localToRemoteType(type));
|
||||||
} else {
|
} else {
|
||||||
response = MessageRequestResponseMessage.forIndividual(RecipientUtil.toSignalServiceAddress(context, recipient), localToRemoteType(type));
|
response = MessageRequestResponseMessage.forIndividual(RecipientUtil.toSignalServiceAddress(context, recipient), localToRemoteType(type));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,13 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.database.PushDatabase;
|
import org.thoughtcrime.securesms.database.PushDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.state.SignalProtocolStore;
|
import org.whispersystems.libsignal.state.SignalProtocolStore;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
@ -233,7 +233,7 @@ public final class PushDecryptMessageJob extends BaseJob {
|
||||||
|
|
||||||
return new PushProcessMessageJob.ExceptionMetadata(sender,
|
return new PushProcessMessageJob.ExceptionMetadata(sender,
|
||||||
e.getSenderDevice(),
|
e.getSenderDevice(),
|
||||||
e.getGroup().transform(g -> GroupUtil.getEncodedId(g.getGroupId(), false)).orNull());
|
e.getGroup().transform(g -> GroupId.v1(g.getGroupId())).orNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PushProcessMessageJob.ExceptionMetadata toExceptionMetadata(@NonNull ProtocolException e) throws NoSenderException {
|
private static PushProcessMessageJob.ExceptionMetadata toExceptionMetadata(@NonNull ProtocolException e) throws NoSenderException {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.thoughtcrime.securesms.jobs;
|
package org.thoughtcrime.securesms.jobs;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
@ -18,6 +19,7 @@ import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||||
|
@ -31,8 +33,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
|
@ -242,7 +242,7 @@ public class PushGroupSendJob extends PushSendJob {
|
||||||
rotateSenderCertificateIfNecessary();
|
rotateSenderCertificateIfNecessary();
|
||||||
|
|
||||||
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
||||||
String groupId = groupRecipient.requireGroupId();
|
GroupId groupId = groupRecipient.requireGroupId();
|
||||||
Optional<byte[]> profileKey = getProfileKey(groupRecipient);
|
Optional<byte[]> profileKey = getProfileKey(groupRecipient);
|
||||||
Optional<Quote> quote = getQuoteFor(message);
|
Optional<Quote> quote = getQuoteFor(message);
|
||||||
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
||||||
|
@ -266,7 +266,7 @@ public class PushGroupSendJob extends PushSendJob {
|
||||||
List<SignalServiceAddress> members = Stream.of(groupContext.getMembersList())
|
List<SignalServiceAddress> members = Stream.of(groupContext.getMembersList())
|
||||||
.map(m -> new SignalServiceAddress(UuidUtil.parseOrNull(m.getUuid()), m.getE164()))
|
.map(m -> new SignalServiceAddress(UuidUtil.parseOrNull(m.getUuid()), m.getE164()))
|
||||||
.toList();
|
.toList();
|
||||||
SignalServiceGroup group = new SignalServiceGroup(type, GroupUtil.getDecodedId(groupId), groupContext.getName(), members, avatar);
|
SignalServiceGroup group = new SignalServiceGroup(type, groupId.getDecodedId(), groupContext.getName(), members, avatar);
|
||||||
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(message.getSentTimeMillis())
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
.withExpiration(groupRecipient.getExpireMessages())
|
.withExpiration(groupRecipient.getExpireMessages())
|
||||||
|
@ -275,7 +275,7 @@ public class PushGroupSendJob extends PushSendJob {
|
||||||
|
|
||||||
return messageSender.sendMessage(addresses, unidentifiedAccess, isRecipientUpdate, groupDataMessage);
|
return messageSender.sendMessage(addresses, unidentifiedAccess, isRecipientUpdate, groupDataMessage);
|
||||||
} else {
|
} else {
|
||||||
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedId(groupId));
|
SignalServiceGroup group = new SignalServiceGroup(groupId.getDecodedId());
|
||||||
SignalServiceDataMessage groupMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage groupMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(message.getSentTimeMillis())
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
.asGroupMessage(group)
|
.asGroupMessage(group)
|
||||||
|
@ -295,7 +295,7 @@ public class PushGroupSendJob extends PushSendJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull List<RecipientId> getGroupMessageRecipients(String groupId, long messageId) {
|
private @NonNull List<RecipientId> getGroupMessageRecipients(@NonNull GroupId groupId, long messageId) {
|
||||||
List<GroupReceiptInfo> destinations = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageId);
|
List<GroupReceiptInfo> destinations = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageId);
|
||||||
if (!destinations.isEmpty()) return Stream.of(destinations).map(GroupReceiptInfo::getRecipientId).toList();
|
if (!destinations.isEmpty()) return Stream.of(destinations).map(GroupReceiptInfo::getRecipientId).toList();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
|
@ -15,7 +16,6 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
|
@ -26,8 +26,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -44,10 +42,10 @@ public class PushGroupUpdateJob extends BaseJob {
|
||||||
private static final String KEY_SOURCE = "source";
|
private static final String KEY_SOURCE = "source";
|
||||||
private static final String KEY_GROUP_ID = "group_id";
|
private static final String KEY_GROUP_ID = "group_id";
|
||||||
|
|
||||||
private RecipientId source;
|
private final RecipientId source;
|
||||||
private byte[] groupId;
|
private final GroupId groupId;
|
||||||
|
|
||||||
public PushGroupUpdateJob(@NonNull RecipientId source, byte[] groupId) {
|
public PushGroupUpdateJob(@NonNull RecipientId source, @NonNull GroupId groupId) {
|
||||||
this(new Job.Parameters.Builder()
|
this(new Job.Parameters.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
|
@ -57,7 +55,7 @@ public class PushGroupUpdateJob extends BaseJob {
|
||||||
groupId);
|
groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PushGroupUpdateJob(@NonNull Job.Parameters parameters, RecipientId source, byte[] groupId) {
|
private PushGroupUpdateJob(@NonNull Job.Parameters parameters, RecipientId source, @NonNull GroupId groupId) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
|
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
@ -67,7 +65,7 @@ public class PushGroupUpdateJob extends BaseJob {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putString(KEY_SOURCE, source.serialize())
|
return new Data.Builder().putString(KEY_SOURCE, source.serialize())
|
||||||
.putString(KEY_GROUP_ID, GroupUtil.getEncodedId(groupId, false))
|
.putString(KEY_GROUP_ID, groupId.toString())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,11 +77,11 @@ public class PushGroupUpdateJob extends BaseJob {
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException, UntrustedIdentityException {
|
public void onRun() throws IOException, UntrustedIdentityException {
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
Optional<GroupRecord> record = groupDatabase.getGroup(GroupUtil.getEncodedId(groupId, false));
|
Optional<GroupRecord> record = groupDatabase.getGroup(groupId);
|
||||||
SignalServiceAttachment avatar = null;
|
SignalServiceAttachment avatar = null;
|
||||||
|
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
Log.w(TAG, "No information for group record info request: " + new String(groupId));
|
Log.w(TAG, "No information for group record info request: " + groupId.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,12 +102,12 @@ public class PushGroupUpdateJob extends BaseJob {
|
||||||
|
|
||||||
SignalServiceGroup groupContext = SignalServiceGroup.newBuilder(Type.UPDATE)
|
SignalServiceGroup groupContext = SignalServiceGroup.newBuilder(Type.UPDATE)
|
||||||
.withAvatar(avatar)
|
.withAvatar(avatar)
|
||||||
.withId(groupId)
|
.withId(groupId.getDecodedId())
|
||||||
.withMembers(members)
|
.withMembers(members)
|
||||||
.withName(record.get().getTitle())
|
.withName(record.get().getTitle())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupUtil.getEncodedId(groupId, false));
|
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||||
|
|
||||||
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder()
|
||||||
|
@ -139,13 +137,9 @@ public class PushGroupUpdateJob extends BaseJob {
|
||||||
public static final class Factory implements Job.Factory<PushGroupUpdateJob> {
|
public static final class Factory implements Job.Factory<PushGroupUpdateJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull PushGroupUpdateJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
|
public @NonNull PushGroupUpdateJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
|
||||||
try {
|
return new PushGroupUpdateJob(parameters,
|
||||||
return new PushGroupUpdateJob(parameters,
|
RecipientId.from(data.getString(KEY_SOURCE)),
|
||||||
RecipientId.from(data.getString(KEY_SOURCE)),
|
GroupId.parse(data.getString(KEY_GROUP_ID)));
|
||||||
GroupUtil.getDecodedId(data.getString(KEY_GROUP_ID)));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
|
@ -62,9 +63,9 @@ import org.thoughtcrime.securesms.mms.StickerSlide;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
|
||||||
import org.thoughtcrime.securesms.ringrtc.IceCandidateParcel;
|
import org.thoughtcrime.securesms.ringrtc.IceCandidateParcel;
|
||||||
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
|
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
|
||||||
|
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
|
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
|
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
|
@ -74,7 +75,6 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
|
@ -217,7 +217,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
dataBuilder.putString(KEY_EXCEPTION_SENDER, exceptionMetadata.sender)
|
dataBuilder.putString(KEY_EXCEPTION_SENDER, exceptionMetadata.sender)
|
||||||
.putInt(KEY_EXCEPTION_DEVICE, exceptionMetadata.senderDevice)
|
.putInt(KEY_EXCEPTION_DEVICE, exceptionMetadata.senderDevice)
|
||||||
.putString(KEY_EXCEPTION_GROUP_ID, exceptionMetadata.groupId);
|
.putString(KEY_EXCEPTION_GROUP_ID, exceptionMetadata.groupId == null ? null : exceptionMetadata.groupId.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataBuilder.build();
|
return dataBuilder.build();
|
||||||
|
@ -272,7 +272,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId);
|
else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId);
|
||||||
else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId);
|
else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId);
|
||||||
|
|
||||||
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) {
|
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupId.v1(message.getGroupInfo().get().getGroupId()))) {
|
||||||
handleUnknownGroupMessage(content, message.getGroupInfo().get());
|
handleUnknownGroupMessage(content, message.getGroupInfo().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,8 +327,8 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull Optional<String> toEncodedId(@NonNull Optional<SignalServiceGroup> groupInfo) {
|
private static @NonNull Optional<GroupId> toEncodedId(@NonNull Optional<SignalServiceGroup> groupInfo) {
|
||||||
return groupInfo.transform(g -> GroupUtil.getEncodedId(g.getGroupId(), false));
|
return groupInfo.transform(g -> GroupId.v1(g.getGroupId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleExceptionMessage(@NonNull ExceptionMetadata e, @NonNull Optional<Long> smsMessageId) {
|
private void handleExceptionMessage(@NonNull ExceptionMetadata e, @NonNull Optional<Long> smsMessageId) {
|
||||||
|
@ -546,7 +546,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
@NonNull SignalServiceGroup group)
|
@NonNull SignalServiceGroup group)
|
||||||
{
|
{
|
||||||
if (group.getType() != SignalServiceGroup.Type.REQUEST_INFO) {
|
if (group.getType() != SignalServiceGroup.Type.REQUEST_INFO) {
|
||||||
ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(Recipient.externalPush(context, content.getSender()).getId(), group.getGroupId()));
|
ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(Recipient.externalPush(context, content.getSender()).getId(), GroupId.v1(group.getGroupId())));
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Received a REQUEST_INFO message for a group we don't know about. Ignoring.");
|
Log.w(TAG, "Received a REQUEST_INFO message for a group we don't know about. Ignoring.");
|
||||||
}
|
}
|
||||||
|
@ -682,7 +682,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
if (response.getPerson().isPresent()) {
|
if (response.getPerson().isPresent()) {
|
||||||
recipient = Recipient.externalPush(context, response.getPerson().get());
|
recipient = Recipient.externalPush(context, response.getPerson().get());
|
||||||
} else if (response.getGroupId().isPresent()) {
|
} else if (response.getGroupId().isPresent()) {
|
||||||
String groupId = GroupUtil.getEncodedId(response.getGroupId().get(), false);
|
GroupId groupId = GroupId.v1(response.getGroupId().get());
|
||||||
recipient = Recipient.externalGroup(context, groupId);
|
recipient = Recipient.externalGroup(context, groupId);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Message request response was missing a thread recipient! Skipping.");
|
Log.w(TAG, "Message request response was missing a thread recipient! Skipping.");
|
||||||
|
@ -743,7 +743,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
threadId = handleSynchronizeSentTextMessage(message);
|
threadId = handleSynchronizeSentTextMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false))) {
|
if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupId.v1(message.getMessage().getGroupInfo().get().getGroupId()))) {
|
||||||
handleUnknownGroupMessage(content, message.getMessage().getGroupInfo().get());
|
handleUnknownGroupMessage(content, message.getMessage().getGroupInfo().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,7 +1017,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
updateGroupReceiptStatus(message, record.getId(), recipient.requireGroupId());
|
updateGroupReceiptStatus(message, record.getId(), recipient.requireGroupId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateGroupReceiptStatus(@NonNull SentTranscriptMessage message, long messageId, @NonNull String groupString) {
|
private void updateGroupReceiptStatus(@NonNull SentTranscriptMessage message, long messageId, @NonNull GroupId groupString) {
|
||||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||||
List<Recipient> messageRecipients = Stream.of(message.getRecipients()).map(address -> Recipient.externalPush(context, address)).toList();
|
List<Recipient> messageRecipients = Stream.of(message.getRecipients()).map(address -> Recipient.externalPush(context, address)).toList();
|
||||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, false);
|
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, false);
|
||||||
|
@ -1183,7 +1183,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
|
|
||||||
private void handleUnsupportedDataMessage(@NonNull String sender,
|
private void handleUnsupportedDataMessage(@NonNull String sender,
|
||||||
int senderDevice,
|
int senderDevice,
|
||||||
@NonNull Optional<String> groupId,
|
@NonNull Optional<GroupId> groupId,
|
||||||
long timestamp,
|
long timestamp,
|
||||||
@NonNull Optional<Long> smsMessageId)
|
@NonNull Optional<Long> smsMessageId)
|
||||||
{
|
{
|
||||||
|
@ -1203,7 +1203,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
|
|
||||||
private void handleInvalidMessage(@NonNull SignalServiceAddress sender,
|
private void handleInvalidMessage(@NonNull SignalServiceAddress sender,
|
||||||
int senderDevice,
|
int senderDevice,
|
||||||
@NonNull Optional<String> groupId,
|
@NonNull Optional<GroupId> groupId,
|
||||||
long timestamp,
|
long timestamp,
|
||||||
@NonNull Optional<Long> smsMessageId)
|
@NonNull Optional<Long> smsMessageId)
|
||||||
{
|
{
|
||||||
|
@ -1313,7 +1313,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
long threadId;
|
long threadId;
|
||||||
|
|
||||||
if (typingMessage.getGroupId().isPresent()) {
|
if (typingMessage.getGroupId().isPresent()) {
|
||||||
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupUtil.getEncodedId(typingMessage.getGroupId().get(), false));
|
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(GroupId.v1(typingMessage.getGroupId().get()));
|
||||||
Recipient groupRecipient = Recipient.resolved(recipientId);
|
Recipient groupRecipient = Recipient.resolved(recipientId);
|
||||||
|
|
||||||
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
|
@ -1478,7 +1478,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
return insertPlaceholder(sender, senderDevice, timestamp, Optional.absent());
|
return insertPlaceholder(sender, senderDevice, timestamp, Optional.absent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp, Optional<String> groupId) {
|
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp, Optional<GroupId> groupId) {
|
||||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.external(context, sender).getId(),
|
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.external(context, sender).getId(),
|
||||||
senderDevice, timestamp, "",
|
senderDevice, timestamp, "",
|
||||||
|
@ -1490,7 +1490,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
|
|
||||||
private Recipient getSyncMessageDestination(SentTranscriptMessage message) {
|
private Recipient getSyncMessageDestination(SentTranscriptMessage message) {
|
||||||
if (message.getMessage().getGroupInfo().isPresent()) {
|
if (message.getMessage().getGroupInfo().isPresent()) {
|
||||||
return Recipient.external(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId(), false));
|
return Recipient.externalGroup(context, GroupId.v1(message.getMessage().getGroupInfo().get().getGroupId()));
|
||||||
} else {
|
} else {
|
||||||
return Recipient.externalPush(context, message.getDestination().get());
|
return Recipient.externalPush(context, message.getDestination().get());
|
||||||
}
|
}
|
||||||
|
@ -1498,7 +1498,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
|
|
||||||
private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||||
if (message.getGroupInfo().isPresent()) {
|
if (message.getGroupInfo().isPresent()) {
|
||||||
return Recipient.external(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false));
|
return Recipient.externalGroup(context, GroupId.v1(message.getGroupInfo().get().getGroupId()));
|
||||||
} else {
|
} else {
|
||||||
return Recipient.externalPush(context, content.getSender());
|
return Recipient.externalPush(context, content.getSender());
|
||||||
}
|
}
|
||||||
|
@ -1529,9 +1529,9 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
if (conversation.isGroup() && conversation.isBlocked()) {
|
if (conversation.isGroup() && conversation.isBlocked()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (conversation.isGroup()) {
|
} else if (conversation.isGroup()) {
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
Optional<String> groupId = message.getGroupInfo().isPresent() ? Optional.of(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))
|
Optional<GroupId> groupId = message.getGroupInfo().isPresent() ? Optional.of(GroupId.v1(message.getGroupInfo().get().getGroupId()))
|
||||||
: Optional.absent();
|
: Optional.absent();
|
||||||
|
|
||||||
if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) {
|
if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1616,7 +1616,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
} else {
|
} else {
|
||||||
ExceptionMetadata exceptionMetadata = new ExceptionMetadata(data.getString(KEY_EXCEPTION_SENDER),
|
ExceptionMetadata exceptionMetadata = new ExceptionMetadata(data.getString(KEY_EXCEPTION_SENDER),
|
||||||
data.getInt(KEY_EXCEPTION_DEVICE),
|
data.getInt(KEY_EXCEPTION_DEVICE),
|
||||||
data.getStringOrDefault(KEY_EXCEPTION_GROUP_ID, null));
|
GroupId.parseNullable(data.getStringOrDefault(KEY_EXCEPTION_GROUP_ID, null)));
|
||||||
|
|
||||||
return new PushProcessMessageJob(parameters,
|
return new PushProcessMessageJob(parameters,
|
||||||
state,
|
state,
|
||||||
|
@ -1643,11 +1643,11 @@ public final class PushProcessMessageJob extends BaseJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ExceptionMetadata {
|
static class ExceptionMetadata {
|
||||||
@NonNull private final String sender;
|
@NonNull private final String sender;
|
||||||
private final int senderDevice;
|
private final int senderDevice;
|
||||||
@Nullable private final String groupId;
|
@Nullable private final GroupId groupId;
|
||||||
|
|
||||||
ExceptionMetadata(@NonNull String sender, int senderDevice, @Nullable String groupId) {
|
ExceptionMetadata(@NonNull String sender, int senderDevice, @Nullable GroupId groupId) {
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.senderDevice = senderDevice;
|
this.senderDevice = senderDevice;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
|
|
|
@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
|
@ -217,7 +216,7 @@ public class ReactionSendJob extends BaseJob {
|
||||||
.withReaction(buildReaction(context, reaction, remove, targetAuthor, targetSentTimestamp));
|
.withReaction(buildReaction(context, reaction, remove, targetAuthor, targetSentTimestamp));
|
||||||
|
|
||||||
if (conversationRecipient.isGroup()) {
|
if (conversationRecipient.isGroup()) {
|
||||||
dataMessage.asGroupMessage(new SignalServiceGroup(GroupUtil.getDecodedId(conversationRecipient.requireGroupId())));
|
dataMessage.asGroupMessage(new SignalServiceGroup(conversationRecipient.requireGroupId().getDecodedId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,18 @@ import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -33,10 +31,10 @@ public class RequestGroupInfoJob extends BaseJob {
|
||||||
private static final String KEY_SOURCE = "source";
|
private static final String KEY_SOURCE = "source";
|
||||||
private static final String KEY_GROUP_ID = "group_id";
|
private static final String KEY_GROUP_ID = "group_id";
|
||||||
|
|
||||||
private RecipientId source;
|
private final RecipientId source;
|
||||||
private byte[] groupId;
|
private final GroupId groupId;
|
||||||
|
|
||||||
public RequestGroupInfoJob(@NonNull RecipientId source, @NonNull byte[] groupId) {
|
public RequestGroupInfoJob(@NonNull RecipientId source, @NonNull GroupId groupId) {
|
||||||
this(new Job.Parameters.Builder()
|
this(new Job.Parameters.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
|
@ -47,7 +45,7 @@ public class RequestGroupInfoJob extends BaseJob {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestGroupInfoJob(@NonNull Job.Parameters parameters, @NonNull RecipientId source, @NonNull byte[] groupId) {
|
private RequestGroupInfoJob(@NonNull Job.Parameters parameters, @NonNull RecipientId source, @NonNull GroupId groupId) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
|
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
@ -57,7 +55,7 @@ public class RequestGroupInfoJob extends BaseJob {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putString(KEY_SOURCE, source.serialize())
|
return new Data.Builder().putString(KEY_SOURCE, source.serialize())
|
||||||
.putString(KEY_GROUP_ID, GroupUtil.getEncodedId(groupId, false))
|
.putString(KEY_GROUP_ID, groupId.toString())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +67,7 @@ public class RequestGroupInfoJob extends BaseJob {
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException, UntrustedIdentityException {
|
public void onRun() throws IOException, UntrustedIdentityException {
|
||||||
SignalServiceGroup group = SignalServiceGroup.newBuilder(Type.REQUEST_INFO)
|
SignalServiceGroup group = SignalServiceGroup.newBuilder(Type.REQUEST_INFO)
|
||||||
.withId(groupId)
|
.withId(groupId.getDecodedId())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder()
|
||||||
|
@ -99,13 +97,9 @@ public class RequestGroupInfoJob extends BaseJob {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull RequestGroupInfoJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
public @NonNull RequestGroupInfoJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||||
try {
|
return new RequestGroupInfoJob(parameters,
|
||||||
return new RequestGroupInfoJob(parameters,
|
RecipientId.from(data.getString(KEY_SOURCE)),
|
||||||
RecipientId.from(data.getString(KEY_SOURCE)),
|
GroupId.parse(data.getString(KEY_GROUP_ID)));
|
||||||
GroupUtil.getDecodedId(data.getString(KEY_GROUP_ID)));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
|
@ -87,7 +86,7 @@ public class TypingSendJob extends BaseJob {
|
||||||
|
|
||||||
if (recipient.isGroup()) {
|
if (recipient.isGroup()) {
|
||||||
recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.requireGroupId(), false);
|
recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.requireGroupId(), false);
|
||||||
groupId = Optional.of(GroupUtil.getDecodedId(recipient.requireGroupId()));
|
groupId = Optional.of(recipient.requireGroupId().getDecodedId());
|
||||||
}
|
}
|
||||||
|
|
||||||
recipients = Stream.of(recipients).map(Recipient::resolve).toList();
|
recipients = Stream.of(recipients).map(Recipient::resolve).toList();
|
||||||
|
|
|
@ -101,7 +101,7 @@ class CameraContactsRepository {
|
||||||
try (GroupDatabase.Reader reader = groupDatabase.getGroupsFilteredByTitle(query, false)) {
|
try (GroupDatabase.Reader reader = groupDatabase.getGroupsFilteredByTitle(query, false)) {
|
||||||
GroupDatabase.GroupRecord groupRecord;
|
GroupDatabase.GroupRecord groupRecord;
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
RecipientId recipientId = recipientDatabase.getOrInsertFromGroupId(groupRecord.getEncodedId());
|
RecipientId recipientId = recipientDatabase.getOrInsertFromGroupId(groupRecord.getId());
|
||||||
recipients.add(Recipient.resolved(recipientId));
|
recipients.add(Recipient.resolved(recipientId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,13 @@ package org.thoughtcrime.securesms.migrations;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -83,7 +82,7 @@ public class AvatarMigrationJob extends MigrationJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValidFileName(@NonNull String name) {
|
private static boolean isValidFileName(@NonNull String name) {
|
||||||
return NUMBER_PATTERN.matcher(name).matches() || GroupUtil.isEncodedGroup(name) || NumberUtil.isValidEmail(name);
|
return NUMBER_PATTERN.matcher(name).matches() || GroupId.isEncodedGroup(name) || NumberUtil.isValidEmail(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Factory implements Job.Factory<AvatarMigrationJob> {
|
public static class Factory implements Job.Factory<AvatarMigrationJob> {
|
||||||
|
|
|
@ -5,9 +5,9 @@ import androidx.annotation.NonNull;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.PointerAttachment;
|
import org.thoughtcrime.securesms.attachments.PointerAttachment;
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
|
@ -19,7 +19,7 @@ import java.util.List;
|
||||||
public class IncomingMediaMessage {
|
public class IncomingMediaMessage {
|
||||||
|
|
||||||
private final RecipientId from;
|
private final RecipientId from;
|
||||||
private final String groupId;
|
private final GroupId groupId;
|
||||||
private final String body;
|
private final String body;
|
||||||
private final boolean push;
|
private final boolean push;
|
||||||
private final long sentTimeMillis;
|
private final long sentTimeMillis;
|
||||||
|
@ -35,7 +35,7 @@ public class IncomingMediaMessage {
|
||||||
private final List<LinkPreview> linkPreviews = new LinkedList<>();
|
private final List<LinkPreview> linkPreviews = new LinkedList<>();
|
||||||
|
|
||||||
public IncomingMediaMessage(@NonNull RecipientId from,
|
public IncomingMediaMessage(@NonNull RecipientId from,
|
||||||
Optional<String> groupId,
|
Optional<GroupId> groupId,
|
||||||
String body,
|
String body,
|
||||||
long sentTimeMillis,
|
long sentTimeMillis,
|
||||||
List<Attachment> attachments,
|
List<Attachment> attachments,
|
||||||
|
@ -86,7 +86,7 @@ public class IncomingMediaMessage {
|
||||||
this.quote = quote.orNull();
|
this.quote = quote.orNull();
|
||||||
this.unidentified = unidentified;
|
this.unidentified = unidentified;
|
||||||
|
|
||||||
if (group.isPresent()) this.groupId = GroupUtil.getEncodedId(group.get().getGroupId(), false);
|
if (group.isPresent()) this.groupId = GroupId.v1(group.get().getGroupId());
|
||||||
else this.groupId = null;
|
else this.groupId = null;
|
||||||
|
|
||||||
this.attachments.addAll(PointerAttachment.forPointers(attachments));
|
this.attachments.addAll(PointerAttachment.forPointers(attachments));
|
||||||
|
@ -114,7 +114,7 @@ public class IncomingMediaMessage {
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGroupId() {
|
public GroupId getGroupId() {
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||||
import com.google.i18n.phonenumbers.Phonenumber;
|
import com.google.i18n.phonenumbers.Phonenumber;
|
||||||
import com.google.i18n.phonenumbers.ShortNumberInfo;
|
import com.google.i18n.phonenumbers.ShortNumberInfo;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.Pair;
|
import org.whispersystems.libsignal.util.Pair;
|
||||||
|
@ -83,7 +83,7 @@ public class PhoneNumberFormatter {
|
||||||
|
|
||||||
public String format(@Nullable String number) {
|
public String format(@Nullable String number) {
|
||||||
if (number == null) return "Unknown";
|
if (number == null) return "Unknown";
|
||||||
if (GroupUtil.isEncodedGroup(number)) return number;
|
if (GroupId.isEncodedGroup(number)) return number;
|
||||||
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
|
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
|
||||||
|
|
||||||
String bareNumber = number.replaceAll("[^0-9+]", "");
|
String bareNumber = number.replaceAll("[^0-9+]", "");
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
@ -198,7 +197,7 @@ public final class LiveRecipient {
|
||||||
List<Recipient> members = Stream.of(groupRecord.get().getMembers()).filterNot(RecipientId::isUnknown).map(this::fetchRecipientFromDisk).toList();
|
List<Recipient> members = Stream.of(groupRecord.get().getMembers()).filterNot(RecipientId::isUnknown).map(this::fetchRecipientFromDisk).toList();
|
||||||
Optional<Long> avatarId = Optional.absent();
|
Optional<Long> avatarId = Optional.absent();
|
||||||
|
|
||||||
if (settings.getGroupId() != null && !GroupUtil.isMmsGroup(settings.getGroupId()) && title == null) {
|
if (settings.getGroupId() != null && !settings.getGroupId().isMmsGroup() && title == null) {
|
||||||
title = unnamedGroupName;
|
title = unnamedGroupName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
|
@ -35,7 +36,6 @@ import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.libsignal.util.guava.Preconditions;
|
import org.whispersystems.libsignal.util.guava.Preconditions;
|
||||||
|
@ -64,7 +64,7 @@ public class Recipient {
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String e164;
|
private final String e164;
|
||||||
private final String email;
|
private final String email;
|
||||||
private final String groupId;
|
private final GroupId groupId;
|
||||||
private final List<Recipient> participants;
|
private final List<Recipient> participants;
|
||||||
private final Optional<Long> groupAvatarId;
|
private final Optional<Long> groupAvatarId;
|
||||||
private final boolean localNumber;
|
private final boolean localNumber;
|
||||||
|
@ -236,11 +236,7 @@ public class Recipient {
|
||||||
* identifier is a groupId.
|
* identifier is a groupId.
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static @NonNull Recipient externalGroup(@NonNull Context context, @NonNull String groupId) {
|
public static @NonNull Recipient externalGroup(@NonNull Context context, @NonNull GroupId groupId) {
|
||||||
if (!GroupUtil.isEncodedGroup(groupId)) {
|
|
||||||
throw new IllegalArgumentException("Invalid groupId!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Recipient.resolved(DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId));
|
return Recipient.resolved(DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,8 +270,8 @@ public class Recipient {
|
||||||
throw new UuidRecipientError();
|
throw new UuidRecipientError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (GroupUtil.isEncodedGroup(identifier)) {
|
} else if (GroupId.isEncodedGroup(identifier)) {
|
||||||
id = db.getOrInsertFromGroupId(identifier);
|
id = db.getOrInsertFromGroupId(GroupId.parse(identifier));
|
||||||
} else if (NumberUtil.isValidEmail(identifier)) {
|
} else if (NumberUtil.isValidEmail(identifier)) {
|
||||||
id = db.getOrInsertFromEmail(identifier);
|
id = db.getOrInsertFromEmail(identifier);
|
||||||
} else {
|
} else {
|
||||||
|
@ -385,7 +381,7 @@ public class Recipient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable String getName(@NonNull Context context) {
|
public @Nullable String getName(@NonNull Context context) {
|
||||||
if (this.name == null && groupId != null && GroupUtil.isMmsGroup(groupId)) {
|
if (this.name == null && groupId != null && groupId.isMmsGroup()) {
|
||||||
List<String> names = new LinkedList<>();
|
List<String> names = new LinkedList<>();
|
||||||
|
|
||||||
for (Recipient recipient : participants) {
|
for (Recipient recipient : participants) {
|
||||||
|
@ -443,7 +439,7 @@ public class Recipient {
|
||||||
return Optional.fromNullable(email);
|
return Optional.fromNullable(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Optional<String> getGroupId() {
|
public @NonNull Optional<GroupId> getGroupId() {
|
||||||
return Optional.fromNullable(groupId);
|
return Optional.fromNullable(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,8 +491,8 @@ public class Recipient {
|
||||||
return getUuid().isPresent();
|
return getUuid().isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull String requireGroupId() {
|
public @NonNull GroupId requireGroupId() {
|
||||||
String resolved = resolving ? resolve().groupId : groupId;
|
GroupId resolved = resolving ? resolve().groupId : groupId;
|
||||||
|
|
||||||
if (resolved == null) {
|
if (resolved == null) {
|
||||||
throw new MissingAddressError();
|
throw new MissingAddressError();
|
||||||
|
@ -532,7 +528,7 @@ public class Recipient {
|
||||||
Recipient resolved = resolving ? resolve() : this;
|
Recipient resolved = resolving ? resolve() : this;
|
||||||
|
|
||||||
if (resolved.isGroup()) {
|
if (resolved.isGroup()) {
|
||||||
return resolved.requireGroupId();
|
return resolved.requireGroupId().toString();
|
||||||
} else if (resolved.getUuid().isPresent()) {
|
} else if (resolved.getUuid().isPresent()) {
|
||||||
return resolved.getUuid().get().toString();
|
return resolved.getUuid().get().toString();
|
||||||
}
|
}
|
||||||
|
@ -570,13 +566,13 @@ public class Recipient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMmsGroup() {
|
public boolean isMmsGroup() {
|
||||||
String groupId = resolve().groupId;
|
GroupId groupId = resolve().groupId;
|
||||||
return groupId != null && GroupUtil.isMmsGroup(groupId);
|
return groupId != null && groupId.isMmsGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPushGroup() {
|
public boolean isPushGroup() {
|
||||||
String groupId = resolve().groupId;
|
GroupId groupId = resolve().groupId;
|
||||||
return groupId != null && !GroupUtil.isMmsGroup(groupId);
|
return groupId != null && !groupId.isMmsGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull List<Recipient> getParticipants() {
|
public @NonNull List<Recipient> getParticipants() {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
@ -28,7 +29,7 @@ public class RecipientDetails {
|
||||||
final String username;
|
final String username;
|
||||||
final String e164;
|
final String e164;
|
||||||
final String email;
|
final String email;
|
||||||
final String groupId;
|
final GroupId groupId;
|
||||||
final String name;
|
final String name;
|
||||||
final String customLabel;
|
final String customLabel;
|
||||||
final Uri systemContactPhoto;
|
final Uri systemContactPhoto;
|
||||||
|
|
|
@ -14,8 +14,9 @@ import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||||
import org.thoughtcrime.securesms.jobs.LeaveGroupJob;
|
import org.thoughtcrime.securesms.jobs.LeaveGroupJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
||||||
|
@ -23,9 +24,9 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
@ -123,7 +124,7 @@ public class RecipientUtil {
|
||||||
ApplicationDependencies.getJobManager().add(LeaveGroupJob.create(recipient));
|
ApplicationDependencies.getJobManager().add(LeaveGroupJob.create(recipient));
|
||||||
|
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
String groupId = resolved.requireGroupId();
|
GroupId groupId = resolved.requireGroupId();
|
||||||
groupDatabase.setActive(groupId, false);
|
groupDatabase.setActive(groupId, false);
|
||||||
groupDatabase.remove(groupId, Recipient.self().getId());
|
groupDatabase.remove(groupId, Recipient.self().getId());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import android.telephony.SmsMessage;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
@ -28,19 +29,19 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
};
|
};
|
||||||
private static final String TAG = IncomingTextMessage.class.getSimpleName();
|
private static final String TAG = IncomingTextMessage.class.getSimpleName();
|
||||||
|
|
||||||
private final String message;
|
private final String message;
|
||||||
private RecipientId sender;
|
private final RecipientId sender;
|
||||||
private final int senderDeviceId;
|
private final int senderDeviceId;
|
||||||
private final int protocol;
|
private final int protocol;
|
||||||
private final String serviceCenterAddress;
|
private final String serviceCenterAddress;
|
||||||
private final boolean replyPathPresent;
|
private final boolean replyPathPresent;
|
||||||
private final String pseudoSubject;
|
private final String pseudoSubject;
|
||||||
private final long sentTimestampMillis;
|
private final long sentTimestampMillis;
|
||||||
private final String groupId;
|
@Nullable private final GroupId groupId;
|
||||||
private final boolean push;
|
private final boolean push;
|
||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresInMillis;
|
private final long expiresInMillis;
|
||||||
private final boolean unidentified;
|
private final boolean unidentified;
|
||||||
|
|
||||||
public IncomingTextMessage(@NonNull RecipientId sender, @NonNull SmsMessage message, int subscriptionId) {
|
public IncomingTextMessage(@NonNull RecipientId sender, @NonNull SmsMessage message, int subscriptionId) {
|
||||||
this.message = message.getDisplayMessageBody();
|
this.message = message.getDisplayMessageBody();
|
||||||
|
@ -59,7 +60,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage(@NonNull RecipientId sender, int senderDeviceId, long sentTimestampMillis,
|
public IncomingTextMessage(@NonNull RecipientId sender, int senderDeviceId, long sentTimestampMillis,
|
||||||
String encodedBody, Optional<String> groupId,
|
String encodedBody, Optional<GroupId> groupId,
|
||||||
long expiresInMillis, boolean unidentified)
|
long expiresInMillis, boolean unidentified)
|
||||||
{
|
{
|
||||||
this.message = encodedBody;
|
this.message = encodedBody;
|
||||||
|
@ -86,7 +87,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.replyPathPresent = (in.readInt() == 1);
|
this.replyPathPresent = (in.readInt() == 1);
|
||||||
this.pseudoSubject = in.readString();
|
this.pseudoSubject = in.readString();
|
||||||
this.sentTimestampMillis = in.readLong();
|
this.sentTimestampMillis = in.readLong();
|
||||||
this.groupId = in.readString();
|
this.groupId = GroupId.parseNullable(in.readString());
|
||||||
this.push = (in.readInt() == 1);
|
this.push = (in.readInt() == 1);
|
||||||
this.subscriptionId = in.readInt();
|
this.subscriptionId = in.readInt();
|
||||||
this.expiresInMillis = in.readLong();
|
this.expiresInMillis = in.readLong();
|
||||||
|
@ -131,7 +132,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.unidentified = fragments.get(0).isUnidentified();
|
this.unidentified = fragments.get(0).isUnidentified();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IncomingTextMessage(@NonNull RecipientId sender, @Nullable String groupId)
|
protected IncomingTextMessage(@NonNull RecipientId sender, @Nullable GroupId groupId)
|
||||||
{
|
{
|
||||||
this.message = "";
|
this.message = "";
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
@ -216,7 +217,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
return push;
|
return push;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable String getGroupId() {
|
public @Nullable GroupId getGroupId() {
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +260,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
out.writeInt(replyPathPresent ? 1 : 0);
|
out.writeInt(replyPathPresent ? 1 : 0);
|
||||||
out.writeString(pseudoSubject);
|
out.writeString(pseudoSubject);
|
||||||
out.writeLong(sentTimestampMillis);
|
out.writeLong(sentTimestampMillis);
|
||||||
out.writeString(groupId);
|
out.writeString(groupId == null ? null : groupId.toString());
|
||||||
out.writeInt(push ? 1 : 0);
|
out.writeInt(push ? 1 : 0);
|
||||||
out.writeInt(subscriptionId);
|
out.writeInt(subscriptionId);
|
||||||
out.writeLong(expiresInMillis);
|
out.writeLong(expiresInMillis);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
|
||||||
import com.annimon.stream.Collectors;
|
import com.annimon.stream.Collectors;
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
||||||
|
|
||||||
|
@ -15,15 +15,15 @@ import java.util.Map;
|
||||||
|
|
||||||
class GroupV1ConflictMerger implements StorageSyncHelper.ConflictMerger<SignalGroupV1Record> {
|
class GroupV1ConflictMerger implements StorageSyncHelper.ConflictMerger<SignalGroupV1Record> {
|
||||||
|
|
||||||
private final Map<String, SignalGroupV1Record> localByGroupId;
|
private final Map<GroupId, SignalGroupV1Record> localByGroupId;
|
||||||
|
|
||||||
GroupV1ConflictMerger(@NonNull Collection<SignalGroupV1Record> localOnly) {
|
GroupV1ConflictMerger(@NonNull Collection<SignalGroupV1Record> localOnly) {
|
||||||
localByGroupId = Stream.of(localOnly).collect(Collectors.toMap(g -> GroupUtil.getEncodedId(g.getGroupId(), false), g -> g));
|
localByGroupId = Stream.of(localOnly).collect(Collectors.toMap(g -> GroupId.v1(g.getGroupId()), g -> g));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Optional<SignalGroupV1Record> getMatching(@NonNull SignalGroupV1Record record) {
|
public @NonNull Optional<SignalGroupV1Record> getMatching(@NonNull SignalGroupV1Record record) {
|
||||||
return Optional.fromNullable(localByGroupId.get(GroupUtil.getEncodedId(record.getGroupId(), false)));
|
return Optional.fromNullable(localByGroupId.get(GroupId.v1(record.getGroupId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,7 +5,6 @@ import androidx.annotation.NonNull;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
|
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
|
||||||
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
||||||
|
@ -56,7 +55,7 @@ public final class StorageSyncModels {
|
||||||
throw new AssertionError("Must have a groupId!");
|
throw new AssertionError("Must have a groupId!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SignalGroupV1Record.Builder(rawStorageId, GroupUtil.getDecodedIdOrThrow(recipient.getGroupId()))
|
return new SignalGroupV1Record.Builder(rawStorageId, recipient.getGroupId().getDecodedId())
|
||||||
.setBlocked(recipient.isBlocked())
|
.setBlocked(recipient.isBlocked())
|
||||||
.setProfileSharingEnabled(recipient.isProfileSharing())
|
.setProfileSharingEnabled(recipient.isProfileSharing())
|
||||||
.setArchived(archived.contains(recipient.getId()))
|
.setArchived(archived.contains(recipient.getId()))
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.google.protobuf.ByteString;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
@ -26,43 +27,16 @@ import java.util.List;
|
||||||
|
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
|
|
||||||
public class GroupUtil {
|
public final class GroupUtil {
|
||||||
|
|
||||||
private static final String ENCODED_SIGNAL_GROUP_PREFIX = "__textsecure_group__!";
|
private GroupUtil() {
|
||||||
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, boolean mms) {
|
|
||||||
return (mms ? ENCODED_MMS_GROUP_PREFIX : ENCODED_SIGNAL_GROUP_PREFIX) + Hex.toStringCondensed(groupId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] getDecodedId(String groupId) throws IOException {
|
private static final String TAG = Log.tag(GroupUtil.class);
|
||||||
if (!isEncodedGroup(groupId)) {
|
|
||||||
throw new IOException("Invalid encoding");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Hex.fromStringCondensed(groupId.split("!", 2)[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] getDecodedIdOrThrow(String groupId) {
|
|
||||||
try {
|
|
||||||
return getDecodedId(groupId);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isEncodedGroup(@NonNull String groupId) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static Optional<OutgoingGroupMediaMessage> createGroupLeaveMessage(@NonNull Context context, @NonNull Recipient groupRecipient) {
|
public static Optional<OutgoingGroupMediaMessage> createGroupLeaveMessage(@NonNull Context context, @NonNull Recipient groupRecipient) {
|
||||||
String encodedGroupId = groupRecipient.requireGroupId();
|
GroupId encodedGroupId = groupRecipient.requireGroupId();
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
|
|
||||||
if (!groupDatabase.isActive(encodedGroupId)) {
|
if (!groupDatabase.isActive(encodedGroupId)) {
|
||||||
|
@ -70,13 +44,7 @@ public class GroupUtil {
|
||||||
return Optional.absent();
|
return Optional.absent();
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteString decodedGroupId;
|
ByteString decodedGroupId = ByteString.copyFrom(encodedGroupId.getDecodedId());
|
||||||
try {
|
|
||||||
decodedGroupId = ByteString.copyFrom(getDecodedId(encodedGroupId));
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, "Failed to decode group ID.", e);
|
|
||||||
return Optional.absent();
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupContext groupContext = GroupContext.newBuilder()
|
GroupContext groupContext = GroupContext.newBuilder()
|
||||||
.setId(decodedGroupId)
|
.setId(decodedGroupId)
|
||||||
|
|
|
@ -78,14 +78,14 @@ public class IdentityUtil {
|
||||||
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) {
|
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) {
|
||||||
|
|
||||||
if (remote) {
|
if (remote) {
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.of(groupRecord.getEncodedId()), 0, false);
|
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.of(groupRecord.getId()), 0, false);
|
||||||
|
|
||||||
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
||||||
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
||||||
|
|
||||||
smsDatabase.insertMessageInbox(incoming);
|
smsDatabase.insertMessageInbox(incoming);
|
||||||
} else {
|
} else {
|
||||||
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupRecord.getEncodedId());
|
RecipientId recipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupRecord.getId());
|
||||||
Recipient groupRecipient = Recipient.resolved(recipientId);
|
Recipient groupRecipient = Recipient.resolved(recipientId);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
OutgoingTextMessage outgoing ;
|
OutgoingTextMessage outgoing ;
|
||||||
|
@ -129,7 +129,7 @@ public class IdentityUtil {
|
||||||
|
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive()) {
|
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive()) {
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.of(groupRecord.getEncodedId()), 0, false);
|
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, null, Optional.of(groupRecord.getId()), 0, false);
|
||||||
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||||
|
|
||||||
smsDatabase.insertMessageInbox(groupUpdate);
|
smsDatabase.insertMessageInbox(groupUpdate);
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
package org.thoughtcrime.securesms.groups;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotSame;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public final class GroupIdTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_create_for_gv1() {
|
||||||
|
GroupId groupId = GroupId.v1(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
|
||||||
|
assertEquals("__textsecure_group__!0001020305060708090b0c0d0e0f", groupId.toString());
|
||||||
|
assertFalse(groupId.isMmsGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_parse_gv1() {
|
||||||
|
GroupId groupId = GroupId.parse("__textsecure_group__!0001020305060708090b0c0d0e0f");
|
||||||
|
|
||||||
|
assertEquals("__textsecure_group__!0001020305060708090b0c0d0e0f", groupId.toString());
|
||||||
|
assertArrayEquals(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 }, groupId.getDecodedId());
|
||||||
|
assertFalse(groupId.isMmsGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_create_for_mms() {
|
||||||
|
GroupId groupId = GroupId.mms(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
|
||||||
|
assertEquals("__signal_mms_group__!0001020305060708090b0c0d0e0f", groupId.toString());
|
||||||
|
assertTrue(groupId.isMmsGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_parse_mms() {
|
||||||
|
GroupId groupId = GroupId.parse("__signal_mms_group__!0001020305060708090b0c0d0e0f");
|
||||||
|
|
||||||
|
assertEquals("__signal_mms_group__!0001020305060708090b0c0d0e0f", groupId.toString());
|
||||||
|
assertArrayEquals(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 }, groupId.getDecodedId());
|
||||||
|
assertTrue(groupId.isMmsGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
@Test
|
||||||
|
public void can_parse_null() {
|
||||||
|
GroupId groupId = GroupId.parseNullable(null);
|
||||||
|
|
||||||
|
assertNull(groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_parse_gv1_with_parseNullable() {
|
||||||
|
GroupId groupId = GroupId.parseNullable("__textsecure_group__!0001020305060708090b0c0d0e0f");
|
||||||
|
|
||||||
|
assertEquals("__textsecure_group__!0001020305060708090b0c0d0e0f", groupId.toString());
|
||||||
|
assertArrayEquals(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 }, groupId.getDecodedId());
|
||||||
|
assertFalse(groupId.isMmsGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = AssertionError.class)
|
||||||
|
public void bad_encoding__bad_prefix__parseNullable() {
|
||||||
|
GroupId.parseNullable("__BAD_PREFIX__!0001020305060708090b0c0d0e0f");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = AssertionError.class)
|
||||||
|
public void bad_encoding__empty__parseNullable() {
|
||||||
|
GroupId.parseNullable("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = AssertionError.class)
|
||||||
|
public void bad_encoding__odd_hex__parseNullable() {
|
||||||
|
GroupId.parseNullable("__textsecure_group__!0001020305060708090bODD_HEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = AssertionError.class)
|
||||||
|
public void bad_encoding__bad_prefix__parse() {
|
||||||
|
GroupId.parse("__BAD_PREFIX__!0001020305060708090b0c0d0e0f");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = AssertionError.class)
|
||||||
|
public void bad_encoding__odd_hex__parse() {
|
||||||
|
GroupId.parse("__textsecure_group__!0001020305060708090b0c0d0e0fODD_HEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void get_bytes() {
|
||||||
|
byte[] bytes = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 };
|
||||||
|
GroupId groupId = GroupId.v1(bytes);
|
||||||
|
|
||||||
|
assertArrayEquals(bytes, groupId.getDecodedId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void equality() {
|
||||||
|
GroupId groupId1 = GroupId.v1(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
GroupId groupId2 = GroupId.v1(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
|
||||||
|
assertNotSame(groupId1, groupId2);
|
||||||
|
assertEquals(groupId1, groupId2);
|
||||||
|
assertEquals(groupId1.hashCode(), groupId2.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void inequality_by_bytes() {
|
||||||
|
GroupId groupId1 = GroupId.v1(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
GroupId groupId2 = GroupId.v1(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16 });
|
||||||
|
|
||||||
|
assertNotSame(groupId1, groupId2);
|
||||||
|
assertNotEquals(groupId1, groupId2);
|
||||||
|
assertNotEquals(groupId1.hashCode(), groupId2.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void inequality_of_sms_and_mms() {
|
||||||
|
GroupId groupId1 = GroupId.v1(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
GroupId groupId2 = GroupId.mms(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
|
||||||
|
assertNotSame(groupId1, groupId2);
|
||||||
|
assertNotEquals(groupId1, groupId2);
|
||||||
|
assertNotEquals(groupId1.hashCode(), groupId2.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void inequality_with_null() {
|
||||||
|
GroupId groupId = GroupId.v1(new byte[]{ 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15 });
|
||||||
|
|
||||||
|
assertNotEquals(groupId, null);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue