mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-21 10:28:27 +00:00
remove unused jobs and wrap up old job refactoring
This commit is contained in:
parent
375815c719
commit
2b48b52df0
@ -355,7 +355,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
|||||||
private void initializeJobManager() {
|
private void initializeJobManager() {
|
||||||
this.jobManager = new JobManager(this, new JobManager.Configuration.Builder()
|
this.jobManager = new JobManager(this, new JobManager.Configuration.Builder()
|
||||||
.setDataSerializer(new JsonDataSerializer())
|
.setDataSerializer(new JsonDataSerializer())
|
||||||
.setJobFactories(JobManagerFactories.getJobFactories(this))
|
.setJobFactories(JobManagerFactories.getJobFactories())
|
||||||
.setConstraintFactories(JobManagerFactories.getConstraintFactories(this))
|
.setConstraintFactories(JobManagerFactories.getConstraintFactories(this))
|
||||||
.setConstraintObservers(JobManagerFactories.getConstraintObservers(this))
|
.setConstraintObservers(JobManagerFactories.getConstraintObservers(this))
|
||||||
.setJobStorage(new FastJobStorage(jobDatabase))
|
.setJobStorage(new FastJobStorage(jobDatabase))
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.jobs;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.session.libsession.messaging.utilities.Data;
|
|
||||||
import org.session.libsession.utilities.DownloadUtilities;
|
|
||||||
import org.session.libsession.utilities.GroupRecord;
|
|
||||||
import org.session.libsignal.exceptions.InvalidMessageException;
|
|
||||||
import org.session.libsignal.exceptions.NonSuccessfulResponseCodeException;
|
|
||||||
import org.session.libsignal.messages.SignalServiceAttachmentPointer;
|
|
||||||
import org.session.libsignal.streams.AttachmentCipherInputStream;
|
|
||||||
import org.session.libsignal.utilities.Hex;
|
|
||||||
import org.session.libsignal.utilities.Log;
|
|
||||||
import org.session.libsignal.utilities.guava.Optional;
|
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|
||||||
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
|
|
||||||
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
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 String groupId;
|
|
||||||
|
|
||||||
public AvatarDownloadJob(@NonNull String groupId) {
|
|
||||||
this(new Job.Parameters.Builder()
|
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
|
||||||
.setMaxAttempts(10)
|
|
||||||
.build(),
|
|
||||||
groupId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AvatarDownloadJob(@NonNull Job.Parameters parameters, @NonNull String groupId) {
|
|
||||||
super(parameters);
|
|
||||||
this.groupId = groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull Data serialize() {
|
|
||||||
return new Data.Builder().putString(KEY_GROUP_ID, groupId).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull String getFactoryKey() {
|
|
||||||
return KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRun() throws IOException {
|
|
||||||
GroupDatabase database = DatabaseComponent.get(context).groupDatabase();
|
|
||||||
Optional<GroupRecord> 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<byte[]> digest = Optional.fromNullable(record.get().getAvatarDigest());
|
|
||||||
Optional<String> fileName = Optional.absent();
|
|
||||||
String url = record.get().getUrl();
|
|
||||||
|
|
||||||
if (avatarId == -1 || key == null || url.isEmpty()) {
|
|
||||||
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();
|
|
||||||
|
|
||||||
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), url);
|
|
||||||
|
|
||||||
if (pointer.getUrl().isEmpty()) throw new InvalidMessageException("Missing attachment URL.");
|
|
||||||
DownloadUtilities.downloadFile(attachment, pointer.getUrl());
|
|
||||||
|
|
||||||
// Assume we're retrieving an attachment for an open group server if the digest is not set
|
|
||||||
InputStream inputStream;
|
|
||||||
if (!pointer.getDigest().isPresent()) {
|
|
||||||
inputStream = new FileInputStream(attachment);
|
|
||||||
} else {
|
|
||||||
inputStream = AttachmentCipherInputStream.createForAttachment(attachment, pointer.getSize().or(0), pointer.getKey(), pointer.getDigest().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
|
|
||||||
|
|
||||||
database.updateProfilePicture(groupId, avatar);
|
|
||||||
inputStream.close();
|
|
||||||
}
|
|
||||||
} catch (BitmapDecodingException | NonSuccessfulResponseCodeException | InvalidMessageException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
} finally {
|
|
||||||
if (attachment != null)
|
|
||||||
attachment.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCanceled() {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onShouldRetry(@NonNull Exception exception) {
|
|
||||||
if (exception instanceof IOException) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Factory implements Job.Factory<AvatarDownloadJob> {
|
|
||||||
@Override
|
|
||||||
public @NonNull AvatarDownloadJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
|
||||||
return new AvatarDownloadJob(parameters, data.getString(KEY_GROUP_ID));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,9 +4,9 @@ import android.app.Application;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.session.libsession.messaging.jobs.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Constraint;
|
import org.thoughtcrime.securesms.jobmanager.Constraint;
|
||||||
import org.thoughtcrime.securesms.jobmanager.ConstraintObserver;
|
import org.thoughtcrime.securesms.jobmanager.ConstraintObserver;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraint;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraintObserver;
|
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraintObserver;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
@ -28,11 +28,9 @@ public final class JobManagerFactories {
|
|||||||
|
|
||||||
public static Map<String, Job.Factory> getJobFactories(@NonNull Application application) {
|
public static Map<String, Job.Factory> getJobFactories(@NonNull Application application) {
|
||||||
HashMap<String, Job.Factory> factoryHashMap = new HashMap<String, Job.Factory>() {{
|
HashMap<String, Job.Factory> factoryHashMap = new HashMap<String, Job.Factory>() {{
|
||||||
put(AvatarDownloadJob.KEY, new AvatarDownloadJob.Factory());
|
put(LocalBackupJob.Companion.getKEY(), new LocalBackupJob.Factory());
|
||||||
put(LocalBackupJob.Companion.getKEY(), new LocalBackupJob.Factory());
|
put(RetrieveProfileAvatarJob.Companion.getKEY(), new RetrieveProfileAvatarJob.Factory());
|
||||||
put(RetrieveProfileAvatarJob.KEY, new RetrieveProfileAvatarJob.Factory(application));
|
put(UpdateApkJob.Companion.getKEY(), new UpdateApkJob.Factory());
|
||||||
put(UpdateApkJob.Companion.getKEY(), new UpdateApkJob.Factory());
|
|
||||||
put(PrepareAttachmentAudioExtrasJob.KEY, new PrepareAttachmentAudioExtrasJob.Factory());
|
|
||||||
}};
|
}};
|
||||||
factoryKeys.addAll(factoryHashMap.keySet());
|
factoryKeys.addAll(factoryHashMap.keySet());
|
||||||
return factoryHashMap;
|
return factoryHashMap;
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.jobs
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
|
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
|
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachmentAudioExtras
|
|
||||||
import org.session.libsession.messaging.utilities.Data
|
|
||||||
import org.session.libsession.utilities.DecodedAudio
|
|
||||||
import org.session.libsession.utilities.InputStreamMediaDataSource
|
|
||||||
import org.session.libsignal.utilities.Log
|
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job
|
|
||||||
import org.thoughtcrime.securesms.jobs.PrepareAttachmentAudioExtrasJob.AudioExtrasUpdatedEvent
|
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority
|
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes the audio content of the related attachment entry
|
|
||||||
* and caches the result with [DatabaseAttachmentAudioExtras] data.
|
|
||||||
*
|
|
||||||
* It only process attachments with "audio" mime types.
|
|
||||||
*
|
|
||||||
* Due to [DecodedAudio] implementation limitations, it only works for API 23+.
|
|
||||||
* For any lower targets fake data will be generated.
|
|
||||||
*
|
|
||||||
* You can subscribe to [AudioExtrasUpdatedEvent] to be notified about the successful result.
|
|
||||||
*/
|
|
||||||
//TODO AC: Rewrite to WorkManager API when
|
|
||||||
// https://github.com/loki-project/session-android/pull/354 is merged.
|
|
||||||
class PrepareAttachmentAudioExtrasJob : BaseJob {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "AttachAudioExtrasJob"
|
|
||||||
|
|
||||||
const val KEY = "PrepareAttachmentAudioExtrasJob"
|
|
||||||
const val DATA_ATTACH_ID = "attachment_id"
|
|
||||||
|
|
||||||
const val VISUAL_RMS_FRAMES = 32 // The amount of values to be computed for the visualization.
|
|
||||||
}
|
|
||||||
|
|
||||||
private val attachmentId: AttachmentId
|
|
||||||
|
|
||||||
constructor(attachmentId: AttachmentId) : this(Parameters.Builder()
|
|
||||||
.setQueue(KEY)
|
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
|
||||||
.build(),
|
|
||||||
attachmentId)
|
|
||||||
|
|
||||||
private constructor(parameters: Parameters, attachmentId: AttachmentId) : super(parameters) {
|
|
||||||
this.attachmentId = attachmentId
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun serialize(): Data {
|
|
||||||
return Data.Builder().putParcelable(DATA_ATTACH_ID, attachmentId).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFactoryKey(): String { return KEY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onShouldRetry(e: Exception): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCanceled() { }
|
|
||||||
|
|
||||||
override fun onRun() {
|
|
||||||
Log.v(TAG, "Processing attachment: $attachmentId")
|
|
||||||
|
|
||||||
val attachDb = DatabaseComponent.get(context).attachmentDatabase()
|
|
||||||
val attachment = attachDb.getAttachment(attachmentId)
|
|
||||||
|
|
||||||
if (attachment == null) {
|
|
||||||
throw IllegalStateException("Cannot find attachment with the ID $attachmentId")
|
|
||||||
}
|
|
||||||
if (!attachment.contentType.startsWith("audio/")) {
|
|
||||||
throw IllegalStateException("Attachment $attachmentId is not of audio type.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the audio extras already exist.
|
|
||||||
if (attachDb.getAttachmentAudioExtras(attachmentId) != null) return
|
|
||||||
|
|
||||||
fun extractAttachmentRandomSeed(attachment: Attachment): Int {
|
|
||||||
return when {
|
|
||||||
attachment.digest != null -> attachment.digest!!.sum()
|
|
||||||
attachment.fileName != null -> attachment.fileName.hashCode()
|
|
||||||
else -> attachment.hashCode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateFakeRms(seed: Int, frames: Int = VISUAL_RMS_FRAMES): ByteArray {
|
|
||||||
return ByteArray(frames).apply { Random(seed.toLong()).nextBytes(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var rmsValues: ByteArray
|
|
||||||
var totalDurationMs: Long = DatabaseAttachmentAudioExtras.DURATION_UNDEFINED
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
||||||
// Due to API version incompatibility, we just display some random waveform for older API.
|
|
||||||
rmsValues = generateFakeRms(extractAttachmentRandomSeed(attachment))
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
|
||||||
val decodedAudio = PartAuthority.getAttachmentStream(context, attachment.dataUri!!).use {
|
|
||||||
DecodedAudio.create(InputStreamMediaDataSource(it))
|
|
||||||
}
|
|
||||||
rmsValues = decodedAudio.calculateRms(VISUAL_RMS_FRAMES)
|
|
||||||
totalDurationMs = (decodedAudio.totalDuration / 1000.0).toLong()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.w(TAG, "Failed to decode sample values for the audio attachment \"${attachment.fileName}\".", e)
|
|
||||||
rmsValues = generateFakeRms(extractAttachmentRandomSeed(attachment))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attachDb.setAttachmentAudioExtras(DatabaseAttachmentAudioExtras(
|
|
||||||
attachmentId,
|
|
||||||
rmsValues,
|
|
||||||
totalDurationMs
|
|
||||||
))
|
|
||||||
|
|
||||||
EventBus.getDefault().post(AudioExtrasUpdatedEvent(attachmentId))
|
|
||||||
}
|
|
||||||
|
|
||||||
class Factory : Job.Factory<PrepareAttachmentAudioExtrasJob> {
|
|
||||||
override fun create(parameters: Parameters, data: Data): PrepareAttachmentAudioExtrasJob {
|
|
||||||
return PrepareAttachmentAudioExtrasJob(parameters, data.getParcelable(DATA_ATTACH_ID, AttachmentId.CREATOR))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets dispatched once the audio extras have been updated. */
|
|
||||||
data class AudioExtrasUpdatedEvent(val attachmentId: AttachmentId)
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.jobs;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.session.libsession.avatars.AvatarHelper;
|
|
||||||
import org.session.libsession.messaging.utilities.Data;
|
|
||||||
import org.session.libsession.utilities.Address;
|
|
||||||
import org.session.libsession.utilities.DownloadUtilities;
|
|
||||||
import org.session.libsession.utilities.TextSecurePreferences;
|
|
||||||
import org.session.libsession.utilities.Util;
|
|
||||||
import org.session.libsession.utilities.recipients.Recipient;
|
|
||||||
import org.session.libsignal.exceptions.PushNetworkException;
|
|
||||||
import org.session.libsignal.streams.ProfileCipherInputStream;
|
|
||||||
import org.session.libsignal.utilities.Log;
|
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class RetrieveProfileAvatarJob extends BaseJob {
|
|
||||||
|
|
||||||
public static final String KEY = "RetrieveProfileAvatarJob";
|
|
||||||
|
|
||||||
private static final String TAG = RetrieveProfileAvatarJob.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final int MAX_PROFILE_SIZE_BYTES = 10 * 1024 * 1024;
|
|
||||||
|
|
||||||
private static final String KEY_PROFILE_AVATAR = "profile_avatar";
|
|
||||||
private static final String KEY_ADDRESS = "address";
|
|
||||||
|
|
||||||
|
|
||||||
private String profileAvatar;
|
|
||||||
private Recipient recipient;
|
|
||||||
|
|
||||||
public RetrieveProfileAvatarJob(Recipient recipient, String profileAvatar) {
|
|
||||||
this(new Job.Parameters.Builder()
|
|
||||||
.setQueue("RetrieveProfileAvatarJob" + recipient.getAddress().serialize())
|
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
|
||||||
.setLifespan(TimeUnit.HOURS.toMillis(1))
|
|
||||||
.setMaxAttempts(2)
|
|
||||||
.setMaxInstances(1)
|
|
||||||
.build(),
|
|
||||||
recipient,
|
|
||||||
profileAvatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RetrieveProfileAvatarJob(@NonNull Job.Parameters parameters, @NonNull Recipient recipient, String profileAvatar) {
|
|
||||||
super(parameters);
|
|
||||||
this.recipient = recipient;
|
|
||||||
this.profileAvatar = profileAvatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull
|
|
||||||
Data serialize() {
|
|
||||||
return new Data.Builder()
|
|
||||||
.putString(KEY_PROFILE_AVATAR, profileAvatar)
|
|
||||||
.putString(KEY_ADDRESS, recipient.getAddress().serialize())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull String getFactoryKey() {
|
|
||||||
return KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRun() throws IOException {
|
|
||||||
RecipientDatabase database = DatabaseComponent.get(context).recipientDatabase();
|
|
||||||
byte[] profileKey = recipient.resolve().getProfileKey();
|
|
||||||
|
|
||||||
if (profileKey == null || (profileKey.length != 32 && profileKey.length != 16)) {
|
|
||||||
Log.w(TAG, "Recipient profile key is gone!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AvatarHelper.avatarFileExists(context, recipient.resolve().getAddress()) && Util.equals(profileAvatar, recipient.resolve().getProfileAvatar())) {
|
|
||||||
Log.w(TAG, "Already retrieved profile avatar: " + profileAvatar);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(profileAvatar)) {
|
|
||||||
Log.w(TAG, "Removing profile avatar for: " + recipient.getAddress().serialize());
|
|
||||||
AvatarHelper.delete(context, recipient.getAddress());
|
|
||||||
database.setProfileAvatar(recipient, profileAvatar);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
File downloadDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
|
|
||||||
|
|
||||||
try {
|
|
||||||
DownloadUtilities.downloadFile(downloadDestination, profileAvatar);
|
|
||||||
InputStream avatarStream = new ProfileCipherInputStream(new FileInputStream(downloadDestination), profileKey);
|
|
||||||
File decryptDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
|
|
||||||
|
|
||||||
Util.copy(avatarStream, new FileOutputStream(decryptDestination));
|
|
||||||
decryptDestination.renameTo(AvatarHelper.getAvatarFile(context, recipient.getAddress()));
|
|
||||||
} finally {
|
|
||||||
if (downloadDestination != null) downloadDestination.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipient.isLocalNumber()) {
|
|
||||||
TextSecurePreferences.setProfileAvatarId(context, new SecureRandom().nextInt());
|
|
||||||
}
|
|
||||||
database.setProfileAvatar(recipient, profileAvatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onShouldRetry(@NonNull Exception e) {
|
|
||||||
if (e instanceof PushNetworkException) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCanceled() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Factory implements Job.Factory<RetrieveProfileAvatarJob> {
|
|
||||||
|
|
||||||
private final Application application;
|
|
||||||
|
|
||||||
public Factory(Application application) {
|
|
||||||
this.application = application;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NonNull RetrieveProfileAvatarJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
|
||||||
return new RetrieveProfileAvatarJob(parameters,
|
|
||||||
Recipient.from(application, Address.fromSerialized(data.getString(KEY_ADDRESS)), true),
|
|
||||||
data.getString(KEY_PROFILE_AVATAR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,99 @@
|
|||||||
|
package org.thoughtcrime.securesms.jobs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.TextUtils
|
||||||
|
import org.session.libsession.avatars.AvatarHelper
|
||||||
|
import org.session.libsession.messaging.jobs.Job
|
||||||
|
import org.session.libsession.messaging.jobs.JobDelegate
|
||||||
|
import org.session.libsession.messaging.utilities.Data
|
||||||
|
import org.session.libsession.utilities.DownloadUtilities.downloadFile
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences.Companion.setProfileAvatarId
|
||||||
|
import org.session.libsession.utilities.Util.copy
|
||||||
|
import org.session.libsession.utilities.Util.equals
|
||||||
|
import org.session.libsession.utilities.Address
|
||||||
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
|
import org.session.libsignal.streams.ProfileCipherInputStream
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.security.SecureRandom
|
||||||
|
|
||||||
|
class RetrieveProfileAvatarJob(val profileAvatar: String, val recipientAddress: Address): Job {
|
||||||
|
override var delegate: JobDelegate? = null
|
||||||
|
override var id: String? = null
|
||||||
|
override var failureCount: Int = 0
|
||||||
|
override val maxFailureCount: Int = 0
|
||||||
|
|
||||||
|
lateinit var context: Context
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val TAG = RetrieveProfileAvatarJob::class.simpleName
|
||||||
|
val KEY: String = "RetrieveProfileAvatarJob"
|
||||||
|
|
||||||
|
// Keys used for database storage
|
||||||
|
private val PROFILE_AVATAR_KEY = "profileAvatar"
|
||||||
|
private val RECEIPIENT_ADDRESS_KEY = "recipient"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun execute(dispatcherName: String) {
|
||||||
|
val recipient = Recipient.from(context, recipientAddress, true)
|
||||||
|
val database = get(context).recipientDatabase()
|
||||||
|
val profileKey = recipient.resolve().profileKey
|
||||||
|
|
||||||
|
if (profileKey == null || (profileKey.size != 32 && profileKey.size != 16)) {
|
||||||
|
Log.w(TAG, "Recipient profile key is gone!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AvatarHelper.avatarFileExists(context, recipient.resolve().address) && equals(profileAvatar, recipient.resolve().profileAvatar)) {
|
||||||
|
Log.w(TAG, "Already retrieved profile avatar: $profileAvatar")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(profileAvatar)) {
|
||||||
|
Log.w(TAG, "Removing profile avatar for: " + recipient.address.serialize())
|
||||||
|
AvatarHelper.delete(context, recipient.address)
|
||||||
|
database.setProfileAvatar(recipient, profileAvatar)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val downloadDestination = File.createTempFile("avatar", ".jpg", context.cacheDir)
|
||||||
|
|
||||||
|
try {
|
||||||
|
downloadFile(downloadDestination, profileAvatar)
|
||||||
|
val avatarStream: InputStream = ProfileCipherInputStream(FileInputStream(downloadDestination), profileKey)
|
||||||
|
val decryptDestination = File.createTempFile("avatar", ".jpg", context.cacheDir)
|
||||||
|
copy(avatarStream, FileOutputStream(decryptDestination))
|
||||||
|
decryptDestination.renameTo(AvatarHelper.getAvatarFile(context, recipient.address))
|
||||||
|
} finally {
|
||||||
|
downloadDestination.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recipient.isLocalNumber) {
|
||||||
|
setProfileAvatarId(context, SecureRandom().nextInt())
|
||||||
|
}
|
||||||
|
database.setProfileAvatar(recipient, profileAvatar)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(): Data {
|
||||||
|
return Data.Builder()
|
||||||
|
.putString(PROFILE_AVATAR_KEY, profileAvatar)
|
||||||
|
.putString(RECEIPIENT_ADDRESS_KEY, recipientAddress.serialize())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFactoryKey(): String {
|
||||||
|
return KEY
|
||||||
|
}
|
||||||
|
|
||||||
|
class Factory: Job.Factory<RetrieveProfileAvatarJob> {
|
||||||
|
override fun create(data: Data): RetrieveProfileAvatarJob {
|
||||||
|
val profileAvatar = data.getString(PROFILE_AVATAR_KEY)
|
||||||
|
val recipientAddress = Address.fromSerialized(data.getString(RECEIPIENT_ADDRESS_KEY))
|
||||||
|
return RetrieveProfileAvatarJob(profileAvatar, recipientAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user