ditch RoundedImageView, make animated gifs work

// FREEBIE
This commit is contained in:
Jake McGinty
2015-07-15 13:42:59 -07:00
committed by Moxie Marlinspike
parent a66dd8be82
commit f13ad54ba1
19 changed files with 231 additions and 66 deletions

View File

@@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.providers.CaptureProvider;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.MediaUtil;
import java.io.IOException;
@@ -68,22 +69,14 @@ public class AttachmentManager {
AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
animation.setDuration(200);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
@Override public void onAnimationStart(Animation animation) {}
@Override public void onAnimationRepeat(Animation animation) {}
@Override public void onAnimationEnd(Animation animation) {
slideDeck.clear();
attachmentView.setVisibility(View.GONE);
attachmentListener.onAttachmentChanged();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
attachmentView.startAnimation(animation);
@@ -95,7 +88,11 @@ public class AttachmentManager {
}
public void setImage(MasterSecret masterSecret, Uri image) throws IOException, BitmapDecodingException {
setMedia(new ImageSlide(context, masterSecret, image), masterSecret);
if (MediaUtil.getMimeType(context, image).startsWith("image/gif")) {
setMedia(new GifSlide(context, masterSecret, image), masterSecret);
} else {
setMedia(new ImageSlide(context, masterSecret, image), masterSecret);
}
}
public void setVideo(Uri video) throws IOException, MediaTooLargeException {
@@ -148,7 +145,6 @@ public class AttachmentManager {
return captureUri;
}
public void setCaptureUri(Uri captureUri) {
this.captureUri = captureUri;
}

View File

@@ -0,0 +1,27 @@
package org.thoughtcrime.securesms.mms;
import android.content.Context;
import android.net.Uri;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import java.io.IOException;
import ws.com.google.android.mms.pdu.PduPart;
public class GifSlide extends ImageSlide {
public GifSlide(Context context, MasterSecret masterSecret, PduPart part) {
super(context, masterSecret, part);
}
public GifSlide(Context context, MasterSecret masterSecret, Uri uri)
throws IOException, BitmapDecodingException
{
super(context, masterSecret, uri);
}
@Override public Uri getThumbnailUri() {
return getPart().getDataUri();
}
}

View File

@@ -24,6 +24,7 @@ import android.support.annotation.DrawableRes;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.MediaUtil;
import java.io.IOException;
@@ -38,7 +39,7 @@ public class ImageSlide extends Slide {
}
public ImageSlide(Context context, MasterSecret masterSecret, Uri uri) throws IOException, BitmapDecodingException {
super(context, masterSecret, constructPartFromUri(uri));
super(context, masterSecret, constructPartFromUri(context, uri));
}
@Override
@@ -62,13 +63,15 @@ public class ImageSlide extends Slide {
return true;
}
private static PduPart constructPartFromUri(Uri uri)
private static PduPart constructPartFromUri(Context context, Uri uri)
throws IOException, BitmapDecodingException
{
PduPart part = new PduPart();
final String mimeType = MediaUtil.getMimeType(context, uri);
part.setDataUri(uri);
part.setContentType(ContentType.IMAGE_JPEG.getBytes());
part.setContentType((mimeType != null ? mimeType : ContentType.IMAGE_JPEG).getBytes());
part.setContentId((System.currentTimeMillis()+"").getBytes());
part.setName(("Image" + System.currentTimeMillis()).getBytes());

View File

@@ -25,15 +25,18 @@ public abstract class MediaConstraints {
public abstract int getImageMaxHeight(Context context);
public abstract int getImageMaxSize();
public abstract int getGifMaxSize();
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()) ||
return (MediaUtil.isGif(part) && part.getDataSize() <= getGifMaxSize()) ||
(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);
@@ -49,7 +52,7 @@ public abstract class MediaConstraints {
}
public boolean canResize(PduPart part) {
return part != null && MediaUtil.isImage(part);
return part != null && MediaUtil.isImage(part) && !MediaUtil.isGif(part);
}
public byte[] getResizedMedia(Context context, MasterSecret masterSecret, PduPart part)

View File

@@ -24,6 +24,11 @@ public class MmsMediaConstraints extends MediaConstraints {
return MAX_MESSAGE_SIZE;
}
@Override
public int getGifMaxSize() {
return MAX_MESSAGE_SIZE;
}
@Override
public int getVideoMaxSize() {
return MAX_MESSAGE_SIZE;

View File

@@ -25,6 +25,11 @@ public class PushMediaConstraints extends MediaConstraints {
return 420 * KB;
}
@Override
public int getGifMaxSize() {
return 1 * MB;
}
@Override
public int getVideoMaxSize() {
return MmsMediaConstraints.MAX_MESSAGE_SIZE;

View File

@@ -0,0 +1,88 @@
package org.thoughtcrime.securesms.mms;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.bumptech.glide.load.resource.bitmap.TransformationUtils;
public class RoundedCorners extends BitmapTransformation {
private final boolean crop;
private final int radius;
private final int colorHint;
public RoundedCorners(@NonNull Context context, boolean crop, int radius, int colorHint) {
super(context);
this.crop = crop;
this.radius = radius;
this.colorHint = colorHint;
}
@Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth,
int outHeight)
{
final Bitmap toRound = crop ? centerCrop(pool, toTransform, outWidth, outHeight)
: fitCenter(pool, toTransform, outWidth, outHeight);
return round(pool, toRound);
}
private Bitmap centerCrop(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
final Bitmap toReuse = pool.get(outWidth, outHeight, getSafeConfig(toTransform));
final Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight);
if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
toReuse.recycle();
}
return transformed;
}
private Bitmap fitCenter(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return TransformationUtils.fitCenter(toTransform, pool, outWidth, outHeight);
}
private Bitmap round(@NonNull BitmapPool pool, @Nullable Bitmap toRound) {
if (toRound == null) {
return null;
}
final Bitmap result;
final Bitmap toReuse = pool.get(toRound.getWidth(), toRound.getHeight(), getSafeConfig(toRound));
if (toReuse != null) {
result = toReuse;
} else {
result = Bitmap.createBitmap(toRound.getWidth(), toRound.getHeight(), getSafeConfig(toRound));
}
final Canvas canvas = new Canvas(result);
final Paint cornerPaint = new Paint();
final Paint shaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
shaderPaint.setShader(new BitmapShader(toRound, TileMode.CLAMP, TileMode.CLAMP));
cornerPaint.setColor(colorHint);
if (Config.RGB_565.equals(result.getConfig())) {
canvas.drawRect(0, 0, radius, radius, cornerPaint);
canvas.drawRect(0, toRound.getHeight() - radius, radius, toRound.getHeight(), cornerPaint);
canvas.drawRect(toRound.getWidth() - radius, 0, toRound.getWidth(), radius, cornerPaint);
canvas.drawRect(toRound.getWidth() - radius, toRound.getHeight() - radius, toRound.getWidth(), toRound.getHeight(), cornerPaint);
}
canvas.drawRoundRect(new RectF(0, 0, toRound.getWidth(), toRound.getHeight()), radius, radius, shaderPaint);
// Log.w("RoundedCorners", "in was " + toRound.getWidth() + "x" + toRound.getHeight() + ", out to " + result.getWidth() + "x" + result.getHeight());
return result;
}
private static Bitmap.Config getSafeConfig(Bitmap bitmap) {
return bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
}
@Override public String getId() {
return RoundedCorners.class.getCanonicalName();
}
}