Add a customizable logger and try/finally network connections (#1162)
diff --git a/lottie/src/main/java/com/airbnb/lottie/L.java b/lottie/src/main/java/com/airbnb/lottie/L.java
index 319958b..f26b6ae 100644
--- a/lottie/src/main/java/com/airbnb/lottie/L.java
+++ b/lottie/src/main/java/com/airbnb/lottie/L.java
@@ -2,20 +2,12 @@
import androidx.annotation.RestrictTo;
import androidx.core.os.TraceCompat;
-import android.util.Log;
-
-import java.util.HashSet;
-import java.util.Set;
@RestrictTo(RestrictTo.Scope.LIBRARY)
public class L {
- public static final String TAG = "LOTTIE";
- public static boolean DBG = false;
- /**
- * Set to ensure that we only log each message one time max.
- */
- private static final Set<String> loggedMessages = new HashSet<>();
+ public static boolean DBG = false;
+ public static final String TAG = "LOTTIE";
private static final int MAX_DEPTH = 20;
private static boolean traceEnabled = false;
@@ -24,21 +16,6 @@
private static int traceDepth = 0;
private static int depthPastMaxDepth = 0;
- public static void debug(String msg) {
- if (DBG) Log.d(TAG, msg);
- }
-
- /**
- * Warn to logcat. Keeps track of messages so they are only logged once ever.
- */
- public static void warn(String msg) {
- if (loggedMessages.contains(msg)) {
- return;
- }
- Log.w(TAG, msg);
- loggedMessages.add(msg);
- }
-
public static void setTraceEnabled(boolean enabled) {
if (traceEnabled == enabled) {
return;
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java b/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java
index 5edb57e..4ffe434 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java
@@ -10,12 +10,12 @@
import androidx.collection.LongSparseArray;
import androidx.collection.SparseArrayCompat;
import android.util.JsonReader;
-import android.util.Log;
import com.airbnb.lottie.model.Font;
import com.airbnb.lottie.model.FontCharacter;
import com.airbnb.lottie.model.Marker;
import com.airbnb.lottie.model.layer.Layer;
+import com.airbnb.lottie.utils.Logger;
import org.json.JSONObject;
@@ -85,7 +85,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY)
public void addWarning(String warning) {
- Log.w(L.TAG, warning);
+ Logger.warning(warning);
warnings.add(warning);
}
@@ -301,7 +301,7 @@
@Deprecated
public static LottieComposition fromInputStreamSync(InputStream stream, boolean close) {
if (close) {
- Log.w(L.TAG, "Lottie now auto-closes input stream!");
+ Logger.warning("Lottie now auto-closes input stream!");
}
return LottieCompositionFactory.fromJsonInputStreamSync(stream, null).getValue();
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
index 1f0a2c9..4769035 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
@@ -16,7 +16,6 @@
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.util.Log;
import android.view.View;
import androidx.annotation.FloatRange;
@@ -32,6 +31,7 @@
import com.airbnb.lottie.model.Marker;
import com.airbnb.lottie.model.layer.CompositionLayer;
import com.airbnb.lottie.parser.LayerParser;
+import com.airbnb.lottie.utils.Logger;
import com.airbnb.lottie.utils.LottieValueAnimator;
import com.airbnb.lottie.utils.MiscUtils;
import com.airbnb.lottie.value.LottieFrameInfo;
@@ -155,7 +155,7 @@
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- Log.w(TAG, "Merge paths are not supported pre-Kit Kat.");
+ Logger.warning("Merge paths are not supported pre-Kit Kat.");
return;
}
enableMergePaths = enable;
@@ -285,7 +285,7 @@
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
- Log.w(L.TAG, "Use addColorFilter instead.");
+ Logger.warning("Use addColorFilter instead.");
}
@Override
@@ -857,7 +857,7 @@
*/
public List<KeyPath> resolveKeyPath(KeyPath keyPath) {
if (compositionLayer == null) {
- Log.w(L.TAG, "Cannot resolve KeyPath. Composition is not set yet.");
+ Logger.warning("Cannot resolve KeyPath. Composition is not set yet.");
return Collections.emptyList();
}
List<KeyPath> keyPaths = new ArrayList<>();
@@ -933,7 +933,7 @@
public Bitmap updateBitmap(String id, @Nullable Bitmap bitmap) {
ImageAssetManager bm = getImageAssetManager();
if (bm == null) {
- Log.w(L.TAG, "Cannot update bitmap. Most likely the drawable is not added to a View " +
+ Logger.warning("Cannot update bitmap. Most likely the drawable is not added to a View " +
"which prevents Lottie from getting a Context.");
return null;
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieLogger.java b/lottie/src/main/java/com/airbnb/lottie/LottieLogger.java
new file mode 100644
index 0000000..638b162
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieLogger.java
@@ -0,0 +1,15 @@
+package com.airbnb.lottie;
+
+/**
+ * Give ability to integrators to provide another logging mechanism.
+ */
+public interface LottieLogger {
+
+ void debug(String message);
+
+ void debug(String message, Throwable exception);
+
+ void warning(String message);
+
+ void warning(String message, Throwable exception);
+}
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieTask.java b/lottie/src/main/java/com/airbnb/lottie/LottieTask.java
index f1b3aeb..c922228 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieTask.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieTask.java
@@ -4,7 +4,8 @@
import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
-import android.util.Log;
+
+import com.airbnb.lottie.utils.Logger;
import java.util.ArrayList;
import java.util.LinkedHashSet;
@@ -149,7 +150,7 @@
// Otherwise we risk ConcurrentModificationException.
List<LottieListener<Throwable>> listenersCopy = new ArrayList<>(failureListeners);
if (listenersCopy.isEmpty()) {
- Log.w(L.TAG, "Lottie encountered an error but no failure listener was added.", e);
+ Logger.warning("Lottie encountered an error but no failure listener was added:", e);
return;
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/manager/FontAssetManager.java b/lottie/src/main/java/com/airbnb/lottie/manager/FontAssetManager.java
index c7b5e37..360893b 100644
--- a/lottie/src/main/java/com/airbnb/lottie/manager/FontAssetManager.java
+++ b/lottie/src/main/java/com/airbnb/lottie/manager/FontAssetManager.java
@@ -10,6 +10,7 @@
import com.airbnb.lottie.FontAssetDelegate;
import com.airbnb.lottie.L;
import com.airbnb.lottie.model.MutablePair;
+import com.airbnb.lottie.utils.Logger;
import java.util.HashMap;
import java.util.Map;
@@ -28,7 +29,7 @@
public FontAssetManager(Drawable.Callback callback, @Nullable FontAssetDelegate delegate) {
this.delegate = delegate;
if (!(callback instanceof View)) {
- Log.w(L.TAG, "LottieDrawable must be inside of a view for images to work.");
+ Logger.warning("LottieDrawable must be inside of a view for images to work.");
assetManager = null;
return;
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/manager/ImageAssetManager.java b/lottie/src/main/java/com/airbnb/lottie/manager/ImageAssetManager.java
index da4568d..aff6f77 100644
--- a/lottie/src/main/java/com/airbnb/lottie/manager/ImageAssetManager.java
+++ b/lottie/src/main/java/com/airbnb/lottie/manager/ImageAssetManager.java
@@ -7,12 +7,11 @@
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
-import android.util.Log;
import android.view.View;
import com.airbnb.lottie.ImageAssetDelegate;
-import com.airbnb.lottie.L;
import com.airbnb.lottie.LottieImageAsset;
+import com.airbnb.lottie.utils.Logger;
import java.io.IOException;
import java.io.InputStream;
@@ -36,7 +35,7 @@
}
if (!(callback instanceof View)) {
- Log.w(L.TAG, "LottieDrawable must be inside of a view for images to work.");
+ Logger.warning("LottieDrawable must be inside of a view for images to work.");
this.imageAssets = new HashMap<>();
context = null;
return;
@@ -95,7 +94,7 @@
try {
data = Base64.decode(filename.substring(filename.indexOf(',') + 1), Base64.DEFAULT);
} catch (IllegalArgumentException e) {
- Log.w(L.TAG, "data URL did not have correct base64 format.", e);
+ Logger.warning("data URL did not have correct base64 format.", e);
return null;
}
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
@@ -110,7 +109,7 @@
}
is = context.getAssets().open(imagesFolder + filename);
} catch (IOException e) {
- Log.w(L.TAG, "Unable to open asset.", e);
+ Logger.warning("Unable to open asset.", e);
return null;
}
bitmap = BitmapFactory.decodeStream(is, null, opts);
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/content/MergePaths.java b/lottie/src/main/java/com/airbnb/lottie/model/content/MergePaths.java
index b4a8884..3d1184d 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/content/MergePaths.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/content/MergePaths.java
@@ -2,11 +2,11 @@
import androidx.annotation.Nullable;
-import com.airbnb.lottie.L;
import com.airbnb.lottie.LottieDrawable;
import com.airbnb.lottie.animation.content.Content;
import com.airbnb.lottie.animation.content.MergePathsContent;
import com.airbnb.lottie.model.layer.BaseLayer;
+import com.airbnb.lottie.utils.Logger;
public class MergePaths implements ContentModel {
@@ -60,7 +60,7 @@
@Override @Nullable public Content toContent(LottieDrawable drawable, BaseLayer layer) {
if (!drawable.enableMergePathsForKitKatAndAbove()) {
- L.warn("Animation contains merge paths but they are disabled.");
+ Logger.warning("Animation contains merge paths but they are disabled.");
return null;
}
return new MergePathsContent(this);
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java b/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java
index 4824a01..5c0cdba 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java
@@ -3,8 +3,8 @@
import android.graphics.PointF;
import androidx.annotation.FloatRange;
-import com.airbnb.lottie.L;
import com.airbnb.lottie.model.CubicCurveData;
+import com.airbnb.lottie.utils.Logger;
import com.airbnb.lottie.utils.MiscUtils;
import java.util.ArrayList;
@@ -53,7 +53,7 @@
if (shapeData1.getCurves().size() != shapeData2.getCurves().size()) {
- L.warn("Curves must have the same number of control points. Shape 1: " +
+ Logger.warning("Curves must have the same number of control points. Shape 1: " +
shapeData1.getCurves().size() + "\tShape 2: " + shapeData2.getCurves().size());
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java b/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
index fc63529..e828ff6 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
@@ -21,6 +21,7 @@
import com.airbnb.lottie.model.KeyPathElement;
import com.airbnb.lottie.model.content.Mask;
import com.airbnb.lottie.model.content.ShapeData;
+import com.airbnb.lottie.utils.Logger;
import com.airbnb.lottie.value.LottieValueCallback;
import java.util.ArrayList;
@@ -58,7 +59,7 @@
case UNKNOWN:
default:
// Do nothing
- L.warn("Unknown layer type " + layerModel.getLayerType());
+ Logger.warning("Unknown layer type " + layerModel.getLayerType());
return null;
}
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/network/FileExtension.java b/lottie/src/main/java/com/airbnb/lottie/network/FileExtension.java
index 98937f9..72a1a5f 100644
--- a/lottie/src/main/java/com/airbnb/lottie/network/FileExtension.java
+++ b/lottie/src/main/java/com/airbnb/lottie/network/FileExtension.java
@@ -1,6 +1,6 @@
package com.airbnb.lottie.network;
-import com.airbnb.lottie.L;
+import com.airbnb.lottie.utils.Logger;
/**
* Helpers for known Lottie file types.
@@ -30,7 +30,7 @@
}
}
// Default to Json.
- L.warn("Unable to find correct extension for " + filename);
+ Logger.warning("Unable to find correct extension for " + filename);
return JSON;
}
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/network/NetworkCache.java b/lottie/src/main/java/com/airbnb/lottie/network/NetworkCache.java
index 305125d..dc8e5bd 100644
--- a/lottie/src/main/java/com/airbnb/lottie/network/NetworkCache.java
+++ b/lottie/src/main/java/com/airbnb/lottie/network/NetworkCache.java
@@ -5,7 +5,7 @@
import androidx.annotation.WorkerThread;
import androidx.core.util.Pair;
-import com.airbnb.lottie.L;
+import com.airbnb.lottie.utils.Logger;
import java.io.File;
import java.io.FileInputStream;
@@ -61,7 +61,7 @@
extension = FileExtension.JSON;
}
- L.debug("Cache hit for " + url + " at " + cachedFile.getAbsolutePath());
+ Logger.debug("Cache hit for " + url + " at " + cachedFile.getAbsolutePath());
return new Pair<>(extension, (InputStream) inputStream);
}
@@ -104,9 +104,9 @@
String newFileName = file.getAbsolutePath().replace(".temp", "");
File newFile = new File(newFileName);
boolean renamed = file.renameTo(newFile);
- L.debug("Copying temp file to real file (" + newFile + ")");
+ Logger.debug("Copying temp file to real file (" + newFile + ")");
if (!renamed) {
- L.warn( "Unable to rename cache file " + file.getAbsolutePath() + " to " + newFile.getAbsolutePath() + ".");
+ Logger.warning("Unable to rename cache file " + file.getAbsolutePath() + " to " + newFile.getAbsolutePath() + ".");
}
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/network/NetworkFetcher.java b/lottie/src/main/java/com/airbnb/lottie/network/NetworkFetcher.java
index 3f01a76..d698c54 100644
--- a/lottie/src/main/java/com/airbnb/lottie/network/NetworkFetcher.java
+++ b/lottie/src/main/java/com/airbnb/lottie/network/NetworkFetcher.java
@@ -5,10 +5,10 @@
import androidx.annotation.WorkerThread;
import androidx.core.util.Pair;
-import com.airbnb.lottie.L;
import com.airbnb.lottie.LottieComposition;
import com.airbnb.lottie.LottieCompositionFactory;
import com.airbnb.lottie.LottieResult;
+import com.airbnb.lottie.utils.Logger;
import java.io.BufferedReader;
import java.io.File;
@@ -44,7 +44,7 @@
return new LottieResult<>(result);
}
- L.debug("Animation for " + url + " not found in cache. Fetching from network.");
+ Logger.debug("Animation for " + url + " not found in cache. Fetching from network.");
return fetchFromNetwork();
}
@@ -84,21 +84,39 @@
@WorkerThread
private LottieResult fetchFromNetworkInternal() throws IOException {
- L.debug( "Fetching " + url);
+ Logger.debug("Fetching " + url);
+
+
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
-
connection.setRequestMethod("GET");
- connection.connect();
- if (connection.getErrorStream() != null || connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
- BufferedReader r = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
- StringBuilder error = new StringBuilder();
- String line;
- while ((line = r.readLine()) != null) {
- error.append(line).append('\n');
+ try {
+ connection.connect();
+
+ if (connection.getErrorStream() != null || connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+
+ int responseCode = connection.getResponseCode();
+ BufferedReader r = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
+ StringBuilder error = new StringBuilder();
+ String line;
+
+ try {
+ while ((line = r.readLine()) != null) {
+ error.append(line).append('\n');
+ }
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ r.close();
+ }
+
+ return new LottieResult<>(new IllegalArgumentException("Unable to fetch " + url + ". Failed with " +
+ responseCode + "\n" + error));
}
- return new LottieResult<>(new IllegalArgumentException("Unable to fetch " + url + ". Failed with " +
- connection.getResponseCode() + "\n" + error));
+ } catch (Exception e) {
+ return new LottieResult<>(e);
+ } finally {
+ connection.disconnect();
}
File file;
@@ -106,14 +124,14 @@
LottieResult<LottieComposition> result;
switch (connection.getContentType()) {
case "application/zip":
- L.debug("Handling zip response.");
+ Logger.debug("Handling zip response.");
extension = FileExtension.ZIP;
file = networkCache.writeTempCacheFile(connection.getInputStream(), extension);
result = LottieCompositionFactory.fromZipStreamSync(new ZipInputStream(new FileInputStream(file)), url);
break;
case "application/json":
default:
- L.debug("Received json response.");
+ Logger.debug("Received json response.");
extension = FileExtension.JSON;
file = networkCache.writeTempCacheFile(connection.getInputStream(), extension);
result = LottieCompositionFactory.fromJsonInputStreamSync(new FileInputStream(new File(file.getAbsolutePath())), url);
@@ -124,7 +142,7 @@
networkCache.renameTempFile(extension);
}
- L.debug("Completed fetch from network. Success: " + (result.getValue() != null));
+ Logger.debug("Completed fetch from network. Success: " + (result.getValue() != null));
return result;
}
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ContentModelParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ContentModelParser.java
index 1df423c..f2430d4 100644
--- a/lottie/src/main/java/com/airbnb/lottie/parser/ContentModelParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/ContentModelParser.java
@@ -2,11 +2,10 @@
import androidx.annotation.Nullable;
import android.util.JsonReader;
-import android.util.Log;
-import com.airbnb.lottie.L;
import com.airbnb.lottie.LottieComposition;
import com.airbnb.lottie.model.content.ContentModel;
+import com.airbnb.lottie.utils.Logger;
import java.io.IOException;
@@ -87,7 +86,7 @@
model = RepeaterParser.parse(reader, composition);
break;
default:
- Log.w(L.TAG, "Unknown shape type " + type);
+ Logger.warning("Unknown shape type " + type);
}
while (reader.hasNext()) {
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/LottieCompositionParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/LottieCompositionParser.java
index 0d560f5..afe8f2d 100644
--- a/lottie/src/main/java/com/airbnb/lottie/parser/LottieCompositionParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/LottieCompositionParser.java
@@ -5,13 +5,13 @@
import androidx.collection.SparseArrayCompat;
import android.util.JsonReader;
-import com.airbnb.lottie.L;
import com.airbnb.lottie.LottieComposition;
import com.airbnb.lottie.LottieImageAsset;
import com.airbnb.lottie.model.Font;
import com.airbnb.lottie.model.FontCharacter;
import com.airbnb.lottie.model.Marker;
import com.airbnb.lottie.model.layer.Layer;
+import com.airbnb.lottie.utils.Logger;
import com.airbnb.lottie.utils.Utils;
import java.io.IOException;
@@ -114,7 +114,7 @@
layerMap.put(layer.getId(), layer);
if (imageCount > 4) {
- L.warn("You have " + imageCount + " images. Lottie should primarily be " +
+ Logger.warning("You have " + imageCount + " images. Lottie should primarily be " +
"used with shapes. If you are using Adobe Illustrator, convert the Illustrator layers" +
" to shape layers.");
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
index a25300e..108bcac 100644
--- a/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
@@ -1,13 +1,12 @@
package com.airbnb.lottie.parser;
import android.util.JsonReader;
-import android.util.Log;
-import com.airbnb.lottie.L;
import com.airbnb.lottie.LottieComposition;
import com.airbnb.lottie.model.animatable.AnimatableIntegerValue;
import com.airbnb.lottie.model.animatable.AnimatableShapeValue;
import com.airbnb.lottie.model.content.Mask;
+import com.airbnb.lottie.utils.Logger;
import java.io.IOException;
@@ -40,7 +39,7 @@
maskMode = Mask.MaskMode.MASK_MODE_INTERSECT;
break;
default:
- Log.w(L.TAG, "Unknown mask mode " + mode + ". Defaulting to Add.");
+ Logger.warning("Unknown mask mode " + mode + ". Defaulting to Add.");
maskMode = Mask.MaskMode.MASK_MODE_ADD;
}
break;
diff --git a/lottie/src/main/java/com/airbnb/lottie/utils/LogcatLogger.java b/lottie/src/main/java/com/airbnb/lottie/utils/LogcatLogger.java
new file mode 100644
index 0000000..ad166a5
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/utils/LogcatLogger.java
@@ -0,0 +1,46 @@
+package com.airbnb.lottie.utils;
+
+import android.util.Log;
+
+import com.airbnb.lottie.L;
+import com.airbnb.lottie.LottieLogger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Default logger.
+ * Warnings with same message will only be logged once.
+ */
+public class LogcatLogger implements LottieLogger {
+
+ /**
+ * Set to ensure that we only log each message one time max.
+ */
+ private static final Set<String> loggedMessages = new HashSet<>();
+
+
+ public void debug(String message) {
+ debug(message, null);
+ }
+
+ public void debug(String message, Throwable exception) {
+ if (L.DBG) {
+ Log.d(L.TAG, message, exception);
+ }
+ }
+
+ public void warning(String message) {
+ warning(message, null);
+ }
+
+ public void warning(String message, Throwable exception) {
+ if (loggedMessages.contains(message)) {
+ return;
+ }
+
+ Log.w(L.TAG, message, exception);
+
+ loggedMessages.add(message);
+ }
+}
diff --git a/lottie/src/main/java/com/airbnb/lottie/utils/Logger.java b/lottie/src/main/java/com/airbnb/lottie/utils/Logger.java
new file mode 100644
index 0000000..acf4ef7
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/utils/Logger.java
@@ -0,0 +1,32 @@
+package com.airbnb.lottie.utils;
+
+import com.airbnb.lottie.LottieLogger;
+
+/**
+ * Singleton object for logging. If you want to provide a custom logger implementation,
+ * implements LottieLogger interface in a custom class and replace Logger.instance
+ */
+public class Logger {
+
+ private static LottieLogger INSTANCE = new LogcatLogger();
+
+ public static void setInstance(LottieLogger instance) {
+ Logger.INSTANCE = instance;
+ }
+
+ public static void debug(String message) {
+ INSTANCE.debug(message);
+ }
+
+ public static void debug(String message, Throwable exception) {
+ INSTANCE.debug(message, exception);
+ }
+
+ public static void warning(String message) {
+ INSTANCE.warning(message);
+ }
+
+ public static void warning(String message, Throwable exception) {
+ INSTANCE.warning(message, exception);
+ }
+}