From 632656ca97662f9f72eb7b9fbbb058ec71751fa6 Mon Sep 17 00:00:00 2001 From: Felipe Lima Date: Mon, 20 Feb 2017 17:27:50 -0800 Subject: [PATCH 1/5] Work in progress --- .../java/com/airbnb/lottie/TestRobot.java | 2 +- .../lottie/samples/AnimationFragment.java | 14 +- .../lottie/samples/LottieFontViewGroup.java | 10 +- .../main/java/com/airbnb/lottie/Factory.java | 20 ++ .../airbnb/lottie/LottieAnimationView.java | 12 +- .../com/airbnb/lottie/LottieComposition.java | 331 ++++++++---------- .../main/java/com/airbnb/lottie/Utils.java | 13 + 7 files changed, 203 insertions(+), 199 deletions(-) create mode 100644 lottie/src/main/java/com/airbnb/lottie/Factory.java diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java b/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java index 8429fb17cd..7360cfcfed 100644 --- a/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java +++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java @@ -20,7 +20,7 @@ static void testAnimation(MainActivity activity, String fileName) { static void testAnimation(MainActivity activity, String fileName, float[] progress) { final LottieAnimationView view = new LottieAnimationView(activity); - view.setComposition(LottieComposition.fromFileSync(activity, fileName)); + view.setComposition(Factory.fromFileSync(activity, fileName)); ViewHelpers.setupView(view) .layout(); diff --git a/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java b/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java index 8ebdf6b0c8..369a928d83 100644 --- a/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java +++ b/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java @@ -28,6 +28,8 @@ import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieComposition; +import com.airbnb.lottie.LottieCompositionFactory; +import com.airbnb.lottie.OnCompositionLoadedListener; import org.json.JSONException; import org.json.JSONObject; @@ -143,8 +145,8 @@ public void onAnimationUpdate(ValueAnimator animation) { switch (requestCode) { case RC_ASSET: final String assetName = data.getStringExtra(EXTRA_ANIMATION_NAME); - LottieComposition.fromAssetFileName(getContext(), assetName, - new LottieComposition.OnCompositionLoadedListener() { + LottieCompositionFactory.fromAssetFileName(getContext(), assetName, + new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { setComposition(composition, assetName); @@ -281,8 +283,8 @@ private void onFileLoaded(final Uri uri) { return; } - LottieComposition - .fromInputStream(getContext(), fis, new LottieComposition.OnCompositionLoadedListener() { + LottieCompositionFactory + .fromInputStream(getContext(), fis, new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { setComposition(composition, uri.getPath()); @@ -317,8 +319,8 @@ private void loadUrl(String url) { try { JSONObject json = new JSONObject(response.body().string()); - LottieComposition - .fromJson(getResources(), json, new LottieComposition.OnCompositionLoadedListener() { + LottieCompositionFactory + .fromJson(getResources(), json, new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { setComposition(composition, "Network Animation"); diff --git a/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java b/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java index 874fe27902..b89d564066 100644 --- a/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java +++ b/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java @@ -14,6 +14,8 @@ import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieComposition; +import com.airbnb.lottie.LottieCompositionFactory; +import com.airbnb.lottie.OnCompositionLoadedListener; import java.util.ArrayList; import java.util.HashMap; @@ -43,8 +45,8 @@ public LottieFontViewGroup(Context context, AttributeSet attrs, int defStyleAttr private void init() { setFocusableInTouchMode(true); - LottieComposition.fromAssetFileName(getContext(), "Mobilo/BlinkingCursor.json", - new LottieComposition.OnCompositionLoadedListener() { + LottieCompositionFactory.fromAssetFileName(getContext(), "Mobilo/BlinkingCursor.json", + new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { cursorView = new LottieAnimationView(getContext()); @@ -180,8 +182,8 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { if (compositionMap.containsKey(fileName)) { addComposition(compositionMap.get(fileName)); } else { - LottieComposition.fromAssetFileName(getContext(), fileName, - new LottieComposition.OnCompositionLoadedListener() { + LottieCompositionFactory.fromAssetFileName(getContext(), fileName, + new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { compositionMap.put(fileName, composition); diff --git a/lottie/src/main/java/com/airbnb/lottie/Factory.java b/lottie/src/main/java/com/airbnb/lottie/Factory.java new file mode 100644 index 0000000000..94bba05dd1 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/Factory.java @@ -0,0 +1,20 @@ +package com.airbnb.lottie; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Rect; +import android.support.v4.util.LongSparseArray; +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import static com.airbnb.lottie.Utils.closeQuietly; + + diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java index ecbc3c2c9b..4ee93e9b2b 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java @@ -55,8 +55,8 @@ public enum CacheStrategy { private static final Map> weakRefCache = new HashMap<>(); - private final LottieComposition.OnCompositionLoadedListener loadedListener = - new LottieComposition.OnCompositionLoadedListener() { + private final OnCompositionLoadedListener loadedListener = + new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { setComposition(composition); @@ -67,7 +67,7 @@ public void onCompositionLoaded(LottieComposition composition) { private final LottieDrawable lottieDrawable = new LottieDrawable(); private String animationName; - @Nullable private LottieComposition.Cancellable compositionLoader; + @Nullable private Cancellable compositionLoader; /** * Can be null because it is created async */ @@ -204,8 +204,8 @@ public void setAnimation(final String animationName, final CacheStrategy cacheSt this.animationName = animationName; lottieDrawable.cancelAnimation(); cancelLoaderTask(); - compositionLoader = LottieComposition.fromAssetFileName(getContext(), animationName, - new LottieComposition.OnCompositionLoadedListener() { + compositionLoader = Factory.fromAssetFileName(getContext(), animationName, + new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { if (cacheStrategy == CacheStrategy.Strong) { @@ -228,7 +228,7 @@ public void onCompositionLoaded(LottieComposition composition) { */ public void setAnimation(final JSONObject json) { cancelLoaderTask(); - compositionLoader = LottieComposition.fromJson(getResources(), json, loadedListener); + compositionLoader = Factory.fromJson(getResources(), json, loadedListener); } private void cancelLoaderTask() { diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java b/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java index dfabc21abb..cbb1870c2c 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java @@ -3,7 +3,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; -import android.os.AsyncTask; import android.support.annotation.Nullable; import android.support.v4.util.LongSparseArray; import android.util.Log; @@ -19,6 +18,9 @@ import java.util.List; import java.util.Map; +import static android.R.attr.width; +import static com.airbnb.lottie.Utils.closeQuietly; + /** * After Effects/Bodymovin composition model. This is the serialized model from which the * animation will be created. @@ -26,14 +28,6 @@ * {@link com.airbnb.lottie.LottieDrawable}. */ public class LottieComposition { - public interface OnCompositionLoadedListener { - void onCompositionLoaded(LottieComposition composition); - } - - interface Cancellable { - void cancel(); - } - /** * The largest bitmap drawing cache can be is 8,294,400 bytes. There are 4 bytes per pixel * leaving ~2.3M pixels available. @@ -43,130 +37,6 @@ interface Cancellable { */ private static final int MAX_PIXELS = 1000; - /** - * Loads a composition from a file stored in /assets. - */ - public static Cancellable fromAssetFileName(Context context, String fileName, - OnCompositionLoadedListener loadedListener) { - InputStream stream; - try { - stream = context.getAssets().open(fileName); - } catch (IOException e) { - throw new IllegalStateException("Unable to find file " + fileName, e); - } - return fromInputStream(context, stream, loadedListener); - } - - /** - * Loads a composition from an arbitrary input stream. - *

- * ex: fromInputStream(context, new FileInputStream(filePath), (composition) -> {}); - */ - public static Cancellable fromInputStream(Context context, InputStream stream, - OnCompositionLoadedListener loadedListener) { - FileCompositionLoader loader = - new FileCompositionLoader(context.getResources(), loadedListener); - loader.execute(stream); - return loader; - } - - static LottieComposition fromFileSync(Context context, String fileName) { - InputStream file; - try { - file = context.getAssets().open(fileName); - } catch (IOException e) { - throw new IllegalStateException("Unable to find file " + fileName, e); - } - return fromInputStream(context.getResources(), file); - } - - /** - * Loads a composition from a raw json object. This is useful for animations loaded from the - * network. - */ - public static Cancellable fromJson(Resources res, JSONObject json, - OnCompositionLoadedListener loadedListener) { - JsonCompositionLoader loader = new JsonCompositionLoader(res, loadedListener); - loader.execute(json); - return loader; - } - - @SuppressWarnings("WeakerAccess") - static LottieComposition fromInputStream(Resources res, InputStream file) { - try { - int size = file.available(); - byte[] buffer = new byte[size]; - //noinspection ResultOfMethodCallIgnored - file.read(buffer); - file.close(); - String json = new String(buffer, "UTF-8"); - - JSONObject jsonObject = new JSONObject(json); - return LottieComposition.fromJsonSync(res, jsonObject); - } catch (IOException e) { - throw new IllegalStateException("Unable to find file.", e); - } catch (JSONException e) { - throw new IllegalStateException("Unable to load JSON.", e); - } - } - - @SuppressWarnings("WeakerAccess") - static LottieComposition fromJsonSync(Resources res, JSONObject json) { - LottieComposition composition = new LottieComposition(res); - - int width = json.optInt("w", -1); - int height = json.optInt("h", -1); - if (width != -1 && height != -1) { - int scaledWidth = (int) (width * composition.scale); - int scaledHeight = (int) (height * composition.scale); - if (Math.max(scaledWidth, scaledHeight) > MAX_PIXELS) { - float factor = (float) MAX_PIXELS / (float) Math.max(scaledWidth, scaledHeight); - scaledWidth *= factor; - scaledHeight *= factor; - composition.scale *= factor; - } - composition.bounds = new Rect(0, 0, scaledWidth, scaledHeight); - } - - composition.startFrame = json.optLong("ip", 0); - composition.endFrame = json.optLong("op", 0); - composition.frameRate = json.optInt("fr", 0); - - JSONArray jsonLayers = json.optJSONArray("layers"); - for (int i = 0; i < jsonLayers.length(); i++) { - Layer layer = new Layer(jsonLayers.optJSONObject(i), composition); - addLayer(composition, layer); - } - - JSONArray precompsJson = json.optJSONArray("assets"); - for (int i = 0; i < precompsJson.length(); i++) { - JSONObject precomp = precompsJson.optJSONObject(i); - JSONArray layersJson = precomp.optJSONArray("layers"); - if (layersJson == null) { - Log.w(L.TAG, "Lottie doesn't yet support images."); - // TODO: image support - continue; - } - List layers = new ArrayList<>(layersJson.length()); - LongSparseArray layerMap = new LongSparseArray<>(); - for (int j = 0; j < layersJson.length(); j++) { - Layer layer = new Layer(layersJson.optJSONObject(j), composition); - layerMap.put(layer.getId(), layer); - layers.add(layer); - if (!layer.getMasks().isEmpty()) { - composition.hasMasks = true; - } - if (layer.getMatteType() != null && layer.getMatteType() != Layer.MatteType.None) { - composition.hasMattes = true; - } - } - String id = precomp.optString("id"); - composition.precomps.put(id, layers); - } - - return composition; - } - private static void addLayer(LottieComposition composition, Layer layer) { composition.layers.add(layer); composition.layerMap.put(layer.getId(), layer); @@ -178,22 +48,32 @@ private static void addLayer(LottieComposition composition, Layer layer) { } } - private final Map> precomps = new HashMap<>(); - private final LongSparseArray layerMap = new LongSparseArray<>(); - private final List layers = new ArrayList<>(); - private Rect bounds; - private long startFrame; - private long endFrame; - private int frameRate; - private boolean hasMasks; - private boolean hasMattes; - private float scale; - - private LottieComposition(Resources res) { - scale = res.getDisplayMetrics().density; + private final Map> precomps; + private final LongSparseArray layerMap; + private final List layers; + private final Rect bounds; + private final long startFrame; + private final long endFrame; + private final int frameRate; + private final boolean hasMasks; + private final boolean hasMattes; + private final float scale; + + private LottieComposition(Map> precomps, LongSparseArray layerMap, + List layers, float scale, Rect bounds, long startFrame, long endFrame, int frameRate, + boolean hasMasks, boolean hasMattes) { + this.precomps = precomps; + this.layerMap = layerMap; + this.layers = layers; + this.scale = scale; + this.bounds = bounds; + this.startFrame = startFrame; + this.endFrame = endFrame; + this.frameRate = frameRate; + this.hasMasks = hasMasks; + this.hasMattes = hasMattes; } - Layer layerModelForId(long id) { return layerMap.get(id); } @@ -245,54 +125,141 @@ float getScale() { return sb.toString(); } - private static final class FileCompositionLoader extends CompositionLoader { - - private final Resources res; - private final OnCompositionLoadedListener loadedListener; + public static class Factory { + /** + * Loads a composition from a file stored in /assets. + */ + public static Cancellable fromAssetFileName(Context context, String fileName, + OnCompositionLoadedListener loadedListener) { + InputStream stream; + try { + stream = context.getAssets().open(fileName); + } catch (IOException e) { + throw new IllegalStateException("Unable to find file " + fileName, e); + } + return fromInputStream(context, stream, loadedListener); + } - FileCompositionLoader(Resources res, OnCompositionLoadedListener loadedListener) { - this.res = res; - this.loadedListener = loadedListener; + /** + * Loads a composition from an arbitrary input stream. + *

+ * ex: fromInputStream(context, new FileInputStream(filePath), (composition) -> {}); + */ + public static Cancellable fromInputStream(Context context, InputStream stream, + OnCompositionLoadedListener loadedListener) { + FileCompositionLoader loader = + new FileCompositionLoader(context.getResources(), loadedListener); + loader.execute(stream); + return loader; } - @Override - protected LottieComposition doInBackground(InputStream... params) { - return fromInputStream(res, params[0]); + static LottieComposition fromFileSync(Context context, String fileName) { + InputStream file; + try { + file = context.getAssets().open(fileName); + } catch (IOException e) { + throw new IllegalStateException("Unable to find file " + fileName, e); + } + return fromInputStream(context.getResources(), file); } - @Override - protected void onPostExecute(LottieComposition composition) { - loadedListener.onCompositionLoaded(composition); + /** + * Loads a composition from a raw json object. This is useful for animations loaded from the + * network. + */ + public static Cancellable fromJson(Resources res, JSONObject json, + OnCompositionLoadedListener loadedListener) { + JsonCompositionLoader + loader = new JsonCompositionLoader(res, loadedListener); + loader.execute(json); + return loader; } - } - private static final class JsonCompositionLoader extends CompositionLoader { + @SuppressWarnings("WeakerAccess") + static LottieComposition fromInputStream(Resources res, InputStream stream) { + try { + /* TODO: + * It is never correct to use the return value of this method to allocate + * a buffer intended to hold all data in this stream. + */ + int size = stream.available(); + byte[] buffer = new byte[size]; + //noinspection ResultOfMethodCallIgnored + stream.read(buffer); + String json = new String(buffer, "UTF-8"); + JSONObject jsonObject = new JSONObject(json); + return fromJsonSync(res, jsonObject); + } catch (IOException e) { + throw new IllegalStateException("Unable to find file.", e); + } catch (JSONException e) { + throw new IllegalStateException("Unable to load JSON.", e); + } finally { + closeQuietly(stream); + } + } - private final Resources res; - private final OnCompositionLoadedListener loadedListener; + @SuppressWarnings("WeakerAccess") + static LottieComposition fromJsonSync(Resources res, JSONObject json) { + float scale = res.getDisplayMetrics().density; + Rect bounds = null; + boolean hasMasks = false; + boolean hasMattes = false; + Map> precomps = new HashMap<>(); + LongSparseArray layerMap = new LongSparseArray<>(); - JsonCompositionLoader(Resources res, OnCompositionLoadedListener loadedListener) { - this.res = res; - this.loadedListener = loadedListener; - } + int width = json.optInt("w", -1); + int height = json.optInt("h", -1); + if (width != -1 && height != -1) { + int scaledWidth = (int) (width * scale); + int scaledHeight = (int) (height * scale); + if (Math.max(scaledWidth, scaledHeight) > LottieComposition.MAX_PIXELS) { + float factor = + (float) LottieComposition.MAX_PIXELS / (float) Math.max(scaledWidth, scaledHeight); + scaledWidth *= factor; + scaledHeight *= factor; + scale *= factor; + } + bounds = new Rect(0, 0, scaledWidth, scaledHeight); + } - @Override - protected LottieComposition doInBackground(JSONObject... params) { - return fromJsonSync(res, params[0]); - } + long startFrame = json.optLong("ip", 0); + long endFrame = json.optLong("op", 0); + int frameRate = json.optInt("fr", 0); - @Override - protected void onPostExecute(LottieComposition composition) { - loadedListener.onCompositionLoaded(composition); - } - } + JSONArray jsonLayers = json.optJSONArray("layers"); + for (int i = 0; i < jsonLayers.length(); i++) { + Layer layer = new Layer(jsonLayers.optJSONObject(i), composition); + LottieComposition.addLayer(composition, layer); + } - private abstract static class CompositionLoader - extends AsyncTask - implements Cancellable { + JSONArray precompsJson = json.optJSONArray("assets"); + for (int i = 0; i < precompsJson.length(); i++) { + JSONObject precomp = precompsJson.optJSONObject(i); + JSONArray layersJson = precomp.optJSONArray("layers"); + if (layersJson == null) { + Log.w(L.TAG, "Lottie doesn't yet support images."); + // TODO: image support + continue; + } + List layers = new ArrayList<>(layersJson.length()); + LongSparseArray layerMap = new LongSparseArray<>(); + for (int j = 0; j < layersJson.length(); j++) { + Layer layer = new Layer(layersJson.optJSONObject(j), composition); + layerMap.put(layer.getId(), layer); + layers.add(layer); + if (!layer.getMasks().isEmpty()) { + hasMasks = true; + } + if (layer.getMatteType() != null && layer.getMatteType() != Layer.MatteType.None) { + hasMattes = true; + } + } + String id = precomp.optString("id"); + precomps.put(id, layers); + } - @Override public void cancel() { - cancel(true); + return new LottieComposition(precomps, layerMap, layers, scale, bounds, startFrame, endFrame, + frameRate, hasMasks, hasMattes); } } } \ No newline at end of file diff --git a/lottie/src/main/java/com/airbnb/lottie/Utils.java b/lottie/src/main/java/com/airbnb/lottie/Utils.java index 4a8dd2dce8..789d410811 100644 --- a/lottie/src/main/java/com/airbnb/lottie/Utils.java +++ b/lottie/src/main/java/com/airbnb/lottie/Utils.java @@ -3,6 +3,8 @@ import android.graphics.Path; import android.graphics.PointF; +import java.io.Closeable; + final class Utils { private static PointF emptyPoint; @@ -27,4 +29,15 @@ static Path createPath(PointF startPoint, PointF endPoint, PointF cp1, PointF cp } return path; } + + static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } } From 2fab3d33f87711b704db174f0996188cca0131d8 Mon Sep 17 00:00:00 2001 From: Felipe Lima Date: Mon, 20 Feb 2017 17:27:59 -0800 Subject: [PATCH 2/5] Add moved classes --- .../java/com/airbnb/lottie/Cancellable.java | 5 ++++ .../com/airbnb/lottie/CompositionLoader.java | 10 ++++++++ .../airbnb/lottie/FileCompositionLoader.java | 25 +++++++++++++++++++ .../airbnb/lottie/JsonCompositionLoader.java | 25 +++++++++++++++++++ .../lottie/OnCompositionLoadedListener.java | 5 ++++ 5 files changed, 70 insertions(+) create mode 100644 lottie/src/main/java/com/airbnb/lottie/Cancellable.java create mode 100644 lottie/src/main/java/com/airbnb/lottie/CompositionLoader.java create mode 100644 lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java create mode 100644 lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java create mode 100644 lottie/src/main/java/com/airbnb/lottie/OnCompositionLoadedListener.java diff --git a/lottie/src/main/java/com/airbnb/lottie/Cancellable.java b/lottie/src/main/java/com/airbnb/lottie/Cancellable.java new file mode 100644 index 0000000000..6eeac5e8e3 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/Cancellable.java @@ -0,0 +1,5 @@ +package com.airbnb.lottie; + +interface Cancellable { + void cancel(); +} diff --git a/lottie/src/main/java/com/airbnb/lottie/CompositionLoader.java b/lottie/src/main/java/com/airbnb/lottie/CompositionLoader.java new file mode 100644 index 0000000000..3036c03101 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/CompositionLoader.java @@ -0,0 +1,10 @@ +package com.airbnb.lottie; + +import android.os.AsyncTask; + +abstract class CompositionLoader extends AsyncTask + implements Cancellable { + @Override public void cancel() { + cancel(true); + } +} diff --git a/lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java b/lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java new file mode 100644 index 0000000000..1db5992325 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java @@ -0,0 +1,25 @@ +package com.airbnb.lottie; + +import android.content.res.Resources; + +import java.io.InputStream; + +final class FileCompositionLoader extends CompositionLoader { + private final Resources res; + private final OnCompositionLoadedListener loadedListener; + + FileCompositionLoader(Resources res, OnCompositionLoadedListener loadedListener) { + this.res = res; + this.loadedListener = loadedListener; + } + + @Override + protected LottieComposition doInBackground(InputStream... params) { + return Factory.fromInputStream(res, params[0]); + } + + @Override + protected void onPostExecute(LottieComposition composition) { + loadedListener.onCompositionLoaded(composition); + } +} diff --git a/lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java b/lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java new file mode 100644 index 0000000000..9f5ce4d14e --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java @@ -0,0 +1,25 @@ +package com.airbnb.lottie; + +import android.content.res.Resources; + +import org.json.JSONObject; + +final class JsonCompositionLoader extends CompositionLoader { + private final Resources res; + private final OnCompositionLoadedListener loadedListener; + + JsonCompositionLoader(Resources res, OnCompositionLoadedListener loadedListener) { + this.res = res; + this.loadedListener = loadedListener; + } + + @Override + protected LottieComposition doInBackground(JSONObject... params) { + return Factory.fromJsonSync(res, params[0]); + } + + @Override + protected void onPostExecute(LottieComposition composition) { + loadedListener.onCompositionLoaded(composition); + } +} diff --git a/lottie/src/main/java/com/airbnb/lottie/OnCompositionLoadedListener.java b/lottie/src/main/java/com/airbnb/lottie/OnCompositionLoadedListener.java new file mode 100644 index 0000000000..92d3c47536 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/OnCompositionLoadedListener.java @@ -0,0 +1,5 @@ +package com.airbnb.lottie; + +public interface OnCompositionLoadedListener { + void onCompositionLoaded(LottieComposition composition); +} From fdfc9f40dd1297ab98c1eb8cc949a164db05ba21 Mon Sep 17 00:00:00 2001 From: Felipe Lima Date: Mon, 20 Feb 2017 17:49:57 -0800 Subject: [PATCH 3/5] Fix usage of Factory methods --- .../java/com/airbnb/lottie/TestRobot.java | 2 +- .../lottie/samples/AnimationFragment.java | 2 +- .../lottie/samples/LottieFontViewGroup.java | 5 +- README.md | 2 +- .../airbnb/lottie/FileCompositionLoader.java | 8 +- .../airbnb/lottie/JsonCompositionLoader.java | 8 +- .../airbnb/lottie/LottieAnimationView.java | 4 +- .../com/airbnb/lottie/LottieComposition.java | 95 +++++++++++-------- 8 files changed, 68 insertions(+), 58 deletions(-) diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java b/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java index 7c8046f771..b1582fcd90 100644 --- a/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java +++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRobot.java @@ -26,7 +26,7 @@ static void testAnimation(MainActivity activity, String fileName, String imageAs float[] progress) { final LottieAnimationView view = new LottieAnimationView(activity); view.setImageAssetsFolder(imageAssetsFolder); - view.setComposition(LottieComposition.fromFileSync(activity, fileName)); + view.setComposition(LottieComposition.Factory.fromFileSync(activity, fileName)); ViewHelpers.setupView(view) .layout(); diff --git a/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java b/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java index 47a1ab13ad..44f55f5475 100644 --- a/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java +++ b/LottieSample/src/main/java/com/airbnb/lottie/samples/AnimationFragment.java @@ -151,7 +151,7 @@ public void onAnimationUpdate(ValueAnimator animation) { case RC_ASSET: final String assetName = data.getStringExtra(EXTRA_ANIMATION_NAME); animationView.setImageAssetsFolder(assetFolders.get(assetName)); - LottieComposition.fromAssetFileName(getContext(), assetName, + LottieComposition.Factory.fromAssetFileName(getContext(), assetName, new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { diff --git a/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java b/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java index b89d564066..b6c395feca 100644 --- a/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java +++ b/LottieSample/src/main/java/com/airbnb/lottie/samples/LottieFontViewGroup.java @@ -14,7 +14,6 @@ import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieComposition; -import com.airbnb.lottie.LottieCompositionFactory; import com.airbnb.lottie.OnCompositionLoadedListener; import java.util.ArrayList; @@ -45,7 +44,7 @@ public LottieFontViewGroup(Context context, AttributeSet attrs, int defStyleAttr private void init() { setFocusableInTouchMode(true); - LottieCompositionFactory.fromAssetFileName(getContext(), "Mobilo/BlinkingCursor.json", + LottieComposition.Factory.fromAssetFileName(getContext(), "Mobilo/BlinkingCursor.json", new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { @@ -182,7 +181,7 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { if (compositionMap.containsKey(fileName)) { addComposition(compositionMap.get(fileName)); } else { - LottieCompositionFactory.fromAssetFileName(getContext(), fileName, + LottieComposition.Factory.fromAssetFileName(getContext(), fileName, new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { diff --git a/README.md b/README.md index 542b3db78e..20c04bcf02 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ animationView.cancelAnimation(); Under the hood, `LottieAnimationView` uses `LottieDrawable` to render its animations. If you need to, you can use the drawable form directly: ```java LottieDrawable drawable = new LottieDrawable(); -LottieComposition.fromAssetFileName(getContext(), "hello-world.json", (composition) -> { +LottieComposition.Factory.fromAssetFileName(getContext(), "hello-world.json", (composition) -> { drawable.setComposition(composition); }); ``` diff --git a/lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java b/lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java index 1db5992325..33b69afc25 100644 --- a/lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java +++ b/lottie/src/main/java/com/airbnb/lottie/FileCompositionLoader.java @@ -13,13 +13,11 @@ final class FileCompositionLoader extends CompositionLoader { this.loadedListener = loadedListener; } - @Override - protected LottieComposition doInBackground(InputStream... params) { - return Factory.fromInputStream(res, params[0]); + @Override protected LottieComposition doInBackground(InputStream... params) { + return LottieComposition.Factory.fromInputStream(res, params[0]); } - @Override - protected void onPostExecute(LottieComposition composition) { + @Override protected void onPostExecute(LottieComposition composition) { loadedListener.onCompositionLoaded(composition); } } diff --git a/lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java b/lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java index 9f5ce4d14e..25de60c406 100644 --- a/lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java +++ b/lottie/src/main/java/com/airbnb/lottie/JsonCompositionLoader.java @@ -13,13 +13,11 @@ final class JsonCompositionLoader extends CompositionLoader { this.loadedListener = loadedListener; } - @Override - protected LottieComposition doInBackground(JSONObject... params) { - return Factory.fromJsonSync(res, params[0]); + @Override protected LottieComposition doInBackground(JSONObject... params) { + return LottieComposition.Factory.fromJsonSync(res, params[0]); } - @Override - protected void onPostExecute(LottieComposition composition) { + @Override protected void onPostExecute(LottieComposition composition) { loadedListener.onCompositionLoaded(composition); } } diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java index 133c5a5344..9196da06b0 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java @@ -205,7 +205,7 @@ public void setAnimation(final String animationName, final CacheStrategy cacheSt this.animationName = animationName; lottieDrawable.cancelAnimation(); cancelLoaderTask(); - compositionLoader = Factory.fromAssetFileName(getContext(), animationName, + compositionLoader = LottieComposition.Factory.fromAssetFileName(getContext(), animationName, new OnCompositionLoadedListener() { @Override public void onCompositionLoaded(LottieComposition composition) { @@ -229,7 +229,7 @@ public void onCompositionLoaded(LottieComposition composition) { */ public void setAnimation(final JSONObject json) { cancelLoaderTask(); - compositionLoader = Factory.fromJson(getResources(), json, loadedListener); + compositionLoader = LottieComposition.Factory.fromJson(getResources(), json, loadedListener); } private void cancelLoaderTask() { diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java b/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java index 6f4af5ec8d..149777420f 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieComposition.java @@ -3,7 +3,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; -import android.os.AsyncTask; import android.support.annotation.Nullable; import android.support.v4.util.LongSparseArray; @@ -18,6 +17,8 @@ import java.util.List; import java.util.Map; +import static com.airbnb.lottie.Utils.closeQuietly; + /** * After Effects/Bodymovin composition model. This is the serialized model from which the * animation will be created. @@ -38,17 +39,21 @@ public class LottieComposition { private final Map images = new HashMap<>(); private final LongSparseArray layerMap = new LongSparseArray<>(); private final List layers = new ArrayList<>(); - private Rect bounds; - private long startFrame; - private long endFrame; - private int frameRate; - private float scale; - - private LottieComposition(Resources res) { - scale = res.getDisplayMetrics().density; + private final Rect bounds; + private final long startFrame; + private final long endFrame; + private final int frameRate; + private final float scale; + + private LottieComposition(Rect bounds, long startFrame, long endFrame, int frameRate, + float scale) { + this.bounds = bounds; + this.startFrame = startFrame; + this.endFrame = endFrame; + this.frameRate = frameRate; + this.scale = scale; } - Layer layerModelForId(long id) { return layerMap.get(id); } @@ -101,7 +106,9 @@ public float getScale() { } public static class Factory { - /** Loads a composition from a file stored in /assets. */ + /** + * Loads a composition from a file stored in /assets. + */ public static Cancellable fromAssetFileName(Context context, String fileName, OnCompositionLoadedListener loadedListener) { InputStream stream; @@ -148,61 +155,68 @@ public static Cancellable fromJson(Resources res, JSONObject json, } @SuppressWarnings("WeakerAccess") - static LottieComposition fromInputStream(Resources res, InputStream file) { + static LottieComposition fromInputStream(Resources res, InputStream stream) { try { - int size = file.available(); + // TODO: It's not correct to use available() to allocate the byte array. + int size = stream.available(); byte[] buffer = new byte[size]; //noinspection ResultOfMethodCallIgnored - file.read(buffer); - file.close(); + stream.read(buffer); String json = new String(buffer, "UTF-8"); - JSONObject jsonObject = new JSONObject(json); return fromJsonSync(res, jsonObject); } catch (IOException e) { throw new IllegalStateException("Unable to find file.", e); } catch (JSONException e) { throw new IllegalStateException("Unable to load JSON.", e); + } finally { + closeQuietly(stream); } } @SuppressWarnings("WeakerAccess") static LottieComposition fromJsonSync(Resources res, JSONObject json) { - LottieComposition composition = new LottieComposition(res); - + Rect bounds = null; + float scale = res.getDisplayMetrics().density; int width = json.optInt("w", -1); int height = json.optInt("h", -1); + if (width != -1 && height != -1) { - int scaledWidth = (int) (width * composition.scale); - int scaledHeight = (int) (height * composition.scale); + int scaledWidth = (int) (width * scale); + int scaledHeight = (int) (height * scale); if (Math.max(scaledWidth, scaledHeight) > MAX_PIXELS) { float factor = (float) MAX_PIXELS / (float) Math.max(scaledWidth, scaledHeight); scaledWidth *= factor; scaledHeight *= factor; - composition.scale *= factor; + scale *= factor; } - composition.bounds = new Rect(0, 0, scaledWidth, scaledHeight); + bounds = new Rect(0, 0, scaledWidth, scaledHeight); } - composition.startFrame = json.optLong("ip", 0); - composition.endFrame = json.optLong("op", 0); - composition.frameRate = json.optInt("fr", 0); + long startFrame = json.optLong("ip", 0); + long endFrame = json.optLong("op", 0); + int frameRate = json.optInt("fr", 0); + LottieComposition composition = + new LottieComposition(bounds, startFrame, endFrame, frameRate, scale); + JSONArray assetsJson = json.optJSONArray("assets"); + parseImages(assetsJson, composition); + parsePrecomps(assetsJson, composition); + parseLayers(json, composition); + return composition; + } + private static void parseLayers(JSONObject json, LottieComposition composition) { JSONArray jsonLayers = json.optJSONArray("layers"); - for (int i = 0; i < jsonLayers.length(); i++) { + int length = jsonLayers.length(); + for (int i = 0; i < length; i++) { Layer layer = new Layer(jsonLayers.optJSONObject(i), composition); - addLayer(composition, layer); + addLayer(composition.layers, composition.layerMap, layer); } - - JSONArray assetsJson = json.optJSONArray("assets"); - parsePrecomps(composition, assetsJson); - parseImages(composition, assetsJson); - - return composition; } - private static void parsePrecomps(LottieComposition composition, JSONArray assetsJson) { - for (int i = 0; i < assetsJson.length(); i++) { + private static void parsePrecomps(JSONArray assetsJson, LottieComposition composition) { + int length = assetsJson.length(); + for (int i = 0; i < length; i++) { JSONObject assetJson = assetsJson.optJSONObject(i); JSONArray layersJson = assetJson.optJSONArray("layers"); if (layersJson == null) { @@ -220,8 +234,9 @@ private static void parsePrecomps(LottieComposition composition, JSONArray asset } } - private static void parseImages(LottieComposition composition, JSONArray assetsJson) { - for (int i = 0; i < assetsJson.length(); i++) { + private static void parseImages(JSONArray assetsJson, LottieComposition composition) { + int length = assetsJson.length(); + for (int i = 0; i < length; i++) { JSONObject assetJson = assetsJson.optJSONObject(i); if (!assetJson.has("p")) { continue; @@ -231,9 +246,9 @@ private static void parseImages(LottieComposition composition, JSONArray assetsJ } } - private static void addLayer(LottieComposition composition, Layer layer) { - composition.layers.add(layer); - composition.layerMap.put(layer.getId(), layer); + private static void addLayer(List layers, LongSparseArray layerMap, Layer layer) { + layers.add(layer); + layerMap.put(layer.getId(), layer); } } } \ No newline at end of file From ec8d6f87cb266d3edf933fb9b236bbba699430db Mon Sep 17 00:00:00 2001 From: Felipe Lima Date: Mon, 20 Feb 2017 18:16:57 -0800 Subject: [PATCH 4/5] Update tests to JUnit 4 --- LottieSample/build.gradle | 1 + .../java/com/airbnb/lottie/LottieTest.java | 81 ++++++++++--------- .../java/com/airbnb/lottie/TestRunner.java | 11 +++ 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/LottieSample/build.gradle b/LottieSample/build.gradle index 74ac10f3e1..53f4ae6179 100644 --- a/LottieSample/build.gradle +++ b/LottieSample/build.gradle @@ -10,6 +10,7 @@ android { targetSdkVersion 25 versionCode 3 versionName "1.0.3" + testInstrumentationRunner "com.airbnb.lottie.TestRunner" } buildTypes { release { diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/LottieTest.java b/LottieSample/src/androidTest/java/com/airbnb/lottie/LottieTest.java index dc1a246f53..4fead439b4 100644 --- a/LottieSample/src/androidTest/java/com/airbnb/lottie/LottieTest.java +++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/LottieTest.java @@ -1,52 +1,55 @@ package com.airbnb.lottie; - -import android.test.ActivityInstrumentationTestCase2; +import android.support.test.filters.LargeTest; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; import com.airbnb.lottie.samples.MainActivity; +import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; /** - * Run these with: ./gradlew --daemon recordMode screenshotTests - * If you run that command, it completes successfully, and nothing shows up in git, then you haven't broken anything! + * Run these with: ./gradlew recordMode screenshotTests + * If you run that command, it completes successfully, and nothing shows up in git, then you + * haven't broken anything! */ -public class LottieTest extends ActivityInstrumentationTestCase2 { - - public LottieTest() { - super(MainActivity.class); - } +@RunWith(AndroidJUnit4.class) +@LargeTest +public class LottieTest { + @Rule public ActivityTestRule activityRule = new ActivityTestRule<>( + MainActivity.class); - @Test - public void testAll() { - TestRobot.testAnimation(getActivity(), "9squares-AlBoardman.json"); - TestRobot.testAnimation(getActivity(), "EmptyState.json"); - TestRobot.testAnimation(getActivity(), "HamburgerArrow.json"); - TestRobot.testAnimation(getActivity(), "LottieLogo1.json"); - TestRobot.testAnimation(getActivity(), "LottieLogo2.json"); - TestRobot.testAnimation(getActivity(), "MotionCorpse-Jrcanest.json"); - TestRobot.testAnimation(getActivity(), "PinJump.json"); - TestRobot.testAnimation(getActivity(), "TwitterHeart.json"); - TestRobot.testAnimation(getActivity(), "Tests/Hosts.json"); - TestRobot.testAnimation(getActivity(), "Tests/LightBulb.json", null, + @Test public void testAll() { + TestRobot.testAnimation(activityRule.getActivity(), "9squares-AlBoardman.json"); + TestRobot.testAnimation(activityRule.getActivity(), "EmptyState.json"); + TestRobot.testAnimation(activityRule.getActivity(), "HamburgerArrow.json"); + TestRobot.testAnimation(activityRule.getActivity(), "LottieLogo1.json"); + TestRobot.testAnimation(activityRule.getActivity(), "LottieLogo2.json"); + TestRobot.testAnimation(activityRule.getActivity(), "MotionCorpse-Jrcanest.json"); + TestRobot.testAnimation(activityRule.getActivity(), "PinJump.json"); + TestRobot.testAnimation(activityRule.getActivity(), "TwitterHeart.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/Hosts.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/LightBulb.json", null, new float[]{0f, 0.05f, 0.10f, 0.2f, 0.3f, 0.4f, 0.5f, 1f}); - TestRobot.testAnimation(getActivity(), "Tests/LoopPlayOnce.json"); - TestRobot.testAnimation(getActivity(), "Tests/Alarm.json"); - TestRobot.testAnimation(getActivity(), "Tests/CheckSwitch.json"); - TestRobot.testAnimation(getActivity(), "Tests/EllipseTrimPath.json"); - TestRobot.testAnimation(getActivity(), "Tests/SplitDimensions.json"); - TestRobot.testAnimation(getActivity(), "Tests/TrimPathsFull.json"); - TestRobot.testAnimation(getActivity(), "Tests/Laugh4.json"); - TestRobot.testAnimation(getActivity(), "Tests/Star.json"); - TestRobot.testAnimation(getActivity(), "Tests/Polygon.json"); - TestRobot.testAnimation(getActivity(), "Tests/AllSet.json"); - TestRobot.testAnimation(getActivity(), "Tests/City.json"); - TestRobot.testAnimation(getActivity(), "Tests/PreCompMadness.json"); - TestRobot.testAnimation(getActivity(), "Tests/MatteParentPrecomp.json"); - TestRobot.testAnimation(getActivity(), "Tests/Image.json", "Tests/weaccept"); - TestRobot.testStatic(getActivity(), "Tests/TrimPathFill.json"); - TestRobot.testStatic(getActivity(), "Tests/Mask_26.json"); - TestRobot.testStatic(getActivity(), "Tests/MatteInv.json"); - TestRobot.testStatic(getActivity(), "Tests/MaskInv.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/LoopPlayOnce.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/Alarm.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/CheckSwitch.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/EllipseTrimPath.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/SplitDimensions.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/TrimPathsFull.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/Laugh4.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/Star.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/Polygon.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/AllSet.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/City.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/PreCompMadness.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/MatteParentPrecomp.json"); + TestRobot.testAnimation(activityRule.getActivity(), "Tests/Image.json", "Tests/weaccept"); + TestRobot.testStatic(activityRule.getActivity(), "Tests/TrimPathFill.json"); + TestRobot.testStatic(activityRule.getActivity(), "Tests/Mask_26.json"); + TestRobot.testStatic(activityRule.getActivity(), "Tests/MatteInv.json"); + TestRobot.testStatic(activityRule.getActivity(), "Tests/MaskInv.json"); } } diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRunner.java b/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRunner.java index 2eaf80f919..c4eb3a1d5b 100644 --- a/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRunner.java +++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/TestRunner.java @@ -1,7 +1,18 @@ package com.airbnb.lottie; +import android.os.Bundle; import android.support.test.runner.AndroidJUnitRunner; +import com.facebook.testing.screenshot.ScreenshotRunner; public class TestRunner extends AndroidJUnitRunner { + @Override public void onCreate(Bundle arguments) { + ScreenshotRunner.onCreate(this, arguments); + super.onCreate(arguments); + } + + @Override public void finish(int resultCode, Bundle results) { + ScreenshotRunner.onDestroy(); + super.finish(resultCode, results); + } } From 5782ac45e56394de53e261edb92423dbbab1c725 Mon Sep 17 00:00:00 2001 From: Felipe Lima Date: Mon, 20 Feb 2017 18:23:40 -0800 Subject: [PATCH 5/5] Delete this file --- .../main/java/com/airbnb/lottie/Factory.java | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 lottie/src/main/java/com/airbnb/lottie/Factory.java diff --git a/lottie/src/main/java/com/airbnb/lottie/Factory.java b/lottie/src/main/java/com/airbnb/lottie/Factory.java deleted file mode 100644 index 94bba05dd1..0000000000 --- a/lottie/src/main/java/com/airbnb/lottie/Factory.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.airbnb.lottie; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Rect; -import android.support.v4.util.LongSparseArray; -import android.util.Log; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import static com.airbnb.lottie.Utils.closeQuietly; - -