Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support animated GiF-Images #9

Merged
merged 10 commits into from
Jun 14, 2016
94 changes: 81 additions & 13 deletions src/com/owncloud/android/ui/preview/ImageViewCustom.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.utils.Log_OC;

import java.io.FileInputStream;
import java.io.InputStream;

public class ImageViewCustom extends ImageView {

private static final String TAG = ImageViewCustom.class.getSimpleName();
Expand All @@ -23,7 +28,12 @@ public class ImageViewCustom extends ImageView {
private int mBitmapHeight;
private int mBitmapWidth;


private Movie mGifMovie;
private int mMovieWidth, mMovieHeight;
private long mMovieDuration;
private long mMovieRunDuration;
private long mLastTick;

public ImageViewCustom(Context context) {
super(context);
}
Expand All @@ -39,18 +49,60 @@ public ImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
@SuppressLint("NewApi")
@Override
protected void onDraw(Canvas canvas) {

if(IS_ICS_OR_HIGHER && checkIfMaximumBitmapExceed(canvas) || IS_VERSION_BUGGY_ON_RECYCLES ) {
// Software type is set with two targets:
// 1. prevent that bitmaps larger than maximum textures allowed are shown as black views in devices
// with LAYER_TYPE_HARDWARE enabled by default;
// 2. grant that bitmaps are correctly dellocated from memory in versions suffering the bug fixed in
// 2. grant that bitmaps are correctly de-allocated from memory in versions suffering the bug fixed in
// https://android.googlesource.com/platform/frameworks/base/+/034de6b1ec561797a2422314e6ef03e3cd3e08e0;
//
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

super.onDraw(canvas);
if(mGifMovie != null) {
long nowTick = android.os.SystemClock.uptimeMillis();
if (mLastTick == 0) {
mMovieRunDuration = 0;
} else {
mMovieRunDuration += nowTick - mLastTick;
if(mMovieRunDuration > mMovieDuration) {
mMovieRunDuration = 0;
}
}

mGifMovie.setTime((int) mMovieRunDuration);

float scale = getScaleToViewFactor(mGifMovie, canvas);

canvas.scale(scale, scale);
canvas.translate(((float) getWidth() / scale - (float) mGifMovie.width()) / 2f,
((float) getHeight() / scale - (float) mGifMovie.height()) /2f);

mGifMovie.draw(canvas, 0, 0);

mLastTick = nowTick;
invalidate();
} else {
super.onDraw(canvas);
}
}

private float getScaleToViewFactor(Movie movie, Canvas canvas) {
if (movie.height() > getHeight() || movie.width() > getWidth()) {
float offset = 0.25f;
return (1f / Math.min(canvas.getHeight() / movie.height(), canvas.getWidth() / movie.width())) + offset;
}

return Math.min(canvas.getHeight() / movie.height(), canvas.getWidth() / movie.width());
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mGifMovie == null) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
} else {
setMeasuredDimension(mMovieWidth, mMovieHeight);
}
}

/**
Expand All @@ -60,24 +112,40 @@ protected void onDraw(Canvas canvas) {
*/
@SuppressLint("NewApi")
private boolean checkIfMaximumBitmapExceed(Canvas canvas) {
Log_OC.v(TAG, "Canvas maximum: " + canvas.getMaximumBitmapWidth() + " - " + canvas.getMaximumBitmapHeight());
if (mBitmapWidth > canvas.getMaximumBitmapWidth()
|| mBitmapHeight > canvas.getMaximumBitmapHeight()) {
return true;
}

return false;
return mBitmapWidth > canvas.getMaximumBitmapWidth()
|| mBitmapHeight > canvas.getMaximumBitmapHeight();

}

@Override
/**
* Keeps the size of the bitmap cached in member variables for faster access in {@link #onDraw(Canvas)} ,
* Keeps the size of the bitmap cached in member variables for faster access in {@link #onDraw(Canvas)},
* but without keeping another reference to the {@link Bitmap}
*/
public void setImageBitmap (Bitmap bm) {
public void setImageBitmap(Bitmap bm) {
mBitmapWidth = bm.getWidth();
mBitmapHeight = bm.getHeight();
super.setImageBitmap(bm);
}

/**
* sets the GIF image of the given storage path.
*
* @param storagePath the storage path of the GIF image
*/
public void setGIFImageFromStoragePath(String storagePath) {
try {
InputStream gifInputStream = new FileInputStream(storagePath);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
setFocusable(true);

mGifMovie = Movie.decodeStream(gifInputStream);
mMovieWidth = mGifMovie.width();
mMovieHeight = mGifMovie.height();
mMovieDuration = mGifMovie.duration();
} catch (Exception e) {
Log_OC.e(TAG, "Failed to set GIF image");
}
}

}
9 changes: 7 additions & 2 deletions src/com/owncloud/android/ui/preview/PreviewImageFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -499,12 +499,17 @@ private void showLoadedImage(LoadImage result) {
Log_OC.d(TAG, "Showing image with resolution " + bitmap.getWidth() + "x" +
bitmap.getHeight());

if (result.ocFile.getMimetype().equalsIgnoreCase("image/png")){
if (result.ocFile.getMimetype().equalsIgnoreCase("image/png")) {
Drawable backrepeat = getResources().getDrawable(R.drawable.backrepeat);
imageView.setBackground(backrepeat);
}

imageView.setImageBitmap(bitmap);
if (result.ocFile.getMimetype().equalsIgnoreCase("image/gif")) {
imageView.setGIFImageFromStoragePath(result.ocFile.getStoragePath());
} else {
imageView.setImageBitmap(bitmap);
}

imageView.setVisibility(View.VISIBLE);
mBitmap = bitmap; // needs to be kept for recycling when not useful
}
Expand Down