Moved LottieComposition parsing to Parser classes

This required setting up a init() method on LottieComposition
to avoid exposing the fields directly outside of the lottie package.
This also removed the bodymovin min version check for text layers
because the layer parsing can no longer know the bodymovin version.
This check can be moved to render time if needed.
diff --git a/lottie/src/main/java/com/airbnb/lottie/L.java b/lottie/src/main/java/com/airbnb/lottie/L.java
index 556b8df..f03f528 100644
--- a/lottie/src/main/java/com/airbnb/lottie/L.java
+++ b/lottie/src/main/java/com/airbnb/lottie/L.java
@@ -2,6 +2,7 @@
 
 import android.support.annotation.RestrictTo;
 import android.support.v4.os.TraceCompat;
+import android.util.Log;
 
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 public class L {
@@ -15,6 +16,10 @@
   private static int traceDepth = 0;
   private static int depthPastMaxDepth = 0;
 
+  public static void warn(String msg) {
+    Log.w(TAG, 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 e2df5a7..384ddf8 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java
@@ -15,6 +15,7 @@
 import com.airbnb.lottie.model.FontCharacter;
 import com.airbnb.lottie.model.JsonCompositionLoader;
 import com.airbnb.lottie.model.layer.Layer;
+import com.airbnb.lottie.parser.LottieCompositionParser;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -22,7 +23,6 @@
 import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -38,23 +38,42 @@
 public class LottieComposition {
 
   private final PerformanceTracker performanceTracker = new PerformanceTracker();
-  final Map<String, List<Layer>> precomps = new HashMap<>();
-  final Map<String, LottieImageAsset> images = new HashMap<>();
+  private final HashSet<String> warnings = new HashSet<>();
+  private Map<String, List<Layer>> precomps;
+  private Map<String, LottieImageAsset> images;
   /** Map of font names to fonts */
-  final Map<String, Font> fonts = new HashMap<>();
-  final SparseArrayCompat<FontCharacter> characters = new SparseArrayCompat<>();
-  final LongSparseArray<Layer> layerMap = new LongSparseArray<>();
-  final List<Layer> layers = new ArrayList<>();
+  private Map<String, Font> fonts;
+  private SparseArrayCompat<FontCharacter> characters;
+  private LongSparseArray<Layer> layerMap;
+  private List<Layer> layers;
   // This is stored as a set to avoid duplicates.
-  final HashSet<String> warnings = new HashSet<>();
-  Rect bounds;
-  float startFrame;
-  float endFrame;
-  float frameRate;
+  private Rect bounds;
+  private float startFrame;
+  private float endFrame;
+  private float frameRate;
   /* Bodymovin version */
-  int majorVersion;
-  int minorVersion;
-  int patchVersion;
+  private int majorVersion;
+  private int minorVersion;
+  private int patchVersion;
+
+  public void init(Rect bounds, float startFrame, float endFrame, float frameRate, int majorVersion,
+      int minorVersion, int patchVersion, List<Layer> layers, LongSparseArray<Layer> layerMap,
+      Map<String, List<Layer>> precomps, Map<String, LottieImageAsset> images,
+      SparseArrayCompat<FontCharacter> characters, Map<String, Font> fonts) {
+    this.bounds = bounds;
+    this.startFrame = startFrame;
+    this.endFrame = endFrame;
+    this.frameRate = frameRate;
+    this.majorVersion = majorVersion;
+    this.minorVersion = minorVersion;
+    this.patchVersion = patchVersion;
+    this.layers = layers;
+    this.layerMap = layerMap;
+    this.precomps = precomps;
+    this.images = images;
+    this.characters = characters;
+    this.fonts = fonts;
+  }
 
   @RestrictTo(RestrictTo.Scope.LIBRARY)
   public void addWarning(String warning) {
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieImageAsset.java b/lottie/src/main/java/com/airbnb/lottie/LottieImageAsset.java
index 370cef6..50fd2f9 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieImageAsset.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieImageAsset.java
@@ -1,9 +1,10 @@
 package com.airbnb.lottie;
 
+import android.support.annotation.RestrictTo;
+
 /**
  * Data class describing an image asset exported by bodymovin.
  */
-@SuppressWarnings("WeakerAccess")
 public class LottieImageAsset {
   private final int width;
   private final int height;
@@ -11,7 +12,8 @@
   private final String fileName;
   private final String dirName;
 
-  LottieImageAsset(int width, int height, String id, String fileName, String dirName) {
+  @RestrictTo(RestrictTo.Scope.LIBRARY)
+  public LottieImageAsset(int width, int height, String id, String fileName, String dirName) {
     this.width = width;
     this.height = height;
     this.id = id;
@@ -19,11 +21,11 @@
     this.dirName = dirName;
   }
 
-  @SuppressWarnings("WeakerAccess") public int getWidth() {
+  public int getWidth() {
     return width;
   }
 
-  @SuppressWarnings("WeakerAccess")public int getHeight() {
+  public int getHeight() {
     return height;
   }
 
diff --git a/lottie/src/main/java/com/airbnb/lottie/json/JsonKeyframe.java b/lottie/src/main/java/com/airbnb/lottie/json/JsonKeyframe.java
deleted file mode 100644
index 7e59f52..0000000
--- a/lottie/src/main/java/com/airbnb/lottie/json/JsonKeyframe.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.airbnb.lottie.json;
-
-public class JsonKeyframe {
-}
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 96276a3..f5f58e7 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
@@ -11,7 +11,6 @@
 import android.support.annotation.CallSuper;
 import android.support.annotation.FloatRange;
 import android.support.annotation.Nullable;
-import android.util.Log;
 
 import com.airbnb.lottie.L;
 import com.airbnb.lottie.LottieComposition;
@@ -56,7 +55,7 @@
       case Unknown:
       default:
         // Do nothing
-        Log.w(L.TAG, "Unknown layer type " + layerModel.getLayerType());
+        L.warn("Unknown layer type " + layerModel.getLayerType());
         return null;
     }
   }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java b/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java
index 65cca14..989b925 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java
@@ -251,7 +251,6 @@
       List<Mask> masks = new ArrayList<>();
       List<ContentModel> shapes = new ArrayList<>();
 
-
       reader.beginObject();
       while (reader.hasNext()) {
         switch (reader.nextName()) {
@@ -409,11 +408,6 @@
         composition.addWarning("Convert your Illustrator layers to shape layers.");
       }
 
-      if (layerType == LayerType.Text && !Utils.isAtLeastVersion(composition, 4, 8, 0)) {
-        layerType = LayerType.Unknown;
-        composition.addWarning("Text is only supported on bodymovin >= 4.8.0");
-      }
-
       return new Layer(shapes, composition, layerName, layerId, layerType, parentId, refId,
           masks, transform, solidWidth, solidHeight, solidColor, timeStretch, startFrame,
           preCompWidth, preCompHeight, text, textProperties, inOutKeyframes, matteType,
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/LottieCompositionParser.java
similarity index 60%
rename from lottie/src/main/java/com/airbnb/lottie/LottieCompositionParser.java
rename to lottie/src/main/java/com/airbnb/lottie/parser/LottieCompositionParser.java
index 834d6d5..61f6df2 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/LottieCompositionParser.java
@@ -1,9 +1,13 @@
-package com.airbnb.lottie;
+package com.airbnb.lottie.parser;
 
 import android.graphics.Rect;
 import android.support.v4.util.LongSparseArray;
+import android.support.v4.util.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.layer.Layer;
@@ -11,12 +15,28 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class LottieCompositionParser {
   public static LottieComposition parse(JsonReader reader) throws IOException {
     float scale = Utils.dpScale();
-    int width = -1;
+    float startFrame = 0f;
+    float endFrame = 0f;
+    float frameRate = 0f;
+    int majorVersion = 0;
+    int minorVersion = 0;
+    int patchVersion = 0;
+    final LongSparseArray<Layer> layerMap = new LongSparseArray<>();
+    final List<Layer> layers = new ArrayList<>();
+    int width = 0;
+    int height = 0;
+    Map<String, List<Layer>> precomps = new HashMap<>();
+    Map<String, LottieImageAsset> images = new HashMap<>();
+    Map<String, Font> fonts = new HashMap<>();
+    SparseArrayCompat<FontCharacter> characters = new SparseArrayCompat<>();
+
     LottieComposition composition = new LottieComposition();
 
     reader.beginObject();
@@ -26,52 +46,57 @@
           width = reader.nextInt();
           break;
         case "h":
-          int height = reader.nextInt();
-          int scaledWidth = (int) (width * scale);
-          int scaledHeight = (int) (height * scale);
-          composition.bounds = new Rect(0, 0, scaledWidth, scaledHeight);
+          height = reader.nextInt();
           break;
         case "ip":
-          composition.startFrame = (float) reader.nextDouble();
+          startFrame = (float) reader.nextDouble();
           break;
         case "op":
-          composition.endFrame = (float) reader.nextDouble();
+          endFrame = (float) reader.nextDouble();
           break;
         case "fr":
-          composition.frameRate = (float) reader.nextDouble();
+          frameRate = (float) reader.nextDouble();
           break;
         case "v":
           String version = reader.nextString();
           String[] versions = version.split("\\.");
-          composition.majorVersion = Integer.parseInt(versions[0]);
-          composition.minorVersion = Integer.parseInt(versions[1]);
-          composition.patchVersion = Integer.parseInt(versions[2]);
+          majorVersion = Integer.parseInt(versions[0]);
+          minorVersion = Integer.parseInt(versions[1]);
+          patchVersion = Integer.parseInt(versions[2]);
           if (!Utils.isAtLeastVersion(composition, 4, 5, 0)) {
             composition.addWarning("Lottie only supports bodymovin >= 4.5.0");
           }
           break;
         case "layers":
-          parseLayers(reader, composition);
+          parseLayers(reader, composition, layers, layerMap);
           break;
         case "assets":
-          parseAssets(reader, composition);
+          parseAssets(reader, composition, precomps, images);
           break;
         case "fonts":
-          parseFonts(reader, composition);
+          parseFonts(reader, fonts);
           break;
         case "chars":
-          parseChars(reader, composition);
+          parseChars(reader, composition, characters);
           break;
         default:
           reader.skipValue();
       }
     }
     reader.endObject();
+
+    int scaledWidth = (int) (width * scale);
+    int scaledHeight = (int) (height * scale);
+    Rect bounds = new Rect(0, 0, scaledWidth, scaledHeight);
+
+    composition.init(bounds, startFrame, endFrame, frameRate, majorVersion, minorVersion,
+        patchVersion, layers, layerMap, precomps, images, characters, fonts);
+
     return composition;
   }
 
-  private static void parseLayers(JsonReader reader, LottieComposition composition)
-      throws IOException {
+  private static void parseLayers(JsonReader reader, LottieComposition composition,
+      List<Layer> layers, LongSparseArray<Layer> layerMap) throws IOException {
     int imageCount = 0;
     reader.beginArray();
     while (reader.hasNext()) {
@@ -79,10 +104,11 @@
       if (layer.getLayerType() == Layer.LayerType.Image) {
         imageCount++;
       }
-      addLayer(composition.layers, composition.layerMap, layer);
+      layers.add(layer);
+      layerMap.put(layer.getId(), layer);
 
       if (imageCount > 4) {
-        composition.warnings.add("You have " + imageCount + " images. Lottie should primarily be " +
+        L.warn("You have " + imageCount + " images. Lottie should primarily be " +
             "used with shapes. If you are using Adobe Illustrator, convert the Illustrator layers" +
             " to shape layers.");
       }
@@ -90,8 +116,8 @@
     reader.endArray();
   }
 
-  private static void parseAssets(
-      JsonReader reader, LottieComposition composition) throws IOException {
+  private static void parseAssets(JsonReader reader, LottieComposition composition,
+      Map<String, List<Layer>> precomps, Map<String, LottieImageAsset> images) throws IOException {
     reader.beginArray();
     while (reader.hasNext()) {
       String id = null;
@@ -136,18 +162,17 @@
       }
       reader.endObject();
       if (!layers.isEmpty()) {
-        composition.precomps.put(id, layers);
+        precomps.put(id, layers);
       } else if (imageFileName != null) {
         LottieImageAsset image =
             new LottieImageAsset(width, height, id, imageFileName, relativeFolder);
-        composition.images.put(image.getId(), image);
+        images.put(image.getId(), image);
       }
     }
     reader.endArray();
   }
 
-  private static void parseFonts(
-      JsonReader reader, LottieComposition composition) throws IOException {
+  private static void parseFonts(JsonReader reader, Map<String, Font> fonts) throws IOException {
 
     reader.beginObject();
     while (reader.hasNext()) {
@@ -156,7 +181,7 @@
           reader.beginArray();
           while (reader.hasNext()) {
             Font font = Font.Factory.newInstance(reader);
-            composition.fonts.put(font.getName(), font);
+            fonts.put(font.getName(), font);
           }
           reader.endArray();
           break;
@@ -168,18 +193,13 @@
   }
 
   private static void parseChars(
-      JsonReader reader, LottieComposition composition) throws IOException {
+      JsonReader reader, LottieComposition composition,
+      SparseArrayCompat<FontCharacter> characters) throws IOException {
     reader.beginArray();
     while (reader.hasNext()) {
-      FontCharacter character =
-          FontCharacter.Factory.newInstance(reader, composition);
-      composition.characters.put(character.hashCode(), character);
+      FontCharacter character = FontCharacter.Factory.newInstance(reader, composition);
+      characters.put(character.hashCode(), character);
     }
     reader.endArray();
   }
-
-  private static void addLayer(List<Layer> layers, LongSparseArray<Layer> layerMap, Layer layer) {
-    layers.add(layer);
-    layerMap.put(layer.getId(), layer);
-  }
 }