Migrate avatars and group avatars.

This commit is contained in:
Greyson Parrelli
2020-03-26 15:38:27 -04:00
parent 9848599807
commit 10bfc8a753
22 changed files with 317 additions and 136 deletions

View File

@@ -42,7 +42,6 @@ public class GroupDatabase extends Database {
static final String RECIPIENT_ID = "recipient_id";
private static final String TITLE = "title";
private static final String MEMBERS = "members";
private static final String AVATAR = "avatar";
private static final String AVATAR_ID = "avatar_id";
private static final String AVATAR_KEY = "avatar_key";
private static final String AVATAR_CONTENT_TYPE = "avatar_content_type";
@@ -59,7 +58,6 @@ public class GroupDatabase extends Database {
RECIPIENT_ID + " INTEGER, " +
TITLE + " TEXT, " +
MEMBERS + " TEXT, " +
AVATAR + " BLOB, " +
AVATAR_ID + " INTEGER, " +
AVATAR_KEY + " BLOB, " +
AVATAR_CONTENT_TYPE + " TEXT, " +
@@ -75,7 +73,7 @@ public class GroupDatabase extends Database {
};
private static final String[] GROUP_PROJECTION = {
GROUP_ID, RECIPIENT_ID, TITLE, MEMBERS, AVATAR, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST,
GROUP_ID, RECIPIENT_ID, TITLE, MEMBERS, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST,
TIMESTAMP, ACTIVE, MMS
};
@@ -120,7 +118,7 @@ public class GroupDatabase extends Database {
return true;
}
boolean noMetadata = group.get().getAvatar() == null && TextUtils.isEmpty(group.get().getTitle());
boolean noMetadata = !group.get().hasAvatar() && TextUtils.isEmpty(group.get().getTitle());
boolean noMembers = group.get().getMembers().isEmpty() || (group.get().getMembers().size() == 1 && group.get().getMembers().contains(Recipient.self().getId()));
return noMetadata && noMembers;
@@ -228,6 +226,8 @@ public class GroupDatabase extends Database {
contentValues.put(AVATAR_KEY, avatar.getKey());
contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType());
contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull());
} else {
contentValues.put(AVATAR_ID, 0);
}
contentValues.put(AVATAR_RELAY, relay);
@@ -252,6 +252,8 @@ public class GroupDatabase extends Database {
contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType());
contentValues.put(AVATAR_KEY, avatar.getKey());
contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull());
} else {
contentValues.put(AVATAR_ID, 0);
}
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,
@@ -274,20 +276,12 @@ public class GroupDatabase extends Database {
Recipient.live(groupRecipient).refresh();
}
public void updateAvatar(@NonNull GroupId groupId, @Nullable Bitmap avatar) {
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
}
public void updateAvatar(@NonNull GroupId groupId, @Nullable byte[] avatar) {
long avatarId;
if (avatar != null) avatarId = Math.abs(new SecureRandom().nextLong());
else avatarId = 0;
ContentValues contentValues = new ContentValues(2);
contentValues.put(AVATAR, avatar);
contentValues.put(AVATAR_ID, avatarId);
/**
* Used to bust the Glide cache when an avatar changes.
*/
public void onAvatarUpdated(@NonNull GroupId groupId, boolean hasAvatar) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(AVATAR_ID, hasAvatar ? Math.abs(new SecureRandom().nextLong()) : 0);
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
new String[] {groupId.toString()});
@@ -388,7 +382,6 @@ public class GroupDatabase extends Database {
RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
cursor.getString(cursor.getColumnIndexOrThrow(TITLE)),
cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)),
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR)),
cursor.getLong(cursor.getColumnIndexOrThrow(AVATAR_ID)),
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_KEY)),
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_CONTENT_TYPE)),
@@ -411,7 +404,6 @@ public class GroupDatabase extends Database {
private final RecipientId recipientId;
private final String title;
private final List<RecipientId> members;
private final byte[] avatar;
private final long avatarId;
private final byte[] avatarKey;
private final byte[] avatarDigest;
@@ -420,14 +412,13 @@ public class GroupDatabase extends Database {
private final boolean active;
private final boolean mms;
public GroupRecord(@NonNull GroupId id, @NonNull RecipientId recipientId, String title, String members, byte[] avatar,
public GroupRecord(@NonNull GroupId id, @NonNull RecipientId recipientId, String title, String members,
long avatarId, byte[] avatarKey, String avatarContentType,
String relay, boolean active, byte[] avatarDigest, boolean mms)
{
this.id = id;
this.recipientId = recipientId;
this.title = title;
this.avatar = avatar;
this.avatarId = avatarId;
this.avatarKey = avatarKey;
this.avatarDigest = avatarDigest;
@@ -456,8 +447,8 @@ public class GroupDatabase extends Database {
return members;
}
public byte[] getAvatar() {
return avatar;
public boolean hasAvatar() {
return avatarId != 0;
}
public long getAvatarId() {

View File

@@ -21,7 +21,9 @@ import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabaseHook;
import net.sqlcipher.database.SQLiteOpenHelper;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.profiles.ProfileName;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
import org.thoughtcrime.securesms.crypto.MasterSecret;
@@ -51,14 +53,17 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.FileUtils;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
public class SQLCipherOpenHelper extends SQLiteOpenHelper {
@@ -118,8 +123,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int GROUPS_V2_RECIPIENT_CAPABILITY = 51;
private static final int TRANSFER_FILE_CLEANUP = 52;
private static final int PROFILE_DATA_MIGRATION = 53;
private static final int AVATAR_LOCATION_MIGRATION = 54;
private static final int DATABASE_VERSION = 53;
private static final int DATABASE_VERSION = 54;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@@ -802,6 +808,49 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
}
}
if (oldVersion < AVATAR_LOCATION_MIGRATION) {
File oldAvatarDirectory = new File(context.getFilesDir(), "avatars");
File[] results = oldAvatarDirectory.listFiles();
if (results != null) {
Log.i(TAG, "Preparing to migrate " + results.length + " avatars.");
for (File file : results) {
if (Util.isLong(file.getName())) {
try {
AvatarHelper.setAvatar(context, RecipientId.from(file.getName()), new FileInputStream(file));
} catch(IOException e) {
Log.w(TAG, "Failed to copy file " + file.getName() + "! Skipping.");
}
} else {
Log.w(TAG, "Invalid avatar name '" + file.getName() + "'! Skipping.");
}
}
} else {
Log.w(TAG, "No avatar directory files found.");
}
if (!FileUtils.deleteDirectory(oldAvatarDirectory)) {
Log.w(TAG, "Failed to delete avatar directory.");
}
try (Cursor cursor = db.rawQuery("SELECT recipient_id, avatar FROM groups", null)) {
while (cursor != null && cursor.moveToNext()) {
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow("recipient_id")));
byte[] avatar = cursor.getBlob(cursor.getColumnIndexOrThrow("avatar"));
try {
AvatarHelper.setAvatar(context, recipientId, avatar != null ? new ByteArrayInputStream(avatar) : null);
} catch (IOException e) {
Log.w(TAG, "Failed to copy avatar for " + recipientId + "! Skipping.", e);
}
}
}
db.execSQL("UPDATE groups SET avatar_id = 0 WHERE avatar IS NULL");
db.execSQL("UPDATE groups SET avatar = NULL");
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();