aboutsummaryrefslogtreecommitdiff
path: root/platform_tools
diff options
context:
space:
mode:
Diffstat (limited to 'platform_tools')
-rw-r--r--platform_tools/android/apps/skottie/src/main/cpp/native-lib.cpp33
-rw-r--r--platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieActivity.java19
-rw-r--r--platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieAnimation.java30
-rw-r--r--platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieRunner.java103
-rw-r--r--platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieView.java61
5 files changed, 156 insertions, 90 deletions
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
index d4b4a74544..e39f73395d 100644
--- a/platform_tools/android/apps/skottie/src/main/cpp/native-lib.cpp
+++ b/platform_tools/android/apps/skottie/src/main/cpp/native-lib.cpp
@@ -105,7 +105,7 @@ struct SkottieAnimation {
extern "C" JNIEXPORT jlong
JNICALL
-Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nCreateProxy(JNIEnv *env, jobject clazz,
+Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nCreateProxy(JNIEnv *env, jobject clazz,
jlong runner, jobject is,
jbyteArray storage) {
@@ -138,7 +138,7 @@ Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nCreateProxy(JNIEnv *e
extern "C" JNIEXPORT void
JNICALL
-Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nDeleteProxy(JNIEnv *env, jclass clazz,
+Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nDeleteProxy(JNIEnv *env, jclass clazz,
jlong nativeProxy) {
if (!nativeProxy) {
return;
@@ -149,11 +149,11 @@ Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nDeleteProxy(JNIEnv *e
extern "C" JNIEXPORT void
JNICALL
-Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nDrawFrame(JNIEnv *env, jclass clazz,
+Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nDrawFrame(JNIEnv *env, jclass clazz,
jlong nativeProxy, jint width,
jint height,
jboolean wideColorGamut,
- jlong frameTimeNanos) {
+ jfloat progress) {
ATRACE_NAME("SkottieDrawFrame");
if (!nativeProxy) {
return;
@@ -188,18 +188,7 @@ Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nDrawFrame(JNIEnv *env
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);
+ skottieAnimation->mAnimation->seek(progress);
SkAutoCanvasRestore acr(canvas, true);
SkRect bounds = SkRect::MakeWH(width, height);
@@ -208,3 +197,15 @@ Java_org_skia_skottie_SkottieRunner_00024SkottieAnimation_nDrawFrame(JNIEnv *env
canvas->flush();
}
+
+extern "C" JNIEXPORT jlong
+JNICALL
+Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nGetDuration(JNIEnv *env,
+ jclass clazz,
+ jlong nativeProxy) {
+ if (!nativeProxy) {
+ return 0;
+ }
+ SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
+ return (jlong) skottieAnimation->mDuration;
+}
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
index 73afc3fe0d..4869476827 100644
--- 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
@@ -58,14 +58,16 @@ public class SkottieActivity extends Activity implements View.OnClickListener {
};
for (int resId : rawAssets) {
- SkottieView view = new SkottieView(this, getResources().openRawResource(resId));
+ SkottieView view = new SkottieView(this);
+ view.setSource(getResources().openRawResource(resId));
mAnimations.add(view);
}
for (Uri uri : mAnimationFiles) {
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
- SkottieView view = new SkottieView(this, inputStream);
+ SkottieView view = new SkottieView(this);
+ view.setSource(inputStream);
mAnimations.add(view);
} catch (FileNotFoundException e) {
e.printStackTrace();
@@ -118,7 +120,7 @@ public class SkottieActivity extends Activity implements View.OnClickListener {
//start and show animations that were in the background
for (SkottieView anyView : mAnimations) {
if (anyView != oldView) {
- anyView.start();
+ anyView.getSkottieAnimation().start();
anyView.setVisibility(View.VISIBLE);
}
}
@@ -128,7 +130,7 @@ public class SkottieActivity extends Activity implements View.OnClickListener {
//stop and hide animations in the background
for (SkottieView anyView : mAnimations) {
if (anyView != view) {
- anyView.stop();
+ anyView.getSkottieAnimation().stop();
anyView.setVisibility(View.INVISIBLE);
}
}
@@ -173,13 +175,13 @@ public class SkottieActivity extends Activity implements View.OnClickListener {
private void startAnimation() {
for (SkottieView view : mAnimations) {
- view.start();
+ view.getSkottieAnimation().start();
}
}
private void stopAnimation() {
for (SkottieView view : mAnimations) {
- view.stop();
+ view.getSkottieAnimation().stop();
}
}
@@ -187,7 +189,8 @@ public class SkottieActivity extends Activity implements View.OnClickListener {
InputStream inputStream = getContentResolver().openInputStream(uri);
int animations = mAnimations.size();
if (animations < mRowCount * mColumnCount) {
- SkottieView view = new SkottieView(this, inputStream);
+ SkottieView view = new SkottieView(this);
+ view.setSource(inputStream);
int row = animations / mColumnCount, column = animations % mColumnCount;
mAnimations.add(view);
mAnimationFiles.add(uri);
@@ -197,7 +200,7 @@ public class SkottieActivity extends Activity implements View.OnClickListener {
}
});
addView(view, row, column, true);
- view.start();
+ view.getSkottieAnimation().start();
} else {
stopAnimation();
mAnimationFiles.add(uri);
diff --git a/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieAnimation.java b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieAnimation.java
new file mode 100644
index 0000000000..4280e69d00
--- /dev/null
+++ b/platform_tools/android/apps/skottie/src/main/java/org/skia/skottie/SkottieAnimation.java
@@ -0,0 +1,30 @@
+package org.skia.skottie;
+
+import android.graphics.drawable.Animatable;
+import android.support.annotation.FloatRange;
+
+public interface SkottieAnimation extends Animatable {
+ /**
+ * Gets animation duration.
+ *
+ * @return Animation duration in milliseconds.
+ */
+ long getDuration();
+
+ /**
+ * Sets current animation progress.
+ *
+ * @param progress animation progress
+ *
+ */
+ void setProgress(@FloatRange(from = 0, to = 1) float progress);
+
+
+ /**
+ * Gets current animation progress.
+ *
+ * @return animation progress.
+ */
+ @FloatRange(from = 0, to = 1) float getProgress();
+}
+
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
index cd6da7287a..ebcd748aa9 100644
--- 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
@@ -59,8 +59,8 @@ public class SkottieRunner {
* 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);
+ public SkottieAnimation createAnimation(TextureView view, InputStream is) {
+ return new SkottieAnimationImpl(view, is);
}
/**
@@ -68,8 +68,8 @@ public class SkottieRunner {
* 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);
+ public SkottieAnimation createAnimation(SurfaceTexture surfaceTexture, InputStream is) {
+ return new SkottieAnimationImpl(surfaceTexture, is);
}
/**
@@ -78,7 +78,7 @@ public class SkottieRunner {
*/
public void updateAnimationSurface(Animatable animation, SurfaceTexture surfaceTexture,
int width, int height) {
- ((SkottieAnimation) animation).updateSurface(surfaceTexture, width, height);
+ ((SkottieAnimationImpl) animation).updateSurface(surfaceTexture, width, height);
}
private SkottieRunner()
@@ -252,7 +252,7 @@ public class SkottieRunner {
}
}
- private class SkottieAnimation implements Animatable, Choreographer.FrameCallback,
+ private class SkottieAnimationImpl implements SkottieAnimation, Choreographer.FrameCallback,
TextureView.SurfaceTextureListener {
boolean mIsRunning = false;
SurfaceTexture mSurfaceTexture;
@@ -264,12 +264,15 @@ public class SkottieRunner {
private long mNativeProxy;
private InputStream mInputStream;
private byte[] mTempStorage;
+ private long mDuration; // duration in ms of the animation
+ private float mProgress; // animation progress in the range of 0.0f to 1.0f
+ private long mAnimationStartTime; // time in System.nanoTime units, when started
- SkottieAnimation(SurfaceTexture surfaceTexture, InputStream is) {
+ SkottieAnimationImpl(SurfaceTexture surfaceTexture, InputStream is) {
init(surfaceTexture, is);
}
- SkottieAnimation(TextureView view, InputStream is) {
+ SkottieAnimationImpl(TextureView view, InputStream is) {
init(view.getSurfaceTexture(), is);
view.setSurfaceTextureListener(this);
}
@@ -280,6 +283,8 @@ public class SkottieRunner {
long proxy = SkottieRunner.getInstance().getNativeProxy();
mNativeProxy = nCreateProxy(proxy, mInputStream, mTempStorage);
mSurfaceTexture = surfaceTexture;
+ mDuration = nGetDuration(mNativeProxy);
+ mProgress = 0f;
}
@Override
@@ -300,6 +305,8 @@ public class SkottieRunner {
mSurfaceWidth = width;
mSurfaceHeight = height;
mNewSurface = true;
+
+ drawFrame();
});
}
catch (Throwable t) {
@@ -313,9 +320,11 @@ public class SkottieRunner {
try {
runOnGLThread(() -> {
if (!mIsRunning) {
+ long currentTime = System.nanoTime();
+ mAnimationStartTime = currentTime - (long)(1000000 * mDuration * mProgress);
mIsRunning = true;
mNewSurface = true;
- Choreographer.getInstance().postFrameCallback(this);
+ doFrame(currentTime);
}
});
}
@@ -351,22 +360,35 @@ public class SkottieRunner {
}
@Override
- public void doFrame(long frameTimeNanos) {
+ public long getDuration() {
+ return mDuration;
+ }
+
+ @Override
+ public void setProgress(float progress) {
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;
+ runOnGLThread(() -> {
+ mProgress = progress;
+ if (mIsRunning) {
+ mAnimationStartTime = System.nanoTime()
+ - (long)(1000000 * mDuration * mProgress);
}
- return;
- }
+ drawFrame();
+ });
+ }
+ catch (Throwable t) {
+ Log.e(LOG_TAG, "setProgress failed", t);
+ throw new RuntimeException(t);
+ }
+ }
+
+ @Override
+ public float getProgress() {
+ return mProgress;
+ }
+
+ private void drawFrame() {
+ try {
if (mNewSurface) {
// if there is a new SurfaceTexture, we need to recreate the EGL surface.
if (mEglSurface != null) {
@@ -399,7 +421,7 @@ public class SkottieRunner {
}
nDrawFrame(mNativeProxy, mSurfaceWidth, mSurfaceHeight, false,
- frameTimeNanos);
+ mProgress);
if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
int error = mEgl.eglGetError();
if (error == EGL10.EGL_BAD_SURFACE
@@ -418,14 +440,42 @@ public class SkottieRunner {
throw new RuntimeException("Cannot swap buffers "
+ GLUtils.getEGLErrorString(error));
}
+
+ // If animation stopped, release EGL surface.
+ if (!mIsRunning) {
+ // 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, "doFrame failed", t);
+ Log.e(LOG_TAG, "drawFrame failed", t);
mIsRunning = false;
}
}
@Override
+ public void doFrame(long frameTimeNanos) {
+ if (mIsRunning) {
+ // Schedule next frame.
+ Choreographer.getInstance().postFrameCallback(this);
+
+ // Advance animation.
+ long durationNS = mDuration * 1000000;
+ long timeSinceAnimationStartNS = frameTimeNanos - mAnimationStartTime;
+ long animationProgressNS = timeSinceAnimationStartNS % durationNS;
+ mProgress = animationProgressNS / (float)durationNS;
+ if (timeSinceAnimationStartNS > durationNS) {
+ mAnimationStartTime += durationNS; // prevents overflow
+ }
+ }
+
+ drawFrame();
+ }
+
+ @Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// will be called on UI thread
updateSurface(surface, width, height);
@@ -452,7 +502,8 @@ public class SkottieRunner {
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);
+ boolean wideColorGamut, float progress);
+ private native long nGetDuration(long nativeProxy);
}
private static native long nCreateProxy();
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
index 5243e731d7..30602ea76b 100644
--- 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
@@ -8,63 +8,44 @@
package org.skia.skottie;
import android.content.Context;
-import android.graphics.drawable.Animatable;
+import android.util.AttributeSet;
import android.view.TextureView;
-import android.view.ViewGroup;
import java.io.InputStream;
-public class SkottieView extends ViewGroup implements Animatable {
+public class SkottieView extends TextureView {
- private TextureView mTextureView;
- private Animatable mAnimation;
+ private SkottieAnimation mAnimation;
- public SkottieView(Context context, InputStream is) {
+ public SkottieView(Context context) {
super(context);
+ init();
+ }
- mTextureView = new TextureView(context);
- mTextureView.setOpaque(false);
- mAnimation = SkottieRunner.getInstance().createAnimation(mTextureView, is);
- addView(mTextureView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ public SkottieView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
}
- /**
- * Starts the animation.
- */
- @Override
- public void start() {
- mAnimation.start();
+ public SkottieView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
}
- /**
- * Stops the animation.
- */
- @Override
- public void stop() {
- mAnimation.stop();
+ public SkottieView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
}
- @Override
- public boolean isRunning() {
- return mAnimation.isRunning();
+ private void init() {
+ setOpaque(false);
}
- /**
- * 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);
+ public void setSource(InputStream inputStream) {
+ mAnimation = SkottieRunner.getInstance().createAnimation(this, inputStream);
}
- @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);
- }
+ public SkottieAnimation getSkottieAnimation() {
+ return mAnimation;
}
}