mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-03 11:32:19 +00:00
Significant MMS changes
1) Remove all our PDU code and switch to the PDU code from the klinker library 2) Switch to using the system Lollipop MMS library by default, and falling back to our own custom library if that fails. 3) Format SMIL differently, using code from klinker instead of what we've pieced together. 4) Pull per-carrier MMS media constraints from the XML config files in the klinker library, instead of hardcoding it at 280kb. Hopefully this is an improvement, but given that MMS is involved, it will probably make things worse instead.
This commit is contained in:
@@ -72,14 +72,14 @@ public class BitmapUtil {
|
||||
Log.w(TAG, "iteration with quality " + quality + " size " + (bytes.length / 1024) + "kb");
|
||||
if (quality == MIN_COMPRESSION_QUALITY) break;
|
||||
|
||||
int nextQuality = (int)Math.floor(quality * Math.sqrt((double)constraints.getImageMaxSize() / bytes.length));
|
||||
int nextQuality = (int)Math.floor(quality * Math.sqrt((double)constraints.getImageMaxSize(context) / bytes.length));
|
||||
if (quality - nextQuality < MIN_COMPRESSION_QUALITY_DECREASE) {
|
||||
nextQuality = quality - MIN_COMPRESSION_QUALITY_DECREASE;
|
||||
}
|
||||
quality = Math.max(nextQuality, MIN_COMPRESSION_QUALITY);
|
||||
}
|
||||
while (bytes.length > constraints.getImageMaxSize() && attempts++ < MAX_COMPRESSION_ATTEMPTS);
|
||||
if (bytes.length > constraints.getImageMaxSize()) {
|
||||
while (bytes.length > constraints.getImageMaxSize(context) && attempts++ < MAX_COMPRESSION_ATTEMPTS);
|
||||
if (bytes.length > constraints.getImageMaxSize(context)) {
|
||||
throw new BitmapDecodingException("Unable to scale image below: " + bytes.length);
|
||||
}
|
||||
Log.w(TAG, "createScaledBytes(" + model.toString() + ") -> quality " + Math.min(quality, MAX_COMPRESSION_QUALITY) + ", " + attempts + " attempt(s)");
|
||||
|
||||
@@ -31,19 +31,25 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import ws.com.google.android.mms.ContentType;
|
||||
|
||||
public class MediaUtil {
|
||||
|
||||
private static final String TAG = MediaUtil.class.getSimpleName();
|
||||
|
||||
public static final String IMAGE_PNG = "image/png";
|
||||
public static final String IMAGE_JPEG = "image/jpeg";
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
public static final String AUDIO_AAC = "audio/aac";
|
||||
public static final String AUDIO_UNSPECIFIED = "audio/*";
|
||||
public static final String VIDEO_UNSPECIFIED = "video/*";
|
||||
|
||||
|
||||
public static @Nullable ThumbnailData generateThumbnail(Context context, MasterSecret masterSecret, String contentType, Uri uri)
|
||||
throws BitmapDecodingException
|
||||
{
|
||||
long startMillis = System.currentTimeMillis();
|
||||
ThumbnailData data = null;
|
||||
|
||||
if (ContentType.isImageType(contentType)) {
|
||||
if (isImageType(contentType)) {
|
||||
data = new ThumbnailData(generateImageThumbnail(context, masterSecret, uri));
|
||||
}
|
||||
|
||||
@@ -77,11 +83,11 @@ public class MediaUtil {
|
||||
Slide slide = null;
|
||||
if (isGif(attachment.getContentType())) {
|
||||
slide = new GifSlide(context, attachment);
|
||||
} else if (ContentType.isImageType(attachment.getContentType())) {
|
||||
} else if (isImageType(attachment.getContentType())) {
|
||||
slide = new ImageSlide(context, attachment);
|
||||
} else if (ContentType.isVideoType(attachment.getContentType())) {
|
||||
} else if (isVideoType(attachment.getContentType())) {
|
||||
slide = new VideoSlide(context, attachment);
|
||||
} else if (ContentType.isAudioType(attachment.getContentType())) {
|
||||
} else if (isAudioType(attachment.getContentType())) {
|
||||
slide = new AudioSlide(context, attachment);
|
||||
} else if (isMms(attachment.getContentType())) {
|
||||
slide = new MmsSlide(context, attachment);
|
||||
@@ -112,8 +118,8 @@ public class MediaUtil {
|
||||
|
||||
switch(mimeType) {
|
||||
case "image/jpg":
|
||||
return MimeTypeMap.getSingleton().hasMimeType(ContentType.IMAGE_JPEG)
|
||||
? ContentType.IMAGE_JPEG
|
||||
return MimeTypeMap.getSingleton().hasMimeType(IMAGE_JPEG)
|
||||
? IMAGE_JPEG
|
||||
: mimeType;
|
||||
default:
|
||||
return mimeType;
|
||||
@@ -140,34 +146,50 @@ public class MediaUtil {
|
||||
return !TextUtils.isEmpty(contentType) && contentType.trim().equals("application/mms");
|
||||
}
|
||||
|
||||
public static boolean isGif(String contentType) {
|
||||
return !TextUtils.isEmpty(contentType) && contentType.trim().equals("image/gif");
|
||||
}
|
||||
|
||||
public static boolean isGif(Attachment attachment) {
|
||||
return isGif(attachment.getContentType());
|
||||
}
|
||||
|
||||
public static boolean isImage(Attachment attachment) {
|
||||
return ContentType.isImageType(attachment.getContentType());
|
||||
return isImageType(attachment.getContentType());
|
||||
}
|
||||
|
||||
public static boolean isAudio(Attachment attachment) {
|
||||
return ContentType.isAudioType(attachment.getContentType());
|
||||
return isAudioType(attachment.getContentType());
|
||||
}
|
||||
|
||||
public static boolean isVideo(Attachment attachment) {
|
||||
return ContentType.isVideoType(attachment.getContentType());
|
||||
return isVideoType(attachment.getContentType());
|
||||
}
|
||||
|
||||
public static boolean isVideo(String contentType) {
|
||||
return !TextUtils.isEmpty(contentType) && contentType.trim().startsWith("video/");
|
||||
}
|
||||
|
||||
public static boolean isGif(String contentType) {
|
||||
return !TextUtils.isEmpty(contentType) && contentType.trim().equals("image/gif");
|
||||
}
|
||||
|
||||
public static boolean isFile(Attachment attachment) {
|
||||
return !isGif(attachment) && !isImage(attachment) && !isAudio(attachment) && !isVideo(attachment);
|
||||
}
|
||||
|
||||
public static boolean isTextType(String contentType) {
|
||||
return (null != contentType) && contentType.startsWith("text/");
|
||||
}
|
||||
|
||||
public static boolean isImageType(String contentType) {
|
||||
return (null != contentType) && contentType.startsWith("image/");
|
||||
}
|
||||
|
||||
public static boolean isAudioType(String contentType) {
|
||||
return (null != contentType) && contentType.startsWith("audio/");
|
||||
}
|
||||
|
||||
public static boolean isVideoType(String contentType) {
|
||||
return (null != contentType) && contentType.startsWith("video/");
|
||||
}
|
||||
|
||||
public static boolean hasVideoThumbnail(Uri uri) {
|
||||
Log.w(TAG, "Checking: " + uri);
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.dom.smil.SmilDocumentImpl;
|
||||
import org.thoughtcrime.securesms.dom.smil.parser.SmilXmlSerializer;
|
||||
import org.thoughtcrime.securesms.mms.PartParser;
|
||||
import org.w3c.dom.smil.SMILDocument;
|
||||
import org.w3c.dom.smil.SMILElement;
|
||||
import org.w3c.dom.smil.SMILLayoutElement;
|
||||
import org.w3c.dom.smil.SMILMediaElement;
|
||||
import org.w3c.dom.smil.SMILParElement;
|
||||
import org.w3c.dom.smil.SMILRegionElement;
|
||||
import org.w3c.dom.smil.SMILRegionMediaElement;
|
||||
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.PduPart;
|
||||
|
||||
public class SmilUtil {
|
||||
private static final String TAG = SmilUtil.class.getSimpleName();
|
||||
|
||||
public static final int ROOT_HEIGHT = 1024;
|
||||
public static final int ROOT_WIDTH = 1024;
|
||||
|
||||
public static PduBody getSmilBody(PduBody body) {
|
||||
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();
|
||||
|
||||
SMILElement smilElement = (SMILElement) document.createElement("smil");
|
||||
document.appendChild(smilElement);
|
||||
|
||||
SMILElement headElement = (SMILElement) document.createElement("head");
|
||||
smilElement.appendChild(headElement);
|
||||
|
||||
SMILLayoutElement layoutElement = (SMILLayoutElement) document.createElement("layout");
|
||||
headElement.appendChild(layoutElement);
|
||||
|
||||
SMILRootLayoutElement rootLayoutElement = (SMILRootLayoutElement) document.createElement("root-layout");
|
||||
rootLayoutElement.setWidth(ROOT_WIDTH);
|
||||
rootLayoutElement.setHeight(ROOT_HEIGHT);
|
||||
layoutElement.appendChild(rootLayoutElement);
|
||||
|
||||
SMILElement bodyElement = (SMILElement) document.createElement("body");
|
||||
smilElement.appendChild(bodyElement);
|
||||
|
||||
SMILParElement par = (SMILParElement) document.createElement("par");
|
||||
bodyElement.appendChild(par);
|
||||
|
||||
for (int i=0; i<body.getPartsNum(); i++) {
|
||||
PduPart part = body.getPart(i);
|
||||
SMILRegionElement regionElement = getRegion(document, part);
|
||||
SMILMediaElement mediaElement = getMediaElement(document, part);
|
||||
|
||||
if (regionElement != null) {
|
||||
((SMILRegionMediaElement)mediaElement).setRegion(regionElement);
|
||||
layoutElement.appendChild(regionElement);
|
||||
}
|
||||
par.appendChild(mediaElement);
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
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() == null
|
||||
? new byte[]{}
|
||||
: part.getName()));
|
||||
}
|
||||
|
||||
private static SMILMediaElement createMediaElement(String tag, SMILDocument document, String src) {
|
||||
SMILMediaElement mediaElement = (SMILMediaElement) document.createElement(tag);
|
||||
mediaElement.setSrc(escapeXML(src));
|
||||
return mediaElement;
|
||||
}
|
||||
|
||||
private static String escapeXML(String str) {
|
||||
return str.replaceAll("&","&")
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll("\"", """)
|
||||
.replaceAll("'", "'");
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,8 @@ import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.google.android.mms.pdu_alt.CharacterSets;
|
||||
import com.google.android.mms.pdu_alt.EncodedStringValue;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
@@ -65,9 +67,6 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ws.com.google.android.mms.pdu.CharacterSets;
|
||||
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
||||
|
||||
public class Util {
|
||||
private static final String TAG = Util.class.getSimpleName();
|
||||
|
||||
|
||||
@@ -6,11 +6,15 @@ import android.support.annotation.Nullable;
|
||||
public class SubscriptionInfoCompat {
|
||||
|
||||
private final int subscriptionId;
|
||||
private final int mcc;
|
||||
private final int mnc;
|
||||
private final @Nullable CharSequence displayName;
|
||||
|
||||
public SubscriptionInfoCompat(int subscriptionId, @Nullable CharSequence displayName) {
|
||||
public SubscriptionInfoCompat(int subscriptionId, @Nullable CharSequence displayName, int mcc, int mnc) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.displayName = displayName;
|
||||
this.mcc = mcc;
|
||||
this.mnc = mnc;
|
||||
}
|
||||
|
||||
public @NonNull CharSequence getDisplayName() {
|
||||
@@ -20,4 +24,12 @@ public class SubscriptionInfoCompat {
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public int getMnc() {
|
||||
return mnc;
|
||||
}
|
||||
|
||||
public int getMcc() {
|
||||
return mcc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ public class SubscriptionManagerCompat {
|
||||
SubscriptionInfo subscriptionInfo = SubscriptionManager.from(context).getActiveSubscriptionInfo(subscriptionId);
|
||||
|
||||
if (subscriptionInfo != null) {
|
||||
return Optional.of(new SubscriptionInfoCompat(subscriptionId, subscriptionInfo.getDisplayName()));
|
||||
return Optional.of(new SubscriptionInfoCompat(subscriptionId, subscriptionInfo.getDisplayName(),
|
||||
subscriptionInfo.getMcc(), subscriptionInfo.getMnc()));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
@@ -56,7 +57,9 @@ public class SubscriptionManagerCompat {
|
||||
|
||||
for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
|
||||
compatList.add(new SubscriptionInfoCompat(subscriptionInfo.getSubscriptionId(),
|
||||
subscriptionInfo.getDisplayName()));
|
||||
subscriptionInfo.getDisplayName(),
|
||||
subscriptionInfo.getMcc(),
|
||||
subscriptionInfo.getMnc()));
|
||||
}
|
||||
|
||||
return compatList;
|
||||
|
||||
Reference in New Issue
Block a user