• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.airbnb.lottie.manager;
2 
3 import android.content.Context;
4 import android.graphics.Bitmap;
5 import android.graphics.BitmapFactory;
6 import android.graphics.drawable.Drawable;
7 import androidx.annotation.Nullable;
8 import android.text.TextUtils;
9 import android.util.Base64;
10 import android.view.View;
11 
12 import com.airbnb.lottie.ImageAssetDelegate;
13 import com.airbnb.lottie.LottieImageAsset;
14 import com.airbnb.lottie.utils.Logger;
15 import com.airbnb.lottie.utils.Utils;
16 
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.util.HashMap;
20 import java.util.Map;
21 
22 public class ImageAssetManager {
23   private static final Object bitmapHashLock = new Object();
24 
25   private final Context context;
26   private String imagesFolder;
27   @Nullable private ImageAssetDelegate delegate;
28   private final Map<String, LottieImageAsset> imageAssets;
29 
ImageAssetManager(Drawable.Callback callback, String imagesFolder, ImageAssetDelegate delegate, Map<String, LottieImageAsset> imageAssets)30   public ImageAssetManager(Drawable.Callback callback, String imagesFolder,
31       ImageAssetDelegate delegate, Map<String, LottieImageAsset> imageAssets) {
32     this.imagesFolder = imagesFolder;
33     if (!TextUtils.isEmpty(imagesFolder) &&
34         this.imagesFolder.charAt(this.imagesFolder.length() - 1) != '/') {
35       this.imagesFolder += '/';
36     }
37 
38     if (!(callback instanceof View)) {
39       Logger.warning("LottieDrawable must be inside of a view for images to work.");
40       this.imageAssets = new HashMap<>();
41       context = null;
42       return;
43     }
44 
45     context = ((View) callback).getContext();
46     this.imageAssets = imageAssets;
47     setDelegate(delegate);
48   }
49 
setDelegate(@ullable ImageAssetDelegate assetDelegate)50   public void setDelegate(@Nullable ImageAssetDelegate assetDelegate) {
51     this.delegate = assetDelegate;
52   }
53 
54   /**
55    * Returns the previously set bitmap or null.
56    */
updateBitmap(String id, @Nullable Bitmap bitmap)57   @Nullable public Bitmap updateBitmap(String id, @Nullable Bitmap bitmap) {
58     if (bitmap == null) {
59       LottieImageAsset asset = imageAssets.get(id);
60       Bitmap ret = asset.getBitmap();
61       asset.setBitmap(null);
62       return ret;
63     }
64     Bitmap prevBitmap = imageAssets.get(id).getBitmap();
65     putBitmap(id, bitmap);
66     return prevBitmap;
67   }
68 
bitmapForId(String id)69   @Nullable public Bitmap bitmapForId(String id) {
70     LottieImageAsset asset = imageAssets.get(id);
71     if (asset == null) {
72       return null;
73     }
74     Bitmap bitmap = asset.getBitmap();
75     if (bitmap != null) {
76       return bitmap;
77     }
78 
79     if (delegate != null) {
80       bitmap = delegate.fetchBitmap(asset);
81       if (bitmap != null) {
82         putBitmap(id, bitmap);
83       }
84       return bitmap;
85     }
86 
87     String filename = asset.getFileName();
88     BitmapFactory.Options opts = new BitmapFactory.Options();
89     opts.inScaled = true;
90     opts.inDensity = 160;
91 
92     if (filename.startsWith("data:") && filename.indexOf("base64,") > 0) {
93       // Contents look like a base64 data URI, with the format data:image/png;base64,<data>.
94       byte[] data;
95       try {
96         data = Base64.decode(filename.substring(filename.indexOf(',') + 1), Base64.DEFAULT);
97       } catch (IllegalArgumentException e) {
98         Logger.warning("data URL did not have correct base64 format.", e);
99         return null;
100       }
101       bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
102       return putBitmap(id, bitmap);
103     }
104 
105     InputStream is;
106     try {
107       if (TextUtils.isEmpty(imagesFolder)) {
108         throw new IllegalStateException("You must set an images folder before loading an image." +
109             " Set it with LottieComposition#setImagesFolder or LottieDrawable#setImagesFolder");
110       }
111       is = context.getAssets().open(imagesFolder + filename);
112     } catch (IOException e) {
113       Logger.warning("Unable to open asset.", e);
114       return null;
115     }
116     bitmap = BitmapFactory.decodeStream(is, null, opts);
117     bitmap = Utils.resizeBitmapIfNeeded(bitmap, asset.getWidth(), asset.getHeight());
118     return putBitmap(id, bitmap);
119   }
120 
hasSameContext(Context context)121   public boolean hasSameContext(Context context) {
122     return context == null && this.context == null || this.context.equals(context);
123   }
124 
putBitmap(String key, @Nullable Bitmap bitmap)125   private Bitmap putBitmap(String key, @Nullable Bitmap bitmap) {
126     synchronized (bitmapHashLock) {
127       imageAssets.get(key).setBitmap(bitmap);
128       return bitmap;
129     }
130   }
131 }
132