Fix SMIL regression

Closes #2654

// FREEBIE
This commit is contained in:
Jake McGinty 2015-03-12 13:39:19 -07:00 committed by Moxie Marlinspike
parent 761ccf4b3f
commit 073d019103
9 changed files with 97 additions and 111 deletions

View File

@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.util.Hex; import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.NumberUtil; import org.thoughtcrime.securesms.util.NumberUtil;
import org.thoughtcrime.securesms.util.TelephonyUtil; import org.thoughtcrime.securesms.util.TelephonyUtil;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement; import org.whispersystems.jobqueue.requirements.NetworkRequirement;
@ -98,6 +99,7 @@ public class MmsSendJob extends SendJob {
MmsRadio radio = MmsRadio.getInstance(context); MmsRadio radio = MmsRadio.getInstance(context);
try { try {
prepareMessageMedia(masterSecret, message, MediaConstraints.MMS_CONSTRAINTS, true);
if (isCdmaDevice()) { if (isCdmaDevice()) {
Log.w(TAG, "Sending MMS directly without radio change..."); Log.w(TAG, "Sending MMS directly without radio change...");
try { try {
@ -129,9 +131,9 @@ public class MmsSendJob extends SendJob {
radio.disconnect(); radio.disconnect();
} }
} catch (MmsRadioException mre) { } catch (MmsRadioException | IOException e) {
Log.w(TAG, mre); Log.w(TAG, e);
throw new UndeliverableMessageException(mre); throw new UndeliverableMessageException(e);
} }
} }
@ -141,8 +143,6 @@ public class MmsSendJob extends SendJob {
{ {
String number = TelephonyUtil.getManager(context).getLine1Number(); String number = TelephonyUtil.getManager(context).getLine1Number();
prepareMessageMedia(masterSecret, message, MediaConstraints.MMS_CONSTRAINTS, true);
if (MmsDatabase.Types.isSecureType(message.getDatabaseMessageBox())) { if (MmsDatabase.Types.isSecureType(message.getDatabaseMessageBox())) {
throw new UndeliverableMessageException("Attempt to send encrypted MMS?"); throw new UndeliverableMessageException("Attempt to send encrypted MMS?");
} }
@ -227,6 +227,12 @@ public class MmsSendJob extends SendJob {
} }
} }
@Override
protected void prepareMessageMedia(MasterSecret masterSecret, SendReq message,
MediaConstraints constraints, boolean toMemory)
throws IOException, UndeliverableMessageException {
super.prepareMessageMedia(masterSecret, message, constraints, toMemory);
message.setBody(SmilUtil.getSmilBody(message.getBody()));
}
} }

View File

@ -22,10 +22,6 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.ResUtil; import org.thoughtcrime.securesms.util.ResUtil;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import ws.com.google.android.mms.pdu.PduPart; import ws.com.google.android.mms.pdu.PduPart;
import android.content.Context; import android.content.Context;
@ -55,16 +51,6 @@ public class AudioSlide extends Slide {
return true; return true;
} }
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
return null;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("audio", document, new String(getPart().getName()));
}
@Override @Override
public ListenableFutureTask<Pair<Drawable,Boolean>> getThumbnail(Context context) { public ListenableFutureTask<Pair<Drawable,Boolean>> getThumbnail(Context context) {
return new ListenableFutureTask<>(new Pair<>(ResUtil.getDrawable(context, R.attr.conversation_icon_attach_audio), true)); return new ListenableFutureTask<>(new Pair<>(ResUtil.getDrawable(context, R.attr.conversation_icon_attach_audio), true));

View File

@ -21,7 +21,6 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -31,11 +30,6 @@ import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.LRUCache; import org.thoughtcrime.securesms.util.LRUCache;
import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ResUtil;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import java.io.IOException; import java.io.IOException;
@ -131,23 +125,6 @@ public class ImageSlide extends Slide {
return true; return true;
} }
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
SMILRegionElement region = (SMILRegionElement) document.createElement("region");
region.setId("Image");
region.setLeft(0);
region.setTop(0);
region.setWidth(SmilUtil.ROOT_WIDTH);
region.setHeight(SmilUtil.ROOT_HEIGHT);
region.setFit("meet");
return region;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("img", document, new String(getPart().getName()));
}
private static PduPart constructPartFromUri(Uri uri) private static PduPart constructPartFromUri(Uri uri)
throws IOException, BitmapDecodingException throws IOException, BitmapDecodingException
{ {

View File

@ -9,6 +9,7 @@ import java.io.UnsupportedEncodingException;
import ws.com.google.android.mms.ContentType; import ws.com.google.android.mms.ContentType;
import ws.com.google.android.mms.pdu.CharacterSets; import ws.com.google.android.mms.pdu.CharacterSets;
import ws.com.google.android.mms.pdu.PduBody; import ws.com.google.android.mms.pdu.PduBody;
import ws.com.google.android.mms.pdu.PduPart;
public class PartParser { public class PartParser {
public static String getMessageText(PduBody body) { public static String getMessageText(PduBody body) {
@ -45,7 +46,7 @@ public class PartParser {
PduBody stripped = new PduBody(); PduBody stripped = new PduBody();
for (int i=0;i<body.getPartsNum();i++) { for (int i=0;i<body.getPartsNum();i++) {
if (isDisplayableMedia(Util.toIsoString(body.getPart(i).getContentType()))) { if (isDisplayableMedia(body.getPart(i))) {
stripped.addPart(body.getPart(i)); stripped.addPart(body.getPart(i));
} }
} }
@ -57,9 +58,7 @@ public class PartParser {
int partCount = 0; int partCount = 0;
for (int i=0;i<body.getPartsNum();i++) { for (int i=0;i<body.getPartsNum();i++) {
String contentType = Util.toIsoString(body.getPart(i).getContentType()); if (isDisplayableMedia(body.getPart(i))) {
if (isDisplayableMedia(contentType)) {
partCount++; partCount++;
} }
} }
@ -67,9 +66,23 @@ public class PartParser {
return partCount; return partCount;
} }
private static boolean isDisplayableMedia(String contentType) { public static boolean isImage(PduPart part) {
return ContentType.isImageType(contentType) || return ContentType.isImageType(Util.toIsoString(part.getContentType()));
ContentType.isAudioType(contentType) || }
ContentType.isVideoType(contentType);
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 boolean isText(PduPart part) {
return ContentType.isTextType(Util.toIsoString(part.getContentType()));
}
public static boolean isDisplayableMedia(PduPart part) {
return isImage(part) || isAudio(part) || isVideo(part);
} }
} }

View File

@ -21,9 +21,6 @@ import java.io.InputStream;
import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import android.content.Context; import android.content.Context;
@ -103,10 +100,6 @@ public abstract class Slide {
return part; return part;
} }
public abstract SMILRegionElement getSmilRegion(SMILDocument document);
public abstract SMILMediaElement getMediaElement(SMILDocument document);
protected static void assertMediaSize(Context context, Uri uri) protected static void assertMediaSize(Context context, Uri uri)
throws MediaTooLargeException, IOException throws MediaTooLargeException, IOException
{ {

View File

@ -68,15 +68,6 @@ public class SlideDeck {
body.addPart(slide.getPart()); body.addPart(slide.getPart());
} }
ByteArrayOutputStream out = new ByteArrayOutputStream();
SmilXmlSerializer.serialize(SmilUtil.createSmilDocument(this), out);
PduPart smilPart = new PduPart();
smilPart.setContentId("smil".getBytes());
smilPart.setContentLocation("smil.xml".getBytes());
smilPart.setContentType(ContentType.APP_SMIL.getBytes());
smilPart.setData(out.toByteArray());
body.addPart(0, smilPart);
return body; return body;
} }

View File

@ -80,23 +80,6 @@ public class TextSlide extends Slide {
} }
} }
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
SMILRegionElement region = (SMILRegionElement) document.createElement("region");
region.setId("Text");
region.setLeft(0);
region.setTop(SmilUtil.ROOT_HEIGHT);
region.setWidth(SmilUtil.ROOT_WIDTH);
region.setHeight(50);
region.setFit("meet");
return region;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("text", document, new String(getPart().getName()));
}
private static PduPart getPartForMessage(String message) { private static PduPart getPartForMessage(String message) {
PduPart part = new PduPart(); PduPart part = new PduPart();

View File

@ -22,10 +22,6 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.ResUtil; import org.thoughtcrime.securesms.util.ResUtil;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import ws.com.google.android.mms.pdu.PduPart; import ws.com.google.android.mms.pdu.PduPart;
import android.content.ContentResolver; import android.content.ContentResolver;
@ -62,23 +58,6 @@ public class VideoSlide extends Slide {
return true; return true;
} }
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
SMILRegionElement region = (SMILRegionElement) document.createElement("region");
region.setId("Image");
region.setLeft(0);
region.setTop(0);
region.setWidth(SmilUtil.ROOT_WIDTH);
region.setHeight(SmilUtil.ROOT_HEIGHT);
region.setFit("meet");
return region;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("video", document, new String(getPart().getName()));
}
private static PduPart constructPartFromUri(Context context, Uri uri) private static PduPart constructPartFromUri(Context context, Uri uri)
throws IOException, MediaTooLargeException throws IOException, MediaTooLargeException
{ {

View File

@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.util;
import android.util.Log; import android.util.Log;
import org.thoughtcrime.securesms.dom.smil.SmilDocumentImpl; import org.thoughtcrime.securesms.dom.smil.SmilDocumentImpl;
import org.thoughtcrime.securesms.dom.smil.parser.SmilXmlSerializer;
import org.thoughtcrime.securesms.mms.PartParser;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.SlideDeck;
import org.w3c.dom.smil.SMILDocument; import org.w3c.dom.smil.SMILDocument;
@ -14,14 +16,34 @@ import org.w3c.dom.smil.SMILRegionElement;
import org.w3c.dom.smil.SMILRegionMediaElement; import org.w3c.dom.smil.SMILRegionMediaElement;
import org.w3c.dom.smil.SMILRootLayoutElement; import org.w3c.dom.smil.SMILRootLayoutElement;
import java.io.ByteArrayOutputStream;
import ws.com.google.android.mms.ContentType;
import ws.com.google.android.mms.pdu.PduBody;
import ws.com.google.android.mms.pdu.PduParser;
import ws.com.google.android.mms.pdu.PduPart;
public class SmilUtil { public class SmilUtil {
private static final String TAG = SmilUtil.class.getSimpleName(); private static final String TAG = SmilUtil.class.getSimpleName();
public static final int ROOT_HEIGHT = 1024; public static final int ROOT_HEIGHT = 1024;
public static final int ROOT_WIDTH = 1024; public static final int ROOT_WIDTH = 1024;
public static SMILDocument createSmilDocument(SlideDeck deck) { public static PduBody getSmilBody(PduBody body) {
Log.w(TAG, "Creating SMIL document from SlideDeck."); ByteArrayOutputStream out = new ByteArrayOutputStream();
SmilXmlSerializer.serialize(SmilUtil.createSmilDocument(body), out);
PduPart smilPart = new PduPart();
smilPart.setContentId("smil".getBytes());
smilPart.setContentLocation("smil.xml".getBytes());
smilPart.setContentType(ContentType.APP_SMIL.getBytes());
smilPart.setData(out.toByteArray());
body.addPart(0, smilPart);
return body;
}
private static SMILDocument createSmilDocument(PduBody body) {
Log.w(TAG, "Creating SMIL document from PduBody.");
SMILDocument document = new SmilDocumentImpl(); SMILDocument document = new SmilDocumentImpl();
@ -45,9 +67,10 @@ public class SmilUtil {
SMILParElement par = (SMILParElement) document.createElement("par"); SMILParElement par = (SMILParElement) document.createElement("par");
bodyElement.appendChild(par); bodyElement.appendChild(par);
for (Slide slide : deck.getSlides()) { for (int i=0; i<body.getPartsNum(); i++) {
SMILRegionElement regionElement = slide.getSmilRegion(document); PduPart part = body.getPart(i);
SMILMediaElement mediaElement = slide.getMediaElement(document); SMILRegionElement regionElement = getRegion(document, part);
SMILMediaElement mediaElement = getMediaElement(document, part);
if (regionElement != null) { if (regionElement != null) {
((SMILRegionMediaElement)mediaElement).setRegion(regionElement); ((SMILRegionMediaElement)mediaElement).setRegion(regionElement);
@ -59,7 +82,42 @@ public class SmilUtil {
return document; return document;
} }
public static SMILMediaElement createMediaElement(String tag, SMILDocument document, String src) { private static SMILRegionElement getRegion(SMILDocument document, PduPart part) {
if (PartParser.isAudio(part)) return null;
SMILRegionElement region = (SMILRegionElement) document.createElement("region");
if (PartParser.isText(part)) {
region.setId("Text");
region.setTop(SmilUtil.ROOT_HEIGHT);
region.setHeight(50);
} else {
region.setId("Image");
region.setTop(0);
region.setHeight(SmilUtil.ROOT_HEIGHT);
}
region.setLeft(0);
region.setWidth(SmilUtil.ROOT_WIDTH);
region.setFit("meet");
return region;
}
private static SMILMediaElement getMediaElement(SMILDocument document, PduPart part) {
final String tag;
if (PartParser.isImage(part)) {
tag = "img";
} else if (PartParser.isAudio(part)) {
tag = "audio";
} else if (PartParser.isVideo(part)) {
tag = "video";
} else if (PartParser.isText(part)) {
tag = "text";
} else {
tag = "ref";
}
return createMediaElement(tag, document, new String(part.getName()));
}
private static SMILMediaElement createMediaElement(String tag, SMILDocument document, String src) {
SMILMediaElement mediaElement = (SMILMediaElement) document.createElement(tag); SMILMediaElement mediaElement = (SMILMediaElement) document.createElement(tag);
mediaElement.setSrc(escapeXML(src)); mediaElement.setSrc(escapeXML(src));
return mediaElement; return mediaElement;