Signal-Android/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java
Moxie Marlinspike d3271f548c Support for retrieving stored messages via websocket.
1) When registering with server, indicate that the server should
   store messages and send notifications.

2) Process notification GCM messages, and connect to the server
   to retrieve actual message content.
2015-02-18 11:09:01 -08:00

116 lines
4.5 KiB
Java

package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import org.thoughtcrime.securesms.Release;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.push.TextSecurePushTrustStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.api.crypto.AttachmentCipherInputStream;
import org.whispersystems.textsecure.internal.push.PushServiceSocket;
import org.whispersystems.textsecure.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.textsecure.internal.util.StaticCredentialsProvider;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class AvatarDownloadJob extends MasterSecretJob {
private static final String TAG = AvatarDownloadJob.class.getSimpleName();
private final byte[] groupId;
public AvatarDownloadJob(Context context, byte[] groupId) {
super(context, JobParameters.newBuilder()
.withRequirement(new MasterSecretRequirement(context))
.withRequirement(new NetworkRequirement(context))
.withPersistence()
.create());
this.groupId = groupId;
}
@Override
public void onAdded() {}
@Override
public void onRun(MasterSecret masterSecret) throws IOException {
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
GroupDatabase.GroupRecord record = database.getGroup(groupId);
File attachment = null;
try {
if (record != null) {
long avatarId = record.getAvatarId();
byte[] key = record.getAvatarKey();
String relay = record.getRelay();
if (avatarId == -1 || key == null) {
return;
}
attachment = downloadAttachment(relay, avatarId);
InputStream scaleInputStream = new AttachmentCipherInputStream(attachment, key);
InputStream measureInputStream = new AttachmentCipherInputStream(attachment, key);
Bitmap avatar = BitmapUtil.createScaledBitmap(measureInputStream, scaleInputStream, 500, 500);
database.updateAvatar(groupId, avatar);
try {
Recipient groupRecipient = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(groupId), true)
.getPrimaryRecipient();
groupRecipient.setContactPhoto(avatar);
} catch (RecipientFormattingException e) {
Log.w("AvatarDownloader", e);
}
}
} catch (InvalidMessageException | BitmapDecodingException | NonSuccessfulResponseCodeException e) {
Log.w(TAG, e);
} finally {
if (attachment != null)
attachment.delete();
}
}
@Override
public void onCanceled() {}
@Override
public boolean onShouldRetryThrowable(Exception exception) {
if (exception instanceof IOException) return true;
return false;
}
private File downloadAttachment(String relay, long contentLocation) throws IOException {
PushServiceSocket socket = new PushServiceSocket(Release.PUSH_URL,
new TextSecurePushTrustStore(context),
new StaticCredentialsProvider(TextSecurePreferences.getLocalNumber(context),
TextSecurePreferences.getPushServerPassword(context),
null));
File destination = File.createTempFile("avatar", "tmp");
destination.deleteOnExit();
socket.retrieveAttachment(relay, contentLocation, destination);
return destination;
}
}