blob: f31378d2263caa7dfa6e602d7148e1e9e37fc6e0 [file] [log] [blame]
package com.airbnb.lottie.manager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
import android.view.View;
import com.airbnb.lottie.ImageAssetDelegate;
import com.airbnb.lottie.LottieImageAsset;
import com.airbnb.lottie.utils.Logger;
import com.airbnb.lottie.utils.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class ImageAssetManager {
private static final Object bitmapHashLock = new Object();
private final Context context;
private String imagesFolder;
@Nullable private ImageAssetDelegate delegate;
private final Map<String, LottieImageAsset> imageAssets;
public ImageAssetManager(Drawable.Callback callback, String imagesFolder,
ImageAssetDelegate delegate, Map<String, LottieImageAsset> imageAssets) {
this.imagesFolder = imagesFolder;
if (!TextUtils.isEmpty(imagesFolder) &&
this.imagesFolder.charAt(this.imagesFolder.length() - 1) != '/') {
this.imagesFolder += '/';
}
if (!(callback instanceof View)) {
Logger.warning("LottieDrawable must be inside of a view for images to work.");
this.imageAssets = new HashMap<>();
context = null;
return;
}
context = ((View) callback).getContext();
this.imageAssets = imageAssets;
setDelegate(delegate);
}
public void setDelegate(@Nullable ImageAssetDelegate assetDelegate) {
this.delegate = assetDelegate;
}
/**
* Returns the previously set bitmap or null.
*/
@Nullable public Bitmap updateBitmap(String id, @Nullable Bitmap bitmap) {
if (bitmap == null) {
LottieImageAsset asset = imageAssets.get(id);
Bitmap ret = asset.getBitmap();
asset.setBitmap(null);
return ret;
}
Bitmap prevBitmap = imageAssets.get(id).getBitmap();
putBitmap(id, bitmap);
return prevBitmap;
}
@Nullable public Bitmap bitmapForId(String id) {
LottieImageAsset asset = imageAssets.get(id);
if (asset == null) {
return null;
}
Bitmap bitmap = asset.getBitmap();
if (bitmap != null) {
return bitmap;
}
if (delegate != null) {
bitmap = delegate.fetchBitmap(asset);
if (bitmap != null) {
putBitmap(id, bitmap);
}
return bitmap;
}
String filename = asset.getFileName();
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = true;
opts.inDensity = 160;
if (filename.startsWith("data:") && filename.indexOf("base64,") > 0) {
// Contents look like a base64 data URI, with the format data:image/png;base64,<data>.
byte[] data;
try {
data = Base64.decode(filename.substring(filename.indexOf(',') + 1), Base64.DEFAULT);
} catch (IllegalArgumentException e) {
Logger.warning("data URL did not have correct base64 format.", e);
return null;
}
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
return putBitmap(id, bitmap);
}
InputStream is;
try {
if (TextUtils.isEmpty(imagesFolder)) {
throw new IllegalStateException("You must set an images folder before loading an image." +
" Set it with LottieComposition#setImagesFolder or LottieDrawable#setImagesFolder");
}
is = context.getAssets().open(imagesFolder + filename);
} catch (IOException e) {
Logger.warning("Unable to open asset.", e);
return null;
}
bitmap = BitmapFactory.decodeStream(is, null, opts);
bitmap = Utils.resizeBitmapIfNeeded(bitmap, asset.getWidth(), asset.getHeight());
return putBitmap(id, bitmap);
}
public boolean hasSameContext(Context context) {
return context == null && this.context == null || this.context.equals(context);
}
private Bitmap putBitmap(String key, @Nullable Bitmap bitmap) {
synchronized (bitmapHashLock) {
imageAssets.get(key).setBitmap(bitmap);
return bitmap;
}
}
}