Audio extra columns for attachment table.

This commit is contained in:
Anton Chekulaev 2020-10-20 18:58:51 +11:00
parent 091847b131
commit 674da88274
3 changed files with 72 additions and 2 deletions

View File

@ -0,0 +1,14 @@
package org.thoughtcrime.securesms.attachments
data class DatabaseAttachmentAudioExtras(val attachmentId: AttachmentId, val visualSamples: ByteArray, val durationMs: Long) {
override fun equals(other: Any?): Boolean {
return other != null &&
other is DatabaseAttachmentAudioExtras &&
other.attachmentId == attachmentId
}
override fun hashCode(): Int {
return attachmentId.hashCode()
}
}

View File

@ -39,6 +39,7 @@ import org.json.JSONException;
import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.AttachmentId; import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.attachments.DatabaseAttachmentAudioExtras;
import org.thoughtcrime.securesms.crypto.AttachmentSecret; import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream;
@ -105,6 +106,9 @@ public class AttachmentDatabase extends Database {
static final String CAPTION = "caption"; static final String CAPTION = "caption";
public static final String URL = "url"; public static final String URL = "url";
public static final String DIRECTORY = "parts"; public static final String DIRECTORY = "parts";
// audio/* mime type only related columns.
static final String AUDIO_VISUAL_SAMPLES = "audio_visual_samples"; // Small amount of audio byte samples to visualise the content (e.g. draw waveform)
static final String AUDIO_DURATION = "audio_duration"; // Duration of the audio track in milliseconds.
public static final int TRANSFER_PROGRESS_DONE = 0; public static final int TRANSFER_PROGRESS_DONE = 0;
public static final int TRANSFER_PROGRESS_STARTED = 1; public static final int TRANSFER_PROGRESS_STARTED = 1;
@ -112,6 +116,7 @@ public class AttachmentDatabase extends Database {
public static final int TRANSFER_PROGRESS_FAILED = 3; public static final int TRANSFER_PROGRESS_FAILED = 3;
private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?"; private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?";
private static final String PART_AUDIO_ONLY_WHERE = CONTENT_TYPE + " LIKE audio/%";
private static final String[] PROJECTION = new String[] {ROW_ID, private static final String[] PROJECTION = new String[] {ROW_ID,
MMS_ID, CONTENT_TYPE, NAME, CONTENT_DISPOSITION, MMS_ID, CONTENT_TYPE, NAME, CONTENT_DISPOSITION,
@ -121,6 +126,8 @@ public class AttachmentDatabase extends Database {
QUOTE, DATA_RANDOM, THUMBNAIL_RANDOM, WIDTH, HEIGHT, QUOTE, DATA_RANDOM, THUMBNAIL_RANDOM, WIDTH, HEIGHT,
CAPTION, STICKER_PACK_ID, STICKER_PACK_KEY, STICKER_ID, URL}; CAPTION, STICKER_PACK_ID, STICKER_PACK_KEY, STICKER_ID, URL};
private static final String[] PROJECTION_AUDIO_EXTRAS = new String[] {AUDIO_VISUAL_SAMPLES, AUDIO_DURATION};
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " + public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " +
MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " + MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " +
CONTENT_TYPE + " TEXT, " + NAME + " TEXT, " + "chset" + " INTEGER, " + CONTENT_TYPE + " TEXT, " + NAME + " TEXT, " + "chset" + " INTEGER, " +
@ -133,7 +140,8 @@ public class AttachmentDatabase extends Database {
VOICE_NOTE + " INTEGER DEFAULT 0, " + DATA_RANDOM + " BLOB, " + THUMBNAIL_RANDOM + " BLOB, " + VOICE_NOTE + " INTEGER DEFAULT 0, " + DATA_RANDOM + " BLOB, " + THUMBNAIL_RANDOM + " BLOB, " +
QUOTE + " INTEGER DEFAULT 0, " + WIDTH + " INTEGER DEFAULT 0, " + HEIGHT + " INTEGER DEFAULT 0, " + QUOTE + " INTEGER DEFAULT 0, " + WIDTH + " INTEGER DEFAULT 0, " + HEIGHT + " INTEGER DEFAULT 0, " +
CAPTION + " TEXT DEFAULT NULL, " + URL + " TEXT, " + STICKER_PACK_ID + " TEXT DEFAULT NULL, " + CAPTION + " TEXT DEFAULT NULL, " + URL + " TEXT, " + STICKER_PACK_ID + " TEXT DEFAULT NULL, " +
STICKER_PACK_KEY + " DEFAULT NULL, " + STICKER_ID + " INTEGER DEFAULT -1);"; STICKER_PACK_KEY + " DEFAULT NULL, " + STICKER_ID + " INTEGER DEFAULT -1," +
AUDIO_VISUAL_SAMPLES + " BLOB, " + AUDIO_DURATION + " INTEGER);";
public static final String[] CREATE_INDEXS = { public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS part_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");", "CREATE INDEX IF NOT EXISTS part_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
@ -822,6 +830,47 @@ public class AttachmentDatabase extends Database {
} }
} }
/**
* Retrieves the audio extra values associated with the attachment. Only "audio/*" mime type attachments are accepted.
* @return the related audio extras or null in case any of the audio extra columns are empty or the attachment is not an audio.
*/
public @Nullable DatabaseAttachmentAudioExtras getAttachmentAudioExtras(@NonNull AttachmentId attachmentId) {
try (Cursor cursor = databaseHelper.getReadableDatabase()
// We expect all the audio extra values to be present (not null) or reject the whole record.
.query(TABLE_NAME,
PROJECTION_AUDIO_EXTRAS,
PART_ID_WHERE +
" AND " + AUDIO_VISUAL_SAMPLES + " IS NOT NULL" +
" AND " + AUDIO_DURATION + " IS NOT NULL" +
" AND " + PART_AUDIO_ONLY_WHERE,
attachmentId.toStrings(),
null, null, null, "1")) {
if (cursor == null || !cursor.moveToFirst()) return null;
byte[] audioSamples = cursor.getBlob(cursor.getColumnIndexOrThrow(AUDIO_VISUAL_SAMPLES));
long duration = cursor.getLong(cursor.getColumnIndexOrThrow(AUDIO_DURATION));
return new DatabaseAttachmentAudioExtras(attachmentId, audioSamples, duration);
}
}
/**
* Updates audio extra columns for the "audio/*" mime type attachments only.
* @return true if the update operation was successful.
*/
public boolean setAttachmentAudioExtras(@NonNull DatabaseAttachmentAudioExtras extras) {
ContentValues values = new ContentValues();
values.put(AUDIO_VISUAL_SAMPLES, extras.getVisualSamples());
values.put(AUDIO_DURATION, extras.getDurationMs());
int alteredRows = databaseHelper.getWritableDatabase().update(TABLE_NAME,
values,
PART_ID_WHERE + " AND " + PART_AUDIO_ONLY_WHERE,
extras.getAttachmentId().toStrings());
return alteredRows > 0;
}
@VisibleForTesting @VisibleForTesting
class ThumbnailFetchCallable implements Callable<InputStream> { class ThumbnailFetchCallable implements Callable<InputStream> {

View File

@ -103,7 +103,9 @@ public class ClassicOpenHelper extends SQLiteOpenHelper {
private static final int GROUP_RECEIPT_TRACKING = 45; private static final int GROUP_RECEIPT_TRACKING = 45;
private static final int UNREAD_COUNT_VERSION = 46; private static final int UNREAD_COUNT_VERSION = 46;
private static final int MORE_RECIPIENT_FIELDS = 47; private static final int MORE_RECIPIENT_FIELDS = 47;
private static final int DATABASE_VERSION = 47; private static final int AUDIO_ATTACHMENT_EXTRAS = 48;
private static final int DATABASE_VERSION = 48;
private static final String TAG = ClassicOpenHelper.class.getSimpleName(); private static final String TAG = ClassicOpenHelper.class.getSimpleName();
@ -1289,6 +1291,11 @@ public class ClassicOpenHelper extends SQLiteOpenHelper {
*/ */
} }
if (oldVersion < AUDIO_ATTACHMENT_EXTRAS) {
db.execSQL("ALTER TABLE part ADD COLUMN audio_visual_samples BLOB");
db.execSQL("ALTER TABLE part ADD COLUMN audio_duration INTEGER");
}
db.setTransactionSuccessful(); db.setTransactionSuccessful();
db.endTransaction(); db.endTransaction();
} }