Prototype an Android lottie player

Create a new Skottie test app, which plays lottie files using
a TextureView.
Implement SkottieView, which takes a JSON input stream and
plays the animation.

Bug: skia:
Change-Id: Ic62688b91692c28f35b13356d1e99b4d15d3e30f
Reviewed-on: https://skia-review.googlesource.com/130125
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Stan Iliev <stani@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 744146f..862c326 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1893,6 +1893,23 @@
       libs = [ "android" ]
     }
   }
+  if (is_android && skia_enable_gpu) {
+    test_app("skottie_android") {
+      is_shared_library = true
+
+      sources = [
+        "platform_tools/android/apps/skottie/src/main/cpp/JavaInputStreamAdaptor.cpp",
+        "platform_tools/android/apps/skottie/src/main/cpp/native-lib.cpp",
+      ]
+      libs = []
+
+      include_dirs = []
+      deps = [
+        ":skia",
+        "modules/skottie",
+      ]
+    }
+  }
 
   test_app("list_gms") {
     sources = [
diff --git a/platform_tools/android/apps/settings.gradle b/platform_tools/android/apps/settings.gradle
index 72774bb..e42c0d4 100644
--- a/platform_tools/android/apps/settings.gradle
+++ b/platform_tools/android/apps/settings.gradle
@@ -1,4 +1,5 @@
 include ':viewer'
 include ':skqp'
 include ':arcore' //must build out directory first: bin/gn gen out/arm64 --args='ndk="NDKPATH" target_cpu="ABI" is_component_build=true'
-include ':skar_java'
\ No newline at end of file
+include ':skar_java'
+include ':skottie'
\ No newline at end of file
diff --git a/platform_tools/android/apps/skottie/build.gradle b/platform_tools/android/apps/skottie/build.gradle
new file mode 100644
index 0000000..1346a2f
--- /dev/null
+++ b/platform_tools/android/apps/skottie/build.gradle
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+apply plugin: 'com.android.application'
+
+dependencies {
+    implementation 'com.android.support:support-v13:23.3.0'
+    implementation 'com.android.support:appcompat-v7:23.3.0'
+}
+
+android {
+    compileSdkVersion 23
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    flavorDimensions "tier"
+    defaultConfig {
+        applicationId "org.skia.skottie"
+        minSdkVersion 23
+        targetSdkVersion 23
+        versionCode 1
+        versionName "1.0"
+        signingConfig signingConfigs.debug
+    }
+    flavorDimensions "base"
+    sourceSets.main.jni.srcDirs = [] //disable automatic ndk-build call
+    sourceSets.main.jniLibs.srcDir "src/main/libs"
+    productFlavors { universal{}; arm {}; arm64 {}; x86 {}; x64 {}; arm64vulkan{}; }
+
+    setupSkiaLibraryBuild(project, applicationVariants, "libskottie_android")
+}
diff --git a/platform_tools/android/apps/skottie/src/main/AndroidManifest.xml b/platform_tools/android/apps/skottie/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d308aed
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- BEGIN_INCLUDE(manifest) -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="org.skia.skottie"
+          android:versionCode="1"
+          android:versionName="1.0">
+
+  <application
+      android:allowBackup="false"
+      android:theme="@android:style/Theme.Holo.Light"
+      android:name=".SkottieApplication"
+      android:label="Skottie">
+
+    <activity android:name=".SkottieActivity">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+  </application>
+
+</manifest>
+<!-- END_INCLUDE(manifest) -->
diff --git a/platform_tools/android/apps/skottie/src/main/cpp/JavaInputStreamAdaptor.cpp b/platform_tools/android/apps/skottie/src/main/cpp/JavaInputStreamAdaptor.cpp
new file mode 100644
index 0000000..dcdf4b7
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/cpp/JavaInputStreamAdaptor.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "JavaInputStreamAdaptor.h"
+#include "SkPostConfig.h"
+
+static jclass findClassCheck(JNIEnv* env, const char classname[]) {
+    jclass clazz = env->FindClass(classname);
+    SkASSERT(!env->ExceptionCheck());
+    return clazz;
+}
+
+static jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
+                                  const char methodname[], const char type[]) {
+    jmethodID id = env->GetMethodID(clazz, methodname, type);
+    SkASSERT(!env->ExceptionCheck());
+    return id;
+}
+
+static jmethodID    gInputStream_readMethodID;
+static jmethodID    gInputStream_skipMethodID;
+
+static JNIEnv* get_env_or_die(JavaVM* jvm) {
+    JNIEnv* env;
+    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        char errorMessage[256];
+        sprintf(errorMessage, "Failed to get JNIEnv for JavaVM: %p", jvm);
+        SK_ABORT(errorMessage);
+    }
+    return env;
+}
+
+/**
+ *  Wrapper for a Java InputStream.
+ */
+class JavaInputStreamAdaptor : public SkStream {
+    JavaInputStreamAdaptor(JavaVM* jvm, jobject js, jbyteArray ar, jint capacity,
+                           bool swallowExceptions)
+            : fJvm(jvm)
+            , fJavaInputStream(js)
+            , fJavaByteArray(ar)
+            , fCapacity(capacity)
+            , fBytesRead(0)
+            , fIsAtEnd(false)
+            , fSwallowExceptions(swallowExceptions) {}
+
+public:
+    static JavaInputStreamAdaptor* Create(JNIEnv* env, jobject js, jbyteArray ar,
+                                          bool swallowExceptions) {
+        JavaVM* jvm;
+        if (env->GetJavaVM(&jvm) != JNI_OK) {
+            SK_ABORT("Failed to get JavaVM");
+        }
+
+        js = env->NewGlobalRef(js);
+        if (!js) {
+            return nullptr;
+        }
+
+        ar = (jbyteArray) env->NewGlobalRef(ar);
+        if (!ar) {
+            env->DeleteGlobalRef(js);
+            return nullptr;
+        }
+
+        jint capacity = env->GetArrayLength(ar);
+        return new JavaInputStreamAdaptor(jvm, js, ar, capacity, swallowExceptions);
+    }
+
+    ~JavaInputStreamAdaptor() override {
+        auto* env = get_env_or_die(fJvm);
+        env->DeleteGlobalRef(fJavaInputStream);
+        env->DeleteGlobalRef(fJavaByteArray);
+    }
+
+    size_t read(void* buffer, size_t size) override {
+        auto* env = get_env_or_die(fJvm);
+        if (!fSwallowExceptions && checkException(env)) {
+            // Just in case the caller did not clear from a previous exception.
+            return 0;
+        }
+        if (NULL == buffer) {
+            if (0 == size) {
+                return 0;
+            } else {
+                /*  InputStream.skip(n) can return <=0 but still not be at EOF
+                    If we see that value, we need to call read(), which will
+                    block if waiting for more data, or return -1 at EOF
+                 */
+                size_t amountSkipped = 0;
+                do {
+                    size_t amount = this->doSkip(size - amountSkipped, env);
+                    if (0 == amount) {
+                        char tmp;
+                        amount = this->doRead(&tmp, 1, env);
+                        if (0 == amount) {
+                            // if read returned 0, we're at EOF
+                            fIsAtEnd = true;
+                            break;
+                        }
+                    }
+                    amountSkipped += amount;
+                } while (amountSkipped < size);
+                return amountSkipped;
+            }
+        }
+        return this->doRead(buffer, size, env);
+    }
+
+    bool isAtEnd() const override { return fIsAtEnd; }
+
+private:
+    size_t doRead(void* buffer, size_t size, JNIEnv* env) {
+        size_t bytesRead = 0;
+        // read the bytes
+        do {
+            jint requested = 0;
+            if (size > static_cast<size_t>(fCapacity)) {
+                requested = fCapacity;
+            } else {
+                // This is safe because requested is clamped to (jint)
+                // fCapacity.
+                requested = static_cast<jint>(size);
+            }
+
+            jint n = env->CallIntMethod(fJavaInputStream,
+                                        gInputStream_readMethodID, fJavaByteArray, 0, requested);
+            if (checkException(env)) {
+                SkDebugf("---- read threw an exception\n");
+                return bytesRead;
+            }
+
+            if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
+                fIsAtEnd = true;
+                break;  // eof
+            }
+
+            env->GetByteArrayRegion(fJavaByteArray, 0, n,
+                                    reinterpret_cast<jbyte*>(buffer));
+            if (checkException(env)) {
+                SkDebugf("---- read:GetByteArrayRegion threw an exception\n");
+                return bytesRead;
+            }
+
+            buffer = (void*)((char*)buffer + n);
+            bytesRead += n;
+            size -= n;
+            fBytesRead += n;
+        } while (size != 0);
+
+        return bytesRead;
+    }
+
+    size_t doSkip(size_t size, JNIEnv* env) {
+        jlong skipped = env->CallLongMethod(fJavaInputStream,
+                                            gInputStream_skipMethodID, (jlong)size);
+        if (checkException(env)) {
+            SkDebugf("------- skip threw an exception\n");
+            return 0;
+        }
+        if (skipped < 0) {
+            skipped = 0;
+        }
+
+        return (size_t)skipped;
+    }
+
+    bool checkException(JNIEnv* env) {
+        if (!env->ExceptionCheck()) {
+            return false;
+        }
+
+        env->ExceptionDescribe();
+        if (fSwallowExceptions) {
+            env->ExceptionClear();
+        }
+
+        // There is no way to recover from the error, so consider the stream
+        // to be at the end.
+        fIsAtEnd = true;
+
+        return true;
+    }
+
+    JavaVM*     fJvm;
+    jobject     fJavaInputStream;
+    jbyteArray  fJavaByteArray;
+    const jint  fCapacity;
+    size_t      fBytesRead;
+    bool        fIsAtEnd;
+    const bool  fSwallowExceptions;
+};
+
+static SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray storage,
+                                       bool swallowExceptions = true) {
+    return JavaInputStreamAdaptor::Create(env, stream, storage, swallowExceptions);
+}
+
+static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
+    SkASSERT(stream != NULL);
+    size_t bufferSize = 4096;
+    size_t streamLen = 0;
+    size_t len;
+    char* data = (char*)sk_malloc_throw(bufferSize);
+
+    while ((len = stream->read(data + streamLen,
+                               bufferSize - streamLen)) != 0) {
+        streamLen += len;
+        if (streamLen == bufferSize) {
+            bufferSize *= 2;
+            data = (char*)sk_realloc_throw(data, bufferSize);
+        }
+    }
+    data = (char*)sk_realloc_throw(data, streamLen);
+
+    SkMemoryStream* streamMem = new SkMemoryStream();
+    streamMem->setMemoryOwned(data, streamLen);
+    return streamMem;
+}
+
+SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
+                                        jbyteArray storage) {
+    std::unique_ptr<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
+    if (NULL == adaptor.get()) {
+        return NULL;
+    }
+    return adaptor_to_mem_stream(adaptor.get());
+}
+
+
+extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        return -1;
+    }
+
+    jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
+    gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
+    gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
+
+    return JNI_VERSION_1_6;
+}
diff --git a/platform_tools/android/apps/skottie/src/main/cpp/JavaInputStreamAdaptor.h b/platform_tools/android/apps/skottie/src/main/cpp/JavaInputStreamAdaptor.h
new file mode 100644
index 0000000..c9193fc
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/cpp/JavaInputStreamAdaptor.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <jni.h>
+#include <SkStream.h>
+#include <SkMalloc.h>
+
+SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
+                                        jbyteArray storage);
diff --git a/platform_tools/android/apps/skottie/src/main/cpp/native-lib.cpp b/platform_tools/android/apps/skottie/src/main/cpp/native-lib.cpp
new file mode 100644
index 0000000..3cbedbc
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/cpp/native-lib.cpp
@@ -0,0 +1,211 @@
+
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <jni.h>
+#include <math.h>
+#include <string>
+#include <utility>
+#include <SkColor.h>
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+#include <SkSurface.h>
+#include <SkTime.h>
+
+#include <GrContextOptions.h>
+#include <GrContext.h>
+#include <gl/GrGLInterface.h>
+#include <GrBackendSurface.h>
+#include <gl/GrGLTypes.h>
+
+#include <Skottie.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <GLES3/gl3.h>
+#include <android/trace.h>
+#include "JavaInputStreamAdaptor.h"
+
+#define STENCIL_BUFFER_SIZE 8
+
+/*#define ATRACE_NAME(name) ScopedTrace ___tracer(name)
+
+// ATRACE_CALL is an ATRACE_NAME that uses the current function name.
+#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
+namespace {
+    class ScopedTrace {
+    public:
+        inline ScopedTrace(const char *name) {
+            ATrace_beginSection(name);
+        }
+
+        inline ~ScopedTrace() {
+            ATrace_endSection();
+        }
+    };
+
+}*/
+
+//disable atrace
+#define ATRACE_NAME(name)
+#define ATRACE_CALL()
+
+struct SkottieRunner {
+    sk_sp<GrContext> mGrContext;
+};
+
+extern "C" JNIEXPORT jlong
+JNICALL
+Java_org_skia_skottie_SkottieRunner_nCreateProxy(JNIEnv *env, jclass clazz) {
+    sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
+    if (!glInterface.get()) {
+        return 0;
+    }
+
+    GrContextOptions options;
+    options.fDisableDistanceFieldPaths = true;
+    options.fDisableCoverageCountingPaths = true;
+    sk_sp<GrContext> grContext = GrContext::MakeGL(std::move(glInterface), options);
+    if (!grContext.get()) {
+        return 0;
+    }
+
+    SkottieRunner* skottie = new SkottieRunner();
+    skottie->mGrContext = grContext;
+
+    return (jlong) skottie;
+}
+
+extern "C" JNIEXPORT void
+JNICALL
+Java_org_skia_skottie_SkottieRunner_nDeleteProxy(JNIEnv *env, jclass clazz, jlong nativeProxy) {
+    if (!nativeProxy) {
+        return;
+    }
+    SkottieRunner* skottie = reinterpret_cast<SkottieRunner*>(nativeProxy);
+    if (skottie->mGrContext) {
+        skottie->mGrContext->releaseResourcesAndAbandonContext();
+        skottie->mGrContext.reset();
+    }
+    delete skottie;
+}
+
+struct SkottieAnimation {
+    SkottieRunner *mRunner;
+    std::unique_ptr<SkStream> mStream;
+    sk_sp<skottie::Animation> mAnimation;
+    long                      mTimeBase;
+    float                     mDuration; //in milliseconds
+};
+
+extern "C" JNIEXPORT jlong
+JNICALL
+Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nCreateProxy(JNIEnv *env, jobject clazz,
+                                                                       jlong runner, jobject is,
+                                                                       jbyteArray storage) {
+
+    if (!runner) {
+        return 0;
+    }
+    SkottieRunner *skottieRunner = reinterpret_cast<SkottieRunner*>(runner);
+    std::unique_ptr<SkStream> stream(CopyJavaInputStream(env, is, storage));
+    if (!stream.get()) {
+        // Cannot create a stream
+        return 0;
+    }
+
+    SkottieAnimation* skottieAnimation = new SkottieAnimation();
+    skottieAnimation->mRunner = skottieRunner;
+    skottieAnimation->mStream = std::move(stream);
+
+    skottieAnimation->mAnimation = skottie::Animation::Make(skottieAnimation->mStream.get(),
+                                                            nullptr, nullptr);
+    skottieAnimation->mTimeBase  = 0.0f; // force a time reset
+    skottieAnimation->mDuration = 1000 * skottieAnimation->mAnimation->duration();
+
+    if (!skottieAnimation->mAnimation) {
+        //failed to load Bodymovin animation
+        delete skottieAnimation;
+        return 0;
+    }
+
+    return (jlong) skottieAnimation;
+}
+
+extern "C" JNIEXPORT void
+JNICALL
+Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nDeleteProxy(JNIEnv *env, jclass clazz,
+                                                                       jlong nativeProxy) {
+    if (!nativeProxy) {
+        return;
+    }
+    SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
+    delete skottieAnimation;
+}
+
+extern "C" JNIEXPORT void
+JNICALL
+Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nDrawFrame(JNIEnv *env, jclass clazz,
+                                                                     jlong nativeProxy, jint width,
+                                                                     jint height,
+                                                                     jboolean wideColorGamut,
+                                                                     jlong frameTimeNanos) {
+    ATRACE_NAME("SkottieDrawFrame");
+    if (!nativeProxy) {
+        return;
+    }
+    SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
+
+    auto grContext = skottieAnimation->mRunner->mGrContext;
+
+    if (!grContext) {
+        return;
+    }
+
+    SkColorType colorType;
+    // setup surface for fbo0
+    GrGLFramebufferInfo fboInfo;
+    fboInfo.fFBOID = 0;
+    if (wideColorGamut) {
+        fboInfo.fFormat = GL_RGBA16F;
+        colorType = kRGBA_F16_SkColorType;
+    } else {
+        fboInfo.fFormat = GL_RGBA8;
+        colorType = kN32_SkColorType;
+    }
+    GrBackendRenderTarget backendRT(width, height, 0, STENCIL_BUFFER_SIZE, fboInfo);
+
+    SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+
+    sk_sp<SkSurface> renderTarget(SkSurface::MakeFromBackendRenderTarget(
+            grContext.get(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType,
+            nullptr, &props));
+
+    auto canvas = renderTarget->getCanvas();
+    canvas->clear(SK_ColorTRANSPARENT);
+    if (skottieAnimation->mAnimation) {
+        SkMSec t = 0;
+        if (skottieAnimation->mTimeBase == 0.0f) {
+            // Reset the animation time.
+            skottieAnimation->mTimeBase = frameTimeNanos;
+        } else {
+            //convert from nanoseconds to milliseconds
+            t = (frameTimeNanos - skottieAnimation->mTimeBase) / 1000000;
+        }
+        //TODO: control repeat count
+        float intpart;
+        float animState = modff(t / skottieAnimation->mDuration, &intpart);
+        skottieAnimation->mAnimation->seek(animState);
+
+        SkAutoCanvasRestore acr(canvas, true);
+        SkRect bounds = SkRect::MakeWH(width, height);
+        skottieAnimation->mAnimation->render(canvas, &bounds);
+    }
+
+    canvas->flush();
+}
diff --git a/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieActivity.java b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieActivity.java
new file mode 100644
index 0000000..73afc3f
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieActivity.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package org.skia.skottie;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.GridLayout;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static java.lang.Math.ceil;
+import static java.lang.Math.sqrt;
+
+public class SkottieActivity extends Activity implements View.OnClickListener {
+
+    private final static long TIME_OUT_MS = 10000;
+
+    private SkottieApplication mApplication;
+
+    private CountDownLatch mEnterAnimationFence = new CountDownLatch(1);
+
+    private GridLayout mGrid;
+    private int mRowCount = 0;
+    private int mColumnCount = 0;
+    private int mCellWidth = 0;
+    private int mCellHeight = 0;
+
+    private List<SkottieView>  mAnimations;
+    static private List<Uri> mAnimationFiles = new ArrayList<Uri>();
+
+    private void populateGrid() {
+        mRowCount = 0;
+        mColumnCount = 0;
+        mAnimations = new ArrayList<SkottieView>();
+        mCellWidth = 0;
+        mCellHeight = 0;
+
+        int rawAssets[] = {
+                R.raw.star, R.raw.movie_loading, R.raw.uk,  R.raw.white_material_wave_loading
+        };
+
+        for (int resId : rawAssets) {
+            SkottieView view = new SkottieView(this, getResources().openRawResource(resId));
+            mAnimations.add(view);
+        }
+
+        for (Uri uri : mAnimationFiles) {
+            try {
+                InputStream inputStream = getContentResolver().openInputStream(uri);
+                SkottieView view = new SkottieView(this, inputStream);
+                mAnimations.add(view);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+
+        Point size = new Point();
+        getWindowManager().getDefaultDisplay().getSize(size);
+        int screenWidth = size.x;
+        int screenHeight = (int)(size.y / 1.3f);
+
+        double unit = sqrt(mAnimations.size() / 6.0f);
+        mRowCount = (int)ceil(3 * unit);
+        mColumnCount = (int)ceil(2 * unit);
+        mGrid.setColumnCount(mColumnCount);
+        mGrid.setRowCount(mRowCount);
+        mCellWidth = screenWidth / mColumnCount;
+        mCellHeight = screenHeight / mRowCount;
+
+        refreshGrid();
+
+        startAnimation();
+
+        for (SkottieView view : mAnimations) {
+            view.setOnClickListener(new View.OnClickListener(){
+                public void onClick(View view){
+                    inflateView((SkottieView)view);
+                }
+            });
+        }
+
+        if (mInflatedIndex >= 0) {
+            SkottieView view = mAnimations.get(mInflatedIndex);
+            mInflatedIndex = -1;
+            inflateView(view);
+        }
+    }
+
+    static int mInflatedIndex = -1;
+
+    private void inflateView(SkottieView view) {
+        if (mInflatedIndex >= 0) {
+            //deflate active view
+            SkottieView oldView = mAnimations.get(mInflatedIndex);
+            if (oldView != null) {
+                int row = mInflatedIndex / mColumnCount, column = mInflatedIndex % mColumnCount;
+                addView(oldView, row, column, false);
+            }
+            mInflatedIndex = -1;
+            //start and show animations that were in the background
+            for (SkottieView anyView : mAnimations) {
+                if (anyView != oldView) {
+                    anyView.start();
+                    anyView.setVisibility(View.VISIBLE);
+                }
+            }
+            return;
+        }
+
+        //stop and hide animations in the background
+        for (SkottieView anyView : mAnimations) {
+            if (anyView != view) {
+                anyView.stop();
+                anyView.setVisibility(View.INVISIBLE);
+            }
+        }
+
+        mInflatedIndex = mAnimations.indexOf(view);
+
+        GridLayout.Spec rowSpec = GridLayout.spec(0, mRowCount, GridLayout.CENTER);
+        GridLayout.Spec colSpec = GridLayout.spec(0, mColumnCount, GridLayout.CENTER);
+        GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpec, colSpec);
+        params.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        params.height =  ViewGroup.LayoutParams.MATCH_PARENT;
+
+        mGrid.updateViewLayout(view, params);
+    }
+
+    private void refreshGrid() {
+        mGrid.removeAllViews();
+        int currentRaw = 0;
+        int row = 0, column = 0;
+        for (SkottieView view : mAnimations) {
+            addView(view, row, column, true);
+            column++;
+            if (column >= mColumnCount) {
+                column = 0;
+                row++;
+            }
+        }
+    }
+
+    private void addView(SkottieView view,  int row , int column, boolean addView) {
+        GridLayout.Spec rowSpec = GridLayout.spec(row, 1, GridLayout.CENTER);
+        GridLayout.Spec colSpec = GridLayout.spec(column, 1, GridLayout.CENTER);
+        GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpec, colSpec);
+        params.width = mCellWidth;
+        params.height = mCellHeight;
+        if (addView) {
+            mGrid.addView(view, params);
+        } else {
+            mGrid.updateViewLayout(view, params);
+        }
+    }
+
+    private void startAnimation() {
+        for (SkottieView view : mAnimations) {
+            view.start();
+        }
+    }
+
+    private void stopAnimation() {
+        for (SkottieView view : mAnimations) {
+            view.stop();
+        }
+    }
+
+    private void addLottie(Uri uri) throws FileNotFoundException {
+        InputStream inputStream = getContentResolver().openInputStream(uri);
+        int animations = mAnimations.size();
+        if (animations < mRowCount * mColumnCount) {
+            SkottieView view = new SkottieView(this, inputStream);
+            int row = animations / mColumnCount, column = animations % mColumnCount;
+            mAnimations.add(view);
+            mAnimationFiles.add(uri);
+            view.setOnClickListener(new View.OnClickListener(){
+                public void onClick(View view){
+                    inflateView((SkottieView)view);
+                }
+            });
+            addView(view, row, column, true);
+            view.start();
+        } else {
+            stopAnimation();
+            mAnimationFiles.add(uri);
+            populateGrid();
+            startAnimation();
+        }
+    }
+
+
+    @Override
+    public void onEnterAnimationComplete() {
+        super.onEnterAnimationComplete();
+        mEnterAnimationFence.countDown();
+    }
+
+    public void waitForEnterAnimationComplete() throws TimeoutException, InterruptedException {
+        if (!mEnterAnimationFence.await(TIME_OUT_MS, TimeUnit.MILLISECONDS)) {
+            throw new TimeoutException();
+        }
+    }
+
+    private void createLayout() {
+        setContentView(R.layout.main_layout);
+        Button button1 = (Button)findViewById(R.id.open_lottie);
+        button1.setOnClickListener(this);
+        mGrid = (GridLayout)findViewById(R.id.grid_lotties);
+        mGrid.setBackgroundColor(Color.LTGRAY);
+
+        populateGrid();
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        createLayout();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+    }
+
+    static final int PICK_FILE_REQUEST = 2;
+
+    @Override
+    public void onClick(View view) {
+        Intent intent = new Intent();
+        intent.setType("application/json");
+        Intent i = Intent.createChooser(intent, "View Default File Manager");
+        startActivityForResult(i, PICK_FILE_REQUEST);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode == Activity.RESULT_OK) {
+            if (requestCode == PICK_FILE_REQUEST) if (data != null) {
+                //no data present
+                Uri uri = data.getData();
+
+                try {
+                    addLottie(uri);
+                } catch (FileNotFoundException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+}
diff --git a/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieApplication.java b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieApplication.java
new file mode 100644
index 0000000..cd34180
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieApplication.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package org.skia.skottie;
+import android.app.Application;
+
+public class SkottieApplication extends Application {
+
+    static {
+        System.loadLibrary("skottie_android");
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    @Override
+    public void onTerminate() {
+        super.onTerminate();
+    }
+}
diff --git a/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieRunner.java b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieRunner.java
new file mode 100644
index 0000000..cd6da72
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieRunner.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package org.skia.skottie;
+
+import android.graphics.SurfaceTexture;
+import android.graphics.drawable.Animatable;
+import android.opengl.GLUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.view.Choreographer;
+import android.view.TextureView;
+
+import java.io.InputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+public class SkottieRunner {
+    private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+    private static final int EGL_OPENGL_ES2_BIT = 4;
+    private static final int STENCIL_BUFFER_SIZE = 8;
+    private static final long TIME_OUT_MS = 10000;
+    private static final String LOG_TAG = "SkottiePlayer";
+
+    private static SkottieRunner sInstance;
+
+    private HandlerThread mGLThreadLooper;
+    private Handler mGLThread;
+    private EGL10 mEgl;
+    private EGLDisplay mEglDisplay;
+    private EGLConfig mEglConfig;
+    private EGLContext mEglContext;
+    private EGLSurface mPBufferSurface;
+    private long mNativeProxy;
+
+    /**
+     * Gets SkottieRunner singleton instance.
+     */
+    public static synchronized SkottieRunner getInstance() {
+        if (sInstance == null) {
+            sInstance = new SkottieRunner();
+        }
+        return sInstance;
+    }
+
+    /**
+     * Create a new animation by feeding data from "is" and replaying in a TextureView.
+     * TextureView is tracked internally for SurfaceTexture state.
+     */
+    public Animatable createAnimation(TextureView view, InputStream is) {
+        return new SkottieAnimation(view, is);
+    }
+
+    /**
+     * Create a new animation by feeding data from "is" and replaying in a SurfaceTexture.
+     * SurfaceTexture is possibly taken from a TextureView and can be updated with
+     * updateAnimationSurface.
+     */
+    public Animatable createAnimation(SurfaceTexture surfaceTexture, InputStream is) {
+        return new SkottieAnimation(surfaceTexture, is);
+    }
+
+    /**
+     * Pass a new SurfaceTexture: use this method only if managing TextureView outside
+     * SkottieRunner.
+     */
+    public void updateAnimationSurface(Animatable animation, SurfaceTexture surfaceTexture,
+                                       int width, int height) {
+        ((SkottieAnimation) animation).updateSurface(surfaceTexture, width, height);
+    }
+
+    private SkottieRunner()
+    {
+        mGLThreadLooper = new HandlerThread("SkottieAnimator");
+        mGLThreadLooper.start();
+        mGLThread = new Handler(mGLThreadLooper.getLooper());
+        initGl();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            runOnGLThread(this::doFinishGL);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private long getNativeProxy() { return mNativeProxy; }
+
+    private class RunSignalAndCatch implements Runnable {
+        public Throwable error;
+        private Runnable mRunnable;
+        private CountDownLatch mFence;
+
+        RunSignalAndCatch(Runnable run, CountDownLatch fence) {
+            mRunnable = run;
+            mFence = fence;
+        }
+
+        @Override
+        public void run() {
+            try {
+                mRunnable.run();
+            } catch (Throwable t) {
+                error = t;
+            } finally {
+                mFence.countDown();
+            }
+        }
+    }
+
+    private void runOnGLThread(Runnable r) throws Throwable {
+        runOnGLThread(r, false);
+    }
+
+    private void runOnGLThread(Runnable r, boolean postAtFront) throws Throwable {
+
+        CountDownLatch fence = new CountDownLatch(1);
+        RunSignalAndCatch wrapper = new RunSignalAndCatch(r, fence);
+        if (postAtFront) {
+            mGLThread.postAtFrontOfQueue(wrapper);
+        } else {
+            mGLThread.post(wrapper);
+        }
+        if (!fence.await(TIME_OUT_MS, TimeUnit.MILLISECONDS)) {
+            throw new TimeoutException();
+        }
+        if (wrapper.error != null) {
+            throw wrapper.error;
+        }
+    }
+
+    private void initGl()
+    {
+        try {
+            runOnGLThread(mDoInitGL);
+        }
+        catch (Throwable t) {
+            Log.e(LOG_TAG, "initGl failed", t);
+            throw new RuntimeException(t);
+        }
+    }
+
+    private Runnable mDoInitGL = new Runnable() {
+        @Override
+        public void run() {
+            mEgl = (EGL10) EGLContext.getEGL();
+
+            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+                throw new RuntimeException("eglGetDisplay failed "
+                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+
+            int[] version = new int[2];
+            if (!mEgl.eglInitialize(mEglDisplay, version)) {
+                throw new RuntimeException("eglInitialize failed " +
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+
+            mEglConfig = chooseEglConfig();
+            if (mEglConfig == null) {
+                throw new RuntimeException("eglConfig not initialized");
+            }
+
+            mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+            int[] attribs = new int[] {
+                    EGL10.EGL_WIDTH, 1,
+                    EGL10.EGL_HEIGHT, 1,
+                    EGL10.EGL_NONE
+            };
+
+            mPBufferSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
+            if (mPBufferSurface == null || mPBufferSurface == EGL10.EGL_NO_SURFACE) {
+                int error = mEgl.eglGetError();
+                throw new RuntimeException("createPbufferSurface failed "
+                        + GLUtils.getEGLErrorString(error));
+            }
+
+            if (!mEgl.eglMakeCurrent(mEglDisplay, mPBufferSurface, mPBufferSurface, mEglContext)) {
+                throw new RuntimeException("eglMakeCurrent failed "
+                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+
+            mNativeProxy = nCreateProxy();
+        }
+    };
+
+    EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+        int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+        return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+    }
+
+    private EGLConfig chooseEglConfig() {
+        int[] configsCount = new int[1];
+        EGLConfig[] configs = new EGLConfig[1];
+        int[] configSpec = getConfig();
+        if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+            throw new IllegalArgumentException("eglChooseConfig failed " +
+                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        } else if (configsCount[0] > 0) {
+            return configs[0];
+        }
+        return null;
+    }
+
+    private int[] getConfig() {
+        return new int[] {
+                EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                EGL10.EGL_RED_SIZE, 8,
+                EGL10.EGL_GREEN_SIZE, 8,
+                EGL10.EGL_BLUE_SIZE, 8,
+                EGL10.EGL_ALPHA_SIZE, 8,
+                EGL10.EGL_DEPTH_SIZE, 0,
+                EGL10.EGL_STENCIL_SIZE, STENCIL_BUFFER_SIZE,
+                EGL10.EGL_NONE
+        };
+    }
+
+    private void doFinishGL() {
+        nDeleteProxy(mNativeProxy);
+        mNativeProxy = 0;
+        if (mEglDisplay != null) {
+            if (mEglContext != null) {
+                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+                mEglContext = null;
+            }
+            if (mPBufferSurface != null) {
+                mEgl.eglDestroySurface(mEglDisplay, mPBufferSurface);
+                mPBufferSurface = null;
+            }
+
+            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,  EGL10.EGL_NO_SURFACE,
+                    EGL10.EGL_NO_CONTEXT);
+
+            mEgl.eglTerminate(mEglDisplay);
+            mEglDisplay = null;
+        }
+    }
+
+    private class SkottieAnimation implements Animatable, Choreographer.FrameCallback,
+            TextureView.SurfaceTextureListener {
+        boolean mIsRunning = false;
+        SurfaceTexture mSurfaceTexture;
+        EGLSurface mEglSurface;
+        boolean mNewSurface = false;
+
+        private int mSurfaceWidth = 0;
+        private int mSurfaceHeight = 0;
+        private long mNativeProxy;
+        private InputStream mInputStream;
+        private byte[]  mTempStorage;
+
+        SkottieAnimation(SurfaceTexture surfaceTexture, InputStream is) {
+            init(surfaceTexture, is);
+        }
+
+        SkottieAnimation(TextureView view, InputStream is) {
+            init(view.getSurfaceTexture(), is);
+            view.setSurfaceTextureListener(this);
+        }
+
+        private void init(SurfaceTexture surfaceTexture, InputStream is) {
+            mTempStorage = new byte[16 * 1024];
+            mInputStream = is;
+            long proxy = SkottieRunner.getInstance().getNativeProxy();
+            mNativeProxy = nCreateProxy(proxy, mInputStream, mTempStorage);
+            mSurfaceTexture = surfaceTexture;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                stop();
+                nDeleteProxy(mNativeProxy);
+                mNativeProxy = 0;
+            } finally {
+                super.finalize();
+            }
+        }
+
+        public void updateSurface(SurfaceTexture surfaceTexture, int width, int height) {
+            try {
+                runOnGLThread(() -> {
+                    mSurfaceTexture = surfaceTexture;
+                    mSurfaceWidth = width;
+                    mSurfaceHeight = height;
+                    mNewSurface = true;
+                });
+            }
+            catch (Throwable t) {
+                Log.e(LOG_TAG, "updateSurface failed", t);
+                throw new RuntimeException(t);
+            }
+        }
+
+        @Override
+        public void start() {
+            try {
+                runOnGLThread(() -> {
+                    if (!mIsRunning) {
+                        mIsRunning = true;
+                        mNewSurface = true;
+                        Choreographer.getInstance().postFrameCallback(this);
+                    }
+                });
+            }
+            catch (Throwable t) {
+                Log.e(LOG_TAG, "start failed", t);
+                throw new RuntimeException(t);
+            }
+        }
+
+        @Override
+        public void stop() {
+            try {
+                runOnGLThread(() -> {
+                    mIsRunning = false;
+                    if (mEglSurface != null) {
+                        // Ensure we always have a valid surface & context.
+                        mEgl.eglMakeCurrent(mEglDisplay, mPBufferSurface, mPBufferSurface,
+                                mEglContext);
+                        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+                        mEglSurface = null;
+                    }
+                });
+            }
+            catch (Throwable t) {
+                Log.e(LOG_TAG, "stop failed", t);
+                throw new RuntimeException(t);
+            }
+        }
+
+        @Override
+        public boolean isRunning() {
+            return mIsRunning;
+        }
+
+        @Override
+        public void doFrame(long frameTimeNanos) {
+            try {
+                if (mIsRunning) {
+                    // Schedule next frame.
+                    Choreographer.getInstance().postFrameCallback(this);
+                } else {
+                    // If animation stopped, release EGL surface.
+                    if (mEglSurface != null) {
+                        // Ensure we always have a valid surface & context.
+                        mEgl.eglMakeCurrent(mEglDisplay, mPBufferSurface, mPBufferSurface,
+                                mEglContext);
+                        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+                        mEglSurface = null;
+                    }
+                    return;
+                }
+                if (mNewSurface) {
+                    // if there is a new SurfaceTexture, we need to recreate the EGL surface.
+                    if (mEglSurface != null) {
+                        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+                        mEglSurface = null;
+                    }
+                    mNewSurface = false;
+                }
+
+                if (mEglSurface == null) {
+                    if (mSurfaceTexture != null) {
+                        mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig,
+                                mSurfaceTexture, null);
+                        if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+                            // If failed to create a surface, log an error and stop the animation
+                            int error = mEgl.eglGetError();
+                            throw new RuntimeException("createWindowSurface failed "
+                                    + GLUtils.getEGLErrorString(error));
+                        }
+                    }
+                }
+
+                if (mEglSurface != null) {
+                    if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                        // If eglMakeCurrent failed, recreate EGL surface on next frame.
+                        Log.w(LOG_TAG, "eglMakeCurrent failed "
+                                + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+                        mNewSurface = true;
+                        return;
+                    }
+
+                    nDrawFrame(mNativeProxy, mSurfaceWidth, mSurfaceHeight, false,
+                            frameTimeNanos);
+                    if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                        int error = mEgl.eglGetError();
+                        if (error == EGL10.EGL_BAD_SURFACE
+                                || error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+                            // For some reason our surface was destroyed. Recreate EGL surface
+                            // on next frame.
+                            mNewSurface = true;
+                            // This really shouldn't happen, but if it does we can recover easily
+                            // by just not trying to use the surface anymore
+                            Log.w(LOG_TAG, "swapBuffers failed "
+                                    + GLUtils.getEGLErrorString(error));
+                            return;
+                        }
+
+                        // Some other fatal EGL error happened, log an error and stop the animation.
+                        throw new RuntimeException("Cannot swap buffers "
+                                + GLUtils.getEGLErrorString(error));
+                    }
+                }
+            } catch (Throwable t) {
+                Log.e(LOG_TAG, "doFrame failed", t);
+                mIsRunning = false;
+            }
+        }
+
+        @Override
+        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+            // will be called on UI thread
+            updateSurface(surface, width, height);
+        }
+
+        @Override
+        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+            // will be called on UI thread
+            onSurfaceTextureAvailable(surface, width, height);
+        }
+
+        @Override
+        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+            // will be called on UI thread
+            onSurfaceTextureAvailable(null, 0, 0);
+            return true;
+        }
+
+        @Override
+        public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+
+        }
+
+        private native long nCreateProxy(long runner, InputStream is, byte[] storage);
+        private native void nDeleteProxy(long nativeProxy);
+        private native void nDrawFrame(long nativeProxy, int width, int height,
+                                       boolean wideColorGamut, long frameTimeNanos);
+    }
+
+    private static native long nCreateProxy();
+    private static native void nDeleteProxy(long nativeProxy);
+}
+
diff --git a/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieView.java b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieView.java
new file mode 100644
index 0000000..5243e73
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieView.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package org.skia.skottie;
+
+import android.content.Context;
+import android.graphics.drawable.Animatable;
+import android.view.TextureView;
+import android.view.ViewGroup;
+
+import java.io.InputStream;
+
+public class SkottieView extends ViewGroup implements Animatable {
+
+    private TextureView mTextureView;
+    private Animatable mAnimation;
+
+    public SkottieView(Context context, InputStream is) {
+        super(context);
+
+        mTextureView = new TextureView(context);
+        mTextureView.setOpaque(false);
+        mAnimation = SkottieRunner.getInstance().createAnimation(mTextureView, is);
+        addView(mTextureView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    }
+
+    /**
+     * Starts the animation.
+     */
+    @Override
+    public void start()  {
+        mAnimation.start();
+    }
+
+    /**
+     * Stops the animation.
+     */
+    @Override
+    public void stop() {
+        mAnimation.stop();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return mAnimation.isRunning();
+    }
+
+    /**
+     * Ask all children to measure themselves and compute the measurement of this
+     * layout based on the children.
+     */
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mTextureView.measure(widthMeasureSpec, heightMeasureSpec);
+        int width = mTextureView.getMeasuredWidth();
+        int height = mTextureView.getMeasuredHeight();
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (changed) { // This is a new size or position for this view
+            mTextureView.layout(0, 0, right - left, bottom - top);
+        }
+    }
+}
diff --git a/platform_tools/android/apps/skottie/src/main/res/layout/main_layout.xml b/platform_tools/android/apps/skottie/src/main/res/layout/main_layout.xml
new file mode 100644
index 0000000..c2005b5
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/res/layout/main_layout.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <Button
+        android:id="@+id/open_lottie"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="Open lottie file"/>
+    <GridLayout
+        android:id="@+id/grid_lotties"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="center"
+        android:columnCount="1"
+        >
+    </GridLayout>
+
+</LinearLayout>
diff --git a/platform_tools/android/apps/skottie/src/main/res/raw/movie_loading.json b/platform_tools/android/apps/skottie/src/main/res/raw/movie_loading.json
new file mode 100644
index 0000000..a3f664f
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/res/raw/movie_loading.json
@@ -0,0 +1 @@
+{"v":"4.6.10","fr":30,"ip":0,"op":150,"w":750,"h":750,"nm":"Loading","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"detail body Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[274.434,569.716,0]},"a":{"a":0,"k":[40.578,26.94,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.476,0],[0,0],[0,3.477],[0,0],[-3.476,0],[0,0],[0,-3.476],[0,0]],"o":[[0,0],[-3.476,0],[0,0],[0,-3.476],[0,0],[3.476,0],[0,0],[0,3.477]],"v":[[16.784,9.441],[-16.783,9.441],[-23.077,3.147],[-23.077,-3.146],[-16.783,-9.441],[16.784,-9.441],[23.077,-3.146],[23.077,3.147]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.91,0.804,0.804,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[40.577,26.94],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"body Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[349.96,502.581,0]},"a":{"a":0,"k":[137.083,117.153,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.762,0],[0,0],[0,4.762],[0,0],[-4.762,0],[0,0],[0,-4.761],[0,0]],"o":[[0,0],[-4.762,0],[0,0],[0,-4.761],[0,0],[4.762,0],[0,0],[0,4.762]],"v":[[110.961,99.653],[-110.961,99.653],[-119.583,91.031],[-119.583,-91.031],[-110.961,-99.653],[110.961,-99.653],[119.583,-91.031],[119.583,91.031]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.631,0.216,0.216,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[137.083,117.153],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"left button Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[213.593,243.485,0]},"a":{"a":0,"k":[27.99,27.99,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-5.793],[-5.794,0],[0,5.793],[5.793,0]],"o":[[0,5.793],[5.793,0],[0,-5.793],[-5.794,0]],"v":[[-10.49,0],[0.001,10.49],[10.49,0],[0.001,-10.49]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.91,0.804,0.804,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[27.989,27.99],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"left arm Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[275.484,319.012,0]},"a":{"a":0,"k":[114.004,123.445,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-12.166,12.166],[-12.166,-12.166],[0,0]],"o":[[0,0],[-12.166,-12.166],[12.166,-12.166],[0,0],[0,0]],"v":[[29.37,105.945],[-84.338,-49.722],[-84.338,-93.779],[-40.281,-93.779],[96.504,101.75]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.631,0.216,0.216,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[114.004,123.445],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"left wheel Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":5,"s":[0],"e":[1080]},{"t":149}]},"p":{"a":0,"k":[215.691,237.191,0]},"a":{"a":0,"k":[128.691,128.691,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,12.745],[-12.746,0],[0,-12.746],[12.745,0]],"o":[[0,-12.746],[12.745,0],[0,12.745],[-12.746,0]],"v":[[-100.701,0],[-77.624,-23.078],[-54.546,0],[-77.624,23.077]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,12.746],[-12.746,0],[0,-12.745],[12.745,0]],"o":[[0,-12.745],[12.745,0],[0,12.746],[-12.746,0]],"v":[[-77.624,54.546],[-54.546,31.469],[-31.469,54.546],[-54.546,77.624]],"c":true}},"nm":"Path 2","mn":"ADBE Vector Shape - Group"},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,-12.745],[12.745,0],[0,12.745],[-12.746,0]],"o":[[0,12.745],[-12.746,0],[0,-12.745],[12.745,0]],"v":[[-29.371,-54.547],[-52.449,-31.469],[-75.527,-54.547],[-52.449,-77.624]],"c":true}},"nm":"Path 3","mn":"ADBE Vector Shape - Group"},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,12.745],[-12.746,0],[0,-12.746],[12.745,0]],"o":[[0,-12.746],[12.745,0],[0,12.745],[-12.746,0]],"v":[[-23.077,-77.624],[0.001,-100.702],[23.077,-77.624],[0.001,-54.547]],"c":true}},"nm":"Path 4","mn":"ADBE Vector Shape - Group"},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,12.745],[-12.746,0],[0,-12.745],[12.745,0]],"o":[[0,-12.745],[12.745,0],[0,12.745],[-12.746,0]],"v":[[-23.077,75.526],[0.001,52.448],[23.077,75.526],[0.001,98.604]],"c":true}},"nm":"Path 5","mn":"ADBE Vector Shape - Group"},{"ind":5,"ty":"sh","ix":6,"ks":{"a":0,"k":{"i":[[0,12.745],[-12.746,0],[0,-12.745],[12.746,0]],"o":[[0,-12.745],[12.746,0],[0,12.745],[-12.746,0]],"v":[[31.469,-54.547],[54.547,-77.624],[77.625,-54.547],[54.547,-31.469]],"c":true}},"nm":"Path 6","mn":"ADBE Vector Shape - Group"},{"ind":6,"ty":"sh","ix":7,"ks":{"a":0,"k":{"i":[[0,12.746],[-12.745,0],[0,-12.745],[12.745,0]],"o":[[0,-12.745],[12.745,0],[0,12.746],[-12.745,0]],"v":[[33.568,54.546],[56.645,31.469],[79.722,54.546],[56.645,77.624]],"c":true}},"nm":"Path 7","mn":"ADBE Vector Shape - Group"},{"ind":7,"ty":"sh","ix":8,"ks":{"a":0,"k":{"i":[[12.745,0],[0,12.745],[-12.746,0],[0,-12.746]],"o":[[-12.746,0],[0,-12.746],[12.745,0],[0,12.745]],"v":[[77.625,23.077],[54.547,0],[77.625,-23.078],[100.702,0]],"c":true}},"nm":"Path 8","mn":"ADBE Vector Shape - Group"},{"ind":8,"ty":"sh","ix":9,"ks":{"a":0,"k":{"i":[[0,-61.41],[-61.41,0],[0,61.409],[61.408,0]],"o":[[0,61.409],[61.408,0],[0,-61.41],[-61.41,0]],"v":[[-111.191,0],[0.001,111.191],[111.191,0],[0.001,-111.191]],"c":true}},"nm":"Path 9","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.725,0.412,0.412,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[128.691,128.691],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":12,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-39.974],[-39.974,0],[0,39.974],[39.974,0]],"o":[[0,39.974],[39.974,0],[0,-39.974],[-39.974,0]],"v":[[-72.379,0],[0,72.379],[72.379,0],[0,-72.379]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.631,0.216,0.216,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[128.691,128.691],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 2","np":3,"cix":2,"ix":2,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"right button Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-206.966},"p":{"a":0,"k":[467.445,283.346,0]},"a":{"a":0,"k":[27.99,27.99,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-5.793],[5.793,0],[0,5.793],[-5.794,0]],"o":[[0,5.793],[-5.794,0],[0,-5.793],[5.793,0]],"v":[[10.49,0],[0,10.49],[-10.49,0],[0,-10.49]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.91,0.804,0.804,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[27.99,27.99],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"right arm Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[422.863,327.929,0]},"a":{"a":0,"k":[96.697,92.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[12.167,12.166],[12.165,-12.166],[0,0]],"o":[[0,0],[12.167,-12.166],[-12.166,-12.166],[0,0],[0,0]],"v":[[-7.866,75],[67.03,-18.777],[67.03,-62.834],[22.974,-62.834],[-79.197,75]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.631,0.216,0.216,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[96.696,92.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":8,"ty":4,"nm":"right wheel Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":5,"s":[0],"e":[1080]},{"t":149}]},"p":{"a":0,"k":[465.347,277.052,0]},"a":{"a":0,"k":[128.691,128.691,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[12.746,0],[0,12.745],[-12.745,0],[0,-12.746]],"o":[[-12.745,0],[0,-12.746],[12.746,0],[0,12.745]],"v":[[77.624,23.077],[54.547,0],[77.624,-23.077],[100.702,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[12.745,0],[0,12.746],[-12.745,0],[0,-12.745]],"o":[[-12.745,0],[0,-12.745],[12.745,0],[0,12.746]],"v":[[54.547,77.625],[31.47,54.547],[54.547,31.47],[77.624,54.547]],"c":true}},"nm":"Path 2","mn":"ADBE Vector Shape - Group"},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-12.746,0],[0,-12.745],[12.745,0],[0,12.746]],"o":[[12.745,0],[0,12.746],[-12.746,0],[0,-12.745]],"v":[[52.449,-77.624],[75.526,-54.546],[52.449,-31.468],[29.371,-54.546]],"c":true}},"nm":"Path 3","mn":"ADBE Vector Shape - Group"},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[12.746,0],[0,12.745],[-12.745,0],[0,-12.746]],"o":[[-12.745,0],[0,-12.746],[12.746,0],[0,12.745]],"v":[[0,-54.546],[-23.077,-77.624],[0,-100.702],[23.077,-77.624]],"c":true}},"nm":"Path 4","mn":"ADBE Vector Shape - Group"},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[12.746,0],[0,12.745],[-12.745,0],[0,-12.745]],"o":[[-12.745,0],[0,-12.745],[12.746,0],[0,12.745]],"v":[[0,98.603],[-23.077,75.526],[0,52.449],[23.077,75.526]],"c":true}},"nm":"Path 5","mn":"ADBE Vector Shape - Group"},{"ind":5,"ty":"sh","ix":6,"ks":{"a":0,"k":{"i":[[12.745,0],[0,12.746],[-12.746,0],[0,-12.745]],"o":[[-12.746,0],[0,-12.745],[12.745,0],[0,12.746]],"v":[[-54.546,-31.468],[-77.624,-54.546],[-54.546,-77.624],[-31.469,-54.546]],"c":true}},"nm":"Path 6","mn":"ADBE Vector Shape - Group"},{"ind":6,"ty":"sh","ix":7,"ks":{"a":0,"k":{"i":[[12.746,0],[0,12.746],[-12.745,0],[0,-12.745]],"o":[[-12.745,0],[0,-12.745],[12.746,0],[0,12.746]],"v":[[-56.645,77.625],[-79.722,54.547],[-56.645,31.47],[-33.567,54.547]],"c":true}},"nm":"Path 7","mn":"ADBE Vector Shape - Group"},{"ind":7,"ty":"sh","ix":8,"ks":{"a":0,"k":{"i":[[0,12.745],[-12.745,0],[0,-12.746],[12.746,0]],"o":[[0,-12.746],[12.746,0],[0,12.745],[-12.745,0]],"v":[[-100.701,0],[-77.624,-23.077],[-54.546,0],[-77.624,23.077]],"c":true}},"nm":"Path 8","mn":"ADBE Vector Shape - Group"},{"ind":8,"ty":"sh","ix":9,"ks":{"a":0,"k":{"i":[[61.409,0],[0,-61.409],[-61.409,0],[0,61.409]],"o":[[-61.409,0],[0,61.409],[61.409,0],[0,-61.409]],"v":[[0,-111.191],[-111.191,0],[0,111.191],[111.191,0]],"c":true}},"nm":"Path 9","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.725,0.412,0.412,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[128.691,128.692],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":12,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[39.975,0],[0,-39.974],[-39.974,0],[0,39.975]],"o":[[-39.974,0],[0,39.975],[39.975,0],[0,-39.974]],"v":[[0,-72.379],[-72.379,0],[0,72.379],[72.379,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.631,0.216,0.216,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[128.691,128.692],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 2","np":3,"cix":2,"ix":2,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":9,"ty":4,"nm":"camera head Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[549.265,504.577,0]},"a":{"a":0,"k":[77.292,110.924,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.3,-1.793],[0,0],[0,7.839],[0,0],[8.546,-3.441],[0,0],[0,-3.993],[0,0]],"o":[[0,0],[8.556,3.567],[0,0],[0,-7.774],[0,0],[-4.389,1.766],[0,0],[0,3.941]],"v":[[-52.785,50.716],[41.08,89.856],[59.791,80.516],[59.791,-80.577],[41.242,-89.983],[-52.624,-52.186],[-59.791,-42.78],[-59.791,41.376]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.631,0.216,0.216,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[77.291,110.924],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":10,"ty":4,"nm":"camera Neck Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[480.033,503.631,0]},"a":{"a":0,"k":[14.391,41.664,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9.441,36.714],[-9.441,36.714],[-9.441,-36.714],[9.441,-36.714]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.541,0.02,0.02,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.725,0.412,0.412,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[14.391,41.664],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":150,"st":0,"bm":0,"sr":1}]}
\ No newline at end of file
diff --git a/platform_tools/android/apps/skottie/src/main/res/raw/star.json b/platform_tools/android/apps/skottie/src/main/res/raw/star.json
new file mode 100644
index 0000000..ef1eab4
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/res/raw/star.json
@@ -0,0 +1 @@
+{"v":"5.1.13","fr":30,"ip":0,"op":30,"w":900,"h":900,"nm":"star","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"01","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[498,623.343,0],"to":[6.33333349227905,20.6666660308838,0],"ti":[-13,-38.4427757263184,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[498,623.343,0],"e":[538,730,0],"to":[13,38.4427757263184,0],"ti":[-6.66666650772095,-17.7761096954346,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[46,46,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"02","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[594,499.343,0],"to":[22.3333339691162,0,0],"ti":[-46.6666679382324,0.55722379684448,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[594,499.343,0],"e":[740,496,0],"to":[46.6666679382324,-0.55722379684448,0],"ti":[-24.3333339691162,0.55722379684448,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[46,46,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"03","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[534,345.343,0],"to":[12.3333330154419,-25.6666660308838,0],"ti":[-20,42.2238922119141,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[534,345.343,0],"e":[580,246,0],"to":[20,-42.2238922119141,0],"ti":[-7.66666650772095,16.5572242736816,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[46,46,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"04","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[466,321.343,0],"to":[1,-29.6666660308838,0],"ti":[-2,54.8905563354492,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[466,321.343,0],"e":[472,170,0],"to":[2,-54.8905563354492,0],"ti":[-1,25.2238903045654,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[46,46,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"05","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[344,407.343,0],"to":[-19.3333339691162,-15.3333330154419,0],"ti":[35.6666679382324,29.2238903045654,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[344,407.343,0],"e":[246,324,0],"to":[-35.6666679382324,-29.2238903045654,0],"ti":[16.3333339691162,13.8905572891235,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[46,46,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"06","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[278,447.343,0],"to":[-30.3333339691162,-8.66666698455811,0],"ti":[58.6666679382324,17.8905563354492,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[278,447.343,0],"e":[108,392,0],"to":[-58.6666679382324,-17.8905563354492,0],"ti":[28.3333339691162,9.22389030456543,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"07","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[310,629.343,0],"to":[-25,21.6666660308838,0],"ti":[52.6666679382324,-39.7761077880859,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[310,629.343,0],"e":[144,738,0],"to":[-52.6666679382324,39.7761077880859,0],"ti":[27.6666660308838,-18.1094436645508,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":" ","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[462,665.343,0],"to":[0.33333334326744,27.6666660308838,0],"ti":[-0.66666668653488,-59.7761077880859,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[462,665.343,0],"e":[464,858,0],"to":[0.66666668653488,59.7761077880859,0],"ti":[-0.33333334326744,-32.1094436645508,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"09","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[572,605.343,0],"to":[18.6666660308838,17.6666660308838,0],"ti":[-43.3333320617676,-41.4427757263184,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[572,605.343,0],"e":[720,748,0],"to":[43.3333320617676,41.4427757263184,0],"ti":[-24.6666660308838,-23.7761096954346,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"10","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[584,389.343,0],"to":[20.6666660308838,-18.3333339691162,0],"ti":[-39,33.5572242736816,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[584,389.343,0],"e":[694,298,0],"to":[39,-33.5572242736816,0],"ti":[-18.3333339691162,15.2238903045654,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"11","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[100],"e":[0]},{"t":14}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":4,"s":[460,499.343,0],"e":[302,309.343,0],"to":[-26.3333339691162,-31.6666660308838,0],"ti":[42,51.8905563354492,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":9,"s":[302,309.343,0],"e":[208,188,0],"to":[-42,-51.8905563354492,0],"ti":[15.6666669845581,20.2238903045654,0]},{"t":14}],"ix":2},"a":{"a":0,"k":[-322,-328,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[38,38],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"타원 패스 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-323,-327],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"타원 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"star 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.649],"y":[0.123]},"o":{"x":[0.167],"y":[0.167]},"n":["0p649_0p123_0p167_0p167"],"t":0,"s":[0],"e":[100]},{"t":8}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[452.026,518.893,0],"ix":2},"a":{"a":0,"k":[14.184,40.525,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0.004,0.004,0]},"n":["0p667_1_1_0p004","0p667_1_1_0p004","0p667_1_0p333_0"],"t":0,"s":[72.233,72.233,100],"e":[410.463,410.463,100]},{"i":{"x":[0.113,0.113,0.667],"y":[0.949,0.949,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p113_0p949_0p333_0","0p113_0p949_0p333_0","0p667_1_0p333_0"],"t":8,"s":[410.463,410.463,100],"e":[329.729,329.729,100]},{"t":14}],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"가우시안 흐림","np":5,"mn":"ADBE Gaussian Blur 2","ix":1,"en":1,"ef":[{"ty":0,"nm":"흐림","mn":"ADBE Gaussian Blur 2-0001","ix":1,"v":{"a":0,"k":84.5,"ix":1}},{"ty":7,"nm":"흐림 차원","mn":"ADBE Gaussian Blur 2-0002","ix":2,"v":{"a":0,"k":1,"ix":2}},{"ty":7,"nm":"가장자리 픽셀 반복","mn":"ADBE Gaussian Blur 2-0003","ix":3,"v":{"a":0,"k":0,"ix":3}}]}],"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":235.086,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":470.172,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"다각형 별 패스 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"rd","nm":"둥근 모퉁이 1","r":{"a":0,"k":64,"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[17.223,37.486],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[16.223,15.154],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"다각형 별 2","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"star","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.649],"y":[0.123]},"o":{"x":[0.167],"y":[0.167]},"n":["0p649_0p123_0p167_0p167"],"t":0,"s":[0],"e":[100]},{"t":8}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[452.026,518.893,0],"ix":2},"a":{"a":0,"k":[14.184,40.525,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0.004,0.004,0]},"n":["0p667_1_1_0p004","0p667_1_1_0p004","0p667_1_0p333_0"],"t":0,"s":[72.233,72.233,100],"e":[410.463,410.463,100]},{"i":{"x":[0.113,0.113,0.667],"y":[0.949,0.949,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p113_0p949_0p333_0","0p113_0p949_0p333_0","0p667_1_0p333_0"],"t":8,"s":[410.463,410.463,100],"e":[329.729,329.729,100]},{"t":14}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":235.086,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":470.172,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"다각형 별 패스 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"rd","nm":"둥근 모퉁이 1","r":{"a":0,"k":64,"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"선 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.74002308565,0.039215682535,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"칠 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[17.223,37.486],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[16.223,15.154],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"변형"}],"nm":"다각형 별 2","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/platform_tools/android/apps/skottie/src/main/res/raw/uk.json b/platform_tools/android/apps/skottie/src/main/res/raw/uk.json
new file mode 100644
index 0000000..ff838e9
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/res/raw/uk.json
@@ -0,0 +1 @@
+{"v":"4.6.3","fr":25,"ip":0,"op":69,"w":500,"h":500,"nm":"UK","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"red","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":32,"s":[0,0,100],"e":[114,114,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":41,"s":[114,114,100],"e":[100,100,100]},{"t":51}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,-12.124],[-1.941,-11.572],[0,0],[0,0],[-12.124,0],[-11.572,1.941],[0,0],[0,0],[0,12.124],[1.941,11.572],[0,0],[0,0],[12.124,0],[11.572,-1.941]],"o":[[0,0],[0,0],[-1.941,11.572],[0,12.124],[0,0],[0,0],[11.572,1.941],[12.124,0],[0,0],[0,0],[1.941,-11.572],[0,-12.124],[0,0],[0,0],[-11.572,-1.941],[-12.124,0],[0,0]],"v":[[-35.583,-210.548],[-35.583,-35.583],[-210.548,-35.583],[-213.5,0],[-210.548,35.583],[-35.583,35.583],[-35.583,210.548],[0,213.5],[35.583,210.548],[35.583,35.583],[210.548,35.583],[213.5,0],[210.548,-35.583],[35.583,-35.583],[35.583,-210.548],[0,-213.5],[-35.583,-210.548]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.9137255,0.2941177,0.2078431,1]},"o":{"a":0,"k":100},"r":2,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":375,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"white","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":23,"s":[0,0,100],"e":[109,109,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":31,"s":[109,109,100],"e":[100,100,100]},{"t":40}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,-16.306],[-3.462,-15.259],[0,0],[0,0],[-16.306,0],[-15.259,3.462],[0,0],[0,0],[0,16.306],[3.462,15.259],[0,0],[0,0],[16.306,0],[15.259,-3.462]],"o":[[0,0],[0,0],[-3.462,15.259],[0,16.306],[0,0],[0,0],[15.259,3.462],[16.306,0],[0,0],[0,0],[3.462,-15.259],[0,-16.306],[0,0],[0,0],[-15.259,-3.462],[-16.306,0],[0,0]],"v":[[-47.444,-208.21],[-47.444,-47.444],[-208.21,-47.444],[-213.5,0],[-208.21,47.444],[-47.444,47.444],[-47.444,208.21],[0,213.5],[47.444,208.21],[47.444,47.444],[208.21,47.444],[213.5,0],[208.21,-47.444],[47.444,-47.444],[47.444,-208.21],[0,-213.5],[-47.444,-208.21]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":2,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":375,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"red","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":24,"s":[0,0,100],"e":[139,139,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":37,"s":[139,139,100],"e":[100,100,100]},{"t":46}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-5.359,6.904]],"o":[[0,0],[0,0],[0,0],[6.151,-6.191],[0,0]],"v":[[168.751,130.804],[59.117,18.978],[22.065,18.978],[151.467,150.466],[168.751,130.804]],"c":true}},"nm":"Path-path","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-7.123,-5.55]],"o":[[0,0],[0,0],[0,0],[6.359,6.392],[0,0]],"v":[[-131.112,168.512],[14.233,21.35],[-23.722,21.35],[-151.355,150.578],[-131.112,168.512]],"c":true}},"nm":"Path-path","mn":"ADBE Vector Shape - Group"},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-5.755,-5.774]],"o":[[0,0],[0,0],[0,0],[6.381,5.088],[0,0]],"v":[[151.218,-150.716],[29.653,-28.17],[-4.744,-28.17],[132.999,-167.024],[151.218,-150.716]],"c":true}},"nm":"Path-path","mn":"ADBE Vector Shape - Group"},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[5.421,-6.961]],"o":[[0,0],[0,0],[0,0],[-6.226,6.234],[0,0]],"v":[[-168.551,-131.061],[-73.439,-35.583],[-36.122,-35.583],[-151.062,-150.872],[-168.551,-131.061]],"c":true}},"nm":"Path-path","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.9137255,0.2941177,0.2078431,1]},"o":{"a":0,"k":100},"r":2,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0.1,0.744],"ix":2},"a":{"a":0,"k":[0.1,0.744],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":5,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":375,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"white","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":11,"s":[0,0,100],"e":[109,109,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":30,"s":[109,109,100],"e":[100,100,100]},{"t":39}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-13.288,-18.323],[0,0],[0,0],[18.323,-13.288],[0,0],[0,0],[13.288,18.323],[0,0],[0,0],[-18.323,13.288]],"o":[[0,0],[0,0],[18.323,13.288],[0,0],[0,0],[-13.288,18.323],[0,0],[0,0],[-18.323,-13.288],[0,0],[0,0],[13.288,-18.323],[0,0]],"v":[[-125.209,-172.949],[0,-47.74],[125.209,-172.949],[172.949,-125.209],[47.74,0],[172.949,125.209],[125.209,172.949],[0,47.74],[-125.209,172.949],[-172.949,125.209],[-47.74,0],[-172.949,-125.209],[-125.209,-172.949]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":2,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":375,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"blue","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":10,"s":[0,0,100],"e":[114,114,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":20,"s":[114,114,100],"e":[100,100,100]},{"t":32}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-117.913,0],[0,117.913],[117.913,0],[0,-117.913]],"o":[[117.913,0],[0,-117.913],[-117.913,0],[0,117.913]],"v":[[0,213.5],[213.5,0],[0,-213.5],[-213.5,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.1333333,0.4980392,0.7333333,1]},"o":{"a":0,"k":100},"r":2,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":375,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"white 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":0,"s":[0,0,100],"e":[114,114,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":10,"s":[114,114,100],"e":[100,100,100]},{"t":22}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-117.714,0],[0,117.677],[117.714,0],[0,-117.677]],"o":[[117.714,0],[0,-117.677],[-117.714,0],[0,117.677]],"v":[[-0.217,213.151],[212.923,0.077],[-0.217,-212.997],[-213.358,0.077]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":2,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-0.217,0.077],"ix":2},"a":{"a":0,"k":[-0.217,0.077],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":375,"st":0,"bm":0,"sr":1}]}
\ No newline at end of file
diff --git a/platform_tools/android/apps/skottie/src/main/res/raw/white_material_wave_loading.json b/platform_tools/android/apps/skottie/src/main/res/raw/white_material_wave_loading.json
new file mode 100644
index 0000000..cafcccf
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/res/raw/white_material_wave_loading.json
@@ -0,0 +1 @@
+{"v":"4.6.8","fr":29.9700012207031,"ip":0,"op":40.0000016292334,"w":256,"h":256,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":20,"s":[208.6,127.969,0],"e":[208.6,88,0],"to":[0,-6.66145849227905,0],"ti":[0,-0.00520833348855,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":30,"s":[208.6,88,0],"e":[208.6,128,0],"to":[0,0.00520833348855,0],"ti":[0,-6.66666650772095,0]},{"t":40.0000016292334}]},"a":{"a":0,"k":[-70,-0.5,0]},"s":{"a":0,"k":[75,75,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[33.75,34.5]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.9843137,0.5490196,0,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-70.125,-0.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":300.00001221925,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":15,"s":[168.6,128,0],"e":[168.6,88,0],"to":[0,-6.66666650772095,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":25,"s":[168.6,88,0],"e":[168.6,128,0],"to":[0,0,0],"ti":[0,-6.66666650772095,0]},{"t":35.0000014255792}]},"a":{"a":0,"k":[-70,-0.5,0]},"s":{"a":0,"k":[75,75,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[33.75,34.5]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.9921569,0.8470588,0.2078431,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-70.125,-0.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":300.00001221925,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":10,"s":[128.594,127.969,0],"e":[128.594,88,0],"to":[0,-6.66145849227905,0],"ti":[0,-0.00520833348855,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":20,"s":[128.594,88,0],"e":[128.594,128,0],"to":[0,0.00520833348855,0],"ti":[0,-6.66666650772095,0]},{"t":30.0000012219251}]},"a":{"a":0,"k":[-70,-0.5,0]},"s":{"a":0,"k":[75,75,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[33.75,34.5]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.2627451,0.627451,0.2784314,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-70.125,-0.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":300.00001221925,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 4","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":5,"s":[88.6,127.969,0],"e":[88.6,88,0],"to":[0,-6.66145849227905,0],"ti":[0,-0.00520833348855,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":15,"s":[88.6,88,0],"e":[88.6,128,0],"to":[0,0.00520833348855,0],"ti":[0,-6.66666650772095,0]},{"t":25.0000010182709}]},"a":{"a":0,"k":[-70,-0.5,0]},"s":{"a":0,"k":[75,75,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[33.75,34.5]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.1176471,0.5333334,0.8980392,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-70.125,-0.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":300.00001221925,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 5","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":0,"s":[48.6,127.969,0],"e":[48.6,88,0],"to":[0,-6.66145849227905,0],"ti":[0,-0.00520833348855,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":10,"s":[48.6,88,0],"e":[48.6,128,0],"to":[0,0.00520833348855,0],"ti":[0,-6.66666650772095,0]},{"t":20.0000008146167}]},"a":{"a":0,"k":[-70,-0.5,0]},"s":{"a":0,"k":[75,75,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[33.75,34.5]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.8980392,0.2235294,0.2078431,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-70.125,-0.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":300.00001221925,"st":0,"bm":0,"sr":1}]}
\ No newline at end of file