ImageViewCustom.java 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package com.owncloud.android.ui.preview;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.Canvas;
  5. import android.graphics.Movie;
  6. import android.os.Build;
  7. import android.support.v7.widget.AppCompatImageView;
  8. import android.util.AttributeSet;
  9. import android.view.View;
  10. import com.owncloud.android.lib.common.utils.Log_OC;
  11. import java.io.FileInputStream;
  12. import java.io.InputStream;
  13. public class ImageViewCustom extends AppCompatImageView {
  14. private static final String TAG = ImageViewCustom.class.getSimpleName();
  15. private static final boolean IS_ICS_OR_HIGHER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
  16. private static final boolean IS_VERSION_BUGGY_ON_RECYCLES =
  17. Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1 ||
  18. Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR2;
  19. private int mBitmapHeight;
  20. private int mBitmapWidth;
  21. private Movie mGifMovie;
  22. private int mMovieWidth, mMovieHeight;
  23. private long mMovieDuration;
  24. private long mMovieRunDuration;
  25. private long mLastTick;
  26. protected PreviewImageFragment previewImageFragment;
  27. public ImageViewCustom(Context context) {
  28. super(context);
  29. }
  30. public ImageViewCustom(Context context, AttributeSet attrs) {
  31. super(context, attrs);
  32. }
  33. public ImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
  34. super(context, attrs, defStyle);
  35. }
  36. @Override
  37. protected void onDraw(Canvas canvas) {
  38. if(IS_ICS_OR_HIGHER && checkIfMaximumBitmapExceed(canvas) || IS_VERSION_BUGGY_ON_RECYCLES ) {
  39. // Software type is set with two targets:
  40. // 1. prevent that bitmaps larger than maximum textures allowed are shown as black views in devices
  41. // with LAYER_TYPE_HARDWARE enabled by default;
  42. // 2. grant that bitmaps are correctly de-allocated from memory in versions suffering the bug fixed in
  43. // https://android.googlesource.com/platform/frameworks/base/+/034de6b1ec561797a2422314e6ef03e3cd3e08e0;
  44. //
  45. setLayerType(View.LAYER_TYPE_SOFTWARE, null);
  46. }
  47. if(mGifMovie != null) {
  48. long nowTick = android.os.SystemClock.uptimeMillis();
  49. if (mLastTick == 0) {
  50. mMovieRunDuration = 0;
  51. } else {
  52. mMovieRunDuration += nowTick - mLastTick;
  53. if(mMovieRunDuration > mMovieDuration) {
  54. mMovieRunDuration = 0;
  55. }
  56. }
  57. mGifMovie.setTime((int) mMovieRunDuration);
  58. float scale = getScaleToViewFactor(mGifMovie, canvas);
  59. canvas.scale(scale, scale);
  60. canvas.translate(((float) getWidth() / scale - (float) mGifMovie.width()) / 2f,
  61. ((float) getHeight() / scale - (float) mGifMovie.height()) /2f);
  62. mGifMovie.draw(canvas, 0, 0);
  63. mLastTick = nowTick;
  64. invalidate();
  65. } else {
  66. super.onDraw(canvas);
  67. }
  68. }
  69. private float getScaleToViewFactor(Movie movie, Canvas canvas) {
  70. if (movie.height() > getHeight() || movie.width() > getWidth()) {
  71. float offset = 0.25f;
  72. return (1f / Math.min(canvas.getHeight() / movie.height(), canvas.getWidth() / movie.width())) + offset;
  73. }
  74. return Math.min(canvas.getHeight() / movie.height(), canvas.getWidth() / movie.width());
  75. }
  76. @Override
  77. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  78. if (mGifMovie == null) {
  79. setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
  80. } else {
  81. setMeasuredDimension(mMovieWidth, mMovieHeight);
  82. }
  83. }
  84. /**
  85. * Checks if current bitmaps exceed the maximum OpenGL texture size limit
  86. * @param canvas Canvas where the view will be drawn into.
  87. * @return boolean True means that the bitmap is too big for the canvas.
  88. */
  89. private boolean checkIfMaximumBitmapExceed(Canvas canvas) {
  90. return mBitmapWidth > canvas.getMaximumBitmapWidth() || mBitmapHeight > canvas.getMaximumBitmapHeight();
  91. }
  92. @Override
  93. /**
  94. * Keeps the size of the bitmap cached in member variables for faster access in {@link #onDraw(Canvas)},
  95. * but without keeping another reference to the {@link Bitmap}
  96. */
  97. public void setImageBitmap(Bitmap bm) {
  98. mBitmapWidth = bm.getWidth();
  99. mBitmapHeight = bm.getHeight();
  100. super.setImageBitmap(bm);
  101. }
  102. /**
  103. * sets the GIF image of the given storage path.
  104. *
  105. * @param storagePath the storage path of the GIF image
  106. */
  107. public void setGIFImageFromStoragePath(String storagePath) {
  108. try (InputStream gifInputStream = new FileInputStream(storagePath)){
  109. setLayerType(View.LAYER_TYPE_SOFTWARE, null);
  110. setFocusable(true);
  111. mGifMovie = Movie.decodeStream(gifInputStream);
  112. mMovieWidth = mGifMovie.width();
  113. mMovieHeight = mGifMovie.height();
  114. mMovieDuration = mGifMovie.duration();
  115. } catch (Exception e) {
  116. Log_OC.e(TAG, "Failed to set GIF image");
  117. }
  118. }
  119. public void setPreviewImageFragment(PreviewImageFragment previewImageFragment) {
  120. this.previewImageFragment = previewImageFragment;
  121. }
  122. }