aboutsummaryrefslogtreecommitdiff
path: root/platform_tools
diff options
context:
space:
mode:
authorStan Iliev <stani@google.com>2018-11-07 10:13:29 -0500
committerSkia Commit-Bot <skia-commit-bot@chromium.org>2018-11-07 15:41:34 +0000
commit762ba1038d3aa8ae6b9ef8197e4749b0f9b5f2f2 (patch)
treee926deca6ef2445290a5edd96b0b5d6544b591b2 /platform_tools
parente475f4ee696421beb829f3ebd3cc942050980e3c (diff)
downloadskqp-762ba1038d3aa8ae6b9ef8197e4749b0f9b5f2f2.tar.gz
Skottie Android demo app improvements
Changed SkottieView base class to TextureView. Implemented new SkottieAnimation interface, which allows to get animation duration, set and get animation progress. SkottieView will draw correctly even if animation is stopped. Test: Ran Skottie app Bug: skia: Change-Id: I952793b75518107f515ddec8ad6524f4048f42e7 Reviewed-on: https://skia-review.googlesource.com/c/167945 Commit-Queue: Stan Iliev <stani@google.com> Reviewed-by: Derek Sollenberger <djsollen@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
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;
}
}