package org.thoughtcrime.securesms.jobs; import android.graphics.Bitmap; import androidx.annotation.NonNull; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel; import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.Hex; import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import java.io.File; import java.io.IOException; import java.io.InputStream; public class AvatarDownloadJob extends BaseJob { public static final String KEY = "AvatarDownloadJob"; private static final String TAG = AvatarDownloadJob.class.getSimpleName(); private static final int MAX_AVATAR_SIZE = 20 * 1024 * 1024; private static final String KEY_GROUP_ID = "group_id"; private @NonNull GroupId.V1 groupId; public AvatarDownloadJob(@NonNull GroupId.V1 groupId) { this(new Job.Parameters.Builder() .addConstraint(NetworkConstraint.KEY) .setMaxAttempts(10) .build(), groupId); } private AvatarDownloadJob(@NonNull Job.Parameters parameters, @NonNull GroupId.V1 groupId) { super(parameters); this.groupId = groupId; } @Override public @NonNull Data serialize() { return new Data.Builder().putString(KEY_GROUP_ID, groupId.toString()).build(); } @Override public @NonNull String getFactoryKey() { return KEY; } @Override public void onRun() throws IOException { GroupDatabase database = DatabaseFactory.getGroupDatabase(context); Optional record = database.getGroup(groupId); File attachment = null; try { if (record.isPresent()) { long avatarId = record.get().getAvatarId(); String contentType = record.get().getAvatarContentType(); byte[] key = record.get().getAvatarKey(); String relay = record.get().getRelay(); Optional digest = Optional.fromNullable(record.get().getAvatarDigest()); Optional fileName = Optional.absent(); if (avatarId == -1 || key == null) { return; } if (digest.isPresent()) { Log.i(TAG, "Downloading group avatar with digest: " + Hex.toString(digest.get())); } attachment = File.createTempFile("avatar", "tmp", context.getCacheDir()); attachment.deleteOnExit(); SignalServiceMessageReceiver receiver = ApplicationDependencies.getSignalServiceMessageReceiver(); SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), Optional.absent()); InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, AvatarHelper.AVATAR_DOWNLOAD_FAILSAFE_MAX_SIZE); AvatarHelper.setAvatar(context, record.get().getRecipientId(), inputStream); DatabaseFactory.getGroupDatabase(context).onAvatarUpdated(groupId, true); inputStream.close(); } } catch (NonSuccessfulResponseCodeException | InvalidMessageException e) { Log.w(TAG, e); } finally { if (attachment != null) attachment.delete(); } } @Override public void onFailure() {} @Override public boolean onShouldRetry(@NonNull Exception exception) { if (exception instanceof IOException) return true; return false; } public static final class Factory implements Job.Factory { @Override public @NonNull AvatarDownloadJob create(@NonNull Parameters parameters, @NonNull Data data) { return new AvatarDownloadJob(parameters, GroupId.parse(data.getString(KEY_GROUP_ID)).requireV1()); } } }