Implement ability to view badges and modify whether they appear.

Note: this is available in staging only.
This commit is contained in:
Alex Hart
2021-09-20 17:05:31 -03:00
parent 556ca5a573
commit 77cf029fdc
48 changed files with 1880 additions and 100 deletions

View File

@@ -23,6 +23,7 @@ import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.groups.GroupMasterKey;
import org.signal.zkgroup.profiles.ProfileKey;
import org.signal.zkgroup.profiles.ProfileKeyCredential;
import org.thoughtcrime.securesms.badges.models.Badge;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
@@ -33,6 +34,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.IdentityRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.database.model.databaseprotos.BadgeList;
import org.thoughtcrime.securesms.database.model.databaseprotos.ChatColor;
import org.thoughtcrime.securesms.database.model.databaseprotos.DeviceLastResetTime;
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileKeyCredentialColumnData;
@@ -153,6 +155,7 @@ public class RecipientDatabase extends Database {
private static final String GROUPS_IN_COMMON = "groups_in_common";
private static final String CHAT_COLORS = "chat_colors";
private static final String CUSTOM_CHAT_COLORS_ID = "custom_chat_colors_id";
private static final String BADGES = "badges";
public static final String SEARCH_PROFILE_NAME = "search_signal_profile";
private static final String SORT_NAME = "sort_name";
@@ -188,7 +191,8 @@ public class RecipientDatabase extends Database {
MENTION_SETTING,
ABOUT, ABOUT_EMOJI,
EXTRAS, GROUPS_IN_COMMON,
CHAT_COLORS, CUSTOM_CHAT_COLORS_ID
CHAT_COLORS, CUSTOM_CHAT_COLORS_ID,
BADGES
};
private static final String[] ID_PROJECTION = new String[]{ID};
@@ -372,7 +376,8 @@ public class RecipientDatabase extends Database {
EXTRAS + " BLOB DEFAULT NULL, " +
GROUPS_IN_COMMON + " INTEGER DEFAULT 0, " +
CHAT_COLORS + " BLOB DEFAULT NULL, " +
CUSTOM_CHAT_COLORS_ID + " INTEGER DEFAULT 0);";
CUSTOM_CHAT_COLORS_ID + " INTEGER DEFAULT 0, " +
BADGES + " BLOB DEFAULT NULL);";
private static final String INSIGHTS_INVITEE_LIST = "SELECT " + TABLE_NAME + "." + ID +
" FROM " + TABLE_NAME +
@@ -1208,49 +1213,52 @@ public class RecipientDatabase extends Database {
}
static @NonNull RecipientSettings getRecipientSettings(@NonNull Context context, @NonNull Cursor cursor, @NonNull String idColumnName) {
long id = CursorUtil.requireLong(cursor, idColumnName);
UUID uuid = UuidUtil.parseOrNull(CursorUtil.requireString(cursor, UUID));
String username = CursorUtil.requireString(cursor, USERNAME);
String e164 = CursorUtil.requireString(cursor, PHONE);
String email = CursorUtil.requireString(cursor, EMAIL);
GroupId groupId = GroupId.parseNullableOrThrow(CursorUtil.requireString(cursor, GROUP_ID));
int groupType = CursorUtil.requireInt(cursor, GROUP_TYPE);
boolean blocked = CursorUtil.requireBoolean(cursor, BLOCKED);
String messageRingtone = CursorUtil.requireString(cursor, MESSAGE_RINGTONE);
String callRingtone = CursorUtil.requireString(cursor, CALL_RINGTONE);
int messageVibrateState = CursorUtil.requireInt(cursor, MESSAGE_VIBRATE);
int callVibrateState = CursorUtil.requireInt(cursor, CALL_VIBRATE);
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
int insightsBannerTier = CursorUtil.requireInt(cursor, SEEN_INVITE_REMINDER);
int defaultSubscriptionId = CursorUtil.requireInt(cursor, DEFAULT_SUBSCRIPTION_ID);
int expireMessages = CursorUtil.requireInt(cursor, MESSAGE_EXPIRATION_TIME);
int registeredState = CursorUtil.requireInt(cursor, REGISTERED);
String profileKeyString = CursorUtil.requireString(cursor, PROFILE_KEY);
String profileKeyCredentialString = CursorUtil.requireString(cursor, PROFILE_KEY_CREDENTIAL);
String systemGivenName = CursorUtil.requireString(cursor, SYSTEM_GIVEN_NAME);
String systemFamilyName = CursorUtil.requireString(cursor, SYSTEM_FAMILY_NAME);
String systemDisplayName = CursorUtil.requireString(cursor, SYSTEM_JOINED_NAME);
String systemContactPhoto = CursorUtil.requireString(cursor, SYSTEM_PHOTO_URI);
String systemPhoneLabel = CursorUtil.requireString(cursor, SYSTEM_PHONE_LABEL);
String systemContactUri = CursorUtil.requireString(cursor, SYSTEM_CONTACT_URI);
String profileGivenName = CursorUtil.requireString(cursor, PROFILE_GIVEN_NAME);
String profileFamilyName = CursorUtil.requireString(cursor, PROFILE_FAMILY_NAME);
String signalProfileAvatar = CursorUtil.requireString(cursor, SIGNAL_PROFILE_AVATAR);
boolean profileSharing = CursorUtil.requireBoolean(cursor, PROFILE_SHARING);
long lastProfileFetch = cursor.getLong(cursor.getColumnIndexOrThrow(LAST_PROFILE_FETCH));
String notificationChannel = CursorUtil.requireString(cursor, NOTIFICATION_CHANNEL);
int unidentifiedAccessMode = CursorUtil.requireInt(cursor, UNIDENTIFIED_ACCESS_MODE);
boolean forceSmsSelection = CursorUtil.requireBoolean(cursor, FORCE_SMS_SELECTION);
long capabilities = CursorUtil.requireLong(cursor, CAPABILITIES);
String storageKeyRaw = CursorUtil.requireString(cursor, STORAGE_SERVICE_ID);
int mentionSettingId = CursorUtil.requireInt(cursor, MENTION_SETTING);
byte[] wallpaper = CursorUtil.requireBlob(cursor, WALLPAPER);
byte[] serializedChatColors = CursorUtil.requireBlob(cursor, CHAT_COLORS);
long customChatColorsId = CursorUtil.requireLong(cursor, CUSTOM_CHAT_COLORS_ID);
String serializedAvatarColor = CursorUtil.requireString(cursor, AVATAR_COLOR);
String about = CursorUtil.requireString(cursor, ABOUT);
String aboutEmoji = CursorUtil.requireString(cursor, ABOUT_EMOJI);
boolean hasGroupsInCommon = CursorUtil.requireBoolean(cursor, GROUPS_IN_COMMON);
long id = CursorUtil.requireLong(cursor, idColumnName);
UUID uuid = UuidUtil.parseOrNull(CursorUtil.requireString(cursor, UUID));
String username = CursorUtil.requireString(cursor, USERNAME);
String e164 = CursorUtil.requireString(cursor, PHONE);
String email = CursorUtil.requireString(cursor, EMAIL);
GroupId groupId = GroupId.parseNullableOrThrow(CursorUtil.requireString(cursor, GROUP_ID));
int groupType = CursorUtil.requireInt(cursor, GROUP_TYPE);
boolean blocked = CursorUtil.requireBoolean(cursor, BLOCKED);
String messageRingtone = CursorUtil.requireString(cursor, MESSAGE_RINGTONE);
String callRingtone = CursorUtil.requireString(cursor, CALL_RINGTONE);
int messageVibrateState = CursorUtil.requireInt(cursor, MESSAGE_VIBRATE);
int callVibrateState = CursorUtil.requireInt(cursor, CALL_VIBRATE);
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
int insightsBannerTier = CursorUtil.requireInt(cursor, SEEN_INVITE_REMINDER);
int defaultSubscriptionId = CursorUtil.requireInt(cursor, DEFAULT_SUBSCRIPTION_ID);
int expireMessages = CursorUtil.requireInt(cursor, MESSAGE_EXPIRATION_TIME);
int registeredState = CursorUtil.requireInt(cursor, REGISTERED);
String profileKeyString = CursorUtil.requireString(cursor, PROFILE_KEY);
String profileKeyCredentialString = CursorUtil.requireString(cursor, PROFILE_KEY_CREDENTIAL);
String systemGivenName = CursorUtil.requireString(cursor, SYSTEM_GIVEN_NAME);
String systemFamilyName = CursorUtil.requireString(cursor, SYSTEM_FAMILY_NAME);
String systemDisplayName = CursorUtil.requireString(cursor, SYSTEM_JOINED_NAME);
String systemContactPhoto = CursorUtil.requireString(cursor, SYSTEM_PHOTO_URI);
String systemPhoneLabel = CursorUtil.requireString(cursor, SYSTEM_PHONE_LABEL);
String systemContactUri = CursorUtil.requireString(cursor, SYSTEM_CONTACT_URI);
String profileGivenName = CursorUtil.requireString(cursor, PROFILE_GIVEN_NAME);
String profileFamilyName = CursorUtil.requireString(cursor, PROFILE_FAMILY_NAME);
String signalProfileAvatar = CursorUtil.requireString(cursor, SIGNAL_PROFILE_AVATAR);
boolean profileSharing = CursorUtil.requireBoolean(cursor, PROFILE_SHARING);
long lastProfileFetch = cursor.getLong(cursor.getColumnIndexOrThrow(LAST_PROFILE_FETCH));
String notificationChannel = CursorUtil.requireString(cursor, NOTIFICATION_CHANNEL);
int unidentifiedAccessMode = CursorUtil.requireInt(cursor, UNIDENTIFIED_ACCESS_MODE);
boolean forceSmsSelection = CursorUtil.requireBoolean(cursor, FORCE_SMS_SELECTION);
long capabilities = CursorUtil.requireLong(cursor, CAPABILITIES);
String storageKeyRaw = CursorUtil.requireString(cursor, STORAGE_SERVICE_ID);
int mentionSettingId = CursorUtil.requireInt(cursor, MENTION_SETTING);
byte[] wallpaper = CursorUtil.requireBlob(cursor, WALLPAPER);
byte[] serializedChatColors = CursorUtil.requireBlob(cursor, CHAT_COLORS);
long customChatColorsId = CursorUtil.requireLong(cursor, CUSTOM_CHAT_COLORS_ID);
String serializedAvatarColor = CursorUtil.requireString(cursor, AVATAR_COLOR);
String about = CursorUtil.requireString(cursor, ABOUT);
String aboutEmoji = CursorUtil.requireString(cursor, ABOUT_EMOJI);
boolean hasGroupsInCommon = CursorUtil.requireBoolean(cursor, GROUPS_IN_COMMON);
byte[] serializedBadgeList = CursorUtil.requireBlob(cursor, BADGES);
List<Badge> badges = parseBadgeList(serializedBadgeList);
byte[] profileKey = null;
ProfileKeyCredential profileKeyCredential = null;
@@ -1343,7 +1351,40 @@ public class RecipientDatabase extends Database {
aboutEmoji,
getSyncExtras(cursor),
getExtras(cursor),
hasGroupsInCommon);
hasGroupsInCommon,
badges);
}
private static @NonNull List<Badge> parseBadgeList(byte[] serializedBadgeList) {
BadgeList badgeList = null;
if (serializedBadgeList != null) {
try {
badgeList = BadgeList.parseFrom(serializedBadgeList);
} catch (InvalidProtocolBufferException e) {
Log.w(TAG, e);
}
}
List<Badge> badges;
if (badgeList != null) {
List<BadgeList.Badge> protoBadges = badgeList.getBadgesList();
badges = new ArrayList<>(protoBadges.size());
for (BadgeList.Badge protoBadge : protoBadges) {
badges.add(new Badge(
protoBadge.getId(),
Badge.Category.Companion.fromCode(protoBadge.getCategory()),
Uri.parse(protoBadge.getImageUrl()),
protoBadge.getName(),
protoBadge.getDescription(),
protoBadge.getExpiration(),
protoBadge.getVisible()
));
}
} else {
badges = Collections.emptyList();
}
return badges;
}
private static @NonNull RecipientSettings.SyncExtras getSyncExtras(@NonNull Cursor cursor) {
@@ -1639,6 +1680,28 @@ public class RecipientDatabase extends Database {
return DeviceLastResetTime.newBuilder().build();
}
public void setBadges(@NonNull RecipientId id, @NonNull List<Badge> badges) {
BadgeList.Builder badgeListBuilder = BadgeList.newBuilder();
for (final Badge badge : badges) {
badgeListBuilder.addBadges(BadgeList.Badge.newBuilder()
.setId(badge.getId())
.setCategory(badge.getCategory().getCode())
.setDescription(badge.getDescription())
.setExpiration(badge.getExpirationTimestamp())
.setVisible(badge.getVisible())
.setName(badge.getName())
.setImageUrl(badge.getImageUrl().toString()));
}
ContentValues values = new ContentValues(1);
values.put(BADGES, badgeListBuilder.build().toByteArray());
if (update(id, values)) {
Recipient.live(id).refresh();
}
}
public void setCapabilities(@NonNull RecipientId id, @NonNull SignalServiceProfile.Capabilities capabilities) {
long value = 0;
@@ -3228,6 +3291,7 @@ public class RecipientDatabase extends Database {
private final SyncExtras syncExtras;
private final Recipient.Extras extras;
private final boolean hasGroupsInCommon;
private final List<Badge> badges;
RecipientSettings(@NonNull RecipientId id,
@Nullable UUID uuid,
@@ -3271,7 +3335,8 @@ public class RecipientDatabase extends Database {
@Nullable String aboutEmoji,
@NonNull SyncExtras syncExtras,
@Nullable Recipient.Extras extras,
boolean hasGroupsInCommon)
boolean hasGroupsInCommon,
@NonNull List<Badge> badges)
{
this.id = id;
this.uuid = uuid;
@@ -3318,9 +3383,10 @@ public class RecipientDatabase extends Database {
this.avatarColor = avatarColor;
this.about = about;
this.aboutEmoji = aboutEmoji;
this.syncExtras = syncExtras;
this.extras = extras;
this.hasGroupsInCommon = hasGroupsInCommon;
this.syncExtras = syncExtras;
this.extras = extras;
this.hasGroupsInCommon = hasGroupsInCommon;
this.badges = badges;
}
public RecipientId getId() {
@@ -3511,6 +3577,10 @@ public class RecipientDatabase extends Database {
return hasGroupsInCommon;
}
public @NonNull List<Badge> getBadges() {
return badges;
}
long getCapabilities() {
return capabilities;
}

View File

@@ -216,8 +216,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
private static final int GROUP_CALL_RING_TABLE = 115;
private static final int CLEANUP_SESSION_MIGRATION = 116;
private static final int RECEIPT_TIMESTAMP = 117;
private static final int BADGES = 118;
private static final int DATABASE_VERSION = 117;
private static final int DATABASE_VERSION = 118;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@@ -2043,6 +2044,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
db.execSQL("ALTER TABLE mms ADD COLUMN receipt_timestamp INTEGER DEFAULT -1");
}
if (oldVersion < BADGES) {
db.execSQL("ALTER TABLE recipient ADD COLUMN badges BLOB DEFAULT NULL");
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();