Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use moshi implementation for json parsing #1234

Merged
merged 19 commits into from
May 30, 2019
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility
import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.model.S3ObjectSummary
import junit.framework.Assert.assertNull
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.produce
Expand Down
4 changes: 4 additions & 0 deletions lottie/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ dependencies {
testImplementation "org.mockito:mockito-core:2.15.0"
testImplementation 'junit:junit:4.12'
testImplementation "org.robolectric:robolectric:4.0-alpha-3"
// Do not ugprade to 2.0 because it will bring in Kotlin as a transitive dependency.
implementation("com.squareup.okio:okio:1.17.4")


}

task javadoc(type: Javadoc) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,21 @@
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.appcompat.widget.AppCompatImageView;
import okio.Okio;

import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.JsonReader;
import android.util.Log;
import android.view.View;

import com.airbnb.lottie.model.KeyPath;
import com.airbnb.lottie.parser.moshi.JsonReader;
import com.airbnb.lottie.utils.Utils;
import com.airbnb.lottie.value.LottieFrameInfo;
import com.airbnb.lottie.value.LottieValueCallback;
import com.airbnb.lottie.value.SimpleLottieValueCallback;

import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -320,7 +323,7 @@ public void setAnimationFromJson(String jsonString) {
* JSONObject never has to be done.
*/
public void setAnimationFromJson(String jsonString, @Nullable String cacheKey) {
setAnimation(new JsonReader(new StringReader(jsonString)), cacheKey);
setAnimation(JsonReader.of(Okio.buffer(Okio.source(new ByteArrayInputStream(jsonString.getBytes())))), cacheKey);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
import androidx.annotation.WorkerThread;
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.parser.moshi.JsonReader;
import com.airbnb.lottie.utils.Logger;

import org.json.JSONObject;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,36 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.WorkerThread;
import android.util.JsonReader;
import android.util.Log;

import com.airbnb.lottie.model.LottieCompositionCache;
import com.airbnb.lottie.network.NetworkFetcher;
import com.airbnb.lottie.parser.LottieCompositionParser;
import com.airbnb.lottie.parser.LottieCompositionMoshiParser;
import com.airbnb.lottie.parser.moshi.JsonReader;

import com.airbnb.lottie.utils.Utils;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.WorkerThread;

import static com.airbnb.lottie.parser.moshi.JsonReader.*;
import static com.airbnb.lottie.utils.Utils.closeQuietly;
import static okio.Okio.buffer;
import static okio.Okio.source;

/**
* Helpers to create or cache a LottieComposition.
*
* <p>
* All factory methods take a cache key. The animation will be stored in an LRU cache for future use.
* In-progress tasks will also be held so they can be returned for subsequent requests for the same
* animation prior to the cache being populated.
Expand Down Expand Up @@ -64,7 +66,8 @@ public static void setMaxCacheSize(int size) {
public static LottieTask<LottieComposition> fromUrl(final Context context, final String url) {
String urlCacheKey = "url_" + url;
return cache(urlCacheKey, new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
return NetworkFetcher.fetchSync(context, url);
}
});
Expand All @@ -91,7 +94,8 @@ public static LottieTask<LottieComposition> fromAsset(Context context, final Str
// Prevent accidentally leaking an Activity.
final Context appContext = context.getApplicationContext();
return cache(fileName, new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
return fromAssetSync(appContext, fileName);
}
});
Expand All @@ -117,6 +121,7 @@ public static LottieResult<LottieComposition> fromAssetSync(Context context, Str
}
}


/**
* Parse an animation from raw/res. This is recommended over putting your animation in assets because
* it uses a hard reference to R.
Expand All @@ -126,7 +131,8 @@ public static LottieTask<LottieComposition> fromRawRes(Context context, @RawRes
// Prevent accidentally leaking an Activity.
final Context appContext = context.getApplicationContext();
return cache(rawResCacheKey(rawRes), new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
return fromRawResSync(appContext, rawRes);
}
});
Expand Down Expand Up @@ -157,7 +163,8 @@ private static String rawResCacheKey(@RawRes int resId) {
*/
public static LottieTask<LottieComposition> fromJsonInputStream(final InputStream stream, @Nullable final String cacheKey) {
return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
return fromJsonInputStreamSync(stream, cacheKey);
}
});
Expand All @@ -171,24 +178,27 @@ public static LottieResult<LottieComposition> fromJsonInputStreamSync(InputStrea
return fromJsonInputStreamSync(stream, cacheKey, true);
}


@WorkerThread
private static LottieResult<LottieComposition> fromJsonInputStreamSync(InputStream stream, @Nullable String cacheKey, boolean close) {
try {
return fromJsonReaderSync(new JsonReader(new InputStreamReader(stream)), cacheKey);
return fromJsonReaderSync(of(buffer(source(stream))), cacheKey);
} finally {
if (close) {
closeQuietly(stream);
}
}
}


/**
* @see #fromJsonSync(JSONObject, String)
*/
@Deprecated
public static LottieTask<LottieComposition> fromJson(final JSONObject json, @Nullable final String cacheKey) {
return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
//noinspection deprecation
return fromJsonSync(json, cacheKey);
}
Expand All @@ -211,7 +221,8 @@ public static LottieResult<LottieComposition> fromJsonSync(JSONObject json, @Nul
*/
public static LottieTask<LottieComposition> fromJsonString(final String json, @Nullable final String cacheKey) {
return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
return fromJsonStringSync(json, cacheKey);
}
});
Expand All @@ -223,29 +234,32 @@ public static LottieTask<LottieComposition> fromJsonString(final String json, @N
*/
@WorkerThread
public static LottieResult<LottieComposition> fromJsonStringSync(String json, @Nullable String cacheKey) {
return fromJsonReaderSync(new JsonReader(new StringReader(json)), cacheKey);


ByteArrayInputStream stream = new ByteArrayInputStream(json.getBytes());
return fromJsonReaderSync(of(buffer(source(stream))), cacheKey);
}

public static LottieTask<LottieComposition> fromJsonReader(final JsonReader reader, @Nullable final String cacheKey) {
return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
return fromJsonReaderSync(reader, cacheKey);
}
});
}

/**
* Return a LottieComposition for the specified json.
*/

@WorkerThread
public static LottieResult<LottieComposition> fromJsonReaderSync(JsonReader reader, @Nullable String cacheKey) {
public static LottieResult<LottieComposition> fromJsonReaderSync(com.airbnb.lottie.parser.moshi.JsonReader reader, @Nullable String cacheKey) {
return fromJsonReaderSyncInternal(reader, cacheKey, true);
}


private static LottieResult<LottieComposition> fromJsonReaderSyncInternal(
JsonReader reader, @Nullable String cacheKey, boolean close) {
com.airbnb.lottie.parser.moshi.JsonReader reader, @Nullable String cacheKey, boolean close) {
try {
LottieComposition composition = LottieCompositionParser.parse(reader);
LottieComposition composition = LottieCompositionMoshiParser.parse(reader);
LottieCompositionCache.getInstance().put(cacheKey, composition);
return new LottieResult<>(composition);
} catch (Exception e) {
Expand All @@ -257,9 +271,11 @@ private static LottieResult<LottieComposition> fromJsonReaderSyncInternal(
}
}


public static LottieTask<LottieComposition> fromZipStream(final ZipInputStream inputStream, @Nullable final String cacheKey) {
return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() {
@Override public LottieResult<LottieComposition> call() {
@Override
public LottieResult<LottieComposition> call() {
return fromZipStreamSync(inputStream, cacheKey);
}
});
Expand Down Expand Up @@ -290,8 +306,8 @@ private static LottieResult<LottieComposition> fromZipStreamSyncInternal(ZipInpu
final String entryName = entry.getName();
if (entryName.contains("__MACOSX")) {
inputStream.closeEntry();
} else if (entryName.contains(".json")) {
JsonReader reader = new JsonReader(new InputStreamReader(inputStream));
} else if (entry.getName().contains(".json")) {
com.airbnb.lottie.parser.moshi.JsonReader reader = of(buffer(source(inputStream)));
composition = LottieCompositionFactory.fromJsonReaderSyncInternal(reader, null, false).getValue();
} else if (entryName.contains(".png") || entryName.contains(".webp")) {
String[] splitName = entryName.split("/");
Expand Down Expand Up @@ -346,7 +362,7 @@ private static LottieImageAsset findImageAssetForFileName(LottieComposition comp
* Then, add the new task to the task cache and set up listeners so it gets cleared when done.
*/
private static LottieTask<LottieComposition> cache(
@Nullable final String cacheKey, Callable<LottieResult<LottieComposition>> callable) {
@Nullable final String cacheKey, Callable<LottieResult<LottieComposition>> callable) {
final LottieComposition cachedComposition = cacheKey == null ? null : LottieCompositionCache.getInstance().get(cacheKey);
if (cachedComposition != null) {
return new LottieTask<>(new Callable<LottieResult<LottieComposition>>() {
Expand All @@ -362,15 +378,17 @@ public LottieResult<LottieComposition> call() {

LottieTask<LottieComposition> task = new LottieTask<>(callable);
task.addListener(new LottieListener<LottieComposition>() {
@Override public void onResult(LottieComposition result) {
@Override
public void onResult(LottieComposition result) {
if (cacheKey != null) {
LottieCompositionCache.getInstance().put(cacheKey, result);
}
taskCache.remove(cacheKey);
}
});
task.addFailureListener(new LottieListener<Throwable>() {
@Override public void onResult(Throwable result) {
@Override
public void onResult(Throwable result) {
taskCache.remove(cacheKey);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import androidx.annotation.Nullable;

import com.airbnb.lottie.LottieDrawable;
import com.airbnb.lottie.LottieProperty;
Expand All @@ -18,6 +17,8 @@

import java.util.List;

import androidx.annotation.Nullable;

public class RectangleContent
implements BaseKeyframeAnimation.AnimationListener, KeyPathElementContent, PathContent {
private final Path path = new Path();
Expand Down Expand Up @@ -50,11 +51,13 @@ public RectangleContent(LottieDrawable lottieDrawable, BaseLayer layer, Rectangl
cornerRadiusAnimation.addUpdateListener(this);
}

@Override public String getName() {
@Override
public String getName() {
return name;
}

@Override public void onValueChanged() {
@Override
public void onValueChanged() {
invalidate();
}

Expand All @@ -63,7 +66,8 @@ private void invalidate() {
lottieDrawable.invalidateSelf();
}

@Override public void setContents(List<Content> contentsBefore, List<Content> contentsAfter) {
@Override
public void setContents(List<Content> contentsBefore, List<Content> contentsAfter) {
for (int i = 0; i < contentsBefore.size(); i++) {
Content content = contentsBefore.get(i);
if (content instanceof TrimPathContent &&
Expand All @@ -75,7 +79,8 @@ private void invalidate() {
}
}

@Override public Path getPath() {
@Override
public Path getPath() {
if (isPathValid) {
return path;
}
Expand All @@ -91,7 +96,7 @@ private void invalidate() {
float halfWidth = size.x / 2f;
float halfHeight = size.y / 2f;
float radius = cornerRadiusAnimation == null ?
0f : ((FloatKeyframeAnimation) cornerRadiusAnimation).getFloatValue();
0f : ((FloatKeyframeAnimation) cornerRadiusAnimation).getFloatValue();
float maxRadius = Math.min(halfWidth, halfHeight);
if (radius > maxRadius) {
radius = maxRadius;
Expand Down Expand Up @@ -149,18 +154,20 @@ private void invalidate() {
return path;
}

@Override public void resolveKeyPath(KeyPath keyPath, int depth, List<KeyPath> accumulator,
KeyPath currentPartialKeyPath) {
@Override
public void resolveKeyPath(KeyPath keyPath, int depth, List<KeyPath> accumulator,
KeyPath currentPartialKeyPath) {
MiscUtils.resolveKeyPath(keyPath, depth, accumulator, currentPartialKeyPath, this);
}

@Override public <T> void addValueCallback(T property, @Nullable LottieValueCallback<T> callback) {
@Override
public <T> void addValueCallback(T property, @Nullable LottieValueCallback<T> callback) {
if (property == LottieProperty.RECTANGLE_SIZE) {
sizeAnimation.setValueCallback((LottieValueCallback<PointF>) callback);
sizeAnimation.setValueCallback((LottieValueCallback<PointF>) callback);
} else if (property == LottieProperty.POSITION) {
positionAnimation.setValueCallback((LottieValueCallback<PointF>) callback);
positionAnimation.setValueCallback((LottieValueCallback<PointF>) callback);
} else if (property == LottieProperty.CORNER_RADIUS) {
cornerRadiusAnimation.setValueCallback((LottieValueCallback<Float>) callback);
cornerRadiusAnimation.setValueCallback((LottieValueCallback<Float>) callback);
}
}
}
Loading