session-android/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java
Moxie Marlinspike 7a5846a6d4 Move more system contact info into recipient database
1) Move contact URI, contact photo URI, and custom label
   into recipient database, so there are no longer any
   contact DB queries during Recipient object loading.

2) Use a SoftHashMap so that any referenced Recipient objects
   can't get kicked out of the cache.

3) Don't load Recipient objects through the provider during sync.
   This was a super expensive thing to do, and blew up the cache.

4) Only apply changes to Recipient objects during sync if they
   are in the cache. Otherwise, there should be no outstanding
   references, and the changes are fine going exclusively to
   the DB.
2017-11-30 10:26:41 -08:00

99 lines
3.3 KiB
Java

package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.inject.Inject;
public class RetrieveProfileAvatarJob extends ContextJob implements InjectableType {
private static final String TAG = RetrieveProfileAvatarJob.class.getSimpleName();
private static final int MAX_PROFILE_SIZE_BYTES = 20 * 1024 * 1024;
@Inject SignalServiceMessageReceiver receiver;
private final String profileAvatar;
private final Recipient recipient;
public RetrieveProfileAvatarJob(Context context, Recipient recipient, String profileAvatar) {
super(context, JobParameters.newBuilder()
.withGroupId(RetrieveProfileAvatarJob.class.getSimpleName() + recipient.getAddress().serialize())
.withRequirement(new NetworkRequirement(context))
.create());
this.recipient = recipient;
this.profileAvatar = profileAvatar;
}
@Override
public void onAdded() {}
@Override
public void onRun() throws IOException {
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
byte[] profileKey = recipient.resolve().getProfileKey();
if (profileKey == null) {
Log.w(TAG, "Recipient profile key is gone!");
return;
}
if (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 {
InputStream avatarStream = receiver.retrieveProfileAvatar(profileAvatar, downloadDestination, profileKey, MAX_PROFILE_SIZE_BYTES);
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();
}
database.setProfileAvatar(recipient, profileAvatar);
}
@Override
public boolean onShouldRetry(Exception e) {
Log.w(TAG, e);
if (e instanceof PushNetworkException) return true;
return false;
}
@Override
public void onCanceled() {
}
}