media constraints model

// FREEBIE
This commit is contained in:
Jake McGinty
2015-01-02 15:43:28 -08:00
committed by Moxie Marlinspike
parent a0ed0842a0
commit b25b95f933
15 changed files with 294 additions and 48 deletions

View File

@@ -12,11 +12,11 @@ import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.MmsRadio;
import org.thoughtcrime.securesms.mms.MmsRadioException;
import org.thoughtcrime.securesms.mms.MmsSendResult;
import org.thoughtcrime.securesms.mms.OutgoingMmsConnection;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.Recipients;
@@ -24,21 +24,17 @@ import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.NumberUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.libaxolotl.NoSessionException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import ws.com.google.android.mms.MmsException;
import ws.com.google.android.mms.pdu.EncodedStringValue;
import ws.com.google.android.mms.pdu.PduBody;
import ws.com.google.android.mms.pdu.PduComposer;
import ws.com.google.android.mms.pdu.PduHeaders;
import ws.com.google.android.mms.pdu.PduPart;
import ws.com.google.android.mms.pdu.SendConf;
import ws.com.google.android.mms.pdu.SendReq;
@@ -69,8 +65,6 @@ public class MmsSendJob extends SendJob {
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
SendReq message = database.getOutgoingMessage(masterSecret, messageId);
populatePartData(message.getBody(), masterSecret);
try {
MmsSendResult result = deliver(masterSecret, message);
@@ -101,24 +95,6 @@ public class MmsSendJob extends SendJob {
notifyMediaMessageDeliveryFailed(context, messageId);
}
private void populatePartData(PduPart part, MasterSecret masterSecret) throws IOException {
if (part.getDataUri() == null) {
return;
}
ByteArrayOutputStream os = part.getDataSize() > 0 && part.getDataSize() < Integer.MAX_VALUE
? new ByteArrayOutputStream((int)part.getDataSize())
: new ByteArrayOutputStream();
Util.copy(PartAuthority.getPartStream(context, masterSecret, part.getDataUri()), os);
part.setData(os.toByteArray());
}
private void populatePartData(PduBody body, MasterSecret masterSecret) throws IOException {
for (int i=body.getPartsNum()-1; i>=0; i--) {
populatePartData(body.getPart(i), masterSecret);
}
}
public MmsSendResult deliver(MasterSecret masterSecret, SendReq message)
throws UndeliverableMessageException, InsecureFallbackApprovalException
{
@@ -182,13 +158,11 @@ public class MmsSendJob extends SendJob {
message.setFrom(new EncodedStringValue(number));
}
prepareMessageMedia(masterSecret, message, MediaConstraints.MMS_CONSTRAINTS, true);
try {
OutgoingMmsConnection connection = new OutgoingMmsConnection(context, radio.getApnInformation(), new PduComposer(context, message).make());
SendConf conf = connection.send(usingMmsRadio, useProxy);
for (int i=0;i<message.getBody().getPartsNum();i++) {
Log.w(TAG, "Sent MMS part of content-type: " + new String(message.getBody().getPart(i).getContentType()));
}
SendConf conf = connection.send(usingMmsRadio, useProxy);
if (conf == null) {
throw new UndeliverableMessageException("No M-Send.conf received in response to send.");

View File

@@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.PartParser;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
@@ -19,6 +20,7 @@ import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.transport.SecureFallbackApprovalException;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.whispersystems.libaxolotl.state.AxolotlStore;
import org.whispersystems.textsecure.api.TextSecureMessageSender;
import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException;
@@ -58,7 +60,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
@Override
public void onSend(MasterSecret masterSecret)
throws RetryLaterException, MmsException, NoSuchMessageException
throws RetryLaterException, MmsException, NoSuchMessageException, UndeliverableMessageException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
SendReq message = database.getOutgoingMessage(masterSecret, messageId);
@@ -99,7 +101,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
private boolean deliver(MasterSecret masterSecret, SendReq message)
throws RetryLaterException, SecureFallbackApprovalException,
InsecureFallbackApprovalException, UntrustedIdentityException
InsecureFallbackApprovalException, UntrustedIdentityException,
UndeliverableMessageException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
TextSecureMessageSender messageSender = messageSenderFactory.create(masterSecret);
@@ -107,6 +110,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
boolean isSmsFallbackSupported = isSmsFallbackSupported(context, destination, true);
try {
prepareMessageMedia(masterSecret, message, MediaConstraints.PUSH_CONSTRAINTS, false);
Recipients recipients = RecipientFactory.getRecipientsFromString(context, destination, false);
PushAddress address = getPushAddress(recipients.getPrimaryRecipient());
List<TextSecureAttachment> attachments = getAttachments(masterSecret, message);

View File

@@ -6,7 +6,10 @@ import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.MmsMediaConstraints;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.PushMediaConstraints;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
@@ -21,7 +24,6 @@ import org.thoughtcrime.securesms.database.TextSecureDirectory;
import org.whispersystems.textsecure.api.push.PushAddress;
import org.whispersystems.textsecure.api.util.InvalidNumberException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;

View File

@@ -1,14 +1,27 @@
package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.util.Log;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.TextSecureExpiredException;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import ws.com.google.android.mms.MmsException;
import ws.com.google.android.mms.pdu.PduPart;
import ws.com.google.android.mms.pdu.SendReq;
public abstract class SendJob extends MasterSecretJob {
private final static String TAG = SendJob.class.getSimpleName();
public SendJob(Context context, JobParameters parameters) {
super(context, parameters);
@@ -26,4 +39,54 @@ public abstract class SendJob extends MasterSecretJob {
}
protected abstract void onSend(MasterSecret masterSecret) throws Exception;
protected void prepareMessageMedia(MasterSecret masterSecret, SendReq message,
MediaConstraints constraints, boolean toMemory)
throws IOException, UndeliverableMessageException
{
try {
for (int i = 0; i < message.getBody().getPartsNum(); i++) {
preparePart(masterSecret, constraints, message.getBody().getPart(i), toMemory);
}
} catch (MmsException me) {
throw new UndeliverableMessageException(me);
}
}
private void preparePart(MasterSecret masterSecret, MediaConstraints constraints,
PduPart part, boolean toMemory)
throws IOException, MmsException, UndeliverableMessageException
{
byte[] resizedData = null;
if (!constraints.isSatisfied(context, masterSecret, part)) {
if (!constraints.canResize(part)) {
throw new UndeliverableMessageException("Size constraints could not be satisfied.");
}
resizedData = resizePart(masterSecret, constraints, part);
}
if (toMemory) {
part.setData(resizedData != null ? resizedData : MediaUtil.getPartData(context, masterSecret, part));
}
if (resizedData != null) {
part.setDataSize(resizedData.length);
}
}
private byte[] resizePart(MasterSecret masterSecret, MediaConstraints constraints,
PduPart part)
throws IOException, MmsException
{
Log.w(TAG, "resizing part " + part.getId());
final long oldSize = part.getDataSize();
final byte[] data = constraints.getResizedMedia(context, masterSecret, part);
DatabaseFactory.getPartDatabase(context).updatePartData(masterSecret, part, new ByteArrayInputStream(data));
Log.w(TAG, String.format("Resized part %.1fkb => %.1fkb", oldSize / 1024.0, part.getDataSize() / 1024.0));
return data;
}
}