mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Optimize uploads during media composition.
By uploading in advance (when on unmetered connections), media messages can send almost instantly.
This commit is contained in:
@@ -76,6 +76,7 @@ import java.io.OutputStream;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
@@ -120,6 +121,7 @@ public class AttachmentDatabase extends Database {
|
||||
private static final String DATA_HASH = "data_hash";
|
||||
static final String BLUR_HASH = "blur_hash";
|
||||
static final String TRANSFORM_PROPERTIES = "transform_properties";
|
||||
static final String DISPLAY_ORDER = "display_order";
|
||||
|
||||
public static final String DIRECTORY = "parts";
|
||||
|
||||
@@ -128,6 +130,8 @@ public class AttachmentDatabase extends Database {
|
||||
public static final int TRANSFER_PROGRESS_PENDING = 2;
|
||||
public static final int TRANSFER_PROGRESS_FAILED = 3;
|
||||
|
||||
public static final long PREUPLOAD_MESSAGE_ID = -8675309;
|
||||
|
||||
private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?";
|
||||
private static final String PART_ID_WHERE_NOT = ROW_ID + " != ? AND " + UNIQUE_ID + " != ?";
|
||||
|
||||
@@ -138,7 +142,8 @@ public class AttachmentDatabase extends Database {
|
||||
UNIQUE_ID, DIGEST, FAST_PREFLIGHT_ID, VOICE_NOTE,
|
||||
QUOTE, DATA_RANDOM, THUMBNAIL_RANDOM, WIDTH, HEIGHT,
|
||||
CAPTION, STICKER_PACK_ID, STICKER_PACK_KEY, STICKER_ID,
|
||||
DATA_HASH, BLUR_HASH, TRANSFORM_PROPERTIES, TRANSFER_FILE };
|
||||
DATA_HASH, BLUR_HASH, TRANSFORM_PROPERTIES, TRANSFER_FILE,
|
||||
DISPLAY_ORDER };
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " +
|
||||
MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " +
|
||||
@@ -154,7 +159,8 @@ public class AttachmentDatabase extends Database {
|
||||
CAPTION + " TEXT DEFAULT NULL, " + STICKER_PACK_ID + " TEXT DEFAULT NULL, " +
|
||||
STICKER_PACK_KEY + " DEFAULT NULL, " + STICKER_ID + " INTEGER DEFAULT -1, " +
|
||||
DATA_HASH + " TEXT DEFAULT NULL, " + BLUR_HASH + " TEXT DEFAULT NULL, " +
|
||||
TRANSFORM_PROPERTIES + " TEXT DEFAULT NULL, " + TRANSFER_FILE + " TEXT DEFAULT NULL);";
|
||||
TRANSFORM_PROPERTIES + " TEXT DEFAULT NULL, " + TRANSFER_FILE + " TEXT DEFAULT NULL, " +
|
||||
DISPLAY_ORDER + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS part_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
|
||||
@@ -320,6 +326,33 @@ public class AttachmentDatabase extends Database {
|
||||
notifyAttachmentListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all attachments with an ID of {@link #PREUPLOAD_MESSAGE_ID}. These represent
|
||||
* attachments that were pre-uploaded and haven't been assigned to a message. This should only be
|
||||
* done when you *know* that all attachments *should* be assigned a real mmsId. For instance, when
|
||||
* the app starts. Otherwise you could delete attachments that are legitimately being
|
||||
* pre-uploaded.
|
||||
*/
|
||||
public int deleteAbandonedPreuploadedAttachments() {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
String query = MMS_ID + " = ?";
|
||||
String[] args = new String[] { String.valueOf(PREUPLOAD_MESSAGE_ID) };
|
||||
int count = 0;
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, null, query, args, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID));
|
||||
long uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID));
|
||||
AttachmentId id = new AttachmentId(rowId, uniqueId);
|
||||
|
||||
deleteAttachment(id);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public void deleteAttachmentFilesForViewOnceMessage(long mmsId) {
|
||||
Log.d(TAG, "[deleteAttachmentFilesForViewOnceMessage] mmsId: " + mmsId);
|
||||
|
||||
@@ -538,6 +571,32 @@ public class AttachmentDatabase extends Database {
|
||||
database.update(TABLE_NAME, contentValues, PART_ID_WHERE, destinationId.toStrings());
|
||||
}
|
||||
|
||||
public void updateAttachmentCaption(@NonNull AttachmentId id, @Nullable String caption) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(CAPTION, caption);
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, values, PART_ID_WHERE, id.toStrings());
|
||||
}
|
||||
|
||||
public void updateDisplayOrder(@NonNull Map<AttachmentId, Integer> orderMap) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
for (Map.Entry<AttachmentId, Integer> entry : orderMap.entrySet()) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(DISPLAY_ORDER, entry.getValue());
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, values, PART_ID_WHERE, entry.getKey().toStrings());
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void updateAttachmentAfterUpload(@NonNull AttachmentId id, @NonNull Attachment attachment) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
@@ -554,6 +613,42 @@ public class AttachmentDatabase extends Database {
|
||||
database.update(TABLE_NAME, values, PART_ID_WHERE, id.toStrings());
|
||||
}
|
||||
|
||||
public @NonNull DatabaseAttachment insertAttachmentForPreUpload(@NonNull Attachment attachment) throws MmsException {
|
||||
Map<Attachment, AttachmentId> result = insertAttachmentsForMessage(PREUPLOAD_MESSAGE_ID,
|
||||
Collections.singletonList(attachment),
|
||||
Collections.emptyList());
|
||||
|
||||
if (result.values().isEmpty()) {
|
||||
throw new MmsException("Bad attachment result!");
|
||||
}
|
||||
|
||||
DatabaseAttachment databaseAttachment = getAttachment(result.values().iterator().next());
|
||||
|
||||
if (databaseAttachment == null) {
|
||||
throw new MmsException("Failed to retrieve attachment we just inserted!");
|
||||
}
|
||||
|
||||
return databaseAttachment;
|
||||
}
|
||||
|
||||
public void updateMessageId(@NonNull Collection<AttachmentId> attachmentIds, long mmsId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(MMS_ID, mmsId);
|
||||
|
||||
for (AttachmentId attachmentId : attachmentIds) {
|
||||
db.update(TABLE_NAME, values, PART_ID_WHERE, attachmentId.toStrings());
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull Map<Attachment, AttachmentId> insertAttachmentsForMessage(long mmsId, @NonNull List<Attachment> attachments, @NonNull List<Attachment> quoteAttachment)
|
||||
throws MmsException
|
||||
{
|
||||
@@ -957,7 +1052,8 @@ public class AttachmentDatabase extends Database {
|
||||
object.getInt(STICKER_ID))
|
||||
: null,
|
||||
BlurHash.parseOrNull(object.getString(BLUR_HASH)),
|
||||
TransformProperties.parse(object.getString(TRANSFORM_PROPERTIES))));
|
||||
TransformProperties.parse(object.getString(TRANSFORM_PROPERTIES)),
|
||||
object.getInt(DISPLAY_ORDER)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -988,7 +1084,8 @@ public class AttachmentDatabase extends Database {
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(STICKER_ID)))
|
||||
: null,
|
||||
BlurHash.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(BLUR_HASH))),
|
||||
TransformProperties.parse(cursor.getString(cursor.getColumnIndexOrThrow(TRANSFORM_PROPERTIES)))));
|
||||
TransformProperties.parse(cursor.getString(cursor.getColumnIndexOrThrow(TRANSFORM_PROPERTIES))),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(DISPLAY_ORDER))));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new AssertionError(e);
|
||||
|
||||
@@ -44,6 +44,7 @@ public class MediaDatabase extends Database {
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_ID + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.BLUR_HASH + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFORM_PROPERTIES + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CAPTION + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.NAME + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.MESSAGE_BOX + ", "
|
||||
@@ -247,9 +248,9 @@ public class MediaDatabase extends Database {
|
||||
}
|
||||
|
||||
public enum Sorting {
|
||||
Newest (AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " DESC"),
|
||||
Oldest (AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " ASC" ),
|
||||
Largest(AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.SIZE + " DESC");
|
||||
Newest (AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " DESC, " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER + " DESC"),
|
||||
Oldest (AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " ASC, " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER + " DESC"),
|
||||
Largest(AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.SIZE + " DESC, " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER + " DESC");
|
||||
|
||||
private final String postFix;
|
||||
|
||||
|
||||
@@ -212,7 +212,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
"'" + AttachmentDatabase.STICKER_PACK_KEY + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_PACK_KEY + ", " +
|
||||
"'" + AttachmentDatabase.STICKER_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_ID + ", " +
|
||||
"'" + AttachmentDatabase.BLUR_HASH + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.BLUR_HASH + ", " +
|
||||
"'" + AttachmentDatabase.TRANSFORM_PROPERTIES + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFORM_PROPERTIES +
|
||||
"'" + AttachmentDatabase.TRANSFORM_PROPERTIES + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFORM_PROPERTIES + ", " +
|
||||
"'" + AttachmentDatabase.DISPLAY_ORDER + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER +
|
||||
")) AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
|
||||
};
|
||||
|
||||
@@ -702,6 +703,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
List<Attachment> attachments = Stream.of(associatedAttachments).filterNot(Attachment::isQuote)
|
||||
.filterNot(contactAttachments::contains)
|
||||
.filterNot(previewAttachments::contains)
|
||||
.sorted(new DatabaseAttachment.DisplayOrderComparator())
|
||||
.map(a -> (Attachment)a).toList();
|
||||
|
||||
Recipient recipient = Recipient.resolved(RecipientId.from(recipientId));
|
||||
@@ -865,7 +867,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
databaseAttachment.getCaption(),
|
||||
databaseAttachment.getSticker(),
|
||||
databaseAttachment.getBlurHash(),
|
||||
databaseAttachment.getTransformProperties()));
|
||||
databaseAttachment.getTransformProperties(),
|
||||
databaseAttachment.getDisplayOrder()));
|
||||
}
|
||||
|
||||
return insertMediaMessage(request.getBody(),
|
||||
@@ -1563,7 +1566,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
List<NetworkFailure> networkFailures = getFailures(networkDocument);
|
||||
List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachment(cursor);
|
||||
List<Contact> contacts = getSharedContacts(cursor, attachments);
|
||||
Set<Attachment> contactAttachments = Stream.of(contacts).map(Contact::getAvatarAttachment).filter(a -> a != null).collect(Collectors.toSet());
|
||||
Set<Attachment> contactAttachments = Stream.of(contacts).map(Contact::getAvatarAttachment).withoutNulls().collect(Collectors.toSet());
|
||||
List<LinkPreview> previews = getLinkPreviews(cursor, attachments);
|
||||
Set<Attachment> previewAttachments = Stream.of(previews).filter(lp -> lp.getThumbnail().isPresent()).map(lp -> lp.getThumbnail().get()).collect(Collectors.toSet());
|
||||
SlideDeck slideDeck = getSlideDeck(Stream.of(attachments).filterNot(contactAttachments::contains).filterNot(previewAttachments::contains).toList());
|
||||
@@ -1601,9 +1604,10 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
private SlideDeck getSlideDeck(@NonNull List<DatabaseAttachment> attachments) {
|
||||
List<? extends Attachment> messageAttachments = Stream.of(attachments)
|
||||
.filterNot(Attachment::isQuote)
|
||||
.toList();
|
||||
List<DatabaseAttachment> messageAttachments = Stream.of(attachments)
|
||||
.filterNot(Attachment::isQuote)
|
||||
.sorted(new DatabaseAttachment.DisplayOrderComparator())
|
||||
.toList();
|
||||
return new SlideDeck(context, messageAttachments);
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +296,8 @@ public class MmsSmsDatabase extends Database {
|
||||
"'" + AttachmentDatabase.STICKER_PACK_KEY + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_PACK_KEY + ", " +
|
||||
"'" + AttachmentDatabase.STICKER_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_ID + ", " +
|
||||
"'" + AttachmentDatabase.BLUR_HASH + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.BLUR_HASH + ", " +
|
||||
"'" + AttachmentDatabase.TRANSFORM_PROPERTIES + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFORM_PROPERTIES +
|
||||
"'" + AttachmentDatabase.TRANSFORM_PROPERTIES + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFORM_PROPERTIES + ", " +
|
||||
"'" + AttachmentDatabase.DISPLAY_ORDER + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER +
|
||||
")) AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
|
||||
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
|
||||
SmsDatabase.TYPE, SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
|
||||
|
||||
@@ -101,8 +101,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
private static final int REACTIONS_UNREAD_INDEX = 39;
|
||||
private static final int RESUMABLE_DOWNLOADS = 40;
|
||||
private static final int KEY_VALUE_STORE = 41;
|
||||
private static final int ATTACHMENT_DISPLAY_ORDER = 42;
|
||||
|
||||
private static final int DATABASE_VERSION = 41;
|
||||
private static final int DATABASE_VERSION = 42;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
@@ -694,6 +695,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
"type INTEGER)");
|
||||
}
|
||||
|
||||
if (oldVersion < ATTACHMENT_DISPLAY_ORDER) {
|
||||
db.execSQL("ALTER TABLE part ADD COLUMN display_order INTEGER DEFAULT 0");
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
||||
Reference in New Issue
Block a user