mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 16:57:50 +00:00
Check result of bitmap size operation for failure
Fixes #5046 // FREEBIE
This commit is contained in:
parent
1b97756b05
commit
4a261bcf68
@ -21,6 +21,7 @@ import android.util.SparseArray;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
@ -29,7 +30,6 @@ import org.thoughtcrime.securesms.util.Util;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ public class EmojiProvider {
|
|||||||
try {
|
try {
|
||||||
Log.w(TAG, "loading page " + model.getSprite());
|
Log.w(TAG, "loading page " + model.getSprite());
|
||||||
return loadPage();
|
return loadPage();
|
||||||
} catch (IOException | ExecutionException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w(TAG, ioe);
|
Log.w(TAG, ioe);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -242,7 +242,7 @@ public class EmojiProvider {
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap loadPage() throws IOException, ExecutionException {
|
private Bitmap loadPage() throws IOException {
|
||||||
if (bitmapReference != null && bitmapReference.get() != null) return bitmapReference.get();
|
if (bitmapReference != null && bitmapReference.get() != null) return bitmapReference.get();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -252,9 +252,9 @@ public class EmojiProvider {
|
|||||||
bitmapReference = new SoftReference<>(bitmap);
|
bitmapReference = new SoftReference<>(bitmap);
|
||||||
Log.w(TAG, "onPageLoaded(" + model.getSprite() + ")");
|
Log.w(TAG, "onPageLoaded(" + model.getSprite() + ")");
|
||||||
return bitmap;
|
return bitmap;
|
||||||
} catch (ExecutionException e) {
|
} catch (BitmapDecodingException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
throw e;
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase;
|
|||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
|
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel;
|
||||||
import org.thoughtcrime.securesms.push.TextSecurePushTrustStore;
|
import org.thoughtcrime.securesms.push.TextSecurePushTrustStore;
|
||||||
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
@ -63,7 +64,7 @@ public class AvatarDownloadJob extends MasterSecretJob {
|
|||||||
|
|
||||||
database.updateAvatar(groupId, avatar);
|
database.updateAvatar(groupId, avatar);
|
||||||
}
|
}
|
||||||
} catch (ExecutionException | NonSuccessfulResponseCodeException e) {
|
} catch (BitmapDecodingException | NonSuccessfulResponseCodeException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
} finally {
|
} finally {
|
||||||
if (attachment != null)
|
if (attachment != null)
|
||||||
|
@ -10,13 +10,13 @@ import android.util.Pair;
|
|||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||||
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import ws.com.google.android.mms.ContentType;
|
import ws.com.google.android.mms.ContentType;
|
||||||
|
|
||||||
@ -50,10 +50,14 @@ public abstract class MediaConstraints {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isWithinBounds(Context context, MasterSecret masterSecret, Uri uri) throws IOException {
|
public boolean isWithinBounds(Context context, MasterSecret masterSecret, Uri uri) throws IOException {
|
||||||
InputStream is = PartAuthority.getAttachmentStream(context, masterSecret, uri);
|
try {
|
||||||
Pair<Integer, Integer> dimensions = BitmapUtil.getDimensions(is);
|
InputStream is = PartAuthority.getAttachmentStream(context, masterSecret, uri);
|
||||||
return dimensions.first > 0 && dimensions.first <= getImageMaxWidth(context) &&
|
Pair<Integer, Integer> dimensions = BitmapUtil.getDimensions(is);
|
||||||
dimensions.second > 0 && dimensions.second <= getImageMaxHeight(context);
|
return dimensions.first > 0 && dimensions.first <= getImageMaxWidth(context) &&
|
||||||
|
dimensions.second > 0 && dimensions.second <= getImageMaxHeight(context);
|
||||||
|
} catch (BitmapDecodingException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canResize(@Nullable Attachment attachment) {
|
public boolean canResize(@Nullable Attachment attachment) {
|
||||||
@ -73,8 +77,8 @@ public abstract class MediaConstraints {
|
|||||||
// XXX - This is loading everything into memory! We want the send path to be stream-like.
|
// XXX - This is loading everything into memory! We want the send path to be stream-like.
|
||||||
return new MediaStream(new ByteArrayInputStream(BitmapUtil.createScaledBytes(context, new DecryptableUri(masterSecret, attachment.getDataUri()), this)),
|
return new MediaStream(new ByteArrayInputStream(BitmapUtil.createScaledBytes(context, new DecryptableUri(masterSecret, attachment.getDataUri()), this)),
|
||||||
ContentType.IMAGE_JPEG);
|
ContentType.IMAGE_JPEG);
|
||||||
} catch (ExecutionException ee) {
|
} catch (BitmapDecodingException e) {
|
||||||
throw new IOException(ee);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
package org.thoughtcrime.securesms.util;
|
package org.thoughtcrime.securesms.util;
|
||||||
|
|
||||||
public class BitmapDecodingException extends Throwable {
|
public class BitmapDecodingException extends Exception {
|
||||||
|
|
||||||
public BitmapDecodingException(String s) {
|
public BitmapDecodingException(String s) {
|
||||||
super(s);
|
super(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BitmapDecodingException(Exception nested) {
|
||||||
|
super(nested);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,10 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class BitmapUtil {
|
public class BitmapUtil {
|
||||||
|
|
||||||
private static final String TAG = BitmapUtil.class.getSimpleName();
|
private static final String TAG = BitmapUtil.class.getSimpleName();
|
||||||
|
|
||||||
private static final int MAX_COMPRESSION_QUALITY = 80;
|
private static final int MAX_COMPRESSION_QUALITY = 80;
|
||||||
@ -41,7 +41,7 @@ public class BitmapUtil {
|
|||||||
private static final int MAX_COMPRESSION_ATTEMPTS = 4;
|
private static final int MAX_COMPRESSION_ATTEMPTS = 4;
|
||||||
|
|
||||||
public static <T> byte[] createScaledBytes(Context context, T model, MediaConstraints constraints)
|
public static <T> byte[] createScaledBytes(Context context, T model, MediaConstraints constraints)
|
||||||
throws ExecutionException, IOException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
int quality = MAX_COMPRESSION_QUALITY;
|
int quality = MAX_COMPRESSION_QUALITY;
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
@ -62,7 +62,7 @@ public class BitmapUtil {
|
|||||||
}
|
}
|
||||||
while (bytes.length > constraints.getImageMaxSize() && attempts++ < MAX_COMPRESSION_ATTEMPTS);
|
while (bytes.length > constraints.getImageMaxSize() && attempts++ < MAX_COMPRESSION_ATTEMPTS);
|
||||||
if (bytes.length > constraints.getImageMaxSize()) {
|
if (bytes.length > constraints.getImageMaxSize()) {
|
||||||
throw new IOException("Unable to scale image below: " + bytes.length);
|
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)");
|
Log.w(TAG, "createScaledBytes(" + model.toString() + ") -> quality " + Math.min(quality, MAX_COMPRESSION_QUALITY) + ", " + attempts + " attempt(s)");
|
||||||
return bytes;
|
return bytes;
|
||||||
@ -72,7 +72,7 @@ public class BitmapUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Bitmap createScaledBitmap(Context context, T model, int maxWidth, int maxHeight)
|
public static <T> Bitmap createScaledBitmap(Context context, T model, int maxWidth, int maxHeight)
|
||||||
throws ExecutionException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
final Pair<Integer, Integer> dimensions = getDimensions(getInputStreamForModel(context, model));
|
final Pair<Integer, Integer> dimensions = getDimensions(getInputStreamForModel(context, model));
|
||||||
final Pair<Integer, Integer> clamped = clampDimensions(dimensions.first, dimensions.second,
|
final Pair<Integer, Integer> clamped = clampDimensions(dimensions.first, dimensions.second,
|
||||||
@ -81,19 +81,19 @@ public class BitmapUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static <T> InputStream getInputStreamForModel(Context context, T model)
|
private static <T> InputStream getInputStreamForModel(Context context, T model)
|
||||||
throws ExecutionException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return Glide.buildStreamModelLoader(model, context)
|
return Glide.buildStreamModelLoader(model, context)
|
||||||
.getResourceFetcher(model, -1, -1)
|
.getResourceFetcher(model, -1, -1)
|
||||||
.loadData(Priority.NORMAL);
|
.loadData(Priority.NORMAL);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ExecutionException(e);
|
throw new BitmapDecodingException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> Bitmap createScaledBitmapInto(Context context, T model, int width, int height)
|
private static <T> Bitmap createScaledBitmapInto(Context context, T model, int width, int height)
|
||||||
throws ExecutionException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
final Bitmap rough = Downsampler.AT_LEAST.decode(getInputStreamForModel(context, model),
|
final Bitmap rough = Downsampler.AT_LEAST.decode(getInputStreamForModel(context, model),
|
||||||
Glide.get(context).getBitmapPool(),
|
Glide.get(context).getBitmapPool(),
|
||||||
@ -104,20 +104,22 @@ public class BitmapUtil {
|
|||||||
final Resource<Bitmap> result = new FitCenter(context).transform(resource, width, height);
|
final Resource<Bitmap> result = new FitCenter(context).transform(resource, width, height);
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new ExecutionException(new BitmapDecodingException("unable to transform Bitmap"));
|
throw new BitmapDecodingException("unable to transform Bitmap");
|
||||||
}
|
}
|
||||||
return result.get();
|
return result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Bitmap createScaledBitmap(Context context, T model, float scale)
|
public static <T> Bitmap createScaledBitmap(Context context, T model, float scale)
|
||||||
throws ExecutionException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
Pair<Integer, Integer> dimens = getDimensions(getInputStreamForModel(context, model));
|
Pair<Integer, Integer> dimens = getDimensions(getInputStreamForModel(context, model));
|
||||||
return createScaledBitmapInto(context, model,
|
return createScaledBitmapInto(context, model,
|
||||||
(int)(dimens.first * scale), (int)(dimens.second * scale));
|
(int)(dimens.first * scale), (int)(dimens.second * scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitmapFactory.Options getImageDimensions(InputStream inputStream) {
|
private static BitmapFactory.Options getImageDimensions(InputStream inputStream)
|
||||||
|
throws BitmapDecodingException
|
||||||
|
{
|
||||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
options.inJustDecodeBounds = true;
|
options.inJustDecodeBounds = true;
|
||||||
BufferedInputStream fis = new BufferedInputStream(inputStream);
|
BufferedInputStream fis = new BufferedInputStream(inputStream);
|
||||||
@ -127,10 +129,15 @@ public class BitmapUtil {
|
|||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w(TAG, "failed to close the InputStream after reading image dimensions");
|
Log.w(TAG, "failed to close the InputStream after reading image dimensions");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.outWidth == -1 || options.outHeight == -1) {
|
||||||
|
throw new BitmapDecodingException("Failed to decode image dimensions: " + options.outWidth + ", " + options.outHeight);
|
||||||
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pair<Integer, Integer> getDimensions(InputStream inputStream) {
|
public static Pair<Integer, Integer> getDimensions(InputStream inputStream) throws BitmapDecodingException {
|
||||||
BitmapFactory.Options options = getImageDimensions(inputStream);
|
BitmapFactory.Options options = getImageDimensions(inputStream);
|
||||||
return new Pair<>(options.outWidth, options.outHeight);
|
return new Pair<>(options.outWidth, options.outHeight);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ public class MediaUtil {
|
|||||||
private static final String TAG = MediaUtil.class.getSimpleName();
|
private static final String TAG = MediaUtil.class.getSimpleName();
|
||||||
|
|
||||||
public static @Nullable ThumbnailData generateThumbnail(Context context, MasterSecret masterSecret, String contentType, Uri uri)
|
public static @Nullable ThumbnailData generateThumbnail(Context context, MasterSecret masterSecret, String contentType, Uri uri)
|
||||||
throws ExecutionException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
long startMillis = System.currentTimeMillis();
|
long startMillis = System.currentTimeMillis();
|
||||||
ThumbnailData data = null;
|
ThumbnailData data = null;
|
||||||
@ -49,7 +49,7 @@ public class MediaUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Bitmap generateImageThumbnail(Context context, MasterSecret masterSecret, Uri uri)
|
private static Bitmap generateImageThumbnail(Context context, MasterSecret masterSecret, Uri uri)
|
||||||
throws ExecutionException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
int maxSize = context.getResources().getDimensionPixelSize(R.dimen.media_bubble_height);
|
int maxSize = context.getResources().getDimensionPixelSize(R.dimen.media_bubble_height);
|
||||||
return BitmapUtil.createScaledBitmap(context, new DecryptableUri(masterSecret, uri), maxSize, maxSize);
|
return BitmapUtil.createScaledBitmap(context, new DecryptableUri(masterSecret, uri), maxSize, maxSize);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user