mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-28 18:57:43 +00:00
media constraints model
// FREEBIE
This commit is contained in:
parent
a0ed0842a0
commit
b25b95f933
@ -73,6 +73,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
||||
import org.thoughtcrime.securesms.mms.AttachmentTypeSelectorAdapter;
|
||||
import org.thoughtcrime.securesms.mms.MediaTooLargeException;
|
||||
import org.thoughtcrime.securesms.mms.MmsMediaConstraints;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMmsConnection;
|
||||
@ -848,8 +849,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
Log.w("ComposeMessageActivity", e);
|
||||
} catch (MediaTooLargeException e) {
|
||||
attachmentManager.clear();
|
||||
|
||||
Toast.makeText(this, getString(R.string.ConversationActivity_sorry_the_selected_video_exceeds_message_size_restrictions,
|
||||
(Slide.MAX_MESSAGE_SIZE/1024)),
|
||||
(MmsMediaConstraints.MAX_MESSAGE_SIZE/1024)),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.w("ComposeMessageActivity", e);
|
||||
}
|
||||
@ -866,7 +868,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
} catch (MediaTooLargeException e) {
|
||||
attachmentManager.clear();
|
||||
Toast.makeText(this, getString(R.string.ConversationActivity_sorry_the_selected_audio_exceeds_message_size_restrictions,
|
||||
(Slide.MAX_MESSAGE_SIZE/1024)),
|
||||
(MmsMediaConstraints.MAX_MESSAGE_SIZE/1024)),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.w("ComposeMessageActivity", e);
|
||||
}
|
||||
|
@ -461,6 +461,38 @@ public class PartDatabase extends Database {
|
||||
notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId));
|
||||
}
|
||||
|
||||
public void updatePartData(MasterSecret masterSecret, PduPart part, InputStream data)
|
||||
throws MmsException
|
||||
{
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
Pair<File, Long> partData = writePartData(masterSecret, part, data);
|
||||
|
||||
if (partData == null) throw new MmsException("couldn't update part data");
|
||||
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[]{DATA}, ID_WHERE,
|
||||
new String[]{part.getId()+""}, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int dataColumn = cursor.getColumnIndexOrThrow(DATA);
|
||||
if (!cursor.isNull(dataColumn) && !new File(cursor.getString(dataColumn)).delete()) {
|
||||
Log.w(TAG, "Couldn't delete old part file");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
ContentValues values = new ContentValues(2);
|
||||
values.put(DATA, partData.first.getAbsolutePath());
|
||||
values.put(SIZE, partData.second);
|
||||
|
||||
part.setDataSize(partData.second);
|
||||
|
||||
database.update(TABLE_NAME, values, ID_WHERE, new String[] {part.getId()+""});
|
||||
Log.w(TAG, "updated data for part #" + part.getId());
|
||||
}
|
||||
|
||||
public void updatePartThumbnail(MasterSecret masterSecret, long partId, PduPart part, InputStream in, float aspectRatio)
|
||||
throws MmsException
|
||||
{
|
||||
|
@ -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.");
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
72
src/org/thoughtcrime/securesms/mms/MediaConstraints.java
Normal file
72
src/org/thoughtcrime/securesms/mms/MediaConstraints.java
Normal file
@ -0,0 +1,72 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
|
||||
public abstract class MediaConstraints {
|
||||
private static final String TAG = MediaConstraints.class.getSimpleName();
|
||||
|
||||
public static MediaConstraints MMS_CONSTRAINTS = new MmsMediaConstraints();
|
||||
public static MediaConstraints PUSH_CONSTRAINTS = new PushMediaConstraints();
|
||||
|
||||
public abstract int getImageMaxWidth();
|
||||
public abstract int getImageMaxHeight();
|
||||
public abstract int getImageMaxSize();
|
||||
|
||||
public abstract int getVideoMaxSize();
|
||||
|
||||
public abstract int getAudioMaxSize();
|
||||
|
||||
public boolean isSatisfied(Context context, MasterSecret masterSecret, PduPart part) {
|
||||
try {
|
||||
return (MediaUtil.isImage(part) && part.getDataSize() <= getImageMaxSize() && isWithinBounds(context, masterSecret, part.getDataUri())) ||
|
||||
(MediaUtil.isAudio(part) && part.getDataSize() <= getAudioMaxSize()) ||
|
||||
(MediaUtil.isVideo(part) && part.getDataSize() <= getVideoMaxSize()) ||
|
||||
(!MediaUtil.isImage(part) && !MediaUtil.isAudio(part) && !MediaUtil.isVideo(part));
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, "Failed to determine if media's constraints are satisfied.", ioe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWithinBounds(Context context, MasterSecret masterSecret, Uri uri) throws IOException {
|
||||
InputStream is = PartAuthority.getPartStream(context, masterSecret, uri);
|
||||
Pair<Integer, Integer> dimensions = BitmapUtil.getDimensions(is);
|
||||
return dimensions.first > 0 && dimensions.first <= getImageMaxWidth() &&
|
||||
dimensions.second > 0 && dimensions.second <= getImageMaxHeight();
|
||||
}
|
||||
|
||||
public boolean canResize(PduPart part) {
|
||||
return part != null && MediaUtil.isImage(part);
|
||||
}
|
||||
|
||||
public byte[] getResizedMedia(Context context, MasterSecret masterSecret, PduPart part)
|
||||
throws IOException
|
||||
{
|
||||
if (!canResize(part) || part.getDataUri() == null) {
|
||||
throw new UnsupportedOperationException("Cannot resize this content type");
|
||||
}
|
||||
|
||||
try {
|
||||
return BitmapUtil.createScaledBytes(context, masterSecret, part.getDataUri(),
|
||||
getImageMaxWidth(),
|
||||
getImageMaxHeight(),
|
||||
getImageMaxSize());
|
||||
} catch (BitmapDecodingException bde) {
|
||||
throw new IOException(bde);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
31
src/org/thoughtcrime/securesms/mms/MmsMediaConstraints.java
Normal file
31
src/org/thoughtcrime/securesms/mms/MmsMediaConstraints.java
Normal file
@ -0,0 +1,31 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
public class MmsMediaConstraints extends MediaConstraints {
|
||||
private static final int MAX_IMAGE_DIMEN = 1280;
|
||||
public static final int MAX_MESSAGE_SIZE = 280 * 1024;
|
||||
|
||||
@Override
|
||||
public int getImageMaxWidth() {
|
||||
return MAX_IMAGE_DIMEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxHeight() {
|
||||
return MAX_IMAGE_DIMEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxSize() {
|
||||
return MAX_MESSAGE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVideoMaxSize() {
|
||||
return MAX_MESSAGE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAudioMaxSize() {
|
||||
return MAX_MESSAGE_SIZE;
|
||||
}
|
||||
}
|
32
src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java
Normal file
32
src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java
Normal file
@ -0,0 +1,32 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
public class PushMediaConstraints extends MediaConstraints {
|
||||
private static final int MAX_IMAGE_DIMEN = 1280;
|
||||
private static final int KB = 1024;
|
||||
private static final int MB = 1024 * KB;
|
||||
|
||||
@Override
|
||||
public int getImageMaxWidth() {
|
||||
return MAX_IMAGE_DIMEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxHeight() {
|
||||
return MAX_IMAGE_DIMEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageMaxSize() {
|
||||
return 300 * KB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVideoMaxSize() {
|
||||
return MmsMediaConstraints.MAX_MESSAGE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAudioMaxSize() {
|
||||
return MmsMediaConstraints.MAX_MESSAGE_SIZE;
|
||||
}
|
||||
}
|
@ -36,8 +36,6 @@ import ws.com.google.android.mms.pdu.PduPart;
|
||||
|
||||
public abstract class Slide {
|
||||
|
||||
public static final int MAX_MESSAGE_SIZE = 280 * 1024;
|
||||
|
||||
protected final PduPart part;
|
||||
protected final Context context;
|
||||
protected MasterSecret masterSecret;
|
||||
@ -124,7 +122,7 @@ public abstract class Slide {
|
||||
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
size += read;
|
||||
if (size > MAX_MESSAGE_SIZE) throw new MediaTooLargeException("Media exceeds maximum message size.");
|
||||
if (size > MmsMediaConstraints.MAX_MESSAGE_SIZE) throw new MediaTooLargeException("Media exceeds maximum message size.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,10 +75,12 @@ public class VideoSlide extends Slide {
|
||||
return SmilUtil.createMediaElement("video", document, new String(getPart().getName()));
|
||||
}
|
||||
|
||||
private static PduPart constructPartFromUri(Context context, Uri uri) throws IOException, MediaTooLargeException {
|
||||
PduPart part = new PduPart();
|
||||
private static PduPart constructPartFromUri(Context context, Uri uri)
|
||||
throws IOException, MediaTooLargeException
|
||||
{
|
||||
PduPart part = new PduPart();
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor cursor = null;
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = resolver.query(uri, new String[] {MediaStore.Video.Media.MIME_TYPE}, null, null, null);
|
||||
|
@ -1,6 +1,6 @@
|
||||
package org.thoughtcrime.securesms.transport;
|
||||
|
||||
public class UndeliverableMessageException extends Throwable {
|
||||
public class UndeliverableMessageException extends Exception {
|
||||
public UndeliverableMessageException() {
|
||||
}
|
||||
|
||||
|
@ -6,13 +6,10 @@ import android.graphics.Bitmap.CompressFormat;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@ -29,9 +26,6 @@ import java.io.InputStream;
|
||||
|
||||
import com.android.gallery3d.data.Exif;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
|
||||
public class BitmapUtil {
|
||||
private static final String TAG = BitmapUtil.class.getSimpleName();
|
||||
|
||||
@ -61,6 +55,8 @@ public class BitmapUtil {
|
||||
quality = Math.max((quality * maxSize) / baos.size(), MIN_COMPRESSION_QUALITY);
|
||||
} while (baos.size() > maxSize && attempts++ < MAX_COMPRESSION_ATTEMPTS);
|
||||
|
||||
Log.w(TAG, "createScaledBytes(" + uri + ") -> quality " + Math.min(quality, MAX_COMPRESSION_QUALITY) + ", " + attempts + " attempt(s)");
|
||||
|
||||
bitmap.recycle();
|
||||
|
||||
if (baos.size() <= maxSize) return baos.toByteArray();
|
||||
@ -216,6 +212,11 @@ public class BitmapUtil {
|
||||
return options;
|
||||
}
|
||||
|
||||
public static Pair<Integer, Integer> getDimensions(InputStream inputStream) {
|
||||
BitmapFactory.Options options = getImageDimensions(inputStream);
|
||||
return new Pair<>(options.outWidth, options.outHeight);
|
||||
}
|
||||
|
||||
public static Bitmap getCircleCroppedBitmap(Bitmap bitmap) {
|
||||
if (bitmap == null) return null;
|
||||
final int srcSize = Math.min(bitmap.getWidth(), bitmap.getHeight());
|
||||
|
@ -9,7 +9,12 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.PartDatabase;
|
||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -18,6 +23,7 @@ import java.util.concurrent.Callable;
|
||||
import ws.com.google.android.mms.ContentType;
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
import ws.com.google.android.mms.pdu.SendReq;
|
||||
|
||||
public class MediaUtil {
|
||||
private static final String TAG = MediaUtil.class.getSimpleName();
|
||||
@ -39,6 +45,16 @@ public class MediaUtil {
|
||||
return data;
|
||||
}
|
||||
|
||||
public static byte[] getPartData(Context context, MasterSecret masterSecret, PduPart part)
|
||||
throws IOException
|
||||
{
|
||||
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);
|
||||
return os.toByteArray();
|
||||
}
|
||||
|
||||
private static Bitmap generateImageThumbnail(Context context, MasterSecret masterSecret, Uri uri)
|
||||
throws IOException, BitmapDecodingException, OutOfMemoryError
|
||||
{
|
||||
@ -46,6 +62,18 @@ public class MediaUtil {
|
||||
return BitmapUtil.createScaledBitmap(context, masterSecret, uri, maxSize, maxSize);
|
||||
}
|
||||
|
||||
public static boolean isImage(PduPart part) {
|
||||
return ContentType.isImageType(Util.toIsoString(part.getContentType()));
|
||||
}
|
||||
|
||||
public static boolean isAudio(PduPart part) {
|
||||
return ContentType.isAudioType(Util.toIsoString(part.getContentType()));
|
||||
}
|
||||
|
||||
public static boolean isVideo(PduPart part) {
|
||||
return ContentType.isVideoType(Util.toIsoString(part.getContentType()));
|
||||
}
|
||||
|
||||
public static class ThumbnailData {
|
||||
Bitmap bitmap;
|
||||
float aspectRatio;
|
||||
|
@ -20,8 +20,13 @@ package ws.com.google.android.mms.pdu;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user