blob: 29956656ba95cd6a9ff652e34a16f98b5da15eea [file] [log] [blame]
package com.airbnb.lottie.snapshots.tests
import android.graphics.Canvas
import android.util.Log
import com.airbnb.lottie.LottieCompositionFactory
import com.airbnb.lottie.LottieDrawable
import com.airbnb.lottie.model.LottieCompositionCache
import com.airbnb.lottie.snapshots.BuildConfig
import com.airbnb.lottie.snapshots.SnapshotTestCase
import com.airbnb.lottie.snapshots.SnapshotTestCaseContext
import com.airbnb.lottie.snapshots.snapshotComposition
import com.airbnb.lottie.snapshots.utils.await
import com.airbnb.lottie.snapshots.utils.retry
import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility
import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.model.ListObjectsV2Request
import com.amazonaws.services.s3.model.S3ObjectSummary
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.produce
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileInputStream
import java.util.concurrent.atomic.AtomicInteger
import java.util.zip.ZipInputStream
class ProdAnimationsTestCase : SnapshotTestCase {
private val filesChannel = Channel<File>(capacity = 2048)
override suspend fun SnapshotTestCaseContext.run() = coroutineScope {
val compositionsChannel = parseCompositions(filesChannel)
val num = AtomicInteger()
repeat(3) {
launch {
for ((name, composition) in compositionsChannel) {
Log.d(TAG, "Snapshot ${num.incrementAndGet()}")
snapshotComposition(name, composition = composition)
}
}
}
// val num = AtomicInteger()
// for (file in filesChannel) {
// @Suppress("BlockingMethodInNonBlockingContext")
// val result = if (file.name.endsWith("zip")) LottieCompositionFactory.fromZipStreamSync(ZipInputStream(FileInputStream(file)), null)
// else LottieCompositionFactory.fromJsonInputStreamSync(FileInputStream(file), null)
// val composition = result.value ?: throw IllegalStateException("Unable to parse ${file.nameWithoutExtension}", result.exception)
// Log.d(TAG, "Snapshot ${num.incrementAndGet()}")
//
//
// val drawable = LottieDrawable()
// drawable.composition = composition
// val bitmap = bitmapPool.acquire(drawable.intrinsicWidth, drawable.intrinsicHeight)
// val canvas = Canvas(bitmap)
// drawable.draw(canvas)
// drawable.progress= 0.5f
// snapshotter.record(bitmap, "prod-${file.nameWithoutExtension}", "default")
// LottieCompositionCache.getInstance().clear()
// bitmapPool.release(bitmap)
//
// snapshotComposition("prod-${file.nameWithoutExtension}", composition = composition)
// }
}
@Suppress("BlockingMethodInNonBlockingContext")
fun CoroutineScope.parseCompositions(files: ReceiveChannel<File>) = produce(
context = Dispatchers.IO,
capacity = 100,
) {
val num = AtomicInteger()
for (file in files) {
val result = if (file.name.endsWith("zip")) LottieCompositionFactory.fromZipStreamSync(ZipInputStream(FileInputStream(file)), null)
else LottieCompositionFactory.fromJsonInputStreamSync(FileInputStream(file), null)
val composition = result.value ?: throw IllegalStateException("Unable to parse ${file.nameWithoutExtension}", result.exception)
Log.d(TAG, "Parse ${num.incrementAndGet()}")
send("prod-${file.nameWithoutExtension}" to composition)
}
}
suspend fun SnapshotTestCaseContext.downloadAnimations() = coroutineScope {
val transferUtility = TransferUtility.builder()
.context(context)
.s3Client(AmazonS3Client(BasicAWSCredentials(BuildConfig.S3AccessKey, BuildConfig.S3SecretKey)))
.defaultBucket("lottie-prod-animations")
.build()
val num = AtomicInteger()
coroutineScope {
val animations = fetchAllObjects("lottie-prod-animations")
animations
// .filterIndexed { i, _ -> i in 400..500 }
// .filter { "app-setup_connection_failed" in it.key || "app-setup_location_permission" in it.key || "walletnfcrel-thermo" in it.key }
// .dropWhile { "com.google.android.wearable" !in it.key }
// .take(200)
.chunked(animations.size / 3)
.forEach { animationsChunk ->
launch(Dispatchers.Main) {
for (animation in animationsChunk) {
repeat(1) {
val file = File(context.cacheDir, animation.key)
file.deleteOnExit()
retry { _, _ ->
transferUtility.download(animation.key, file).await()
}
Log.d(TAG, "Downloaded ${num.incrementAndGet()} ${file.nameWithoutExtension}")
filesChannel.send(file)
}
}
}
}
}
Log.d(TAG, "Finished downloading")
filesChannel.close()
}
private fun fetchAllObjects(bucket: String): List<S3ObjectSummary> {
val allObjects = mutableListOf<S3ObjectSummary>()
val s3Client = AmazonS3Client(BasicAWSCredentials(BuildConfig.S3AccessKey, BuildConfig.S3SecretKey))
var request = ListObjectsV2Request().apply {
bucketName = bucket
}
var result = s3Client.listObjectsV2(request)
allObjects.addAll(result.objectSummaries)
var startAfter = result.objectSummaries.lastOrNull()?.key
while (startAfter != null) {
request = ListObjectsV2Request().apply {
bucketName = bucket
this.startAfter = startAfter
}
result = s3Client.listObjectsV2(request)
allObjects.addAll(result.objectSummaries)
startAfter = result.objectSummaries.lastOrNull()?.key
}
return allObjects
}
companion object {
private const val TAG = "ProdAnimationsTest"
}
}