Fix flashing gradient
diff --git a/lottie/src/main/java/com/airbnb/lottie/animation/content/PolystarContent.java b/lottie/src/main/java/com/airbnb/lottie/animation/content/PolystarContent.java
index cfa9523..9c5fc83 100644
--- a/lottie/src/main/java/com/airbnb/lottie/animation/content/PolystarContent.java
+++ b/lottie/src/main/java/com/airbnb/lottie/animation/content/PolystarContent.java
@@ -1,10 +1,9 @@
 package com.airbnb.lottie.animation.content;
 
 import android.graphics.Path;
+import android.graphics.PathMeasure;
 import android.graphics.PointF;
-
 import androidx.annotation.Nullable;
-
 import com.airbnb.lottie.LottieDrawable;
 import com.airbnb.lottie.LottieProperty;
 import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation;
@@ -28,6 +27,9 @@
   private static final float POLYSTAR_MAGIC_NUMBER = .47829f;
   private static final float POLYGON_MAGIC_NUMBER = .25f;
   private final Path path = new Path();
+  private final Path lastSegmentPath = new Path();
+  private final PathMeasure lastSegmentPathMeasure = new PathMeasure();
+  private final float[] lastSegmentPosition = new float[2];
 
   private final String name;
   private final LottieDrawable lottieDrawable;
@@ -291,8 +293,28 @@
         float cp1y = radius * roundedness * POLYGON_MAGIC_NUMBER * cp1Dy;
         float cp2x = radius * roundedness * POLYGON_MAGIC_NUMBER * cp2Dx;
         float cp2y = radius * roundedness * POLYGON_MAGIC_NUMBER * cp2Dy;
-        path.cubicTo(previousX - cp1x, previousY - cp1y, x + cp2x, y + cp2y, x, y);
+
+        if (i == numPoints - 1) {
+          // When there is a huge stroke, it will flash if the path ends where it starts.
+          // We want the final bezier curve to end *slightly* before the start.
+          // The close() call at the end will complete the polystar.
+          // https://github.com/airbnb/lottie-android/issues/2329
+          lastSegmentPath.reset();
+          lastSegmentPath.moveTo(previousX, previousY);
+          lastSegmentPath.cubicTo(previousX - cp1x, previousY - cp1y, x + cp2x, y + cp2y, x, y);
+          lastSegmentPathMeasure.setPath(lastSegmentPath, false);
+          lastSegmentPathMeasure.getPosTan(lastSegmentPathMeasure.getLength() * 0.9999f, lastSegmentPosition, null);
+          path.cubicTo(previousX - cp1x, previousY - cp1y, x + cp2x, y + cp2y,lastSegmentPosition[0], lastSegmentPosition[1]);
+        } else {
+          path.cubicTo(previousX - cp1x, previousY - cp1y, x + cp2x, y + cp2y, x, y);
+        }
       } else {
+        if (i == numPoints - 1) {
+          // When there is a huge stroke, it will flash if the path ends where it starts.
+          // The close() call should make the path effectively equivalent.
+          // https://github.com/airbnb/lottie-android/issues/2329
+          continue;
+        }
         path.lineTo(x, y);
       }
 
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 3341722..803f8c0 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
@@ -31,6 +31,7 @@
 import com.airbnb.lottie.snapshots.tests.NightModeTestCase
 import com.airbnb.lottie.snapshots.tests.OutlineMasksAndMattesTestCase
 import com.airbnb.lottie.snapshots.tests.PartialFrameProgressTestCase
+import com.airbnb.lottie.snapshots.tests.PolygonStrokeTestCase
 import com.airbnb.lottie.snapshots.tests.ProdAnimationsTestCase
 import com.airbnb.lottie.snapshots.tests.ScaleTypesTestCase
 import com.airbnb.lottie.snapshots.tests.SeekBarTestCase
@@ -159,6 +160,7 @@
             ClipChildrenTestCase(),
             SoftwareRenderingDynamicPropertiesInvalidationTestCase(),
             SeekBarTestCase(),
+            PolygonStrokeTestCase(),
             CompositionFrameRate(),
         )
 
diff --git a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/PolygonStrokeTestCase.kt b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/PolygonStrokeTestCase.kt
new file mode 100644
index 0000000..470e179
--- /dev/null
+++ b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/PolygonStrokeTestCase.kt
@@ -0,0 +1,13 @@
+package com.airbnb.lottie.snapshots.tests
+
+import com.airbnb.lottie.snapshots.SnapshotTestCase
+import com.airbnb.lottie.snapshots.SnapshotTestCaseContext
+import com.airbnb.lottie.snapshots.withDrawable
+
+class PolygonStrokeTestCase : SnapshotTestCase {
+    override suspend fun SnapshotTestCaseContext.run() {
+        withDrawable("Tests/TriangleLargeStroke.json", "Triangle", "Large Stroke") { drawable ->
+            drawable.progress = 0.40999988f
+        }
+    }
+}
diff --git a/snapshot-tests/src/main/assets/Tests/TriangleLargeStroke.json b/snapshot-tests/src/main/assets/Tests/TriangleLargeStroke.json
new file mode 100644
index 0000000..19c4144
--- /dev/null
+++ b/snapshot-tests/src/main/assets/Tests/TriangleLargeStroke.json
@@ -0,0 +1 @@
+{"v":"5.12.2","fr":29.9700012207031,"ip":0,"op":60.0000024438501,"w":1200,"h":1200,"nm":"Repro 2 - Large","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[600,376,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":301,"ix":7},"os":{"a":0,"k":30,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":100,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-205.188,19.281],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":59.0000024031193,"s":[360]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":301,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 2","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":100,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[225,421],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":59.0000024031193,"s":[360]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}