/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.imagepipeline.image;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import com.facebook.common.internal.Preconditions;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.references.ResourceReleaser;
import com.facebook.imageutils.BitmapUtil;
/**
* CloseableImage that contains array of Bitmaps and frame durations.
*/
@ThreadSafe
public class CloseableAnimatedBitmap extends CloseableBitmap {
// bitmap frames
@GuardedBy("this")
private List<CloseableReference<Bitmap>> mBitmapReferences;
private volatile List<Bitmap> mBitmaps;
// frame durations
private volatile List<Integer> mDurations;
public CloseableAnimatedBitmap(
List<CloseableReference<Bitmap>> bitmapReferences,
List<Integer> durations) {
Preconditions.checkNotNull(bitmapReferences);
Preconditions.checkState(bitmapReferences.size() >= 1, "Need at least 1 frame!");
mBitmapReferences = new ArrayList<>(bitmapReferences.size());
mBitmaps = new ArrayList<>(bitmapReferences.size());
for (CloseableReference<Bitmap> bitmapReference : bitmapReferences) {
mBitmapReferences.add(bitmapReference.clone());
mBitmaps.add(bitmapReference.get());
}
mDurations = Preconditions.checkNotNull(durations);
Preconditions.checkState(mDurations.size() == mBitmaps.size(), "Arrays length mismatch!");
}
/**
* Creates a new instance of a CloseableStaticBitmap.
*
* @param bitmaps the bitmap frames. This list must be immutable.
* @param durations the frame durations, This list must be immutable.
* @param resourceReleaser ResourceReleaser to release the bitmaps to
*/
public CloseableAnimatedBitmap(
List<Bitmap> bitmaps,
List<Integer> durations,
ResourceReleaser<Bitmap> resourceReleaser) {
Preconditions.checkNotNull(bitmaps);
Preconditions.checkState(bitmaps.size() >= 1, "Need at least 1 frame!");
mBitmaps = new ArrayList<>(bitmaps.size());
mBitmapReferences = new ArrayList<>(bitmaps.size());
for (Bitmap bitmap : bitmaps) {
mBitmapReferences.add(CloseableReference.of(bitmap, resourceReleaser));
mBitmaps.add(bitmap);
}
mDurations = Preconditions.checkNotNull(durations);
Preconditions.checkState(mDurations.size() == mBitmaps.size(), "Arrays length mismatch!");
}
/**
* Releases the bitmaps to the pool.
*/
@Override
public void close() {
List<CloseableReference<Bitmap>> bitmapReferences;
synchronized (this) {
if (mBitmapReferences == null) {
return;
}
bitmapReferences = mBitmapReferences;
mBitmapReferences = null;
mBitmaps = null;
mDurations = null;
}
CloseableReference.closeSafely(bitmapReferences);
}
/**
* Returns whether this instance is closed.
*/
@Override
public synchronized boolean isClosed() {
return mBitmaps == null;
}
/**
* Gets the bitmap frames.
*
* @return bitmap frames
*/
public List<Bitmap> getBitmaps() {
return mBitmaps;
}
/**
* Gets the frame durations.
*
* @return frame durations
*/
public List<Integer> getDurations() {
return mDurations;
}
/**
* Gets the first frame.
*
* @return the first frame
*/
@Override
public Bitmap getUnderlyingBitmap() {
List<Bitmap> bitmaps = mBitmaps;
return (bitmaps != null) ? bitmaps.get(0) : null;
}
/**
* @return size in bytes all bitmaps in sum
*/
@Override
public int getSizeInBytes() {
List<Bitmap> bitmaps = mBitmaps;
if (bitmaps == null || bitmaps.size() == 0) {
return 0;
} else {
return BitmapUtil.getSizeInBytes(bitmaps.get(0)) * bitmaps.size();
}
}
/**
* @return width of the image
*/
@Override
public int getWidth() {
List<Bitmap> bitmaps = mBitmaps;
return (bitmaps == null) ? 0 : bitmaps.get(0).getWidth();
}
/**
* @return height of the image
*/
@Override
public int getHeight() {
List<Bitmap> bitmaps = mBitmaps;
return (bitmaps == null) ? 0 : bitmaps.get(0).getHeight();
}
}