Disable the path interpolator cache for snapshot tests
diff --git a/lottie/src/main/java/com/airbnb/lottie/L.java b/lottie/src/main/java/com/airbnb/lottie/L.java index c88fd6e..8bfe62c 100644 --- a/lottie/src/main/java/com/airbnb/lottie/L.java +++ b/lottie/src/main/java/com/airbnb/lottie/L.java
@@ -24,6 +24,7 @@ private static final int MAX_DEPTH = 20; private static boolean traceEnabled = false; private static boolean networkCacheEnabled = true; + private static boolean disablePathInterpolatorCache = true; private static String[] sections; private static long[] startTimeNs; private static int traceDepth = 0; @@ -130,4 +131,12 @@ } return local; } + + public static void setDisablePathInterpolatorCache(boolean disablePathInterpolatorCache) { + L.disablePathInterpolatorCache = disablePathInterpolatorCache; + } + + public static boolean getDisablePathInterpolatorCache() { + return disablePathInterpolatorCache; + } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/Lottie.java b/lottie/src/main/java/com/airbnb/lottie/Lottie.java index 8faaeb7..c585572 100644 --- a/lottie/src/main/java/com/airbnb/lottie/Lottie.java +++ b/lottie/src/main/java/com/airbnb/lottie/Lottie.java
@@ -20,5 +20,7 @@ L.setCacheProvider(lottieConfig.cacheProvider); L.setTraceEnabled(lottieConfig.enableSystraceMarkers); L.setNetworkCacheEnabled(lottieConfig.enableNetworkCache); + L.setNetworkCacheEnabled(lottieConfig.enableNetworkCache); + L.setDisablePathInterpolatorCache(lottieConfig.disablePathInterpolatorCache); } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieConfig.java b/lottie/src/main/java/com/airbnb/lottie/LottieConfig.java index be426fa..b186058 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieConfig.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieConfig.java
@@ -19,13 +19,15 @@ @Nullable final LottieNetworkCacheProvider cacheProvider; final boolean enableSystraceMarkers; final boolean enableNetworkCache; + final boolean disablePathInterpolatorCache; private LottieConfig(@Nullable LottieNetworkFetcher networkFetcher, @Nullable LottieNetworkCacheProvider cacheProvider, - boolean enableSystraceMarkers, boolean enableNetworkCache) { + boolean enableSystraceMarkers, boolean enableNetworkCache, boolean disablePathInterpolatorCache) { this.networkFetcher = networkFetcher; this.cacheProvider = cacheProvider; this.enableSystraceMarkers = enableSystraceMarkers; this.enableNetworkCache = enableNetworkCache; + this.disablePathInterpolatorCache = disablePathInterpolatorCache; } public static final class Builder { @@ -36,6 +38,7 @@ private LottieNetworkCacheProvider cacheProvider; private boolean enableSystraceMarkers = false; private boolean enableNetworkCache = true; + private boolean disablePathInterpolatorCache = true; /** * Lottie has a default network fetching stack built on {@link java.net.HttpURLConnection}. However, if you would like to hook into your own @@ -111,9 +114,22 @@ return this; } + /** + * When parsing animations, Lottie has a path interpolator cache. This cache allows Lottie to reuse PathInterpolators + * across an animation. This is desirable in most cases. However, when shared across screenshot tests, it can cause slight + * deviations in the rendering due to underlying approximations in the PathInterpolator. + * + * The cache is enabled by default and should probably only be disabled for screenshot tests. + */ + @NonNull + public Builder setDisablePathInterpolatorCache(boolean disable) { + disablePathInterpolatorCache = disable; + return this; + } + @NonNull public LottieConfig build() { - return new LottieConfig(networkFetcher, cacheProvider, enableSystraceMarkers, enableNetworkCache); + return new LottieConfig(networkFetcher, cacheProvider, enableSystraceMarkers, enableNetworkCache, disablePathInterpolatorCache); } } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java index 4f0bd87..219b554 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java
@@ -8,6 +8,8 @@ import androidx.collection.SparseArrayCompat; import androidx.core.view.animation.PathInterpolatorCompat; +import com.airbnb.lottie.L; +import com.airbnb.lottie.Lottie; import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.parser.moshi.JsonReader; import com.airbnb.lottie.utils.MiscUtils; @@ -332,7 +334,7 @@ cp2.x = MiscUtils.clamp(cp2.x, -1f, 1f); cp2.y = MiscUtils.clamp(cp2.y, -MAX_CP_VALUE, MAX_CP_VALUE); int hash = Utils.hashFor(cp1.x, cp1.y, cp2.x, cp2.y); - WeakReference<Interpolator> interpolatorRef = getInterpolator(hash); + WeakReference<Interpolator> interpolatorRef = L.getDisablePathInterpolatorCache() ? null : getInterpolator(hash); if (interpolatorRef != null) { interpolator = interpolatorRef.get(); } @@ -350,13 +352,15 @@ interpolator = new LinearInterpolator(); } } - try { - putInterpolator(hash, new WeakReference<>(interpolator)); - } catch (ArrayIndexOutOfBoundsException e) { - // It is not clear why but SparseArrayCompat sometimes fails with this: - // https://github.com/airbnb/lottie-android/issues/452 - // Because this is not a critical operation, we can safely just ignore it. - // I was unable to repro this to attempt a proper fix. + if (!L.getDisablePathInterpolatorCache()) { + try { + putInterpolator(hash, new WeakReference<>(interpolator)); + } catch (ArrayIndexOutOfBoundsException e) { + // It is not clear why but SparseArrayCompat sometimes fails with this: + // https://github.com/airbnb/lottie-android/issues/452 + // Because this is not a critical operation, we can safely just ignore it. + // I was unable to repro this to attempt a proper fix. + } } } return interpolator;
diff --git a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt index 9af9410..8dfd190 100644 --- a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt +++ b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt
@@ -11,7 +11,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest import androidx.test.rule.GrantPermissionRule +import com.airbnb.lottie.Lottie import com.airbnb.lottie.LottieAnimationView +import com.airbnb.lottie.LottieConfig import com.airbnb.lottie.model.LottieCompositionCache import com.airbnb.lottie.snapshots.tests.ApplyOpacityToLayerTestCase import com.airbnb.lottie.snapshots.tests.AssetsTestCase @@ -67,6 +69,11 @@ @Before fun setup() { LottieCompositionCache.getInstance().resize(1) + Lottie.initialize( + LottieConfig.Builder() + .setDisablePathInterpolatorCache(true) + .build() + ) val context = ApplicationProvider.getApplicationContext<Context>() snapshotter = HappoSnapshotter(context) { name, variant -> snapshotActivityRule.scenario.onActivity { activity ->