1 /* 2 * Copyright 2018 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.skottie; 9 10 import android.app.Activity; 11 import android.content.Intent; 12 import android.graphics.Color; 13 import android.graphics.Point; 14 import android.net.Uri; 15 import android.os.Bundle; 16 import android.view.View; 17 import android.view.ViewGroup; 18 import android.widget.Button; 19 import android.widget.GridLayout; 20 21 import java.io.FileNotFoundException; 22 import java.io.InputStream; 23 import java.util.ArrayList; 24 import java.util.List; 25 import java.util.concurrent.CountDownLatch; 26 import java.util.concurrent.TimeUnit; 27 import java.util.concurrent.TimeoutException; 28 29 import static java.lang.Math.ceil; 30 import static java.lang.Math.sqrt; 31 32 public class SkottieActivity extends Activity implements View.OnClickListener { 33 34 private final static long TIME_OUT_MS = 10000; 35 36 private SkottieApplication mApplication; 37 38 private CountDownLatch mEnterAnimationFence = new CountDownLatch(1); 39 40 private GridLayout mGrid; 41 private int mRowCount = 0; 42 private int mColumnCount = 0; 43 private int mCellWidth = 0; 44 private int mCellHeight = 0; 45 46 private List<SkottieView> mAnimations; 47 static private List<Uri> mAnimationFiles = new ArrayList<Uri>(); 48 populateGrid()49 private void populateGrid() { 50 mRowCount = 0; 51 mColumnCount = 0; 52 mAnimations = new ArrayList<SkottieView>(); 53 mCellWidth = 0; 54 mCellHeight = 0; 55 56 int rawAssets[] = { 57 R.raw.star, R.raw.movie_loading, R.raw.uk, R.raw.white_material_wave_loading 58 }; 59 60 for (int resId : rawAssets) { 61 SkottieView view = new SkottieView(this); 62 view.setSource(getResources().openRawResource(resId)); 63 mAnimations.add(view); 64 } 65 66 for (Uri uri : mAnimationFiles) { 67 try { 68 InputStream inputStream = getContentResolver().openInputStream(uri); 69 SkottieView view = new SkottieView(this); 70 view.setSource(inputStream); 71 mAnimations.add(view); 72 } catch (FileNotFoundException e) { 73 e.printStackTrace(); 74 } 75 } 76 77 Point size = new Point(); 78 getWindowManager().getDefaultDisplay().getSize(size); 79 int screenWidth = size.x; 80 int screenHeight = (int)(size.y / 1.3f); 81 82 double unit = sqrt(mAnimations.size() / 6.0f); 83 mRowCount = (int)ceil(3 * unit); 84 mColumnCount = (int)ceil(2 * unit); 85 mGrid.setColumnCount(mColumnCount); 86 mGrid.setRowCount(mRowCount); 87 mCellWidth = screenWidth / mColumnCount; 88 mCellHeight = screenHeight / mRowCount; 89 90 refreshGrid(); 91 92 startAnimation(); 93 94 for (SkottieView view : mAnimations) { 95 view.setOnClickListener(new View.OnClickListener(){ 96 public void onClick(View view){ 97 inflateView((SkottieView)view); 98 } 99 }); 100 } 101 102 if (mInflatedIndex >= 0) { 103 SkottieView view = mAnimations.get(mInflatedIndex); 104 mInflatedIndex = -1; 105 inflateView(view); 106 } 107 } 108 109 static int mInflatedIndex = -1; 110 inflateView(SkottieView view)111 private void inflateView(SkottieView view) { 112 if (mInflatedIndex >= 0) { 113 //deflate active view 114 SkottieView oldView = mAnimations.get(mInflatedIndex); 115 if (oldView != null) { 116 int row = mInflatedIndex / mColumnCount, column = mInflatedIndex % mColumnCount; 117 addView(oldView, row, column, false); 118 } 119 mInflatedIndex = -1; 120 //start and show animations that were in the background 121 for (SkottieView anyView : mAnimations) { 122 if (anyView != oldView) { 123 anyView.getSkottieAnimation().start(); 124 anyView.setVisibility(View.VISIBLE); 125 } 126 } 127 return; 128 } 129 130 //stop and hide animations in the background 131 for (SkottieView anyView : mAnimations) { 132 if (anyView != view) { 133 anyView.getSkottieAnimation().stop(); 134 anyView.setVisibility(View.INVISIBLE); 135 } 136 } 137 138 mInflatedIndex = mAnimations.indexOf(view); 139 140 GridLayout.Spec rowSpec = GridLayout.spec(0, mRowCount, GridLayout.CENTER); 141 GridLayout.Spec colSpec = GridLayout.spec(0, mColumnCount, GridLayout.CENTER); 142 GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpec, colSpec); 143 params.width = ViewGroup.LayoutParams.MATCH_PARENT; 144 params.height = ViewGroup.LayoutParams.MATCH_PARENT; 145 146 mGrid.updateViewLayout(view, params); 147 } 148 refreshGrid()149 private void refreshGrid() { 150 mGrid.removeAllViews(); 151 int currentRaw = 0; 152 int row = 0, column = 0; 153 for (SkottieView view : mAnimations) { 154 addView(view, row, column, true); 155 column++; 156 if (column >= mColumnCount) { 157 column = 0; 158 row++; 159 } 160 } 161 } 162 addView(SkottieView view, int row , int column, boolean addView)163 private void addView(SkottieView view, int row , int column, boolean addView) { 164 GridLayout.Spec rowSpec = GridLayout.spec(row, 1, GridLayout.CENTER); 165 GridLayout.Spec colSpec = GridLayout.spec(column, 1, GridLayout.CENTER); 166 GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpec, colSpec); 167 params.width = mCellWidth; 168 params.height = mCellHeight; 169 if (addView) { 170 mGrid.addView(view, params); 171 } else { 172 mGrid.updateViewLayout(view, params); 173 } 174 } 175 startAnimation()176 private void startAnimation() { 177 for (SkottieView view : mAnimations) { 178 view.getSkottieAnimation().start(); 179 } 180 } 181 stopAnimation()182 private void stopAnimation() { 183 for (SkottieView view : mAnimations) { 184 view.getSkottieAnimation().stop(); 185 } 186 } 187 addLottie(Uri uri)188 private void addLottie(Uri uri) throws FileNotFoundException { 189 InputStream inputStream = getContentResolver().openInputStream(uri); 190 int animations = mAnimations.size(); 191 if (animations < mRowCount * mColumnCount) { 192 SkottieView view = new SkottieView(this); 193 view.setSource(inputStream); 194 int row = animations / mColumnCount, column = animations % mColumnCount; 195 mAnimations.add(view); 196 mAnimationFiles.add(uri); 197 view.setOnClickListener(new View.OnClickListener(){ 198 public void onClick(View view){ 199 inflateView((SkottieView)view); 200 } 201 }); 202 addView(view, row, column, true); 203 view.getSkottieAnimation().start(); 204 } else { 205 stopAnimation(); 206 mAnimationFiles.add(uri); 207 populateGrid(); 208 startAnimation(); 209 } 210 } 211 212 213 @Override onEnterAnimationComplete()214 public void onEnterAnimationComplete() { 215 super.onEnterAnimationComplete(); 216 mEnterAnimationFence.countDown(); 217 } 218 waitForEnterAnimationComplete()219 public void waitForEnterAnimationComplete() throws TimeoutException, InterruptedException { 220 if (!mEnterAnimationFence.await(TIME_OUT_MS, TimeUnit.MILLISECONDS)) { 221 throw new TimeoutException(); 222 } 223 } 224 createLayout()225 private void createLayout() { 226 setContentView(R.layout.main_layout); 227 Button button1 = (Button)findViewById(R.id.open_lottie); 228 button1.setOnClickListener(this); 229 mGrid = (GridLayout)findViewById(R.id.grid_lotties); 230 mGrid.setBackgroundColor(Color.LTGRAY); 231 232 populateGrid(); 233 } 234 235 @Override onCreate(Bundle savedInstanceState)236 protected void onCreate(Bundle savedInstanceState) { 237 super.onCreate(savedInstanceState); 238 239 createLayout(); 240 } 241 242 @Override onDestroy()243 protected void onDestroy() { 244 super.onDestroy(); 245 } 246 247 static final int PICK_FILE_REQUEST = 2; 248 249 @Override onClick(View view)250 public void onClick(View view) { 251 Intent intent = new Intent(); 252 intent.setType("application/json"); 253 Intent i = Intent.createChooser(intent, "View Default File Manager"); 254 startActivityForResult(i, PICK_FILE_REQUEST); 255 } 256 257 @Override onActivityResult(int requestCode, int resultCode, Intent data)258 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 259 super.onActivityResult(requestCode, resultCode, data); 260 if (resultCode == Activity.RESULT_OK) { 261 if (requestCode == PICK_FILE_REQUEST) if (data != null) { 262 //no data present 263 Uri uri = data.getData(); 264 265 try { 266 addLottie(uri); 267 } catch (FileNotFoundException e) { 268 e.printStackTrace(); 269 } 270 } 271 } 272 } 273 } 274