[androidkit] initial upload of SkottieView util
Change-Id: I6f83ee6947121bef8a0c5b76b7a96ad85f24bd36
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/430018
Commit-Queue: Jorge Betancourt <jmbetancourt@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Color.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Color.java
index e9919ea..693eb31 100644
--- a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Color.java
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Color.java
@@ -21,6 +21,17 @@
this(0, 0, 0, 1);
}
+ /*
+ * Converts int given by android.graphics.Color
+ * to AndroidKit Color
+ */
+ public Color(int color) {
+ mA = ((color >> 24) & 0xff) / 255.f;
+ mR = ((color >> 16) & 0xff) / 255.f;
+ mG = ((color >> 8) & 0xff) / 255.f;
+ mB = ((color) & 0xff) / 255.f;
+ }
+
public float r() { return mR; }
public float g() { return mG; }
public float b() { return mB; }
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/util/SkottieView.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/util/SkottieView.java
new file mode 100644
index 0000000..2d449b0
--- /dev/null
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/util/SkottieView.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2021 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.androidkit.util;
+
+import android.content.Context;
+
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.SurfaceView;
+
+import android.view.TextureView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import java.io.InputStream;
+
+import org.skia.androidkit.Canvas;
+import org.skia.androidkit.Color;
+import org.skia.androidkit.Matrix;
+import org.skia.androidkit.SkottieAnimation;
+import org.skia.androidkit.Surface;
+
+import org.skia.androidkit.R;
+
+class SkottieRenderer extends SurfaceRenderer {
+ private float mSurfaceWidth,
+ mSurfaceHeight;
+ private Color mBackground;
+ private SkottieAnimation mAnimation;
+ private boolean mPlaying;
+
+ SkottieRenderer(SkottieAnimation mAnimation, Color mBackground) {
+ this.mAnimation = mAnimation;
+ this.mBackground = mBackground;
+ }
+ @Override
+ protected void onSurfaceInitialized(Surface surface) {
+ mSurfaceWidth = surface.getWidth();
+ mSurfaceHeight = surface.getHeight();
+ mPlaying = true;
+ }
+
+ @Override
+ protected void onRenderFrame(Canvas canvas, long ms) {
+ if(mPlaying) {
+ canvas.drawColor(mBackground);
+ double t = (double)ms / 1000 % mAnimation.getDuration();
+ mAnimation.seekTime(t);
+
+ float s = Math.min(mSurfaceWidth / mAnimation.getWidth(),
+ mSurfaceHeight / mAnimation.getHeight());
+ canvas.save();
+ canvas.concat(new Matrix().translate((mSurfaceWidth - s*mAnimation.getWidth())/2,
+ (mSurfaceHeight - s*mAnimation.getHeight())/2)
+ .scale(s, s));
+
+ mAnimation.render(canvas);
+ canvas.restore();
+ }
+ }
+
+ void play() {
+ if (!mPlaying) {
+ mPlaying = true;
+ }
+ }
+
+ void pause() {
+ if (mPlaying) {
+ mPlaying = false;
+ }
+ }
+
+ // TODO: adjust the super time base (otherwise onRenderFrame will overwrite via seekTime).
+ void seekFrame(double f) {
+ mAnimation.seekFrame(f);
+ }
+
+ @Override
+ public void release() {
+ mAnimation.release();
+ super.release();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ this.release();
+ }
+}
+
+public class SkottieView extends FrameLayout {
+ private SurfaceView mBackingView;
+ private SkottieRenderer mRenderer;
+
+ private final String LOG_TAG = "SkottieView";
+
+ public SkottieView(Context context, int resID, Color background) {
+ super(context);
+ mBackingView = new SurfaceView(context);
+ initBackingView();
+ InputStream inputStream = context.getResources().openRawResource(resID);
+ mRenderer = new SkottieRenderer(makeAnimation(inputStream), background);
+ mBackingView.getHolder().addCallback(mRenderer);
+ }
+
+ public SkottieView(Context context) {
+ super(context);
+ mBackingView = new SurfaceView(context);
+ initBackingView();
+ }
+
+ public SkottieView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public SkottieView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ // SkottieView constructor when initialized in XML layout
+ public SkottieView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs);
+ TypedArray a = context.getTheme()
+ .obtainStyledAttributes(attrs, R.styleable.SkottieView, defStyleAttr, defStyleRes);
+ try {
+ // set backing view and background color
+ mBackingView = new SurfaceView(context);
+ initBackingView();
+ int backgroundColor = a.getColor(R.styleable.SkottieView_background_color, -1);
+ if (backgroundColor == -1) {
+ throw new RuntimeException("background_color attribute "
+ + "needed for SurfaceView");
+ }
+ if (android.graphics.Color.alpha(backgroundColor) != 255) {
+ throw new RuntimeException("background_color cannot be transparent");
+ }
+ // set source
+ int src = a.getResourceId(R.styleable.SkottieView_src, -1);
+ Color c = new Color(backgroundColor);
+ setSource(src, context, new Color(backgroundColor));
+ } finally {
+ a.recycle();
+ }
+ }
+
+ private void initBackingView() {
+ mBackingView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ addView(mBackingView);
+ }
+
+ static private SkottieAnimation makeAnimation(InputStream is) {
+ String json = "";
+ try {
+ byte[] data = new byte[is.available()];
+ is.read(data);
+ json = new String(data);
+ } catch (Exception e) {}
+ return new SkottieAnimation(json);
+ }
+
+ public void setSource(int resID, Context context, Color background) {
+ InputStream inputStream = context.getResources().openRawResource(resID);
+ mRenderer = new SkottieRenderer(makeAnimation(inputStream), background);
+ mBackingView.getHolder().addCallback(mRenderer);
+ }
+
+ public void play() {
+ mRenderer.play();
+ }
+
+ public void pause() {
+ mRenderer.pause();
+ }
+
+ // TODO: track the time base locally
+ public void seekFrame(float frame) {
+ mRenderer.seekFrame(frame);
+ }
+}
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/util/SurfaceRenderer.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/util/SurfaceRenderer.java
index 2ed79b7..6a774f2 100644
--- a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/util/SurfaceRenderer.java
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/util/SurfaceRenderer.java
@@ -92,4 +92,8 @@
} catch (InterruptedException e) {}
}
}
+
+ public void release() {
+ stopRenderThread();
+ }
}
diff --git a/platform_tools/android/apps/AndroidKit/src/main/res/values/attrs.xml b/platform_tools/android/apps/AndroidKit/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..d6dddef
--- /dev/null
+++ b/platform_tools/android/apps/AndroidKit/src/main/res/values/attrs.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <declare-styleable name="SkottieView">
+ <attr name="background_color" format="color"/>
+ <attr name="src" format="reference"/>
+ <attr name="android:repeatCount" format="integer"/>
+ </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
index fc44c50..d60cb05 100644
--- a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
+++ b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
@@ -14,8 +14,13 @@
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
+import android.widget.LinearLayout;
+
import org.skia.androidkit.*;
+import org.skia.androidkit.util.SkottieView;
import org.skia.androidkit.util.SurfaceRenderer;
public class MainActivity extends Activity {
@@ -83,6 +88,18 @@
*/
SurfaceView runtimeEffectView = findViewById(R.id.runtimeEffect);
runtimeEffectView.getHolder().addCallback(new DemoRuntimeShaderRenderer());
+
+ /*
+ * SkottieView added programmatically to view hierarchy
+ */
+ SkottieView skottieView = new SkottieView(this, R.raw.im_thirsty, new Color(1, 1, 1, 1));
+ skottieView.setLayoutParams(new ViewGroup.LayoutParams(400, 400));
+ skottieView.setOnClickListener((View v) -> {
+ SkottieView s = (SkottieView)v;
+ s.pause();
+ });
+ LinearLayout skottieContainer = findViewById(R.id.skottie_container);
+ skottieContainer.addView(skottieView);
}
private class ThreadedSurfaceHandler implements SurfaceHolder.Callback {
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml b/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml
index 079e854..283c11a 100644
--- a/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml
+++ b/platform_tools/android/apps/androidkitdemo/src/main/res/layout/activity_main.xml
@@ -83,8 +83,15 @@
app:layout_constraintTop_toTopOf="parent"
android:text="Runtime effect drawn on a AndroidKit's\nutil thread. GL on Surface View.">
</TextView>
-
</android.support.constraint.ConstraintLayout>
+
+ <org.skia.androidkit.util.SkottieView
+ android:layout_width="400px"
+ android:layout_height="400px"
+ app:background_color="#fefefe"
+ app:src="@raw/permission">
+ </org.skia.androidkit.util.SkottieView>
+
</LinearLayout>
</ScrollView>
<org.skia.androidkitdemo1.NavigationSpinner