Convert AttachmentTable and models to kotlin.

This commit is contained in:
Greyson Parrelli 2024-01-03 14:43:05 -05:00 committed by Alex Hart
parent 888a40a5c4
commit 3554f82ea3
62 changed files with 2626 additions and 2986 deletions

View file

@ -1,319 +0,0 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.os.ParcelCompat;
import org.thoughtcrime.securesms.audio.AudioHash;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.util.ParcelUtil;
import java.util.Objects;
public abstract class Attachment implements Parcelable {
@NonNull
private final String contentType;
private final int transferState;
private final long size;
@Nullable
private final String fileName;
private final int cdnNumber;
@Nullable
private final String location;
@Nullable
private final String key;
@Nullable
private final String relay;
@Nullable
private final byte[] digest;
@Nullable
private final byte[] incrementalDigest;
@Nullable
private final String fastPreflightId;
private final boolean voiceNote;
private final boolean borderless;
private final boolean videoGif;
private final int width;
private final int height;
private final boolean quote;
private final long uploadTimestamp;
private final int incrementalMacChunkSize;
@Nullable
private final String caption;
@Nullable
private final StickerLocator stickerLocator;
@Nullable
private final BlurHash blurHash;
@Nullable
private final AudioHash audioHash;
@NonNull
private final TransformProperties transformProperties;
public Attachment(@NonNull String contentType,
int transferState,
long size,
@Nullable String fileName,
int cdnNumber,
@Nullable String location,
@Nullable String key,
@Nullable String relay,
@Nullable byte[] digest,
@Nullable byte[] incrementalDigest,
@Nullable String fastPreflightId,
boolean voiceNote,
boolean borderless,
boolean videoGif,
int width,
int height,
int incrementalMacChunkSize,
boolean quote,
long uploadTimestamp,
@Nullable String caption,
@Nullable StickerLocator stickerLocator,
@Nullable BlurHash blurHash,
@Nullable AudioHash audioHash,
@Nullable TransformProperties transformProperties)
{
this.contentType = contentType;
this.transferState = transferState;
this.size = size;
this.fileName = fileName;
this.cdnNumber = cdnNumber;
this.location = location;
this.key = key;
this.relay = relay;
this.digest = digest;
this.incrementalDigest = incrementalDigest;
this.fastPreflightId = fastPreflightId;
this.voiceNote = voiceNote;
this.borderless = borderless;
this.videoGif = videoGif;
this.width = width;
this.height = height;
this.incrementalMacChunkSize = incrementalMacChunkSize;
this.quote = quote;
this.uploadTimestamp = uploadTimestamp;
this.stickerLocator = stickerLocator;
this.caption = caption;
this.blurHash = blurHash;
this.audioHash = audioHash;
this.transformProperties = transformProperties != null ? transformProperties : TransformProperties.empty();
}
protected Attachment(Parcel in) {
this.contentType = Objects.requireNonNull(in.readString());
this.transferState = in.readInt();
this.size = in.readLong();
this.fileName = in.readString();
this.cdnNumber = in.readInt();
this.location = in.readString();
this.key = in.readString();
this.relay = in.readString();
this.digest = ParcelUtil.readByteArray(in);
this.incrementalDigest = ParcelUtil.readByteArray(in);
this.fastPreflightId = in.readString();
this.voiceNote = ParcelUtil.readBoolean(in);
this.borderless = ParcelUtil.readBoolean(in);
this.videoGif = ParcelUtil.readBoolean(in);
this.width = in.readInt();
this.height = in.readInt();
this.incrementalMacChunkSize = in.readInt();
this.quote = ParcelUtil.readBoolean(in);
this.uploadTimestamp = in.readLong();
this.stickerLocator = ParcelCompat.readParcelable(in, StickerLocator.class.getClassLoader(), StickerLocator.class);
this.caption = in.readString();
this.blurHash = ParcelCompat.readParcelable(in, BlurHash.class.getClassLoader(), BlurHash.class);
this.audioHash = ParcelCompat.readParcelable(in, AudioHash.class.getClassLoader(), AudioHash.class);
this.transformProperties = Objects.requireNonNull(ParcelCompat.readParcelable(in, TransformProperties.class.getClassLoader(), TransformProperties.class));
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
AttachmentCreator.writeSubclass(dest, this);
dest.writeString(contentType);
dest.writeInt(transferState);
dest.writeLong(size);
dest.writeString(fileName);
dest.writeInt(cdnNumber);
dest.writeString(location);
dest.writeString(key);
dest.writeString(relay);
ParcelUtil.writeByteArray(dest, digest);
ParcelUtil.writeByteArray(dest, incrementalDigest);
dest.writeString(fastPreflightId);
ParcelUtil.writeBoolean(dest, voiceNote);
ParcelUtil.writeBoolean(dest, borderless);
ParcelUtil.writeBoolean(dest, videoGif);
dest.writeInt(width);
dest.writeInt(height);
dest.writeInt(incrementalMacChunkSize);
ParcelUtil.writeBoolean(dest, quote);
dest.writeLong(uploadTimestamp);
dest.writeParcelable(stickerLocator, 0);
dest.writeString(caption);
dest.writeParcelable(blurHash, 0);
dest.writeParcelable(audioHash, 0);
dest.writeParcelable(transformProperties, 0);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Attachment> CREATOR = AttachmentCreator.INSTANCE;
@Nullable
public abstract Uri getUri();
public abstract @Nullable Uri getPublicUri();
public int getTransferState() {
return transferState;
}
public boolean isInProgress() {
return transferState != AttachmentTable.TRANSFER_PROGRESS_DONE &&
transferState != AttachmentTable.TRANSFER_PROGRESS_FAILED &&
transferState != AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE;
}
public boolean isPermanentlyFailed() {
return transferState == AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE;
}
public long getSize() {
return size;
}
@Nullable
public String getFileName() {
return fileName;
}
@NonNull
public String getContentType() {
return contentType;
}
public int getCdnNumber() {
return cdnNumber;
}
@Nullable
public String getLocation() {
return location;
}
@Nullable
public String getKey() {
return key;
}
@Nullable
public String getRelay() {
return relay;
}
@Nullable
public byte[] getDigest() {
return digest;
}
@Nullable
public byte[] getIncrementalDigest() {
if (incrementalDigest != null && incrementalDigest.length > 0) {
return incrementalDigest;
} else {
return null;
}
}
@Nullable
public String getFastPreflightId() {
return fastPreflightId;
}
public boolean isVoiceNote() {
return voiceNote;
}
public boolean isBorderless() {
return borderless;
}
public boolean isVideoGif() {
return videoGif;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getIncrementalMacChunkSize() {
return incrementalMacChunkSize;
}
public boolean isQuote() {
return quote;
}
public long getUploadTimestamp() {
return uploadTimestamp;
}
public boolean isSticker() {
return stickerLocator != null;
}
public @Nullable StickerLocator getSticker() {
return stickerLocator;
}
public @Nullable BlurHash getBlurHash() {
return blurHash;
}
public @Nullable AudioHash getAudioHash() {
return audioHash;
}
public @Nullable String getCaption() {
return caption;
}
public @NonNull TransformProperties getTransformProperties() {
return transformProperties;
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.attachments
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import androidx.core.os.ParcelCompat
import org.thoughtcrime.securesms.audio.AudioHash
import org.thoughtcrime.securesms.blurhash.BlurHash
import org.thoughtcrime.securesms.database.AttachmentTable
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties
import org.thoughtcrime.securesms.stickers.StickerLocator
import org.thoughtcrime.securesms.util.ParcelUtil
/**
* Note: We have to use our own Parcelable implementation because we need to do custom stuff to preserve
* subclass information.
*/
abstract class Attachment(
@JvmField
val contentType: String,
@JvmField
val transferState: Int,
@JvmField
val size: Long,
@JvmField
val fileName: String?,
@JvmField
val cdnNumber: Int,
@JvmField
val location: String?,
@JvmField
val key: String?,
@JvmField
val relay: String?,
@JvmField
val digest: ByteArray?,
@JvmField
val incrementalDigest: ByteArray?,
@JvmField
val fastPreflightId: String?,
@JvmField
val voiceNote: Boolean,
@JvmField
val borderless: Boolean,
@JvmField
val videoGif: Boolean,
@JvmField
val width: Int,
@JvmField
val height: Int,
@JvmField
val incrementalMacChunkSize: Int,
@JvmField
val quote: Boolean,
@JvmField
val uploadTimestamp: Long,
@JvmField
val caption: String?,
@JvmField
val stickerLocator: StickerLocator?,
@JvmField
val blurHash: BlurHash?,
@JvmField
val audioHash: AudioHash?,
@JvmField
val transformProperties: TransformProperties?
) : Parcelable {
abstract val uri: Uri?
abstract val publicUri: Uri?
protected constructor(parcel: Parcel) : this(
contentType = parcel.readString()!!,
transferState = parcel.readInt(),
size = parcel.readLong(),
fileName = parcel.readString(),
cdnNumber = parcel.readInt(),
location = parcel.readString(),
key = parcel.readString(),
relay = parcel.readString(),
digest = ParcelUtil.readByteArray(parcel),
incrementalDigest = ParcelUtil.readByteArray(parcel),
fastPreflightId = parcel.readString(),
voiceNote = ParcelUtil.readBoolean(parcel),
borderless = ParcelUtil.readBoolean(parcel),
videoGif = ParcelUtil.readBoolean(parcel),
width = parcel.readInt(),
height = parcel.readInt(),
incrementalMacChunkSize = parcel.readInt(),
quote = ParcelUtil.readBoolean(parcel),
uploadTimestamp = parcel.readLong(),
caption = parcel.readString(),
stickerLocator = ParcelCompat.readParcelable(parcel, StickerLocator::class.java.classLoader, StickerLocator::class.java),
blurHash = ParcelCompat.readParcelable(parcel, BlurHash::class.java.classLoader, BlurHash::class.java),
audioHash = ParcelCompat.readParcelable(parcel, AudioHash::class.java.classLoader, AudioHash::class.java),
transformProperties = ParcelCompat.readParcelable(parcel, TransformProperties::class.java.classLoader, TransformProperties::class.java)
)
override fun writeToParcel(dest: Parcel, flags: Int) {
AttachmentCreator.writeSubclass(dest, this)
dest.writeString(contentType)
dest.writeInt(transferState)
dest.writeLong(size)
dest.writeString(fileName)
dest.writeInt(cdnNumber)
dest.writeString(location)
dest.writeString(key)
dest.writeString(relay)
ParcelUtil.writeByteArray(dest, digest)
ParcelUtil.writeByteArray(dest, incrementalDigest)
dest.writeString(fastPreflightId)
ParcelUtil.writeBoolean(dest, voiceNote)
ParcelUtil.writeBoolean(dest, borderless)
ParcelUtil.writeBoolean(dest, videoGif)
dest.writeInt(width)
dest.writeInt(height)
dest.writeInt(incrementalMacChunkSize)
ParcelUtil.writeBoolean(dest, quote)
dest.writeLong(uploadTimestamp)
dest.writeString(caption)
dest.writeParcelable(stickerLocator, 0)
dest.writeParcelable(blurHash, 0)
dest.writeParcelable(audioHash, 0)
dest.writeParcelable(transformProperties, 0)
}
override fun describeContents(): Int {
return 0
}
val isInProgress: Boolean
get() = transferState != AttachmentTable.TRANSFER_PROGRESS_DONE && transferState != AttachmentTable.TRANSFER_PROGRESS_FAILED && transferState != AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE
val isPermanentlyFailed: Boolean
get() = transferState == AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE
val isSticker: Boolean
get() = stickerLocator != null
fun getIncrementalDigest(): ByteArray? {
return if (incrementalDigest != null && incrementalDigest.size > 0) {
incrementalDigest
} else {
null
}
}
companion object {
@JvmField
val CREATOR: Parcelable.Creator<Attachment> = AttachmentCreator
}
}

View file

@ -15,7 +15,6 @@ import android.os.Parcelable
object AttachmentCreator : Parcelable.Creator<Attachment> {
enum class Subclass(val clazz: Class<out Attachment>, val code: String) {
DATABASE(DatabaseAttachment::class.java, "database"),
MMS_NOTIFICATION(MmsNotificationAttachment::class.java, "mms_notification"),
POINTER(PointerAttachment::class.java, "pointer"),
TOMBSTONE(TombstoneAttachment::class.java, "tombstone"),
URI(UriAttachment::class.java, "uri")
@ -32,7 +31,6 @@ object AttachmentCreator : Parcelable.Creator<Attachment> {
return when (Subclass.values().first { rawCode == it.code }) {
Subclass.DATABASE -> DatabaseAttachment(source)
Subclass.MMS_NOTIFICATION -> MmsNotificationAttachment(source)
Subclass.POINTER -> PointerAttachment(source)
Subclass.TOMBSTONE -> TombstoneAttachment(source)
Subclass.URI -> UriAttachment(source)

View file

@ -1,142 +0,0 @@
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.os.ParcelCompat;
import org.thoughtcrime.securesms.audio.AudioHash;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ParcelUtil;
import java.util.Comparator;
public class DatabaseAttachment extends Attachment {
private final AttachmentId attachmentId;
private final long mmsId;
private final boolean hasData;
private final boolean hasThumbnail;
private final int displayOrder;
public DatabaseAttachment(AttachmentId attachmentId,
long mmsId,
boolean hasData,
boolean hasThumbnail,
String contentType,
int transferProgress,
long size,
String fileName,
int cdnNumber,
String location,
String key,
String relay,
byte[] digest,
byte[] incrementalDigest,
int incrementalMacChunkSize,
String fastPreflightId,
boolean voiceNote,
boolean borderless,
boolean videoGif,
int width,
int height,
boolean quote,
@Nullable String caption,
@Nullable StickerLocator stickerLocator,
@Nullable BlurHash blurHash,
@Nullable AudioHash audioHash,
@Nullable TransformProperties transformProperties,
int displayOrder,
long uploadTimestamp)
{
super(contentType, transferProgress, size, fileName, cdnNumber, location, key, relay, digest, incrementalDigest, fastPreflightId, voiceNote, borderless, videoGif, width, height, incrementalMacChunkSize, quote, uploadTimestamp, caption, stickerLocator, blurHash, audioHash, transformProperties);
this.attachmentId = attachmentId;
this.hasData = hasData;
this.hasThumbnail = hasThumbnail;
this.mmsId = mmsId;
this.displayOrder = displayOrder;
}
protected DatabaseAttachment(Parcel in) {
super(in);
this.attachmentId = ParcelCompat.readParcelable(in, AttachmentId.class.getClassLoader(), AttachmentId.class);
this.hasData = ParcelUtil.readBoolean(in);
this.hasThumbnail = ParcelUtil.readBoolean(in);
this.mmsId = in.readLong();
this.displayOrder = in.readInt();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(attachmentId, 0);
ParcelUtil.writeBoolean(dest, hasData);
ParcelUtil.writeBoolean(dest, hasThumbnail);
dest.writeLong(mmsId);
dest.writeInt(displayOrder);
}
@Override
@Nullable
public Uri getUri() {
if (hasData || (FeatureFlags.instantVideoPlayback() && getIncrementalDigest() != null)) {
return PartAuthority.getAttachmentDataUri(attachmentId);
} else {
return null;
}
}
@Override
public @Nullable Uri getPublicUri() {
if (hasData) {
return PartAuthority.getAttachmentPublicUri(getUri());
} else {
return null;
}
}
public AttachmentId getAttachmentId() {
return attachmentId;
}
public int getDisplayOrder() {
return displayOrder;
}
@Override
public boolean equals(Object other) {
return other != null &&
other instanceof DatabaseAttachment &&
((DatabaseAttachment) other).attachmentId.equals(this.attachmentId);
}
@Override
public int hashCode() {
return attachmentId.hashCode();
}
public long getMmsId() {
return mmsId;
}
public boolean hasData() {
return hasData;
}
public boolean hasThumbnail() {
return hasThumbnail;
}
public static class DisplayOrderComparator implements Comparator<DatabaseAttachment> {
@Override
public int compare(DatabaseAttachment lhs, DatabaseAttachment rhs) {
return Integer.compare(lhs.getDisplayOrder(), rhs.getDisplayOrder());
}
}
}

View file

@ -0,0 +1,135 @@
package org.thoughtcrime.securesms.attachments
import android.net.Uri
import android.os.Parcel
import androidx.core.os.ParcelCompat
import org.thoughtcrime.securesms.audio.AudioHash
import org.thoughtcrime.securesms.blurhash.BlurHash
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties
import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.stickers.StickerLocator
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.ParcelUtil
class DatabaseAttachment : Attachment {
@JvmField
val attachmentId: AttachmentId
@JvmField
val mmsId: Long
@JvmField
val hasData: Boolean
private val hasThumbnail: Boolean
val displayOrder: Int
constructor(
attachmentId: AttachmentId,
mmsId: Long,
hasData: Boolean,
hasThumbnail: Boolean,
contentType: String?,
transferProgress: Int,
size: Long,
fileName: String?,
cdnNumber: Int,
location: String?,
key: String?,
relay: String?,
digest: ByteArray?,
incrementalDigest: ByteArray?,
incrementalMacChunkSize: Int,
fastPreflightId: String?,
voiceNote: Boolean,
borderless: Boolean,
videoGif: Boolean,
width: Int,
height: Int,
quote: Boolean,
caption: String?,
stickerLocator: StickerLocator?,
blurHash: BlurHash?,
audioHash: AudioHash?,
transformProperties: TransformProperties?,
displayOrder: Int,
uploadTimestamp: Long
) : super(
contentType = contentType!!,
transferState = transferProgress,
size = size,
fileName = fileName,
cdnNumber = cdnNumber,
location = location,
key = key,
relay = relay,
digest = digest,
incrementalDigest = incrementalDigest,
fastPreflightId = fastPreflightId,
voiceNote = voiceNote,
borderless = borderless,
videoGif = videoGif, width = width,
height = height,
incrementalMacChunkSize = incrementalMacChunkSize,
quote = quote,
uploadTimestamp = uploadTimestamp,
caption = caption,
stickerLocator = stickerLocator,
blurHash = blurHash,
audioHash = audioHash,
transformProperties = transformProperties
) {
this.attachmentId = attachmentId
this.mmsId = mmsId
this.hasData = hasData
this.hasThumbnail = hasThumbnail
this.displayOrder = displayOrder
}
constructor(parcel: Parcel) : super(parcel) {
attachmentId = ParcelCompat.readParcelable(parcel, AttachmentId::class.java.classLoader, AttachmentId::class.java)!!
hasData = ParcelUtil.readBoolean(parcel)
hasThumbnail = ParcelUtil.readBoolean(parcel)
mmsId = parcel.readLong()
displayOrder = parcel.readInt()
}
override fun writeToParcel(dest: Parcel, flags: Int) {
super.writeToParcel(dest, flags)
dest.writeParcelable(attachmentId, 0)
ParcelUtil.writeBoolean(dest, hasData)
ParcelUtil.writeBoolean(dest, hasThumbnail)
dest.writeLong(mmsId)
dest.writeInt(displayOrder)
}
override val uri: Uri?
get() = if (hasData || FeatureFlags.instantVideoPlayback() && getIncrementalDigest() != null) {
PartAuthority.getAttachmentDataUri(attachmentId)
} else {
null
}
override val publicUri: Uri?
get() = if (hasData) {
PartAuthority.getAttachmentPublicUri(uri)
} else {
null
}
override fun equals(other: Any?): Boolean {
return other != null &&
other is DatabaseAttachment && other.attachmentId == attachmentId
}
override fun hashCode(): Int {
return attachmentId.hashCode()
}
class DisplayOrderComparator : Comparator<DatabaseAttachment> {
override fun compare(lhs: DatabaseAttachment, rhs: DatabaseAttachment): Int {
return lhs.displayOrder.compareTo(rhs.displayOrder)
}
}
}

View file

@ -1,45 +0,0 @@
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.database.MessageTable;
public class MmsNotificationAttachment extends Attachment {
public MmsNotificationAttachment(int status, long size) {
super("application/mms", getTransferStateFromStatus(status), size, null, 0, null, null, null, null, null, null, false, false, false, 0, 0, 0, false, 0, null, null, null, null, null);
}
protected MmsNotificationAttachment(Parcel in) {
super(in);
}
@Nullable
@Override
public Uri getUri() {
return null;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
private static int getTransferStateFromStatus(int status) {
if (status == MessageTable.MmsStatus.DOWNLOAD_INITIALIZED ||
status == MessageTable.MmsStatus.DOWNLOAD_NO_CONNECTIVITY)
{
return AttachmentTable.TRANSFER_PROGRESS_PENDING;
} else if (status == MessageTable.MmsStatus.DOWNLOAD_CONNECTING) {
return AttachmentTable.TRANSFER_PROGRESS_STARTED;
} else {
return AttachmentTable.TRANSFER_PROGRESS_FAILED;
}
}
}

View file

@ -1,194 +0,0 @@
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.signal.core.util.Base64;
import org.whispersystems.signalservice.api.InvalidMessageStructureException;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.util.AttachmentPointerUtil;
import org.whispersystems.signalservice.internal.push.DataMessage;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
public class PointerAttachment extends Attachment {
private PointerAttachment(@NonNull String contentType,
int transferState,
long size,
@Nullable String fileName,
int cdnNumber,
@NonNull String location,
@Nullable String key,
@Nullable String relay,
@Nullable byte[] digest,
@Nullable byte[] incrementalDigest,
int incrementalMacChunkSize,
@Nullable String fastPreflightId,
boolean voiceNote,
boolean borderless,
boolean videoGif,
int width,
int height,
long uploadTimestamp,
@Nullable String caption,
@Nullable StickerLocator stickerLocator,
@Nullable BlurHash blurHash)
{
super(contentType, transferState, size, fileName, cdnNumber, location, key, relay, digest, incrementalDigest, fastPreflightId, voiceNote, borderless, videoGif, width, height, incrementalMacChunkSize, false, uploadTimestamp, caption, stickerLocator, blurHash, null, null);
}
protected PointerAttachment(Parcel in) {
super(in);
}
@Nullable
@Override
public Uri getUri() {
return null;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
public static List<Attachment> forPointers(Optional<List<SignalServiceAttachment>> pointers) {
List<Attachment> results = new LinkedList<>();
if (pointers.isPresent()) {
for (SignalServiceAttachment pointer : pointers.get()) {
Optional<Attachment> result = forPointer(Optional.of(pointer));
if (result.isPresent()) {
results.add(result.get());
}
}
}
return results;
}
public static List<Attachment> forPointers(@Nullable List<SignalServiceDataMessage.Quote.QuotedAttachment> pointers) {
List<Attachment> results = new LinkedList<>();
if (pointers != null) {
for (SignalServiceDataMessage.Quote.QuotedAttachment pointer : pointers) {
Optional<Attachment> result = forPointer(pointer);
if (result.isPresent()) {
results.add(result.get());
}
}
}
return results;
}
public static Optional<Attachment> forPointer(Optional<SignalServiceAttachment> pointer) {
return forPointer(pointer, null, null);
}
public static Optional<Attachment> forPointer(Optional<SignalServiceAttachment> pointer, @Nullable StickerLocator stickerLocator) {
return forPointer(pointer, stickerLocator, null);
}
public static Optional<Attachment> forPointer(Optional<SignalServiceAttachment> pointer, @Nullable StickerLocator stickerLocator, @Nullable String fastPreflightId) {
if (!pointer.isPresent() || !pointer.get().isPointer()) return Optional.empty();
String encodedKey = null;
if (pointer.get().asPointer().getKey() != null) {
encodedKey = Base64.encodeWithPadding(pointer.get().asPointer().getKey());
}
return Optional.of(new PointerAttachment(pointer.get().getContentType(),
AttachmentTable.TRANSFER_PROGRESS_PENDING,
pointer.get().asPointer().getSize().orElse(0),
pointer.get().asPointer().getFileName().orElse(null),
pointer.get().asPointer().getCdnNumber(),
pointer.get().asPointer().getRemoteId().toString(),
encodedKey,
null,
pointer.get().asPointer().getDigest().orElse(null),
pointer.get().asPointer().getIncrementalDigest().orElse(null),
pointer.get().asPointer().getIncrementalMacChunkSize(),
fastPreflightId,
pointer.get().asPointer().getVoiceNote(),
pointer.get().asPointer().isBorderless(),
pointer.get().asPointer().isGif(),
pointer.get().asPointer().getWidth(),
pointer.get().asPointer().getHeight(),
pointer.get().asPointer().getUploadTimestamp(),
pointer.get().asPointer().getCaption().orElse(null),
stickerLocator,
BlurHash.parseOrNull(pointer.get().asPointer().getBlurHash().orElse(null))));
}
public static Optional<Attachment> forPointer(SignalServiceDataMessage.Quote.QuotedAttachment pointer) {
SignalServiceAttachment thumbnail = pointer.getThumbnail();
return Optional.of(new PointerAttachment(pointer.getContentType(),
AttachmentTable.TRANSFER_PROGRESS_PENDING,
thumbnail != null ? thumbnail.asPointer().getSize().orElse(0) : 0,
pointer.getFileName(),
thumbnail != null ? thumbnail.asPointer().getCdnNumber() : 0,
thumbnail != null ? thumbnail.asPointer().getRemoteId().toString() : "0",
thumbnail != null && thumbnail.asPointer().getKey() != null ? Base64.encodeWithPadding(thumbnail.asPointer().getKey()) : null,
null,
thumbnail != null ? thumbnail.asPointer().getDigest().orElse(null) : null,
thumbnail != null ? thumbnail.asPointer().getIncrementalDigest().orElse(null) : null,
thumbnail != null ? thumbnail.asPointer().getIncrementalMacChunkSize() : 0,
null,
false,
false,
false,
thumbnail != null ? thumbnail.asPointer().getWidth() : 0,
thumbnail != null ? thumbnail.asPointer().getHeight() : 0,
thumbnail != null ? thumbnail.asPointer().getUploadTimestamp() : 0,
thumbnail != null ? thumbnail.asPointer().getCaption().orElse(null) : null,
null,
null));
}
public static Optional<Attachment> forPointer(DataMessage.Quote.QuotedAttachment quotedAttachment) {
SignalServiceAttachment thumbnail;
try {
thumbnail = quotedAttachment.thumbnail != null ? AttachmentPointerUtil.createSignalAttachmentPointer(quotedAttachment.thumbnail) : null;
} catch (InvalidMessageStructureException e) {
return Optional.empty();
}
return Optional.of(new PointerAttachment(quotedAttachment.contentType,
AttachmentTable.TRANSFER_PROGRESS_PENDING,
thumbnail != null ? thumbnail.asPointer().getSize().orElse(0) : 0,
quotedAttachment.fileName,
thumbnail != null ? thumbnail.asPointer().getCdnNumber() : 0,
thumbnail != null ? thumbnail.asPointer().getRemoteId().toString() : "0",
thumbnail != null && thumbnail.asPointer().getKey() != null ? Base64.encodeWithPadding(thumbnail.asPointer().getKey()) : null,
null,
thumbnail != null ? thumbnail.asPointer().getDigest().orElse(null) : null,
thumbnail != null ? thumbnail.asPointer().getIncrementalDigest().orElse(null) : null,
thumbnail != null ? thumbnail.asPointer().getIncrementalMacChunkSize() : 0,
null,
false,
false,
false,
thumbnail != null ? thumbnail.asPointer().getWidth() : 0,
thumbnail != null ? thumbnail.asPointer().getHeight() : 0,
thumbnail != null ? thumbnail.asPointer().getUploadTimestamp() : 0,
thumbnail != null ? thumbnail.asPointer().getCaption().orElse(null) : null,
null,
null));
}
}

View file

@ -0,0 +1,192 @@
package org.thoughtcrime.securesms.attachments
import android.net.Uri
import android.os.Parcel
import org.signal.core.util.Base64.encodeWithPadding
import org.thoughtcrime.securesms.blurhash.BlurHash
import org.thoughtcrime.securesms.database.AttachmentTable
import org.thoughtcrime.securesms.stickers.StickerLocator
import org.whispersystems.signalservice.api.InvalidMessageStructureException
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
import org.whispersystems.signalservice.api.util.AttachmentPointerUtil
import org.whispersystems.signalservice.internal.push.DataMessage
import java.util.Optional
class PointerAttachment : Attachment {
private constructor(
contentType: String,
transferState: Int,
size: Long,
fileName: String?,
cdnNumber: Int,
location: String,
key: String?,
relay: String?,
digest: ByteArray?,
incrementalDigest: ByteArray?,
incrementalMacChunkSize: Int,
fastPreflightId: String?,
voiceNote: Boolean,
borderless: Boolean,
videoGif: Boolean,
width: Int,
height: Int,
uploadTimestamp: Long,
caption: String?,
stickerLocator: StickerLocator?,
blurHash: BlurHash?
) : super(
contentType = contentType,
transferState = transferState,
size = size,
fileName = fileName,
cdnNumber = cdnNumber,
location = location,
key = key,
relay = relay,
digest = digest,
incrementalDigest = incrementalDigest,
fastPreflightId = fastPreflightId,
voiceNote = voiceNote,
borderless = borderless,
videoGif = videoGif,
width = width,
height = height,
incrementalMacChunkSize = incrementalMacChunkSize,
quote = false,
uploadTimestamp = uploadTimestamp,
caption = caption,
stickerLocator = stickerLocator,
blurHash = blurHash,
audioHash = null,
transformProperties = null
)
constructor(parcel: Parcel) : super(parcel)
override val uri: Uri? = null
override val publicUri: Uri? = null
companion object {
@JvmStatic
fun forPointers(pointers: Optional<List<SignalServiceAttachment>>): List<Attachment> {
if (!pointers.isPresent) {
return emptyList()
}
return pointers.get()
.map { forPointer(Optional.ofNullable(it)) }
.filter { it.isPresent }
.map { it.get() }
}
@JvmStatic
@JvmOverloads
fun forPointer(pointer: Optional<SignalServiceAttachment>, stickerLocator: StickerLocator? = null, fastPreflightId: String? = null): Optional<Attachment> {
if (!pointer.isPresent || !pointer.get().isPointer) {
return Optional.empty()
}
val encodedKey: String? = if (pointer.get().asPointer().key != null) {
encodeWithPadding(pointer.get().asPointer().key)
} else {
null
}
return Optional.of(
PointerAttachment(
contentType = pointer.get().contentType,
transferState = AttachmentTable.TRANSFER_PROGRESS_PENDING,
size = pointer.get().asPointer().size.orElse(0).toLong(),
fileName = pointer.get().asPointer().fileName.orElse(null),
cdnNumber = pointer.get().asPointer().cdnNumber,
location = pointer.get().asPointer().remoteId.toString(),
key = encodedKey,
relay = null,
digest = pointer.get().asPointer().digest.orElse(null),
incrementalDigest = pointer.get().asPointer().incrementalDigest.orElse(null),
incrementalMacChunkSize = pointer.get().asPointer().incrementalMacChunkSize,
fastPreflightId = fastPreflightId,
voiceNote = pointer.get().asPointer().voiceNote,
borderless = pointer.get().asPointer().isBorderless,
videoGif = pointer.get().asPointer().isGif,
width = pointer.get().asPointer().width,
height = pointer.get().asPointer().height,
uploadTimestamp = pointer.get().asPointer().uploadTimestamp,
caption = pointer.get().asPointer().caption.orElse(null),
stickerLocator = stickerLocator,
blurHash = BlurHash.parseOrNull(pointer.get().asPointer().blurHash.orElse(null))
)
)
}
fun forPointer(pointer: SignalServiceDataMessage.Quote.QuotedAttachment): Optional<Attachment> {
val thumbnail = pointer.thumbnail
return Optional.of(
PointerAttachment(
contentType = pointer.contentType,
transferState = AttachmentTable.TRANSFER_PROGRESS_PENDING,
size = (if (thumbnail != null) thumbnail.asPointer().size.orElse(0) else 0).toLong(),
fileName = pointer.fileName,
cdnNumber = thumbnail?.asPointer()?.cdnNumber ?: 0,
location = thumbnail?.asPointer()?.remoteId?.toString() ?: "0",
key = if (thumbnail != null && thumbnail.asPointer().key != null) encodeWithPadding(thumbnail.asPointer().key) else null,
relay = null,
digest = thumbnail?.asPointer()?.digest?.orElse(null),
incrementalDigest = thumbnail?.asPointer()?.incrementalDigest?.orElse(null),
incrementalMacChunkSize = thumbnail?.asPointer()?.incrementalMacChunkSize ?: 0,
fastPreflightId = null,
voiceNote = false,
borderless = false,
videoGif = false,
width = thumbnail?.asPointer()?.width ?: 0,
height = thumbnail?.asPointer()?.height ?: 0,
uploadTimestamp = thumbnail?.asPointer()?.uploadTimestamp ?: 0,
caption = thumbnail?.asPointer()?.caption?.orElse(null),
stickerLocator = null,
blurHash = null
)
)
}
fun forPointer(quotedAttachment: DataMessage.Quote.QuotedAttachment): Optional<Attachment> {
val thumbnail: SignalServiceAttachment? = try {
if (quotedAttachment.thumbnail != null) {
AttachmentPointerUtil.createSignalAttachmentPointer(quotedAttachment.thumbnail)
} else {
null
}
} catch (e: InvalidMessageStructureException) {
return Optional.empty()
}
return Optional.of(
PointerAttachment(
contentType = quotedAttachment.contentType!!,
transferState = AttachmentTable.TRANSFER_PROGRESS_PENDING,
size = (if (thumbnail != null) thumbnail.asPointer().size.orElse(0) else 0).toLong(),
fileName = quotedAttachment.fileName,
cdnNumber = thumbnail?.asPointer()?.cdnNumber ?: 0,
location = thumbnail?.asPointer()?.remoteId?.toString() ?: "0",
key = if (thumbnail != null && thumbnail.asPointer().key != null) encodeWithPadding(thumbnail.asPointer().key) else null,
relay = null,
digest = thumbnail?.asPointer()?.digest?.orElse(null),
incrementalDigest = thumbnail?.asPointer()?.incrementalDigest?.orElse(null),
incrementalMacChunkSize = thumbnail?.asPointer()?.incrementalMacChunkSize ?: 0,
fastPreflightId = null,
voiceNote = false,
borderless = false,
videoGif = false,
width = thumbnail?.asPointer()?.width ?: 0,
height = thumbnail?.asPointer()?.height ?: 0,
uploadTimestamp = thumbnail?.asPointer()?.uploadTimestamp ?: 0,
caption = thumbnail?.asPointer()?.caption?.orElse(null),
stickerLocator = null,
blurHash = null
)
)
}
}
}

View file

@ -1,36 +0,0 @@
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.AttachmentTable;
/**
* An attachment that represents where an attachment used to be. Useful when you need to know that
* a message had an attachment and some metadata about it (like the contentType), even though the
* underlying media no longer exists. An example usecase would be view-once messages, so that we can
* quote them and know their contentType even though the media has been deleted.
*/
public class TombstoneAttachment extends Attachment {
public TombstoneAttachment(@NonNull String contentType, boolean quote) {
super(contentType, AttachmentTable.TRANSFER_PROGRESS_DONE, 0, null, 0, null, null, null, null, null, null, false, false, false, 0, 0, 0, quote, 0, null, null, null, null, null);
}
protected TombstoneAttachment(Parcel in) {
super(in);
}
@Override
public @Nullable Uri getUri() {
return null;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
}

View file

@ -0,0 +1,45 @@
package org.thoughtcrime.securesms.attachments
import android.net.Uri
import android.os.Parcel
import org.thoughtcrime.securesms.database.AttachmentTable
/**
* An attachment that represents where an attachment used to be. Useful when you need to know that
* a message had an attachment and some metadata about it (like the contentType), even though the
* underlying media no longer exists. An example usecase would be view-once messages, so that we can
* quote them and know their contentType even though the media has been deleted.
*/
class TombstoneAttachment : Attachment {
constructor(contentType: String, quote: Boolean) : super(
contentType = contentType,
quote = quote,
transferState = AttachmentTable.TRANSFER_PROGRESS_DONE,
size = 0,
fileName = null,
cdnNumber = 0,
location = null,
key = null,
relay = null,
digest = null,
incrementalDigest = null,
fastPreflightId = null,
voiceNote = false,
borderless = false,
videoGif = false,
width = 0,
height = 0,
incrementalMacChunkSize = 0,
uploadTimestamp = 0,
caption = null,
stickerLocator = null,
blurHash = null,
audioHash = null,
transformProperties = null
)
constructor(parcel: Parcel) : super(parcel)
override val uri: Uri? = null
override val publicUri: Uri? = null
}

View file

@ -1,92 +0,0 @@
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.os.ParcelCompat;
import org.thoughtcrime.securesms.audio.AudioHash;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import java.util.Objects;
public class UriAttachment extends Attachment {
private final @NonNull Uri dataUri;
public UriAttachment(@NonNull Uri uri,
@NonNull String contentType,
int transferState,
long size,
@Nullable String fileName,
boolean voiceNote,
boolean borderless,
boolean videoGif,
boolean quote,
@Nullable String caption,
@Nullable StickerLocator stickerLocator,
@Nullable BlurHash blurHash,
@Nullable AudioHash audioHash,
@Nullable TransformProperties transformProperties)
{
this(uri, contentType, transferState, size, 0, 0, fileName, null, voiceNote, borderless, videoGif, quote, caption, stickerLocator, blurHash, audioHash, transformProperties);
}
public UriAttachment(@NonNull Uri dataUri,
@NonNull String contentType,
int transferState,
long size,
int width,
int height,
@Nullable String fileName,
@Nullable String fastPreflightId,
boolean voiceNote,
boolean borderless,
boolean videoGif,
boolean quote,
@Nullable String caption,
@Nullable StickerLocator stickerLocator,
@Nullable BlurHash blurHash,
@Nullable AudioHash audioHash,
@Nullable TransformProperties transformProperties)
{
super(contentType, transferState, size, fileName, 0, null, null, null, null, null, fastPreflightId, voiceNote, borderless, videoGif, width, height, 0, quote, 0, caption, stickerLocator, blurHash, audioHash, transformProperties);
this.dataUri = Objects.requireNonNull(dataUri);
}
protected UriAttachment(Parcel in) {
super(in);
this.dataUri = Objects.requireNonNull(ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class));
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(dataUri, 0);
}
@Override
@NonNull
public Uri getUri() {
return dataUri;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
@Override
public boolean equals(Object other) {
return other != null && other instanceof UriAttachment && ((UriAttachment) other).dataUri.equals(this.dataUri);
}
@Override
public int hashCode() {
return dataUri.hashCode();
}
}

View file

@ -0,0 +1,115 @@
package org.thoughtcrime.securesms.attachments
import android.net.Uri
import android.os.Parcel
import androidx.core.os.ParcelCompat
import org.thoughtcrime.securesms.audio.AudioHash
import org.thoughtcrime.securesms.blurhash.BlurHash
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties
import org.thoughtcrime.securesms.stickers.StickerLocator
import java.util.Objects
class UriAttachment : Attachment {
constructor(
uri: Uri,
contentType: String,
transferState: Int,
size: Long,
fileName: String?,
voiceNote: Boolean,
borderless: Boolean,
videoGif: Boolean,
quote: Boolean,
caption: String?,
stickerLocator: StickerLocator?,
blurHash: BlurHash?,
audioHash: AudioHash?,
transformProperties: TransformProperties?
) : this(
dataUri = uri,
contentType = contentType,
transferState = transferState,
size = size,
width = 0,
height = 0,
fileName = fileName,
fastPreflightId = null,
voiceNote = voiceNote,
borderless = borderless,
videoGif = videoGif,
quote = quote,
caption = caption,
stickerLocator = stickerLocator,
blurHash = blurHash,
audioHash = audioHash,
transformProperties = transformProperties
)
constructor(
dataUri: Uri,
contentType: String,
transferState: Int,
size: Long,
width: Int,
height: Int,
fileName: String?,
fastPreflightId: String?,
voiceNote: Boolean,
borderless: Boolean,
videoGif: Boolean,
quote: Boolean,
caption: String?,
stickerLocator: StickerLocator?,
blurHash: BlurHash?,
audioHash: AudioHash?,
transformProperties: TransformProperties?
) : super(
contentType = contentType,
transferState = transferState,
size = size,
fileName = fileName,
cdnNumber = 0,
location = null,
key = null,
relay = null,
digest = null,
incrementalDigest = null,
fastPreflightId = fastPreflightId,
voiceNote = voiceNote,
borderless = borderless,
videoGif = videoGif,
width = width,
height = height,
incrementalMacChunkSize = 0,
quote = quote,
uploadTimestamp = 0,
caption = caption,
stickerLocator = stickerLocator,
blurHash = blurHash,
audioHash = audioHash,
transformProperties = transformProperties
) {
uri = Objects.requireNonNull(dataUri)
}
constructor(parcel: Parcel) : super(parcel) {
uri = ParcelCompat.readParcelable(parcel, Uri::class.java.classLoader, Uri::class.java)!!
}
override val uri: Uri
override val publicUri: Uri? = null
override fun writeToParcel(dest: Parcel, flags: Int) {
super.writeToParcel(dest, flags)
dest.writeParcelable(uri, 0)
}
override fun equals(other: Any?): Boolean {
return other != null && other is UriAttachment && other.uri == uri
}
override fun hashCode(): Int {
return uri.hashCode()
}
}

View file

@ -63,7 +63,7 @@ public class BorderlessImageView extends FrameLayout {
image.setImageResource(glideRequests, slide, showControls, false);
} else {
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
image.setImageResource(glideRequests, slide, showControls, false, slide.asAttachment().getWidth(), slide.asAttachment().getHeight());
image.setImageResource(glideRequests, slide, showControls, false, slide.asAttachment().width, slide.asAttachment().height);
}
missingShade.setVisibility(showControls ? View.VISIBLE : View.GONE);

View file

@ -397,7 +397,7 @@ public class ThumbnailView extends FrameLayout {
Log.i(TAG, "loading part with id " + slide.asAttachment().getUri()
+ ", progress " + slide.getTransferState() + ", fast preflight id: " +
slide.asAttachment().getFastPreflightId());
slide.asAttachment().fastPreflightId);
BlurHash previousBlurHash = this.slide != null ? this.slide.getPlaceholderBlur() : null;
@ -532,8 +532,8 @@ public class ThumbnailView extends FrameLayout {
if (Util.equals(slide, other)) {
if (slide != null && other != null) {
byte[] digestLeft = slide.asAttachment().getDigest();
byte[] digestRight = other.asAttachment().getDigest();
byte[] digestLeft = slide.asAttachment().digest;
byte[] digestRight = other.asAttachment().digest;
return Arrays.equals(digestLeft, digestRight);
}

View file

@ -2023,10 +2023,10 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
if (messageRecord.isMms()) {
TextSlide slide = ((MmsMessageRecord) messageRecord).getSlideDeck().getTextSlide();
if (slide != null && (slide.asAttachment().getTransferState() == AttachmentTable.TRANSFER_PROGRESS_DONE || MessageRecordUtil.isScheduled(messageRecord))) {
if (slide != null && (slide.asAttachment().transferState == AttachmentTable.TRANSFER_PROGRESS_DONE || MessageRecordUtil.isScheduled(messageRecord))) {
message = getResources().getString(R.string.ConversationItem_read_more);
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getId(), messageRecord.getId(), messageRecord.isMms());
} else if (slide != null && slide.asAttachment().getTransferState() == AttachmentTable.TRANSFER_PROGRESS_STARTED) {
} else if (slide != null && slide.asAttachment().transferState == AttachmentTable.TRANSFER_PROGRESS_STARTED) {
message = getResources().getString(R.string.ConversationItem_pending);
action = () -> {};
} else if (slide != null) {
@ -2438,7 +2438,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
for (Slide slide : slides) {
ApplicationDependencies.getJobManager().add(new AttachmentDownloadJob(messageRecord.getId(),
((DatabaseAttachment) slide.asAttachment()).getAttachmentId(),
((DatabaseAttachment) slide.asAttachment()).attachmentId,
true));
}
}
@ -2457,7 +2457,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
Log.i(TAG, "Canceling push attachment downloads for " + slides.size() + " items");
for (Slide slide : slides) {
final String queue = AttachmentDownloadJob.constructQueueString(((DatabaseAttachment) slide.asAttachment()).getAttachmentId());
final String queue = AttachmentDownloadJob.constructQueueString(((DatabaseAttachment) slide.asAttachment()).attachmentId);
jobManager.cancelAllInQueue(queue);
}
}
@ -2477,8 +2477,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
}
if (MediaUtil.isInstantVideoSupported(slide)) {
final DatabaseAttachment databaseAttachment = (DatabaseAttachment) slide.asAttachment();
if (databaseAttachment.getTransferState() != AttachmentTable.TRANSFER_PROGRESS_STARTED) {
final AttachmentId attachmentId = databaseAttachment.getAttachmentId();
if (databaseAttachment.transferState != AttachmentTable.TRANSFER_PROGRESS_STARTED) {
final AttachmentId attachmentId = databaseAttachment.attachmentId;
final JobManager jobManager = ApplicationDependencies.getJobManager();
final String queue = AttachmentDownloadJob.constructQueueString(attachmentId);
setup(v, slide);
@ -2550,7 +2550,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
performClick();
} else if (eventListener != null && hasSticker(messageRecord)) {
//noinspection ConstantConditions
eventListener.onStickerClicked(((MmsMessageRecord) messageRecord).getSlideDeck().getStickerSlide().asAttachment().getSticker());
eventListener.onStickerClicked(((MmsMessageRecord) messageRecord).getSlideDeck().getStickerSlide().asAttachment().stickerLocator);
}
}
}
@ -2617,7 +2617,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
messageRecord.getTimestamp(),
mediaUri,
slide.getContentType(),
slide.asAttachment().getSize(),
slide.asAttachment().size,
slide.getCaption().orElse(null),
false,
false,
@ -2626,8 +2626,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
MediaTable.Sorting.Newest,
slide.isVideoGif(),
new MediaIntentFactory.SharedElementArgs(
slide.asAttachment().getWidth(),
slide.asAttachment().getHeight(),
slide.asAttachment().width,
slide.asAttachment().height,
mediaThumbnailStub.require().getCorners().getTopLeft(),
mediaThumbnailStub.require().getCorners().getTopRight(),
mediaThumbnailStub.require().getCorners().getBottomRight(),

View file

@ -175,7 +175,7 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor(
if (mediaMessage.slideDeck.stickerSlide != null) {
builder.withDataUri(mediaMessage.slideDeck.stickerSlide?.asAttachment()?.uri)
builder.withStickerLocator(mediaMessage.slideDeck.stickerSlide?.asAttachment()?.sticker)
builder.withStickerLocator(mediaMessage.slideDeck.stickerSlide?.asAttachment()?.stickerLocator)
builder.withDataType(mediaMessage.slideDeck.stickerSlide?.asAttachment()?.contentType)
}
@ -203,11 +203,11 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor(
height,
size,
0,
isBorderless,
isVideoGif,
borderless,
videoGif,
Optional.empty(),
Optional.ofNullable(caption),
Optional.of(transformProperties)
Optional.ofNullable(transformProperties)
)
}
}

File diff suppressed because it is too large Load diff

View file

@ -2316,7 +2316,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val quoteText = cursor.requireString(QUOTE_BODY)
val quoteType = cursor.requireInt(QUOTE_TYPE)
val quoteMissing = cursor.requireBoolean(QUOTE_MISSING)
val quoteAttachments: List<Attachment> = associatedAttachments.filter { it.isQuote }.toList()
val quoteAttachments: List<Attachment> = associatedAttachments.filter { it.quote }.toList()
val quoteMentions: List<Mention> = parseQuoteMentions(cursor)
val quoteBodyRanges: BodyRangeList? = parseQuoteBodyRanges(cursor)
val quote: QuoteModel? = if (quoteId != QUOTE_NOT_PRESENT_ID && quoteAuthor > 0 && (!TextUtils.isEmpty(quoteText) || quoteAttachments.isNotEmpty())) {
@ -2330,7 +2330,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val previews: List<LinkPreview> = getLinkPreviews(cursor, associatedAttachments)
val previewAttachments: Set<Attachment> = previews.filter { it.thumbnail.isPresent }.map { it.thumbnail.get() }.toSet()
val attachments: List<Attachment> = associatedAttachments
.filterNot { it.isQuote }
.filterNot { it.quote }
.filterNot { contactAttachments.contains(it) }
.filterNot { previewAttachments.contains(it) }
.sortedWith(DisplayOrderComparator())
@ -5119,7 +5119,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val bodyRanges = parseQuoteBodyRanges(cursor)
val attachments = attachments.getAttachments(cursor)
val quoteAttachments: List<Attachment> = attachments.filter { it.isQuote }
val quoteAttachments: List<Attachment> = attachments.filter { it.quote }
val quoteDeck = SlideDeck(quoteAttachments)
return if (quoteId != QUOTE_NOT_PRESENT_ID && quoteAuthor > 0) {
@ -5170,7 +5170,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
@JvmStatic
fun buildSlideDeck(attachments: List<DatabaseAttachment>): SlideDeck {
val messageAttachments = attachments
.filterNot { it.isQuote }
.filterNot { it.quote }
.sortedWith(DisplayOrderComparator())
return SlideDeck(messageAttachments)

View file

@ -182,7 +182,7 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader<GroupedThrea
@Override
public int groupForRecord(@NonNull MediaTable.MediaRecord mediaRecord) {
long size = mediaRecord.getAttachment().getSize();
long size = mediaRecord.getAttachment().size;
if (size < MB) return SMALL;
if (size < 20 * MB) return MEDIUM;

View file

@ -294,7 +294,7 @@ public class MmsMessageRecord extends MessageRecord {
public @NonNull MmsMessageRecord withAttachments(@NonNull List<DatabaseAttachment> attachments) {
Map<AttachmentId, DatabaseAttachment> attachmentIdMap = new HashMap<>();
for (DatabaseAttachment attachment : attachments) {
attachmentIdMap.put(attachment.getAttachmentId(), attachment);
attachmentIdMap.put(attachment.attachmentId, attachment);
}
List<Contact> contacts = updateContacts(getSharedContacts(), attachmentIdMap);
@ -369,7 +369,7 @@ public class MmsMessageRecord extends MessageRecord {
return null;
}
List<DatabaseAttachment> quoteAttachments = attachments.stream().filter(Attachment::isQuote).collect(Collectors.toList());
List<DatabaseAttachment> quoteAttachments = attachments.stream().filter(a -> a.quote).collect(Collectors.toList());
return quote.withAttachment(new SlideDeck(quoteAttachments));
}

View file

@ -37,7 +37,6 @@ import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ImageCompressionUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.MemoryFileDescriptor;
import org.thoughtcrime.securesms.util.MemoryFileDescriptor.MemoryFileException;
import org.thoughtcrime.securesms.video.InMemoryTranscoder;
import org.thoughtcrime.securesms.video.StreamingTranscoder;
@ -73,7 +72,7 @@ public final class AttachmentCompressionJob extends BaseJob {
boolean mms,
int mmsSubscriptionId)
{
return new AttachmentCompressionJob(databaseAttachment.getAttachmentId(),
return new AttachmentCompressionJob(databaseAttachment.attachmentId,
MediaUtil.isVideo(databaseAttachment) && MediaConstraints.isVideoTranscodeAvailable(),
mms,
mmsSubscriptionId);
@ -136,13 +135,13 @@ public final class AttachmentCompressionJob extends BaseJob {
throw new UndeliverableMessageException("Cannot find the specified attachment.");
}
if (databaseAttachment.getTransformProperties().shouldSkipTransform()) {
if (databaseAttachment.transformProperties.shouldSkipTransform()) {
Log.i(TAG, "Skipping at the direction of the TransformProperties.");
return;
}
MediaConstraints mediaConstraints = mms ? MediaConstraints.getMmsMediaConstraints(mmsSubscriptionId)
: MediaConstraints.getPushMediaConstraints(SentMediaQuality.fromCode(databaseAttachment.getTransformProperties().getSentMediaQuality()));
: MediaConstraints.getPushMediaConstraints(SentMediaQuality.fromCode(databaseAttachment.transformProperties.sentMediaQuality));
compress(database, mediaConstraints, databaseAttachment);
}
@ -194,12 +193,12 @@ public final class AttachmentCompressionJob extends BaseJob {
@NonNull TranscoderCancelationSignal cancelationSignal)
throws UndeliverableMessageException
{
AttachmentTable.TransformProperties transformProperties = attachment.getTransformProperties();
AttachmentTable.TransformProperties transformProperties = attachment.transformProperties;
boolean allowSkipOnFailure = false;
if (!MediaConstraints.isVideoTranscodeAvailable()) {
if (transformProperties.isVideoEdited()) {
if (transformProperties.getVideoEdited()) {
throw new UndeliverableMessageException("Video edited, but transcode is not available");
}
return attachment;
@ -210,15 +209,15 @@ public final class AttachmentCompressionJob extends BaseJob {
notification.setIndeterminate(true);
}
try (MediaDataSource dataSource = attachmentDatabase.mediaDataSourceFor(attachment.getAttachmentId(), false)) {
try (MediaDataSource dataSource = attachmentDatabase.mediaDataSourceFor(attachment.attachmentId, false)) {
if (dataSource == null) {
throw new UndeliverableMessageException("Cannot get media data source for attachment.");
}
allowSkipOnFailure = !transformProperties.isVideoEdited();
allowSkipOnFailure = !transformProperties.getVideoEdited();
TranscoderOptions options = null;
if (transformProperties.isVideoTrim()) {
options = new TranscoderOptions(transformProperties.getVideoTrimStartTimeUs(), transformProperties.getVideoTrimEndTimeUs());
if (transformProperties.videoTrim) {
options = new TranscoderOptions(transformProperties.videoTrimStartTimeUs, transformProperties.videoTrimEndTimeUs);
}
if (FeatureFlags.useStreamingVideoMuxer()) {
@ -228,7 +227,7 @@ public final class AttachmentCompressionJob extends BaseJob {
Log.i(TAG, "Compressing with streaming muxer");
AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
File file = SignalDatabase.attachments().newFile();
File file = SignalDatabase.attachments().newFile(context);
file.deleteOnExit();
try {
@ -258,9 +257,9 @@ public final class AttachmentCompressionJob extends BaseJob {
}
}
attachmentDatabase.markAttachmentAsTransformed(attachment.getAttachmentId(), false);
attachmentDatabase.markAttachmentAsTransformed(attachment.attachmentId, false);
return Objects.requireNonNull(attachmentDatabase.getAttachment(attachment.getAttachmentId()));
return Objects.requireNonNull(attachmentDatabase.getAttachment(attachment.attachmentId));
} else {
Log.i(TAG, "Transcode was not required");
}
@ -279,14 +278,14 @@ public final class AttachmentCompressionJob extends BaseJob {
percent));
}, cancelationSignal)) {
attachmentDatabase.updateAttachmentData(attachment, mediaStream, true);
attachmentDatabase.markAttachmentAsTransformed(attachment.getAttachmentId(), mediaStream.getFaststart());
attachmentDatabase.markAttachmentAsTransformed(attachment.attachmentId, mediaStream.getFaststart());
}
eventBus.postSticky(new PartProgressEvent(attachment,
PartProgressEvent.Type.COMPRESSION,
100,
100));
return Objects.requireNonNull(attachmentDatabase.getAttachment(attachment.getAttachmentId()));
return Objects.requireNonNull(attachmentDatabase.getAttachment(attachment.attachmentId));
} else {
Log.i(TAG, "Transcode was not required (in-memory transcoder)");
}
@ -294,7 +293,7 @@ public final class AttachmentCompressionJob extends BaseJob {
}
}
} catch (VideoSourceException | EncodingException | MemoryFileException e) {
if (attachment.getSize() > constraints.getVideoMaxSize(context)) {
if (attachment.size > constraints.getVideoMaxSize(context)) {
throw new UndeliverableMessageException("Duration not found, attachment too large to skip transcode", e);
} else {
if (allowSkipOnFailure) {
@ -330,7 +329,7 @@ public final class AttachmentCompressionJob extends BaseJob {
try {
for (int size : mediaConstraints.getImageDimensionTargets(context)) {
result = ImageCompressionUtil.compressWithinConstraints(context,
attachment.getContentType(),
attachment.contentType,
new DecryptableStreamUriLoader.DecryptableUri(uri),
size,
mediaConstraints.getImageMaxSize(context),

View file

@ -119,8 +119,8 @@ public final class AttachmentDownloadJob extends BaseJob {
final AttachmentTable database = SignalDatabase.attachments();
final AttachmentId attachmentId = new AttachmentId(partRowId, partUniqueId);
final DatabaseAttachment attachment = database.getAttachment(attachmentId);
final boolean pending = attachment != null && attachment.getTransferState() != AttachmentTable.TRANSFER_PROGRESS_DONE
&& attachment.getTransferState() != AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE;
final boolean pending = attachment != null && attachment.transferState != AttachmentTable.TRANSFER_PROGRESS_DONE
&& attachment.transferState != AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE;
if (pending && (manual || AttachmentUtil.isAutoDownloadPermitted(context, attachment))) {
Log.i(TAG, "onAdded() Marking attachment progress as 'started'");
@ -168,7 +168,7 @@ public final class AttachmentDownloadJob extends BaseJob {
Log.i(TAG, "Downloading push part " + attachmentId);
database.setTransferState(messageId, attachmentId, AttachmentTable.TRANSFER_PROGRESS_STARTED);
if (attachment.getCdnNumber() != ReleaseChannel.CDN_NUMBER) {
if (attachment.cdnNumber != ReleaseChannel.CDN_NUMBER) {
retrieveAttachment(messageId, attachmentId, attachment);
} else {
retrieveUrlAttachment(messageId, attachmentId, attachment);
@ -200,7 +200,7 @@ public final class AttachmentDownloadJob extends BaseJob {
File attachmentFile = database.getOrCreateTransferFile(attachmentId);
try {
if (attachment.getSize() > maxReceiveSize) {
if (attachment.size > maxReceiveSize) {
throw new MmsException("Attachment too large, failing download");
}
SignalServiceMessageReceiver messageReceiver = ApplicationDependencies.getSignalServiceMessageReceiver();
@ -243,38 +243,38 @@ public final class AttachmentDownloadJob extends BaseJob {
}
private SignalServiceAttachmentPointer createAttachmentPointer(Attachment attachment) throws InvalidPartException {
if (TextUtils.isEmpty(attachment.getLocation())) {
if (TextUtils.isEmpty(attachment.location)) {
throw new InvalidPartException("empty content id");
}
if (TextUtils.isEmpty(attachment.getKey())) {
if (TextUtils.isEmpty(attachment.key)) {
throw new InvalidPartException("empty encrypted key");
}
try {
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.getLocation());
final byte[] key = Base64.decode(attachment.getKey());
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.location);
final byte[] key = Base64.decode(attachment.key);
if (attachment.getDigest() != null) {
Log.i(TAG, "Downloading attachment with digest: " + Hex.toString(attachment.getDigest()));
if (attachment.digest != null) {
Log.i(TAG, "Downloading attachment with digest: " + Hex.toString(attachment.digest));
} else {
Log.i(TAG, "Downloading attachment with no digest...");
}
return new SignalServiceAttachmentPointer(attachment.getCdnNumber(), remoteId, null, key,
Optional.of(Util.toIntExact(attachment.getSize())),
return new SignalServiceAttachmentPointer(attachment.cdnNumber, remoteId, null, key,
Optional.of(Util.toIntExact(attachment.size)),
Optional.empty(),
0, 0,
Optional.ofNullable(attachment.getDigest()),
Optional.ofNullable(attachment.digest),
Optional.ofNullable(attachment.getIncrementalDigest()),
attachment.getIncrementalMacChunkSize(),
Optional.ofNullable(attachment.getFileName()),
attachment.isVoiceNote(),
attachment.isBorderless(),
attachment.isVideoGif(),
attachment.incrementalMacChunkSize,
Optional.ofNullable(attachment.fileName),
attachment.voiceNote,
attachment.borderless,
attachment.videoGif,
Optional.empty(),
Optional.ofNullable(attachment.getBlurHash()).map(BlurHash::getHash),
attachment.getUploadTimestamp());
Optional.ofNullable(attachment.blurHash).map(BlurHash::getHash),
attachment.uploadTimestamp);
} catch (IOException | ArithmeticException e) {
Log.w(TAG, e);
throw new InvalidPartException(e);
@ -286,7 +286,7 @@ public final class AttachmentDownloadJob extends BaseJob {
final Attachment attachment)
throws IOException
{
try (Response response = S3.getObject(Objects.requireNonNull(attachment.getFileName()))) {
try (Response response = S3.getObject(Objects.requireNonNull(attachment.fileName))) {
ResponseBody body = response.body();
if (body != null) {
if (body.contentLength() > FeatureFlags.maxAttachmentReceiveSizeBytes()) {

View file

@ -174,10 +174,10 @@ class AttachmentUploadJob private constructor(
.withContentType(attachment.contentType)
.withLength(attachment.size)
.withFileName(attachment.fileName)
.withVoiceNote(attachment.isVoiceNote)
.withBorderless(attachment.isBorderless)
.withGif(attachment.isVideoGif)
.withFaststart(attachment.transformProperties.isMp4Faststart)
.withVoiceNote(attachment.voiceNote)
.withBorderless(attachment.borderless)
.withGif(attachment.videoGif)
.withFaststart(attachment.transformProperties?.mp4FastStart ?: false)
.withWidth(attachment.width)
.withHeight(attachment.height)
.withUploadTimestamp(System.currentTimeMillis())

View file

@ -126,22 +126,22 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
throw new InvalidAttachmentException("Cannot find the specified attachment.");
}
long timeSinceUpload = System.currentTimeMillis() - databaseAttachment.getUploadTimestamp();
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.getLocation())) {
long timeSinceUpload = System.currentTimeMillis() - databaseAttachment.uploadTimestamp;
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.location)) {
Log.i(TAG, "We can re-use an already-uploaded file. It was uploaded " + timeSinceUpload + " ms ago. Skipping.");
return;
} else if (databaseAttachment.getUploadTimestamp() > 0) {
} else if (databaseAttachment.uploadTimestamp > 0) {
Log.i(TAG, "This file was previously-uploaded, but too long ago to be re-used. Age: " + timeSinceUpload + " ms");
}
Log.i(TAG, "Uploading attachment for message " + databaseAttachment.getMmsId() + " with ID " + databaseAttachment.getAttachmentId());
Log.i(TAG, "Uploading attachment for message " + databaseAttachment.mmsId + " with ID " + databaseAttachment.attachmentId);
try (NotificationController notification = getNotificationForAttachment(databaseAttachment)) {
try (SignalServiceAttachmentStream localAttachment = getAttachmentFor(databaseAttachment, notification, resumableUploadSpec)) {
SignalServiceAttachmentPointer remoteAttachment = messageSender.uploadAttachment(localAttachment);
Attachment attachment = PointerAttachment.forPointer(Optional.of(remoteAttachment), null, databaseAttachment.getFastPreflightId()).get();
Attachment attachment = PointerAttachment.forPointer(Optional.of(remoteAttachment), null, databaseAttachment.fastPreflightId).get();
database.updateAttachmentAfterUpload(databaseAttachment.getAttachmentId(), attachment, remoteAttachment.getUploadTimestamp());
database.updateAttachmentAfterUpload(databaseAttachment.attachmentId, attachment, remoteAttachment.getUploadTimestamp());
}
} catch (NonSuccessfulResumableUploadResponseCodeException e) {
if (e.getCode() == 400) {
@ -152,7 +152,7 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
}
private @Nullable NotificationController getNotificationForAttachment(@NonNull Attachment attachment) {
if (attachment.getSize() >= FOREGROUND_LIMIT) {
if (attachment.size >= FOREGROUND_LIMIT) {
try {
return ForegroundServiceUtil.startGenericTaskWhenCapable(context, context.getString(R.string.AttachmentUploadJob_uploading_media));
} catch (UnableToStartException e) {
@ -179,7 +179,7 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
}
private @NonNull SignalServiceAttachmentStream getAttachmentFor(Attachment attachment, @Nullable NotificationController notification, @Nullable ResumableUploadSpec resumableUploadSpec) throws InvalidAttachmentException {
if (attachment.getUri() == null || attachment.getSize() == 0) {
if (attachment.getUri() == null || attachment.size == 0) {
throw new InvalidAttachmentException(new IOException("Assertion failed, outgoing attachment has no data!"));
}
@ -187,17 +187,17 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
InputStream is = PartAuthority.getAttachmentStream(context, attachment.getUri());
SignalServiceAttachment.Builder builder = SignalServiceAttachment.newStreamBuilder()
.withStream(is)
.withContentType(attachment.getContentType())
.withLength(attachment.getSize())
.withFileName(attachment.getFileName())
.withVoiceNote(attachment.isVoiceNote())
.withBorderless(attachment.isBorderless())
.withGif(attachment.isVideoGif())
.withFaststart(attachment.getTransformProperties().isMp4Faststart())
.withWidth(attachment.getWidth())
.withHeight(attachment.getHeight())
.withContentType(attachment.contentType)
.withLength(attachment.size)
.withFileName(attachment.fileName)
.withVoiceNote(attachment.voiceNote)
.withBorderless(attachment.borderless)
.withGif(attachment.videoGif)
.withFaststart(attachment.transformProperties.mp4FastStart)
.withWidth(attachment.width)
.withHeight(attachment.height)
.withUploadTimestamp(System.currentTimeMillis())
.withCaption(attachment.getCaption())
.withCaption(attachment.caption)
.withCancelationSignal(this::isCanceled)
.withResumableUploadSpec(resumableUploadSpec)
.withListener(new SignalServiceAttachment.ProgressListener() {
@ -214,9 +214,9 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
return isCanceled();
}
});
if (MediaUtil.isImageType(attachment.getContentType())) {
if (MediaUtil.isImageType(attachment.contentType)) {
return builder.withBlurHash(getImageBlurHash(attachment)).build();
} else if (MediaUtil.isVideoType(attachment.getContentType())) {
} else if (MediaUtil.isVideoType(attachment.contentType)) {
return builder.withBlurHash(getVideoBlurHash(attachment)).build();
} else {
return builder.build();
@ -227,7 +227,7 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
}
private @Nullable String getImageBlurHash(@NonNull Attachment attachment) throws IOException {
if (attachment.getBlurHash() != null) return attachment.getBlurHash().getHash();
if (attachment.blurHash != null) return attachment.blurHash.getHash();
if (attachment.getUri() == null) return null;
try (InputStream inputStream = PartAuthority.getAttachmentStream(context, attachment.getUri())) {
@ -236,8 +236,8 @@ public final class LegacyAttachmentUploadJob extends BaseJob {
}
private @Nullable String getVideoBlurHash(@NonNull Attachment attachment) throws IOException {
if (attachment.getBlurHash() != null) {
return attachment.getBlurHash().getHash();
if (attachment.blurHash != null) {
return attachment.blurHash.getHash();
}
if (Build.VERSION.SDK_INT < 23) {

View file

@ -285,21 +285,21 @@ public final class MmsSendJob extends SendJob {
try {
if (attachment.getUri() == null) throw new IOException("Assertion failed, attachment for outgoing MMS has no data!");
String fileName = attachment.getFileName();
String fileName = attachment.fileName;
PduPart part = new PduPart();
if (fileName == null) {
fileName = String.valueOf(Math.abs(new SecureRandom().nextLong()));
String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType(attachment.getContentType());
String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType(attachment.contentType);
if (fileExtension != null) fileName = fileName + "." + fileExtension;
}
if (attachment.getContentType().startsWith("text")) {
if (attachment.contentType.startsWith("text")) {
part.setCharset(CharacterSets.UTF_8);
}
part.setContentType(attachment.getContentType().getBytes());
part.setContentType(attachment.contentType.getBytes());
part.setContentLocation(fileName.getBytes());
part.setName(fileName.getBytes());

View file

@ -106,7 +106,7 @@ public final class PushDistributionListSendJob extends PushSendJob {
if (!message.getStoryType().isTextStory()) {
DatabaseAttachment storyAttachment = (DatabaseAttachment) message.getAttachments().get(0);
SignalDatabase.attachments().updateAttachmentCaption(storyAttachment.getAttachmentId(), message.getBody());
SignalDatabase.attachments().updateAttachmentCaption(storyAttachment.attachmentId, message.getBody());
}
Set<String> attachmentUploadIds = enqueueCompressingAndUploadAttachmentsChains(jobManager, message);

View file

@ -197,20 +197,20 @@ public abstract class PushSendJob extends SendJob {
protected SignalServiceAttachment getAttachmentFor(Attachment attachment) {
try {
if (attachment.getUri() == null || attachment.getSize() == 0) throw new IOException("Assertion failed, outgoing attachment has no data!");
if (attachment.getUri() == null || attachment.size == 0) throw new IOException("Assertion failed, outgoing attachment has no data!");
InputStream is = PartAuthority.getAttachmentStream(context, attachment.getUri());
return SignalServiceAttachment.newStreamBuilder()
.withStream(is)
.withContentType(attachment.getContentType())
.withLength(attachment.getSize())
.withFileName(attachment.getFileName())
.withVoiceNote(attachment.isVoiceNote())
.withBorderless(attachment.isBorderless())
.withGif(attachment.isVideoGif())
.withFaststart(attachment.getTransformProperties().isMp4Faststart())
.withWidth(attachment.getWidth())
.withHeight(attachment.getHeight())
.withCaption(attachment.getCaption())
.withContentType(attachment.contentType)
.withLength(attachment.size)
.withFileName(attachment.fileName)
.withVoiceNote(attachment.voiceNote)
.withBorderless(attachment.borderless)
.withGif(attachment.videoGif)
.withFaststart(attachment.transformProperties.mp4FastStart)
.withWidth(attachment.width)
.withHeight(attachment.height)
.withCaption(attachment.caption)
.withListener(new SignalServiceAttachment.ProgressListener() {
@Override
public void onAttachmentProgress(long total, long progress) {
@ -246,7 +246,7 @@ public abstract class PushSendJob extends SendJob {
.toList());
return new HashSet<>(Stream.of(attachments).map(a -> {
AttachmentUploadJob attachmentUploadJob = new AttachmentUploadJob(((DatabaseAttachment) a).getAttachmentId());
AttachmentUploadJob attachmentUploadJob = new AttachmentUploadJob(((DatabaseAttachment) a).attachmentId);
jobManager.startChain(AttachmentCompressionJob.fromAttachment((DatabaseAttachment) a, false, -1))
.then(attachmentUploadJob)
@ -262,22 +262,22 @@ public abstract class PushSendJob extends SendJob {
}
protected @Nullable SignalServiceAttachment getAttachmentPointerFor(Attachment attachment) {
if (TextUtils.isEmpty(attachment.getLocation())) {
if (TextUtils.isEmpty(attachment.location)) {
Log.w(TAG, "empty content id");
return null;
}
if (TextUtils.isEmpty(attachment.getKey())) {
if (TextUtils.isEmpty(attachment.key)) {
Log.w(TAG, "empty encrypted key");
return null;
}
try {
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.getLocation());
final byte[] key = Base64.decode(attachment.getKey());
final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.location);
final byte[] key = Base64.decode(attachment.key);
int width = attachment.getWidth();
int height = attachment.getHeight();
int width = attachment.width;
int height = attachment.height;
if ((width == 0 || height == 0) && MediaUtil.hasVideoThumbnail(context, attachment.getUri())) {
Bitmap thumbnail = MediaUtil.getVideoThumbnail(context, attachment.getUri(), 1000);
@ -288,24 +288,24 @@ public abstract class PushSendJob extends SendJob {
}
}
return new SignalServiceAttachmentPointer(attachment.getCdnNumber(),
return new SignalServiceAttachmentPointer(attachment.cdnNumber,
remoteId,
attachment.getContentType(),
attachment.contentType,
key,
Optional.of(Util.toIntExact(attachment.getSize())),
Optional.of(Util.toIntExact(attachment.size)),
Optional.empty(),
width,
height,
Optional.ofNullable(attachment.getDigest()),
Optional.ofNullable(attachment.digest),
Optional.ofNullable(attachment.getIncrementalDigest()),
attachment.getIncrementalMacChunkSize(),
Optional.ofNullable(attachment.getFileName()),
attachment.isVoiceNote(),
attachment.isBorderless(),
attachment.isVideoGif(),
Optional.ofNullable(attachment.getCaption()),
Optional.ofNullable(attachment.getBlurHash()).map(BlurHash::getHash),
attachment.getUploadTimestamp());
attachment.incrementalMacChunkSize,
Optional.ofNullable(attachment.fileName),
attachment.voiceNote,
attachment.borderless,
attachment.videoGif,
Optional.ofNullable(attachment.caption),
Optional.ofNullable(attachment.blurHash).map(BlurHash::getHash),
attachment.uploadTimestamp);
} catch (IOException | ArithmeticException e) {
Log.w(TAG, e);
return null;
@ -353,7 +353,7 @@ public abstract class PushSendJob extends SendJob {
Optional<Attachment> localQuoteAttachment = message.getOutgoingQuote()
.getAttachments()
.stream()
.filter(a -> !MediaUtil.isViewOnceType(a.getContentType()))
.filter(a -> !MediaUtil.isViewOnceType(a.contentType))
.findFirst();
if (localQuoteAttachment.isPresent()) {
@ -363,13 +363,13 @@ public abstract class PushSendJob extends SendJob {
SignalServiceAttachment thumbnail = null;
try {
if (MediaUtil.isImageType(attachment.getContentType()) && attachment.getUri() != null) {
thumbnailData = ImageCompressionUtil.compress(context, attachment.getContentType(), new DecryptableUri(attachment.getUri()), 100, 50);
} else if (Build.VERSION.SDK_INT >= 23 && MediaUtil.isVideoType(attachment.getContentType()) && attachment.getUri() != null) {
if (MediaUtil.isImageType(attachment.contentType) && attachment.getUri() != null) {
thumbnailData = ImageCompressionUtil.compress(context, attachment.contentType, new DecryptableUri(attachment.getUri()), 100, 50);
} else if (Build.VERSION.SDK_INT >= 23 && MediaUtil.isVideoType(attachment.contentType) && attachment.getUri() != null) {
Bitmap bitmap = MediaUtil.getVideoThumbnail(context, attachment.getUri(), 1000);
if (bitmap != null) {
thumbnailData = ImageCompressionUtil.compress(context, attachment.getContentType(), new DecryptableUri(attachment.getUri()), 100, 50);
thumbnailData = ImageCompressionUtil.compress(context, attachment.contentType, new DecryptableUri(attachment.getUri()), 100, 50);
}
}
@ -385,8 +385,8 @@ public abstract class PushSendJob extends SendJob {
thumbnail = builder.build();
}
quoteAttachments.add(new SignalServiceDataMessage.Quote.QuotedAttachment(attachment.isVideoGif() ? MediaUtil.IMAGE_GIF : attachment.getContentType(),
attachment.getFileName(),
quoteAttachments.add(new SignalServiceDataMessage.Quote.QuotedAttachment(attachment.videoGif ? MediaUtil.IMAGE_GIF : attachment.contentType,
attachment.fileName,
thumbnail));
} catch (BitmapDecodingException e) {
Log.w(TAG, e);
@ -412,10 +412,10 @@ public abstract class PushSendJob extends SendJob {
}
try {
byte[] packId = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackId());
byte[] packKey = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackKey());
int stickerId = stickerAttachment.getSticker().getStickerId();
StickerRecord record = SignalDatabase.stickers().getSticker(stickerAttachment.getSticker().getPackId(), stickerId, false);
byte[] packId = Hex.fromStringCondensed(stickerAttachment.stickerLocator.packId);
byte[] packKey = Hex.fromStringCondensed(stickerAttachment.stickerLocator.packKey);
int stickerId = stickerAttachment.stickerLocator.stickerId;
StickerRecord record = SignalDatabase.stickers().getSticker(stickerAttachment.stickerLocator.packId, stickerId, false);
String emoji = record != null ? record.getEmoji() : null;
SignalServiceAttachment attachment = getAttachmentPointerFor(stickerAttachment);

View file

@ -66,7 +66,7 @@ public abstract class SendJob extends BaseJob {
protected String buildAttachmentString(@NonNull List<Attachment> attachments) {
List<String> strings = attachments.stream().map(attachment -> {
if (attachment instanceof DatabaseAttachment) {
return ((DatabaseAttachment) attachment).getAttachmentId().toString();
return ((DatabaseAttachment) attachment).attachmentId.toString();
} else if (attachment.getUri() != null) {
return attachment.getUri().toString();
} else {

View file

@ -45,7 +45,7 @@ public class LinkPreview implements Parcelable {
this.description = description;
this.date = date;
this.thumbnail = Optional.of(thumbnail);
this.attachmentId = thumbnail.getAttachmentId();
this.attachmentId = thumbnail.attachmentId;
}
public LinkPreview(@NonNull String url, @NonNull String title, @NonNull String description, long date, @NonNull Optional<Attachment> thumbnail) {

View file

@ -101,7 +101,7 @@ final class MediaActions {
attachments.add(new SaveAttachmentTask.Attachment(mediaRecord.getAttachment().getUri(),
mediaRecord.getContentType(),
mediaRecord.getDate(),
mediaRecord.getAttachment().getFileName()));
mediaRecord.getAttachment().fileName));
}
}

View file

@ -203,7 +203,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
}
public void toggleSelection(@NonNull MediaRecord mediaRecord) {
AttachmentId attachmentId = mediaRecord.getAttachment().getAttachmentId();
AttachmentId attachmentId = mediaRecord.getAttachment().attachmentId;
MediaTable.MediaRecord removed = selected.remove(attachmentId);
if (removed == null) {
selected.put(attachmentId, mediaRecord);
@ -219,7 +219,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
public long getSelectedMediaTotalFileSize() {
//noinspection ConstantConditions attacment cannot be null if selected
return Stream.of(selected.values())
.collect(Collectors.summingLong(a -> a.getAttachment().getSize()));
.collect(Collectors.summingLong(a -> a.getAttachment().size));
}
@NonNull
@ -238,7 +238,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
int sectionItemCount = media.getSectionItemCount(section);
for (int item = 0; item < sectionItemCount; item++) {
MediaRecord mediaRecord = media.get(section, item);
selected.put(mediaRecord.getAttachment().getAttachmentId(), mediaRecord);
selected.put(mediaRecord.getAttachment().attachmentId, mediaRecord);
}
}
this.notifyItemRangeChanged(0, getItemCount(), PAYLOAD_SELECTED);
@ -282,7 +282,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
}
protected boolean isSelected() {
return selected.containsKey(mediaRecord.getAttachment().getAttachmentId());
return selected.containsKey(mediaRecord.getAttachment().attachmentId);
}
protected void updateSelectedView() {
@ -539,11 +539,11 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
throw new AssertionError();
}
isVoiceNote = slide.asAttachment().isVoiceNote();
isVoiceNote = slide.asAttachment().voiceNote;
super.bind(context, mediaRecord, slide);
long mmsId = Objects.requireNonNull(mediaRecord.getAttachment()).getMmsId();
long mmsId = Objects.requireNonNull(mediaRecord.getAttachment()).mmsId;
audioItemListener.unregisterPlaybackStateObserver(audioView.getPlaybackStateObserver());
audioView.setAudio((AudioSlide) slide, new AudioViewCallbacksAdapter(audioItemListener, mmsId), true, true);

View file

@ -247,17 +247,17 @@ public final class MediaOverviewPageFragment extends Fragment
mediaRecord.getDate(),
Objects.requireNonNull(mediaRecord.getAttachment().getUri()),
mediaRecord.getContentType(),
mediaRecord.getAttachment().getSize(),
mediaRecord.getAttachment().getCaption(),
mediaRecord.getAttachment().size,
mediaRecord.getAttachment().caption,
true,
true,
threadId == MediaTable.ALL_THREADS,
true,
sorting,
attachment.isVideoGif(),
attachment.videoGif,
new MediaIntentFactory.SharedElementArgs(
attachment.getWidth(),
attachment.getHeight(),
attachment.width,
attachment.height,
DimensionUnit.DP.toDp(12),
DimensionUnit.DP.toDp(12),
DimensionUnit.DP.toDp(12),

View file

@ -77,7 +77,7 @@ object MediaIntentFactory {
leftIsRecent,
allMediaInRail = allMediaInRail,
sorting = MediaTable.Sorting.Newest,
isVideoGif = attachment.isVideoGif,
isVideoGif = attachment.videoGif,
sharedElementArgs = SharedElementArgs(
attachment.width,
attachment.height,

View file

@ -31,8 +31,8 @@ class MediaPreviewV2Adapter(fragment: Fragment) : FragmentStateAdapter(fragment)
MediaPreviewFragment.DATA_URI to attachment.uri,
MediaPreviewFragment.DATA_CONTENT_TYPE to contentType,
MediaPreviewFragment.DATA_SIZE to attachment.size,
MediaPreviewFragment.AUTO_PLAY to attachment.isVideoGif,
MediaPreviewFragment.VIDEO_GIF to attachment.isVideoGif
MediaPreviewFragment.AUTO_PLAY to attachment.videoGif,
MediaPreviewFragment.VIDEO_GIF to attachment.videoGif
)
val fragment = if (MediaUtil.isVideo(contentType)) {
VideoMediaPreviewFragment()

View file

@ -331,7 +331,7 @@ class MediaPreviewV2Fragment : LoggingFragment(R.layout.fragment_media_preview_v
}
private fun bindMediaPreviewPlaybackControls(currentItem: MediaTable.MediaRecord, currentFragment: MediaPreviewFragment?) {
val mediaType: MediaPreviewPlayerControlView.MediaMode = if (currentItem.attachment?.isVideoGif == true) {
val mediaType: MediaPreviewPlayerControlView.MediaMode = if (currentItem.attachment?.videoGif == true) {
MediaPreviewPlayerControlView.MediaMode.IMAGE
} else {
MediaPreviewPlayerControlView.MediaMode.fromString(currentItem.contentType)

View file

@ -127,8 +127,8 @@ fun MediaTable.MediaRecord.toMedia(): Media? {
attachment.height,
attachment.size,
0,
attachment.isBorderless,
attachment.isVideoGif,
attachment.borderless,
attachment.videoGif,
Optional.empty(),
Optional.ofNullable(attachment.caption),
Optional.empty()

View file

@ -100,7 +100,7 @@ public class MediaUploadRepository {
return oldProperties == newProperties;
}
return !newProperties.isVideoEdited() && oldProperties.getSentMediaQuality() == newProperties.getSentMediaQuality();
return !newProperties.getVideoEdited() && oldProperties.sentMediaQuality == newProperties.sentMediaQuality;
}
public void cancelUpload(@NonNull Media media) {

View file

@ -109,7 +109,7 @@ class MediaSelectionRepository(context: Context) {
val updatedMedia = oldToNewMediaMap.values.toList()
for (media in updatedMedia) {
Log.w(TAG, media.uri.toString() + " : " + media.transformProperties.map { t: TransformProperties -> "" + t.isVideoTrim }.orElse("null"))
Log.w(TAG, media.uri.toString() + " : " + media.transformProperties.map { t: TransformProperties -> "" + t.videoTrim }.orElse("null"))
}
val singleRecipient: Recipient? = singleContact?.let { Recipient.resolved(it.recipientId) }

View file

@ -246,15 +246,15 @@ public class LegacyMigrationJob extends MigrationJob {
Log.i(TAG, pendingAttachments.size() + " pending parts.");
for (DatabaseAttachment attachment : pendingAttachments) {
final MmsReader reader = MessageTable.mmsReaderFor(mmsDb.getMessageCursor(attachment.getMmsId()));
final MmsReader reader = MessageTable.mmsReaderFor(mmsDb.getMessageCursor(attachment.mmsId));
final MessageRecord record = reader.getNext();
if (attachment.hasData()) {
Log.i(TAG, "corrected a pending media part " + attachment.getAttachmentId() + "that already had data.");
attachmentDb.setTransferState(attachment.getMmsId(), attachment.getAttachmentId(), AttachmentTable.TRANSFER_PROGRESS_DONE);
if (attachment.hasData) {
Log.i(TAG, "corrected a pending media part " + attachment.attachmentId + "that already had data.");
attachmentDb.setTransferState(attachment.mmsId, attachment.attachmentId, AttachmentTable.TRANSFER_PROGRESS_DONE);
} else if (record != null && !record.isOutgoing() && record.isPush()) {
Log.i(TAG, "queuing new attachment download job for incoming push part " + attachment.getAttachmentId() + ".");
ApplicationDependencies.getJobManager().add(new AttachmentDownloadJob(attachment.getMmsId(), attachment.getAttachmentId(), false));
Log.i(TAG, "queuing new attachment download job for incoming push part " + attachment.attachmentId + ".");
ApplicationDependencies.getJobManager().add(new AttachmentDownloadJob(attachment.mmsId, attachment.attachmentId, false));
}
reader.close();
}

View file

@ -323,7 +323,7 @@ public class AttachmentManager {
result.set(true);
} else {
Attachment attachment = slide.asAttachment();
result.deferTo(thumbnail.setImageResource(glideRequests, slide, false, true, attachment.getWidth(), attachment.getHeight()));
result.deferTo(thumbnail.setImageResource(glideRequests, slide, false, true, attachment.width, attachment.height));
removableMediaView.display(thumbnail, mediaType == SlideFactory.MediaType.IMAGE);
}
@ -546,7 +546,7 @@ public class AttachmentManager {
MediaIntentFactory.UNKNOWN_TIMESTAMP,
slide.getUri(),
slide.getContentType(),
slide.asAttachment().getSize(),
slide.asAttachment().size,
slide.getCaption().orElse(null),
false,
false,

View file

@ -14,7 +14,7 @@ public class GifSlide extends ImageSlide {
public GifSlide(Attachment attachment) {
super(attachment);
this.borderless = attachment.isBorderless();
this.borderless = attachment.borderless;
}
public GifSlide(Context context, Uri uri, long size, int width, int height) {

View file

@ -40,7 +40,7 @@ public class ImageSlide extends Slide {
public ImageSlide(@NonNull Attachment attachment) {
super(attachment);
this.borderless = attachment.isBorderless();
this.borderless = attachment.borderless;
}
public ImageSlide(Context context, Uri uri, long size, int width, int height, @Nullable BlurHash blurHash) {

View file

@ -75,7 +75,7 @@ public abstract class MediaConstraints {
public boolean isSatisfied(@NonNull Context context, @NonNull Attachment attachment) {
try {
long size = attachment.getSize();
long size = attachment.size;
if (size > getMaxAttachmentSize()) {
return false;
}

View file

@ -97,7 +97,7 @@ public class PartAuthority {
case PART_ROW:
Attachment attachment = SignalDatabase.attachments().getAttachment(new PartUriParser(uri).getPartId());
if (attachment != null) return attachment.getFileName();
if (attachment != null) return attachment.fileName;
else return null;
case PERSISTENT_ROW:
return DeprecatedPersistentBlobProvider.getFileName(context, uri);
@ -115,7 +115,7 @@ public class PartAuthority {
case PART_ROW:
Attachment attachment = SignalDatabase.attachments().getAttachment(new PartUriParser(uri).getPartId());
if (attachment != null) return attachment.getSize();
if (attachment != null) return attachment.size;
else return null;
case PERSISTENT_ROW:
return DeprecatedPersistentBlobProvider.getFileSize(context, uri);
@ -133,7 +133,7 @@ public class PartAuthority {
case PART_ROW:
Attachment attachment = SignalDatabase.attachments().getAttachment(new PartUriParser(uri).getPartId());
if (attachment != null) return attachment.getContentType();
if (attachment != null) return attachment.contentType;
else return null;
case PERSISTENT_ROW:
return DeprecatedPersistentBlobProvider.getMimeType(context, uri);
@ -151,7 +151,7 @@ public class PartAuthority {
case PART_ROW:
Attachment attachment = SignalDatabase.attachments().getAttachment(new PartUriParser(uri).getPartId());
if (attachment != null) return attachment.isVideoGif();
if (attachment != null) return attachment.videoGif;
else return false;
default:
return false;

View file

@ -46,7 +46,7 @@ public abstract class Slide {
}
public String getContentType() {
return attachment.getContentType();
return attachment.contentType;
}
@Nullable
@ -69,21 +69,21 @@ public abstract class Slide {
@NonNull
public Optional<String> getCaption() {
return Optional.ofNullable(attachment.getCaption());
return Optional.ofNullable(attachment.caption);
}
@NonNull
public Optional<String> getFileName() {
return Optional.ofNullable(attachment.getFileName());
return Optional.ofNullable(attachment.fileName);
}
@Nullable
public String getFastPreflightId() {
return attachment.getFastPreflightId();
return attachment.fastPreflightId;
}
public long getFileSize() {
return attachment.getSize();
return attachment.size;
}
public boolean hasImage() {
@ -117,7 +117,7 @@ public abstract class Slide {
}
public boolean isVideoGif() {
return hasVideo() && attachment.isVideoGif();
return hasVideo() && attachment.videoGif;
}
public @NonNull String getContentDescription(@NonNull Context context) { return ""; }
@ -136,7 +136,7 @@ public abstract class Slide {
}
public int getTransferState() {
return attachment.getTransferState();
return attachment.transferState;
}
public @DrawableRes int getPlaceholderRes(Theme theme) {
@ -144,7 +144,7 @@ public abstract class Slide {
}
public @Nullable BlurHash getPlaceholderBlur() {
return attachment.getBlurHash();
return attachment.blurHash;
}
public boolean hasPlaceholder() {

View file

@ -23,12 +23,12 @@ public class StickerSlide extends Slide {
public StickerSlide(@NonNull Attachment attachment) {
super(attachment);
this.stickerLocator = Objects.requireNonNull(attachment.getSticker());
this.stickerLocator = Objects.requireNonNull(attachment.stickerLocator);
}
public StickerSlide(Context context, Uri uri, long size, @NonNull StickerLocator stickerLocator, @NonNull String contentType) {
super(constructAttachmentFromUri(context, uri, contentType, size, WIDTH, HEIGHT, true, null, null, stickerLocator, null, null, false, false, false, false));
this.stickerLocator = Objects.requireNonNull(attachment.getSticker());
this.stickerLocator = Objects.requireNonNull(attachment.stickerLocator);
}
@Override
@ -52,6 +52,6 @@ public class StickerSlide extends Slide {
}
public @Nullable String getEmoji() {
return stickerLocator.getEmoji();
return stickerLocator.emoji;
}
}

View file

@ -134,8 +134,8 @@ public final class PartProvider extends BaseContentProvider {
DatabaseAttachment attachment = SignalDatabase.attachments().getAttachment(partUriParser.getPartId());
if (attachment != null) {
Log.i(TAG, "getType() called: " + uri + " It's " + attachment.getContentType());
return attachment.getContentType();
Log.i(TAG, "getType() called: " + uri + " It's " + attachment.contentType);
return attachment.contentType;
}
}
@ -163,15 +163,15 @@ public final class PartProvider extends BaseContentProvider {
if (attachment == null) return null;
long fileSize = attachment.getSize();
long fileSize = attachment.size;
if (fileSize <= 0) {
Log.w(TAG, "Empty file " + fileSize);
return null;
}
String fileName = attachment.getFileName() != null ? attachment.getFileName()
: createFileNameForMimeType(attachment.getContentType());
String fileName = attachment.fileName != null ? attachment.fileName
: createFileNameForMimeType(attachment.contentType);
return createCursor(projection, fileName, fileSize);
} else {
@ -229,9 +229,9 @@ public final class PartProvider extends BaseContentProvider {
@Override
public long onGetSize() throws ErrnoException {
DatabaseAttachment attachment = attachments.getAttachment(attachmentId);
if (attachment != null && attachment.getSize() > 0) {
if (attachment != null && attachment.size > 0) {
Log.i(TAG, attachmentId + ":getSize");
return attachment.getSize();
return attachment.size;
} else {
Log.w(TAG, attachmentId + ":getSize:attachment is null or size is 0");
throw new ErrnoException("Attachment is invalid", OsConstants.ENOENT);
@ -242,7 +242,7 @@ public final class PartProvider extends BaseContentProvider {
public int onRead(long offset, int size, byte[] data) throws ErrnoException {
try {
DatabaseAttachment attachment = attachments.getAttachment(attachmentId);
if (attachment == null || attachment.getSize() <= 0) {
if (attachment == null || attachment.size <= 0) {
Log.w(TAG, attachmentId + ":onRead:attachment is null or size is 0");
throw new ErrnoException("Attachment is invalid", OsConstants.ENOENT);
}

View file

@ -95,8 +95,8 @@ public class ViewOnceMessageView extends LinearLayout {
}
Attachment attachment = messageRecord.getSlideDeck().getThumbnailSlide().asAttachment();
return attachment.getTransferState() == AttachmentTable.TRANSFER_PROGRESS_FAILED ||
attachment.getTransferState() == AttachmentTable.TRANSFER_PROGRESS_PENDING;
return attachment.transferState == AttachmentTable.TRANSFER_PROGRESS_FAILED ||
attachment.transferState == AttachmentTable.TRANSFER_PROGRESS_PENDING;
}
public void setMessage(@NonNull MmsMessageRecord message, boolean hasWallpaper) {
@ -169,7 +169,7 @@ public class ViewOnceMessageView extends LinearLayout {
if (messageRecord.getSlideDeck().getThumbnailSlide() == null) return false;
Attachment attachment = messageRecord.getSlideDeck().getThumbnailSlide().asAttachment();
return attachment.getTransferState() == AttachmentTable.TRANSFER_PROGRESS_STARTED;
return attachment.transferState == AttachmentTable.TRANSFER_PROGRESS_STARTED;
}
private @NonNull String formatFileSize(@NonNull MmsMessageRecord messageRecord) {

View file

@ -329,15 +329,15 @@ public final class MultiShareSender {
: thumbnail.getUri() == null
? null
: new ImageSlide(context,
thumbnail.getUri(),
thumbnail.getContentType(),
thumbnail.getSize(),
thumbnail.getWidth(),
thumbnail.getHeight(),
thumbnail.isBorderless(),
thumbnail.getCaption(),
thumbnail.getBlurHash(),
thumbnail.getTransformProperties()).asAttachment()
thumbnail.getUri(),
thumbnail.contentType,
thumbnail.size,
thumbnail.width,
thumbnail.height,
thumbnail.borderless,
thumbnail.caption,
thumbnail.blurHash,
thumbnail.transformProperties).asAttachment()
)
));
}
@ -345,17 +345,17 @@ public final class MultiShareSender {
private static Slide ensureDefaultQuality(@NonNull Context context, @NonNull ImageSlide imageSlide) {
Attachment attachment = imageSlide.asAttachment();
if (attachment.getTransformProperties().getSentMediaQuality() == SentMediaQuality.HIGH.getCode()) {
if (attachment.transformProperties.sentMediaQuality == SentMediaQuality.HIGH.getCode()) {
return new ImageSlide(
context,
attachment.getUri(),
attachment.getContentType(),
attachment.getSize(),
attachment.getWidth(),
attachment.getHeight(),
attachment.isBorderless(),
attachment.getCaption(),
attachment.getBlurHash(),
attachment.contentType,
attachment.size,
attachment.width,
attachment.height,
attachment.borderless,
attachment.caption,
attachment.blurHash,
AttachmentTable.TransformProperties.empty()
);
} else {

View file

@ -344,7 +344,7 @@ public class MessageSender {
List<AttachmentId> attachmentIds = new ArrayList<>(preUploadAttachmentIds.size());
for (int i = 0; i < preUploadAttachments.size(); i++) {
AttachmentId attachmentId = attachmentDatabase.insertAttachmentForPreUpload(preUploadAttachments.get(i)).getAttachmentId();
AttachmentId attachmentId = attachmentDatabase.insertAttachmentForPreUpload(preUploadAttachments.get(i)).attachmentId;
attachmentCopies.get(i).add(attachmentId);
attachmentIds.add(attachmentId);
}
@ -418,14 +418,14 @@ public class MessageSender {
DatabaseAttachment databaseAttachment = attachmentDatabase.insertAttachmentForPreUpload(attachment);
Job compressionJob = AttachmentCompressionJob.fromAttachment(databaseAttachment, false, -1);
Job uploadJob = new AttachmentUploadJob(databaseAttachment.getAttachmentId());
Job uploadJob = new AttachmentUploadJob(databaseAttachment.attachmentId);
ApplicationDependencies.getJobManager()
.startChain(compressionJob)
.then(uploadJob)
.enqueue();
return new PreUploadResult(media, databaseAttachment.getAttachmentId(), Arrays.asList(compressionJob.getId(), uploadJob.getId()));
return new PreUploadResult(media, databaseAttachment.attachmentId, Arrays.asList(compressionJob.getId(), uploadJob.getId()));
} catch (MmsException e) {
Log.w(TAG, "preUploadPushAttachment() - Failed to upload!", e);
return null;
@ -645,7 +645,7 @@ public class MessageSender {
.toList();
List<AttachmentMarkUploadedJob> fakeUploadJobs = Stream.of(attachments)
.map(a -> new AttachmentMarkUploadedJob(messageId, ((DatabaseAttachment) a).getAttachmentId()))
.map(a -> new AttachmentMarkUploadedJob(messageId, ((DatabaseAttachment) a).attachmentId))
.toList();
ApplicationDependencies.getJobManager().startChain(compressionJobs)

View file

@ -6,6 +6,7 @@ import org.thoughtcrime.securesms.attachments.AttachmentId
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
import org.thoughtcrime.securesms.attachments.UriAttachment
import org.thoughtcrime.securesms.database.AttachmentTable
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.JobManager
import org.thoughtcrime.securesms.jobs.AttachmentCompressionJob
@ -43,7 +44,7 @@ class UploadDependencyGraph private constructor(
*/
private data class AttachmentKey<A : Attachment>(
val attachment: A,
private val transformProperties: AttachmentTable.TransformProperties = attachment.transformProperties
private val transformProperties: AttachmentTable.TransformProperties = attachment.transformProperties ?: AttachmentTable.TransformProperties.empty()
)
private var hasConsumedJobQueue = false
@ -75,14 +76,14 @@ class UploadDependencyGraph private constructor(
* Allows representation of a unique database attachment by its internal id and its transform properties.
*/
private fun DatabaseAttachment.asDatabaseAttachmentKey(): AttachmentKey<DatabaseAttachment> {
return AttachmentKey(this, this.transformProperties)
return AttachmentKey(this, this.transformProperties ?: TransformProperties.empty())
}
/**
* Allows representation of a unique URI attachment by its internal Uri and its transform properties.
*/
private fun UriAttachment.asUriAttachmentKey(): AttachmentKey<UriAttachment> {
return AttachmentKey(this, transformProperties)
return AttachmentKey(this, transformProperties ?: TransformProperties.empty())
}
/**
@ -119,7 +120,7 @@ class UploadDependencyGraph private constructor(
message.linkPreviews.mapNotNull { it.thumbnail.orElse(null) } +
message.sharedContacts.mapNotNull { it.avatar?.attachment }
val uniqueAttachments: Set<AttachmentKey<Attachment>> = attachmentList.map { AttachmentKey(it, it.transformProperties) }.toSet()
val uniqueAttachments: Set<AttachmentKey<Attachment>> = attachmentList.map { AttachmentKey(it, it.transformProperties ?: TransformProperties.empty()) }.toSet()
for (attachmentKey in uniqueAttachments) {
when (val attachment = attachmentKey.attachment) {

View file

@ -1,70 +0,0 @@
package org.thoughtcrime.securesms.stickers;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class StickerLocator implements Parcelable {
private final String packId;
private final String packKey;
private final int stickerId;
private final String emoji;
public StickerLocator(@NonNull String packId, @NonNull String packKey, int stickerId, @Nullable String emoji) {
this.packId = packId;
this.packKey = packKey;
this.stickerId = stickerId;
this.emoji = emoji;
}
private StickerLocator(Parcel in) {
packId = in.readString();
packKey = in.readString();
stickerId = in.readInt();
emoji = in.readString();
}
public @NonNull String getPackId() {
return packId;
}
public @NonNull String getPackKey() {
return packKey;
}
public int getStickerId() {
return stickerId;
}
public @Nullable String getEmoji() {
return emoji;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(packId);
dest.writeString(packKey);
dest.writeInt(stickerId);
dest.writeString(emoji);
}
public static final Creator<StickerLocator> CREATOR = new Creator<StickerLocator>() {
@Override
public StickerLocator createFromParcel(Parcel in) {
return new StickerLocator(in);
}
@Override
public StickerLocator[] newArray(int size) {
return new StickerLocator[size];
}
};
}

View file

@ -0,0 +1,16 @@
package org.thoughtcrime.securesms.stickers
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
class StickerLocator(
@JvmField
val packId: String,
@JvmField
val packKey: String,
@JvmField
val stickerId: Int,
@JvmField
val emoji: String?
) : Parcelable

View file

@ -246,7 +246,7 @@ object Stories {
return if (MediaUtil.isVideo(media.mimeType)) {
val mediaDuration = if (media.duration == 0L && media.transformProperties.map(TransformProperties::shouldSkipTransform).orElse(true)) {
getVideoDuration(media.uri)
} else if (media.transformProperties.map { it.isVideoTrim }.orElse(false)) {
} else if (media.transformProperties.map { it.videoTrim }.orElse(false)) {
TimeUnit.MICROSECONDS.toMillis(media.transformProperties.get().videoTrimEndTimeUs - media.transformProperties.get().videoTrimStartTimeUs)
} else {
media.duration

View file

@ -41,18 +41,18 @@ class StoryPostViewModel(private val repository: StoryTextPostRepository) : View
store.update { StoryPostState.None() }
} else if (storyPostContent.isVideo()) {
store.update {
val shouldSkipTransform = storyPostContent.attachment.transformProperties.shouldSkipTransform()
val shouldSkipTransform = storyPostContent.attachment.transformProperties?.shouldSkipTransform() == true
val clipStart: Duration = if (shouldSkipTransform) {
0L.microseconds
} else {
storyPostContent.attachment.transformProperties.videoTrimStartTimeUs.microseconds
storyPostContent.attachment.transformProperties?.videoTrimStartTimeUs?.microseconds ?: 0L.microseconds
}
val clipEnd: Duration = if (shouldSkipTransform) {
0L.microseconds
} else {
storyPostContent.attachment.transformProperties.videoTrimEndTimeUs.microseconds
storyPostContent.attachment.transformProperties?.videoTrimEndTimeUs?.microseconds ?: 0L.microseconds
}
StoryPostState.VideoPost(

View file

@ -37,15 +37,15 @@ public class AttachmentUtil {
}
Set<String> allowedTypes = getAllowedAutoDownloadTypes(context);
String contentType = attachment.getContentType();
String contentType = attachment.contentType;
if (attachment.isVoiceNote() ||
(MediaUtil.isAudio(attachment) && TextUtils.isEmpty(attachment.getFileName())) ||
MediaUtil.isLongTextType(attachment.getContentType()) ||
if (attachment.voiceNote ||
(MediaUtil.isAudio(attachment) && TextUtils.isEmpty(attachment.fileName)) ||
MediaUtil.isLongTextType(attachment.contentType) ||
attachment.isSticker())
{
return true;
} else if (attachment.isVideoGif()) {
} else if (attachment.videoGif) {
boolean allowed = NotInCallConstraint.isNotInConnectedCall() && allowedTypes.contains("image");
if (!allowed) {
Log.w(TAG, "Not auto downloading. inCall: " + NotInCallConstraint.isNotInConnectedCall() + " allowedType: " + allowedTypes.contains("image"));
@ -74,8 +74,8 @@ public class AttachmentUtil {
public static void deleteAttachment(@NonNull Context context,
@NonNull DatabaseAttachment attachment)
{
AttachmentId attachmentId = attachment.getAttachmentId();
long mmsId = attachment.getMmsId();
AttachmentId attachmentId = attachment.attachmentId;
long mmsId = attachment.mmsId;
int attachmentCount = SignalDatabase.attachments()
.getAttachmentsForMessage(mmsId)
.size();
@ -104,7 +104,7 @@ public class AttachmentUtil {
@WorkerThread
private static boolean isFromTrustedConversation(@NonNull Context context, @NonNull DatabaseAttachment attachment) {
try {
MessageRecord message = SignalDatabase.messages().getMessageRecord(attachment.getMmsId());
MessageRecord message = SignalDatabase.messages().getMessageRecord(attachment.mmsId);
Recipient fromRecipient = message.getFromRecipient();
Recipient toRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId());

View file

@ -100,7 +100,7 @@ public class MediaUtil {
return new StickerSlide(attachment);
}
switch (getSlideTypeFromContentType(attachment.getContentType())) {
switch (getSlideTypeFromContentType(attachment.contentType)) {
case GIF : return new GifSlide(attachment);
case IMAGE : return new ImageSlide(attachment);
case VIDEO : return new VideoSlide(attachment);
@ -262,31 +262,31 @@ public class MediaUtil {
}
public static boolean isGif(Attachment attachment) {
return isGif(attachment.getContentType());
return isGif(attachment.contentType);
}
public static boolean isJpeg(Attachment attachment) {
return isJpegType(attachment.getContentType());
return isJpegType(attachment.contentType);
}
public static boolean isHeic(Attachment attachment) {
return isHeicType(attachment.getContentType());
return isHeicType(attachment.contentType);
}
public static boolean isHeif(Attachment attachment) {
return isHeifType(attachment.getContentType());
return isHeifType(attachment.contentType);
}
public static boolean isImage(Attachment attachment) {
return isImageType(attachment.getContentType());
return isImageType(attachment.contentType);
}
public static boolean isAudio(Attachment attachment) {
return isAudioType(attachment.getContentType());
return isAudioType(attachment.contentType);
}
public static boolean isVideo(Attachment attachment) {
return isVideoType(attachment.getContentType());
return isVideoType(attachment.contentType);
}
public static boolean isVideo(String contentType) {
@ -473,7 +473,7 @@ public class MediaUtil {
}
final Attachment attachment = slide.asAttachment();
final boolean isIncremental = attachment.getIncrementalDigest() != null;
final boolean hasIncrementalMacChunkSizeDefined = attachment.getIncrementalMacChunkSize() > 0;
final boolean hasIncrementalMacChunkSizeDefined = attachment.incrementalMacChunkSize > 0;
final boolean contentTypeSupported = isVideoType(slide.getContentType());
return isIncremental && contentTypeSupported && hasIncrementalMacChunkSizeDefined;
}

View file

@ -58,13 +58,14 @@ class PartDataSource implements DataSource {
final boolean hasIncrementalDigest = attachment.getIncrementalDigest() != null;
final boolean inProgress = attachment.isInProgress();
final String attachmentKey = attachment.getKey();
final boolean hasData = attachment.hasData();
final String attachmentKey = attachment.key;
final boolean hasData = attachment.hasData;
if (inProgress && !hasData && hasIncrementalDigest && attachmentKey != null && FeatureFlags.instantVideoPlayback()) {
final byte[] decode = Base64.decode(attachmentKey);
final File transferFile = attachmentDatabase.getOrCreateTransferFile(attachment.getAttachmentId());
final File transferFile = attachmentDatabase.getOrCreateTransferFile(attachment.attachmentId);
try {
this.inputStream = AttachmentCipherInputStream.createForAttachment(transferFile, attachment.getSize(), decode, attachment.getDigest(), attachment.getIncrementalDigest(), attachment.getIncrementalMacChunkSize());
this.inputStream = AttachmentCipherInputStream.createForAttachment(transferFile, attachment.size, decode, attachment.digest, attachment.getIncrementalDigest(), attachment.incrementalMacChunkSize);
long skipped = 0;
while (skipped < dataSpec.position) {
@ -81,8 +82,8 @@ class PartDataSource implements DataSource {
Log.d(TAG, "Successfully loaded completed attachment file.");
} else {
throw new IOException("Ineligible " + attachment.getAttachmentId().toString()
+ "\nTransfer state: " + attachment.getTransferState()
throw new IOException("Ineligible " + attachment.attachmentId.toString()
+ "\nTransfer state: " + attachment.transferState
+ "\nIncremental Digest Present: " + hasIncrementalDigest
+ "\nAttachment Key Non-Empty: " + (attachmentKey != null && !attachmentKey.isEmpty()));
}
@ -91,9 +92,9 @@ class PartDataSource implements DataSource {
listener.onTransferStart(this, dataSpec, false);
}
if (attachment.getSize() - dataSpec.position <= 0) throw new EOFException("No more data");
if (attachment.size - dataSpec.position <= 0) throw new EOFException("No more data");
return attachment.getSize() - dataSpec.position;
return attachment.size - dataSpec.position;
}
@Override

View file

@ -21,8 +21,8 @@ public class AttachmentDatabaseTransformPropertiesTest {
AttachmentTable.TransformProperties properties = AttachmentTable.TransformProperties.parse(json);
assertEquals(0, properties.getSentMediaQuality());
assertEquals(SentMediaQuality.STANDARD, SentMediaQuality.fromCode(properties.getSentMediaQuality()));
assertEquals(0, properties.sentMediaQuality);
assertEquals(SentMediaQuality.STANDARD, SentMediaQuality.fromCode(properties.sentMediaQuality));
}
}

View file

@ -228,35 +228,35 @@ class UploadDependencyGraphTest {
private fun getAttachmentForPreUpload(id: Long, attachment: Attachment): DatabaseAttachment {
return DatabaseAttachment(
AttachmentId(id, id),
AttachmentTable.PREUPLOAD_MESSAGE_ID,
false,
false,
attachment.contentType,
AttachmentTable.TRANSFER_PROGRESS_PENDING,
attachment.size,
attachment.fileName,
attachment.cdnNumber,
attachment.location,
attachment.key,
attachment.relay,
attachment.digest,
attachment.incrementalDigest,
attachment.incrementalMacChunkSize,
attachment.fastPreflightId,
attachment.isVoiceNote,
attachment.isBorderless,
attachment.isVideoGif,
attachment.width,
attachment.height,
attachment.isQuote,
attachment.caption,
attachment.sticker,
attachment.blurHash,
attachment.audioHash,
attachment.transformProperties,
0,
attachment.uploadTimestamp
attachmentId = AttachmentId(id, id),
mmsId = AttachmentTable.PREUPLOAD_MESSAGE_ID,
hasData = false,
hasThumbnail = false,
contentType = attachment.contentType,
transferProgress = AttachmentTable.TRANSFER_PROGRESS_PENDING,
size = attachment.size,
fileName = attachment.fileName,
cdnNumber = attachment.cdnNumber,
location = attachment.location,
key = attachment.key,
relay = attachment.relay,
digest = attachment.digest,
incrementalDigest = attachment.incrementalDigest,
incrementalMacChunkSize = attachment.incrementalMacChunkSize,
fastPreflightId = attachment.fastPreflightId,
voiceNote = attachment.voiceNote,
borderless = attachment.borderless,
videoGif = attachment.videoGif,
width = attachment.width,
height = attachment.height,
quote = attachment.quote,
caption = attachment.caption,
stickerLocator = attachment.stickerLocator,
blurHash = attachment.blurHash,
audioHash = attachment.audioHash,
transformProperties = attachment.transformProperties,
displayOrder = 0,
uploadTimestamp = attachment.uploadTimestamp
)
}

View file

@ -148,6 +148,23 @@ inline fun <K, V> Cursor.readToMap(predicate: (Pair<K, V>) -> Boolean = { true }
return readToList(predicate, mapper).associate { it }
}
/**
* Groups the cursor by the given key, and returns a map of keys to lists of values.
*/
inline fun <K, V> Cursor.groupBy(mapper: (Cursor) -> Pair<K, V>): Map<K, List<V>> {
val map: MutableMap<K, MutableList<V>> = mutableMapOf()
use {
while (moveToNext()) {
val pair = mapper(this)
val list = map.getOrPut(pair.first) { mutableListOf() }
list += pair.second
}
}
return map
}
inline fun <T> Cursor.readToSet(predicate: (T) -> Boolean = { true }, mapper: (Cursor) -> T): Set<T> {
val set = mutableSetOf<T>()
use {