Add support for backing up wallpapers.

This commit is contained in:
Greyson Parrelli
2024-09-20 12:24:57 -04:00
committed by GitHub
parent e14078d2ec
commit a7bdfb6d76
30 changed files with 907 additions and 410 deletions

View File

@@ -70,6 +70,7 @@ import org.thoughtcrime.securesms.attachments.Attachment
import org.thoughtcrime.securesms.attachments.AttachmentId
import org.thoughtcrime.securesms.attachments.Cdn
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
import org.thoughtcrime.securesms.attachments.WallpaperAttachment
import org.thoughtcrime.securesms.audio.AudioHash
import org.thoughtcrime.securesms.blurhash.BlurHash
import org.thoughtcrime.securesms.crypto.AttachmentSecret
@@ -182,6 +183,7 @@ class AttachmentTable(
const val TRANSFER_RESTORE_IN_PROGRESS = 6
const val TRANSFER_RESTORE_OFFLOADED = 7
const val PREUPLOAD_MESSAGE_ID: Long = -8675309
const val WALLPAPER_MESSAGE_ID: Long = -8675308
private val PROJECTION = arrayOf(
ID,
@@ -816,7 +818,7 @@ class AttachmentTable(
fun trimAllAbandonedAttachments() {
val deleteCount = writableDatabase
.delete(TABLE_NAME)
.where("$MESSAGE_ID != $PREUPLOAD_MESSAGE_ID AND $MESSAGE_ID NOT IN (SELECT ${MessageTable.ID} FROM ${MessageTable.TABLE_NAME})")
.where("$MESSAGE_ID != $PREUPLOAD_MESSAGE_ID AND $MESSAGE_ID != $WALLPAPER_MESSAGE_ID AND $MESSAGE_ID NOT IN (SELECT ${MessageTable.ID} FROM ${MessageTable.TABLE_NAME})")
.run()
if (deleteCount > 0) {
@@ -2184,6 +2186,16 @@ class AttachmentTable(
throw MmsException(e)
}
return insertAttachmentWithData(messageId, dataStream, attachment, quote)
}
/**
* Inserts an attachment with existing data. This is likely an outgoing attachment that we're in the process of sending.
*
* @param dataStream The stream to read the data from. This stream will be closed by this method.
*/
@Throws(MmsException::class)
private fun insertAttachmentWithData(messageId: Long, dataStream: InputStream, attachment: Attachment, quote: Boolean): AttachmentId {
// To avoid performing long-running operations in a transaction, we write the data to an independent file first in a way that doesn't rely on db state.
val fileWriteResult: DataFileWriteResult = writeToDataFile(newDataFile(context), dataStream, attachment.transformProperties ?: TransformProperties.empty())
Log.d(TAG, "[insertAttachmentWithData] Wrote data to file: ${fileWriteResult.file.absolutePath} (MessageId: $messageId, ${attachment.uri})")
@@ -2212,12 +2224,16 @@ class AttachmentTable(
}
if (hashMatch != null) {
if (fileWriteResult.hash == hashMatch.hashStart) {
Log.i(TAG, "[insertAttachmentWithData] Found that the new attachment hash matches the DATA_HASH_START of ${hashMatch.id}. Using all of it's fields. (MessageId: $messageId, ${attachment.uri})")
} else if (fileWriteResult.hash == hashMatch.hashEnd) {
Log.i(TAG, "[insertAttachmentWithData] Found that the new attachment hash matches the DATA_HASH_END of ${hashMatch.id}. Using all of it's fields. (MessageId: $messageId, ${attachment.uri})")
} else {
throw IllegalStateException("Should not be possible based on query.")
when (fileWriteResult.hash) {
hashMatch.hashStart -> {
Log.i(TAG, "[insertAttachmentWithData] Found that the new attachment hash matches the DATA_HASH_START of ${hashMatch.id}. Using all of it's fields. (MessageId: $messageId, ${attachment.uri})")
}
hashMatch.hashEnd -> {
Log.i(TAG, "[insertAttachmentWithData] Found that the new attachment hash matches the DATA_HASH_END of ${hashMatch.id}. Using all of it's fields. (MessageId: $messageId, ${attachment.uri})")
}
else -> {
throw IllegalStateException("Should not be possible based on query.")
}
}
contentValues.put(DATA_FILE, hashMatch.file.absolutePath)
@@ -2309,6 +2325,21 @@ class AttachmentTable(
return attachmentId
}
fun insertWallpaper(dataStream: InputStream): AttachmentId {
return insertAttachmentWithData(WALLPAPER_MESSAGE_ID, dataStream, WallpaperAttachment(), quote = false).also { id ->
createKeyIvIfNecessary(id)
}
}
fun getAllWallpapers(): List<AttachmentId> {
return readableDatabase
.select(ID)
.from(TABLE_NAME)
.where("$MESSAGE_ID = $WALLPAPER_MESSAGE_ID")
.run()
.readToList { AttachmentId(it.requireLong(ID)) }
}
private fun getTransferFile(db: SQLiteDatabase, attachmentId: AttachmentId): File? {
return db
.select(TRANSFER_FILE)

View File

@@ -98,6 +98,7 @@ import org.thoughtcrime.securesms.util.ProfileUtil
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperFactory
import org.thoughtcrime.securesms.wallpaper.WallpaperStorage
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile
import org.whispersystems.signalservice.api.push.ServiceId
@@ -1968,7 +1969,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
for (pair in idWithWallpaper) {
AppDependencies.databaseObserver.notifyRecipientChanged(pair.first)
if (pair.second != null) {
WallpaperStorage.onWallpaperDeselected(context, Uri.parse(pair.second))
WallpaperStorage.onWallpaperDeselected(Uri.parse(pair.second))
}
}
} else {
@@ -1980,11 +1981,11 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
}
fun setWallpaper(id: RecipientId, chatWallpaper: ChatWallpaper?) {
setWallpaper(id, chatWallpaper?.serialize())
fun setWallpaper(id: RecipientId, chatWallpaper: ChatWallpaper?, notifyDeselected: Boolean) {
setWallpaper(id, chatWallpaper?.serialize(), notifyDeselected)
}
private fun setWallpaper(id: RecipientId, wallpaper: Wallpaper?) {
private fun setWallpaper(id: RecipientId, wallpaper: Wallpaper?, notifyDeselected: Boolean) {
val existingWallpaperUri = getWallpaperUri(id)
val values = ContentValues().apply {
put(WALLPAPER, wallpaper?.encode())
@@ -1999,8 +2000,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
AppDependencies.databaseObserver.notifyRecipientChanged(id)
}
if (existingWallpaperUri != null) {
WallpaperStorage.onWallpaperDeselected(context, existingWallpaperUri)
if (notifyDeselected && existingWallpaperUri != null) {
WallpaperStorage.onWallpaperDeselected(existingWallpaperUri)
}
}
@@ -2010,7 +2011,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
.dimLevelInDarkTheme(if (enabled) ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME else 0f)
.build()
setWallpaper(id, updated)
setWallpaper(id, updated, false)
}
private fun getWallpaper(id: RecipientId): Wallpaper? {
@@ -2055,6 +2056,23 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
return 0
}
/**
* Migrates all recipients using [legacyUri] for their wallpaper to [newUri].
* Needed for an app migration.
*/
fun migrateWallpaperUri(legacyUri: Uri, newUri: Uri): Int {
val newWallpaper = ChatWallpaperFactory.create(newUri)
return writableDatabase
.update(TABLE_NAME)
.values(
WALLPAPER to newWallpaper.serialize().encode(),
WALLPAPER_URI to newUri.toString()
)
.where("$WALLPAPER_URI = ?", legacyUri)
.run()
}
fun getPhoneNumberDiscoverability(id: RecipientId): PhoneNumberDiscoverableState? {
return readableDatabase
.select(PHONE_NUMBER_DISCOVERABLE)