• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 package org.skia.jetski.util;
9 
10 import android.content.Context;
11 
12 import android.content.res.TypedArray;
13 import android.util.AttributeSet;
14 import android.view.SurfaceView;
15 
16 import android.view.ViewGroup;
17 import android.widget.FrameLayout;
18 import java.io.InputStream;
19 
20 import org.skia.jetski.Canvas;
21 import org.skia.jetski.Color;
22 import org.skia.jetski.Matrix;
23 import org.skia.jetski.SkottieAnimation;
24 import org.skia.jetski.Surface;
25 
26 import org.skia.jetski.R;
27 
28 class SkottieRenderer extends SurfaceRenderer {
29     private float mSurfaceWidth,
30                   mSurfaceHeight;
31     private Color mBackground;
32     private SkottieAnimation mAnimation;
33     private boolean mPlaying;
34 
SkottieRenderer(SkottieAnimation mAnimation, Color mBackground)35     SkottieRenderer(SkottieAnimation mAnimation, Color mBackground) {
36         this.mAnimation = mAnimation;
37         this.mBackground = mBackground;
38     }
39     @Override
onSurfaceInitialized(Surface surface)40     protected void onSurfaceInitialized(Surface surface) {
41         mSurfaceWidth  = surface.getWidth();
42         mSurfaceHeight = surface.getHeight();
43         mPlaying = true;
44     }
45 
46     @Override
onRenderFrame(Canvas canvas, long ms)47     protected void onRenderFrame(Canvas canvas, long ms) {
48         if(mPlaying) {
49             canvas.drawColor(mBackground);
50             double t = (double)ms / 1000 % mAnimation.getDuration();
51             mAnimation.seekTime(t);
52 
53             float s = Math.min(mSurfaceWidth / mAnimation.getWidth(),
54                     mSurfaceHeight / mAnimation.getHeight());
55             canvas.save();
56             canvas.concat(new Matrix().translate((mSurfaceWidth  - s*mAnimation.getWidth())/2,
57                     (mSurfaceHeight - s*mAnimation.getHeight())/2)
58                     .scale(s, s));
59 
60             mAnimation.render(canvas);
61             canvas.restore();
62         }
63     }
64 
play()65     void play() {
66         if (!mPlaying) {
67             mPlaying = true;
68         }
69     }
70 
pause()71     void pause() {
72         if (mPlaying) {
73             mPlaying = false;
74         }
75     }
76 
getAnimation()77     SkottieAnimation getAnimation() {
78         return mAnimation;
79     }
80 
81     @Override
release()82     public void release() {
83         mAnimation.release();
84         super.release();
85     }
86 
87     @Override
finalize()88     protected void finalize() throws Throwable {
89         this.release();
90     }
91 }
92 
93 public class SkottieView extends FrameLayout {
94     private SurfaceView mBackingView;
95     private SkottieRenderer mRenderer;
96 
97     private final String LOG_TAG = "SkottieView";
98 
SkottieView(Context context, int resID, Color background)99     public SkottieView(Context context, int resID, Color background) {
100         super(context);
101         mBackingView = new SurfaceView(context);
102         initBackingView();
103         InputStream inputStream = context.getResources().openRawResource(resID);
104         mRenderer = new SkottieRenderer(makeAnimation(inputStream), background);
105         mBackingView.getHolder().addCallback(mRenderer);
106     }
107 
SkottieView(Context context)108     public SkottieView(Context context) {
109         super(context);
110         mBackingView = new SurfaceView(context);
111         initBackingView();
112     }
113 
SkottieView(Context context, AttributeSet attrs)114     public SkottieView(Context context, AttributeSet attrs) {
115         this(context, attrs, 0, 0);
116     }
117 
SkottieView(Context context, AttributeSet attrs, int defStyleAttr)118     public SkottieView(Context context, AttributeSet attrs, int defStyleAttr) {
119         this(context, attrs, defStyleAttr, 0);
120     }
121 
122     // SkottieView constructor when initialized in XML layout
SkottieView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)123     public SkottieView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
124         super(context, attrs);
125         TypedArray a = context.getTheme()
126                 .obtainStyledAttributes(attrs, R.styleable.SkottieView, defStyleAttr, defStyleRes);
127         try {
128             // set backing view and background color
129             mBackingView = new SurfaceView(context);
130             initBackingView();
131             int backgroundColor = a.getColor(R.styleable.SkottieView_background_color, -1);
132             if (backgroundColor == -1) {
133                 throw new RuntimeException("background_color attribute "
134                         + "needed for SurfaceView");
135             }
136             if (android.graphics.Color.alpha(backgroundColor) != 255) {
137                 throw new RuntimeException("background_color cannot be transparent");
138             }
139             // set source
140             int src = a.getResourceId(R.styleable.SkottieView_src, -1);
141             Color c = new Color(backgroundColor);
142             setSource(src, context, new Color(backgroundColor));
143         } finally {
144             a.recycle();
145         }
146     }
147 
initBackingView()148     private void initBackingView() {
149         mBackingView.setLayoutParams(new ViewGroup.LayoutParams(
150                 ViewGroup.LayoutParams.MATCH_PARENT,
151                 ViewGroup.LayoutParams.MATCH_PARENT));
152         addView(mBackingView);
153     }
154 
makeAnimation(InputStream is)155     static private SkottieAnimation makeAnimation(InputStream is) {
156         String json = "";
157         try {
158             byte[] data = new byte[is.available()];
159             is.read(data);
160             json = new String(data);
161         } catch (Exception e) {}
162         return new SkottieAnimation(json);
163     }
164 
setSource(int resID, Context context, Color background)165     public void setSource(int resID, Context context, Color background) {
166         InputStream inputStream = context.getResources().openRawResource(resID);
167         mRenderer = new SkottieRenderer(makeAnimation(inputStream), background);
168         mBackingView.getHolder().addCallback(mRenderer);
169     }
170 
play()171     public void play() {
172         mRenderer.play();
173     }
174 
pause()175     public void pause() {
176         mRenderer.pause();
177     }
178 
seekTime(double t)179     public void seekTime(double t) {
180         mRenderer.setBaseTime(java.lang.System.currentTimeMillis() - ((long)t * 1000));
181     }
182 
seekFrame(double f)183     public void seekFrame(double f) {
184         double totalFrames = mRenderer.getAnimation().getFrameCount();
185         double totalTime = mRenderer.getAnimation().getDuration();
186         double targetTime = (f % totalFrames) / totalFrames * totalTime;
187         seekTime(targetTime);
188     }
189 }
190