/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.fresco.buildsrc

object Deps {
  const val javaxAnnotation = "javax.annotation:javax.annotation-api:1.2"
  const val jsr305 = "com.google.code.findbugs:jsr305:3.0.2"

  const val inferAnnotation = "com.facebook.infer.annotation:infer-annotation:0.18.0"

  const val okhttp3 = "com.squareup.okhttp3:okhttp:3.12.1"

  const val volley = "com.android.volley:volley:1.2.1"

  object AndroidX {
    const val androidxAnnotation = "androidx.annotation:annotation:1.1.0"
    const val core = "androidx.core:core:1.3.1"
    const val legacySupportCoreUtils = "androidx.legacy:legacy-support-core-utils:1.0.0"
  }

  object Bolts {
    const val tasks = "com.parse.bolts:bolts-tasks:1.4.0"
  }

  object Kotlin {
    const val version = GradleDeps.Kotlin.version

    const val stdlibJdk = "org.jetbrains.kotlin:kotlin-stdlib:$version"
  }

  object Litho {
    private const val version = "0.41.2"

    const val core = "com.facebook.litho:litho-core:$version"
    const val lithoAnnotations = "com.facebook.litho:litho-annotations:$version"
    const val processor = "com.facebook.litho:litho-processor:$version"
    const val widget = "com.facebook.litho:litho-widget:$version"

    object Sections {
      const val core = "com.facebook.litho:litho-sections-core:$version"
      const val processor = "com.facebook.litho:litho-sections-processor:$version"
      const val sectionsAnnotations = "com.facebook.litho:litho-sections-annotations:$version"
      const val widget = "com.facebook.litho:litho-sections-widget:$version"
    }
  }

  object SoLoader {
    private const val version = "0.10.5"
    const val soloaderAnnotation = "com.facebook.soloader:annotation:$version"
    const val nativeloader = "com.facebook.soloader:nativeloader:$version"
    const val soloader = "com.facebook.soloader:soloader:$version"
  }

  object Tools {
    object Flipper {
      private const val version = "0.183.0"
      const val flipper = "com.facebook.flipper:flipper:$version"
    }

    object Stetho {
      private const val version = "1.6.0"
      const val stetho = "com.facebook.stetho:stetho:$version"
      const val okhttp3 = "com.facebook.stetho:stetho-okhttp3:$version"
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

object FrescoConfig {
  const val buildToolsVersion = "34.0.0"

  const val compileSdkVersion = 34
  const val minSdkVersion = 14
  const val flipperPluginMinSdkVersion = 16
  const val vitoLithoMinSdkVersion = 16
  const val samplesMinSdkVersion = 16
  const val targetSdkVersion = 34
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.fresco.buildsrc

object GradleDeps {

  object Android {
    private const val version = "7.2.0"

    const val gradlePlugin = "com.android.tools.build:gradle:$version"
  }

  object Kotlin {
    const val version = "1.8.10"
    const val gradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$version"
    const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib:$version"
  }

  object Publishing {
    const val gradleMavenPublishPlugin = "com.vanniktech:gradle-maven-publish-plugin:0.15.1"
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.fresco.buildsrc

object TestDeps {
  const val assertjCore = "org.assertj:assertj-core:2.9.0"

  const val junit = "junit:junit:4.12"

  const val mockitoCore = "org.mockito:mockito-core:2.28.2"

  const val mockitoInline = "org.mockito:mockito-inline:2.28.2"
  const val mockitoKotlin = "org.mockito.kotlin:mockito-kotlin:2.2.11"

  const val festAssertCore = "org.easytesting:fest-assert-core:2.0M10"

  const val robolectric = "org.robolectric:robolectric:4.9.2"

  const val truth = "com.google.truth:truth:1.0.1"

  object AndroidX {
    const val espressoCore = "androidx.test.espresso:espresso-core:3.1.1"
    const val testRules = "androidx.test:rules:1.1.1"
    const val testRunner = "androidx.test:runner:1.1.1"
  }

  object Powermock {
    private const val version = "2.0.2"

    const val apiMockito = "org.powermock:powermock-api-mockito2:$version"
    const val moduleJunit4 = "org.powermock:powermock-module-junit4:$version"
    const val moduleJunit4Rule = "org.powermock:powermock-module-junit4-rule:$version"
    const val classloadingXstream = "org.powermock:powermock-classloading-xstream:$version"
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.drawee.backends.pipeline.info

object ImagePerfExtra {
  const val IMAGE_ORIGIN: String = "IMAGE_ORIGIN"
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.common.closeables

import java.io.Closeable
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
 * Property delegate to call a cleanup function when the value changes (including being set to
 * null). It will NOT trigger the cleanup function if the same value is set again.
 */
open class AutoCleanupDelegate<T>(
    private var currentValue: T? = null,
    private val cleanupFunction: (T) -> Unit
) : ReadWriteProperty<Any?, T?> {

  override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
    val cur = currentValue
    if (cur != null && cur !== value) {
      cleanupFunction(cur)
    }
    currentValue = value
  }

  override operator fun getValue(thisRef: Any?, property: KProperty<*>): T? = currentValue
}

class AutoCloseableDelegate<T : Closeable>(initialValue: T? = null) :
    AutoCleanupDelegate<T>(initialValue, closeableCleanupFunction)

private val closeableCleanupFunction: (Closeable) -> Unit = { it.close() }


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.common.media

import androidx.annotation.NonNull
import java.util.Locale

/** Utility class. */
object MediaUtils {

  @JvmField // Additional mime types that we know to be a particular media type but which may not be
  // supported natively on the device.
  val ADDITIONAL_ALLOWED_MIME_TYPES =
      mapOf(
          "mkv" to "video/x-matroska",
          "glb" to "model/gltf-binary",
      )

  @JvmStatic fun isPhoto(mimeType: String?): Boolean = mimeType?.startsWith("image/") ?: false

  @JvmStatic fun isVideo(mimeType: String?): Boolean = mimeType?.startsWith("video/") ?: false

  @JvmStatic fun isThreeD(mimeType: String?): Boolean = mimeType == "model/gltf-binary"

  @JvmStatic
  fun extractMime(@NonNull path: String): String? {
    val extension = extractExtension(path)?.toLowerCase(Locale.US) ?: return null

    // If we did not find a mime type for the extension specified, check our additional
    // extension/mime-type mappings.
    return MimeTypeMapWrapper.getMimeTypeFromExtension(extension)
        ?: ADDITIONAL_ALLOWED_MIME_TYPES[extension]
  }

  private fun extractExtension(@NonNull path: String): String? {
    val pos = path.lastIndexOf('.')
    return if (pos < 0 || pos == path.length - 1) null else path.substring(pos + 1)
  }

  /**
   * @return true if the mime type is one of our whitelisted mimetypes that we support beyond what
   *   the native platform supports.
   */
  @JvmStatic
  fun isNonNativeSupportedMimeType(@NonNull mimeType: String): Boolean {
    return ADDITIONAL_ALLOWED_MIME_TYPES.containsValue(mimeType)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.datasource

object SuccessfulVoidDataSource : AbstractDataSource<Void>() {
  init {
    setResult(null, true)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.bitmaps

import android.annotation.TargetApi
import android.graphics.Bitmap
import android.os.Build
import com.facebook.common.references.CloseableReference
import com.facebook.imagepipeline.core.CloseableReferenceFactory
import com.facebook.imagepipeline.memory.BitmapPool
import com.facebook.imageutils.BitmapUtil
import javax.annotation.concurrent.ThreadSafe

/** Bitmap factory for ART VM (Lollipop and up). */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@ThreadSafe
class ArtBitmapFactory(
    private val bitmapPool: BitmapPool,
    private val closeableReferenceFactory: CloseableReferenceFactory
) : PlatformBitmapFactory() {
  /**
   * Creates a bitmap of the specified width and height.
   *
   * @param width the width of the bitmap
   * @param height the height of the bitmap
   * @param bitmapConfig the [android.graphics.Bitmap.Config] used to create the decoded Bitmap
   * @return a reference to the bitmap
   * @exception java.lang.OutOfMemoryError if the Bitmap cannot be allocated
   */
  override fun createBitmapInternal(
      width: Int,
      height: Int,
      bitmapConfig: Bitmap.Config
  ): CloseableReference<Bitmap> {
    val sizeInBytes = BitmapUtil.getSizeInByteForBitmap(width, height, bitmapConfig)
    val bitmap = bitmapPool[sizeInBytes]
    check(
        bitmap.allocationByteCount >=
            width * height * BitmapUtil.getPixelSizeForBitmapConfig(bitmapConfig))
    bitmap.reconfigure(width, height, bitmapConfig)
    return closeableReferenceFactory.create(bitmap, bitmapPool)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.bitmaps

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.BitmapFactory.Options
import android.graphics.Color
import com.facebook.common.references.CloseableReference
import com.facebook.common.webp.BitmapCreator
import com.facebook.imageformat.DefaultImageFormats
import com.facebook.imagepipeline.image.EncodedImage
import com.facebook.imagepipeline.memory.FlexByteArrayPool
import com.facebook.imagepipeline.memory.PoolFactory

/** This is the implementation of the BitmapCreator for the Honeycomb */
class HoneycombBitmapCreator(poolFactory: PoolFactory) : BitmapCreator {

  private val jpegGenerator: EmptyJpegGenerator =
      EmptyJpegGenerator(poolFactory.pooledByteBufferFactory)
  private val flexByteArrayPool: FlexByteArrayPool = poolFactory.flexByteArrayPool

  override fun createNakedBitmap(width: Int, height: Int, bitmapConfig: Bitmap.Config): Bitmap {
    val jpgRef = jpegGenerator.generate(width.toShort(), height.toShort())
    var encodedImage: EncodedImage? = null
    var encodedBytesArrayRef: CloseableReference<ByteArray?>? = null
    return try {
      encodedImage = EncodedImage(jpgRef)
      encodedImage.imageFormat = DefaultImageFormats.JPEG
      val options = getBitmapFactoryOptions(encodedImage.sampleSize, bitmapConfig)
      val length = jpgRef.get().size()
      val pooledByteBuffer = jpgRef.get()
      encodedBytesArrayRef = flexByteArrayPool[length + 2]
      val encodedBytesArray = encodedBytesArrayRef.get()
      pooledByteBuffer.read(0, encodedBytesArray, 0, length)
      val bitmap =
          checkNotNull(BitmapFactory.decodeByteArray(encodedBytesArray, 0, length, options))
      bitmap.setHasAlpha(true)
      bitmap.eraseColor(Color.TRANSPARENT)
      bitmap
    } finally {
      CloseableReference.closeSafely(encodedBytesArrayRef)
      EncodedImage.closeSafely(encodedImage)
      CloseableReference.closeSafely(jpgRef)
    }
  }

  companion object {
    private fun getBitmapFactoryOptions(sampleSize: Int, bitmapConfig: Bitmap.Config): Options {
      val options = Options()
      options.inDither = true // known to improve picture quality at low cost
      options.inPreferredConfig = bitmapConfig
      // Decode the image into a 'purgeable' bitmap that lives on the ashmem heap
      options.inPurgeable = true
      // Enable copy of of bitmap to enable purgeable decoding by filedescriptor
      options.inInputShareable = true
      // Sample size should ONLY be different than 1 when downsampling is enabled in the pipeline
      options.inSampleSize = sampleSize
      options.inMutable = true // no known perf difference; allows postprocessing to work
      return options
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.bitmaps

import android.annotation.TargetApi
import android.graphics.Bitmap
import android.graphics.Color
import android.os.Build
import com.facebook.common.logging.FLog
import com.facebook.common.references.CloseableReference
import com.facebook.imageformat.DefaultImageFormats
import com.facebook.imagepipeline.core.CloseableReferenceFactory
import com.facebook.imagepipeline.image.EncodedImage
import com.facebook.imagepipeline.platform.PlatformDecoder
import javax.annotation.concurrent.ThreadSafe

/** Factory implementation for Honeycomb through Kitkat */
@ThreadSafe
class HoneycombBitmapFactory(
    private val jpegGenerator: EmptyJpegGenerator,
    private val purgeableDecoder: PlatformDecoder,
    private val closeableReferenceFactory: CloseableReferenceFactory
) : PlatformBitmapFactory() {

  private var immutableBitmapFallback = false

  /**
   * Creates a bitmap of the specified width and height.
   *
   * @param width the width of the bitmap
   * @param height the height of the bitmap
   * @param bitmapConfig the [android.graphics.Bitmap.Config] used to create the decoded Bitmap
   * @return a reference to the bitmap
   * @throws TooManyBitmapsException if the pool is full
   * @throws java.lang.OutOfMemoryError if the Bitmap cannot be allocated
   */
  @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
  override fun createBitmapInternal(
      width: Int,
      height: Int,
      bitmapConfig: Bitmap.Config
  ): CloseableReference<Bitmap> {
    if (immutableBitmapFallback) {
      return createFallbackBitmap(width, height, bitmapConfig)
    }
    val jpgRef = jpegGenerator.generate(width.toShort(), height.toShort())
    return try {
      val encodedImage = EncodedImage(jpgRef)
      encodedImage.imageFormat = DefaultImageFormats.JPEG
      try {
        val bitmapRef =
            purgeableDecoder.decodeJPEGFromEncodedImage(
                encodedImage, bitmapConfig, null, jpgRef.get().size())
        checkNotNull(bitmapRef)
        if (!bitmapRef.get().isMutable) {
          CloseableReference.closeSafely(bitmapRef)
          immutableBitmapFallback = true
          FLog.wtf(TAG, "Immutable bitmap returned by decoder")
          // On some devices (Samsung GT-S7580) the returned bitmap can be immutable, in that case
          // let's jut use Bitmap.createBitmap() to hopefully create a mutable one.
          return createFallbackBitmap(width, height, bitmapConfig)
        }
        bitmapRef.get().setHasAlpha(true)
        bitmapRef.get().eraseColor(Color.TRANSPARENT)
        bitmapRef
      } finally {
        EncodedImage.closeSafely(encodedImage)
      }
    } finally {
      jpgRef.close()
    }
  }

  private fun createFallbackBitmap(
      width: Int,
      height: Int,
      bitmapConfig: Bitmap.Config
  ): CloseableReference<Bitmap> =
      closeableReferenceFactory.create(
          Bitmap.createBitmap(width, height, bitmapConfig), SimpleBitmapReleaser.getInstance())

  companion object {
    private val TAG = HoneycombBitmapFactory::class.java.simpleName
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.bitmaps

import android.os.Build
import com.facebook.imagepipeline.core.CloseableReferenceFactory
import com.facebook.imagepipeline.memory.PoolFactory
import com.facebook.imagepipeline.platform.PlatformDecoder

object PlatformBitmapFactoryProvider {
  /**
   * Provide the implementation of the PlatformBitmapFactory for the current platform using the
   * provided PoolFactory
   *
   * @param poolFactory The PoolFactory
   * @param platformDecoder The PlatformDecoder
   * @return The PlatformBitmapFactory implementation
   */
  @JvmStatic
  fun buildPlatformBitmapFactory(
      poolFactory: PoolFactory,
      platformDecoder: PlatformDecoder,
      closeableReferenceFactory: CloseableReferenceFactory
  ): PlatformBitmapFactory =
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        ArtBitmapFactory(poolFactory.bitmapPool, closeableReferenceFactory)
      } else {
        HoneycombBitmapFactory(
            EmptyJpegGenerator(poolFactory.pooledByteBufferFactory),
            platformDecoder,
            closeableReferenceFactory)
      }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.cache

import android.net.Uri
import com.facebook.cache.common.CacheKey
import com.facebook.common.time.RealtimeSinceBootClock
import com.facebook.common.util.HashCodeUtil
import com.facebook.imagepipeline.common.ImageDecodeOptions
import com.facebook.imagepipeline.common.ResizeOptions
import com.facebook.imagepipeline.common.RotationOptions

/** Cache key for BitmapMemoryCache */
data class BitmapMemoryCacheKey(
    val sourceString: String,
    val resizeOptions: ResizeOptions?,
    val rotationOptions: RotationOptions,
    val imageDecodeOptions: ImageDecodeOptions,
    val postprocessorCacheKey: CacheKey?,
    val postprocessorName: String?,
) : CacheKey {

  var callerContext: Any? = null

  private val hash: Int =
      HashCodeUtil.hashCode(
          sourceString.hashCode(),
          resizeOptions?.hashCode() ?: 0,
          rotationOptions.hashCode(),
          imageDecodeOptions,
          postprocessorCacheKey,
          postprocessorName)
  val inBitmapCacheSince: Long = RealtimeSinceBootClock.get().now()

  override fun hashCode(): Int = hash

  override fun containsUri(uri: Uri): Boolean {
    return uriString.contains(uri.toString())
  }

  override fun getUriString(): String = sourceString

  override fun isResourceIdForDebugging() = false
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.cache

import bolts.Task
import com.facebook.cache.common.CacheKey
import com.facebook.cache.disk.FileCache
import com.facebook.common.logging.FLog
import com.facebook.common.memory.PooledByteBuffer
import com.facebook.common.memory.PooledByteBufferFactory
import com.facebook.common.memory.PooledByteStreams
import com.facebook.common.references.CloseableReference
import com.facebook.imagepipeline.image.EncodedImage
import com.facebook.imagepipeline.instrumentation.FrescoInstrumenter
import com.facebook.imagepipeline.systrace.FrescoSystrace
import java.io.IOException
import java.util.concurrent.Callable
import java.util.concurrent.CancellationException
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicBoolean

/**
 * BufferedDiskCache provides get and put operations to take care of scheduling disk-cache
 * read/writes.
 */
class BufferedDiskCache(
    private val fileCache: FileCache,
    private val pooledByteBufferFactory: PooledByteBufferFactory,
    private val pooledByteStreams: PooledByteStreams,
    private val readExecutor: Executor,
    private val writeExecutor: Executor,
    private val imageCacheStatsTracker: ImageCacheStatsTracker
) {

  private val stagingArea: StagingArea = StagingArea.getInstance()

  /**
   * Returns true if the key is in the in-memory key index.
   *
   * Not guaranteed to be correct. The cache may yet have this key even if this returns false. But
   * if it returns true, it definitely has it.
   *
   * Avoids a disk read.
   */
  fun containsSync(key: CacheKey): Boolean =
      stagingArea.containsKey(key) || fileCache.hasKeySync(key)

  /**
   * Performs a key-value look up in the disk cache. If no value is found in the staging area, then
   * disk cache checks are scheduled on a background thread. Any error manifests itself as a cache
   * miss, i.e. the returned Task resolves to false.
   *
   * @param key
   * @return Task that resolves to true if an element is found, or false otherwise
   */
  fun contains(key: CacheKey): Task<Boolean> =
      if (containsSync(key)) {
        Task.forResult(true)
      } else {
        containsAsync(key)
      }

  private fun containsAsync(key: CacheKey): Task<Boolean> {
    return try {
      val token = FrescoInstrumenter.onBeforeSubmitWork("BufferedDiskCache_containsAsync")
      Task.call(
          Callable {
            val currentToken = FrescoInstrumenter.onBeginWork(token, null)
            try {
              return@Callable checkInStagingAreaAndFileCache(key)
            } catch (th: Throwable) {
              FrescoInstrumenter.markFailure(token, th)
              throw th
            } finally {
              FrescoInstrumenter.onEndWork(currentToken)
            }
          },
          readExecutor)
    } catch (exception: Exception) {
      // Log failure
      // TODO: 3697790
      FLog.w(TAG, exception, "Failed to schedule disk-cache read for %s", key.uriString)
      Task.forError(exception)
    }
  }

  /**
   * Performs disk cache check synchronously.
   *
   * @param key
   * @return true if the key is found in disk cache else false
   */
  fun diskCheckSync(key: CacheKey): Boolean =
      if (containsSync(key)) {
        true
      } else {
        checkInStagingAreaAndFileCache(key)
      }

  /**
   * Performs key-value look up in disk cache. If value is not found in disk cache staging area then
   * disk cache read is scheduled on background thread. Any error manifests itself as cache miss,
   * i.e. the returned task resolves to null.
   *
   * @param key
   * @return Task that resolves to cached element or null if one cannot be retrieved; returned task
   *   never rethrows any exception
   */
  operator fun get(key: CacheKey, isCancelled: AtomicBoolean): Task<EncodedImage> =
      try {
        if (FrescoSystrace.isTracing()) {
          FrescoSystrace.beginSection("BufferedDiskCache#get")
        }
        val pinnedImage = stagingArea[key]
        pinnedImage?.let { foundPinnedImage(key, it) } ?: getAsync(key, isCancelled)
      } finally {
        if (FrescoSystrace.isTracing()) {
          FrescoSystrace.endSection()
        }
      }

  /**
   * Performs key-value look up in disk cache. If value is not found in disk cache staging area then
   * disk cache probing is scheduled on background thread.
   *
   * @param key
   */
  fun probe(key: CacheKey): Task<Void> {
    checkNotNull(key)
    return try {
      val token = FrescoInstrumenter.onBeforeSubmitWork("BufferedDiskCache_probe")
      Task.call(
          {
            val currentToken = FrescoInstrumenter.onBeginWork(token, null)
            try {
              fileCache.probe(key)
            } finally {
              FrescoInstrumenter.onEndWork(currentToken)
            }
            null
          },
          writeExecutor)
    } catch (exception: Exception) {
      FLog.w(TAG, exception, "Failed to schedule disk-cache probe for %s", key.uriString)
      Task.forError(exception)
    }
  }

  fun addKeyForAsyncProbing(key: CacheKey) {
    fileCache.probe(key)
  }

  /**
   * Performs key-value loop up in staging area and file cache. Any error manifests itself as a
   * miss, i.e. returns false.
   *
   * @param key
   * @return true if the image is found in staging area or File cache, false if not found
   */
  private fun checkInStagingAreaAndFileCache(key: CacheKey): Boolean {
    val result = stagingArea[key]
    return if (result != null) {
      result.close()
      FLog.v(TAG, "Found image for %s in staging area", key.uriString)
      imageCacheStatsTracker.onStagingAreaHit(key)
      true
    } else {
      FLog.v(TAG, "Did not find image for %s in staging area", key.uriString)
      imageCacheStatsTracker.onStagingAreaMiss(key)
      try {
        fileCache.hasKey(key)
      } catch (exception: Exception) {
        false
      }
    }
  }

  private fun getAsync(key: CacheKey, isCancelled: AtomicBoolean): Task<EncodedImage> {
    return try {
      val token = FrescoInstrumenter.onBeforeSubmitWork("BufferedDiskCache_getAsync")
      Task.call(
          Callable {
            val currentToken = FrescoInstrumenter.onBeginWork(token, null)
            try {
              if (isCancelled.get()) {
                throw CancellationException()
              }
              var result = stagingArea[key]
              if (result != null) {
                FLog.v(TAG, "Found image for %s in staging area", key.uriString)
                imageCacheStatsTracker.onStagingAreaHit(key)
              } else {
                FLog.v(TAG, "Did not find image for %s in staging area", key.uriString)
                imageCacheStatsTracker.onStagingAreaMiss(key)
                result =
                    try {
                      val buffer = readFromDiskCache(key) ?: return@Callable null
                      val ref = CloseableReference.of(buffer)
                      try {
                        EncodedImage(ref)
                      } finally {
                        CloseableReference.closeSafely(ref)
                      }
                    } catch (exception: Exception) {
                      return@Callable null
                    }
              }
              if (Thread.interrupted()) {
                FLog.v(TAG, "Host thread was interrupted, decreasing reference count")
                result?.close()
                throw InterruptedException()
              } else {
                return@Callable result
              }
            } catch (th: Throwable) {
              FrescoInstrumenter.markFailure(token, th)
              throw th
            } finally {
              FrescoInstrumenter.onEndWork(currentToken)
            }
          },
          readExecutor)
    } catch (exception: Exception) {
      // Log failure
      // TODO: 3697790
      FLog.w(TAG, exception, "Failed to schedule disk-cache read for %s", key.uriString)
      Task.forError(exception)
    }
  }

  /**
   * Associates encodedImage with given key in disk cache. Disk write is performed on background
   * thread, so the caller of this method is not blocked
   */
  fun put(key: CacheKey, encodedImage: EncodedImage) {
    try {
      if (FrescoSystrace.isTracing()) {
        FrescoSystrace.beginSection("BufferedDiskCache#put")
      }
      check(EncodedImage.isValid(encodedImage))

      // Store encodedImage in staging area
      stagingArea.put(key, encodedImage)

      // Write to disk cache. This will be executed on background thread, so increment the ref
      // count. When this write completes (with success/failure), then we will bump down the
      // ref count again.
      val finalEncodedImage = EncodedImage.cloneOrNull(encodedImage)
      try {
        val token = FrescoInstrumenter.onBeforeSubmitWork("BufferedDiskCache_putAsync")
        writeExecutor.execute {
          val currentToken = FrescoInstrumenter.onBeginWork(token, null)
          try {
            writeToDiskCache(key, finalEncodedImage)
          } catch (th: Throwable) {
            FrescoInstrumenter.markFailure(token, th)
            throw th
          } finally {
            stagingArea.remove(key, finalEncodedImage!!)
            EncodedImage.closeSafely(finalEncodedImage)
            FrescoInstrumenter.onEndWork(currentToken)
          }
        }
      } catch (exception: Exception) {
        // We failed to enqueue cache write. Log failure and decrement ref count
        // TODO: 3697790
        FLog.w(TAG, exception, "Failed to schedule disk-cache write for %s", key.uriString)
        stagingArea.remove(key, encodedImage)
        EncodedImage.closeSafely(finalEncodedImage)
      }
    } finally {
      if (FrescoSystrace.isTracing()) {
        FrescoSystrace.endSection()
      }
    }
  }

  /** Removes the item from the disk cache and the staging area. */
  fun remove(key: CacheKey): Task<Void> {
    stagingArea.remove(key)
    return try {
      val token = FrescoInstrumenter.onBeforeSubmitWork("BufferedDiskCache_remove")
      Task.call(
          {
            val currentToken = FrescoInstrumenter.onBeginWork(token, null)
            try {
              stagingArea.remove(key)
              fileCache.remove(key)
            } catch (th: Throwable) {
              FrescoInstrumenter.markFailure(token, th)
              throw th
            } finally {
              FrescoInstrumenter.onEndWork(currentToken)
            }
            null
          },
          writeExecutor)
    } catch (exception: Exception) {
      // Log failure
      // TODO: 3697790
      FLog.w(TAG, exception, "Failed to schedule disk-cache remove for %s", key.uriString)
      Task.forError(exception)
    }
  }

  /** Clears the disk cache and the staging area. */
  fun clearAll(): Task<Void> {
    stagingArea.clearAll()
    val token = FrescoInstrumenter.onBeforeSubmitWork("BufferedDiskCache_clearAll")
    return try {
      Task.call(
          Callable {
            val currentToken = FrescoInstrumenter.onBeginWork(token, null)
            try {
              stagingArea.clearAll()
              fileCache.clearAll()
              return@Callable null
            } catch (th: Throwable) {
              FrescoInstrumenter.markFailure(token, th)
              throw th
            } finally {
              FrescoInstrumenter.onEndWork(currentToken)
            }
          },
          writeExecutor)
    } catch (exception: Exception) {
      // Log failure
      // TODO: 3697790
      FLog.w(TAG, exception, "Failed to schedule disk-cache clear")
      Task.forError(exception)
    }
  }

  val size: Long
    get() = fileCache.size

  private fun foundPinnedImage(key: CacheKey, pinnedImage: EncodedImage): Task<EncodedImage> {
    FLog.v(TAG, "Found image for %s in staging area", key.uriString)
    imageCacheStatsTracker.onStagingAreaHit(key)
    return Task.forResult(pinnedImage)
  }

  /** Performs disk cache read. In case of any exception null is returned. */
  @Throws(IOException::class)
  private fun readFromDiskCache(key: CacheKey): PooledByteBuffer? {
    return try {
      FLog.v(TAG, "Disk cache read for %s", key.uriString)
      val diskCacheResource = fileCache.getResource(key)
      if (diskCacheResource == null) {
        FLog.v(TAG, "Disk cache miss for %s", key.uriString)
        imageCacheStatsTracker.onDiskCacheMiss(key)
        return null
      } else {
        FLog.v(TAG, "Found entry in disk cache for %s", key.uriString)
        imageCacheStatsTracker.onDiskCacheHit(key)
      }
      val `is` = diskCacheResource.openStream()
      val byteBuffer =
          try {
            pooledByteBufferFactory.newByteBuffer(`is`, diskCacheResource.size().toInt())
          } finally {
            `is`.close()
          }
      FLog.v(TAG, "Successful read from disk cache for %s", key.uriString)
      byteBuffer
    } catch (ioe: IOException) {
      // TODO: 3697790 log failures
      // TODO: 5258772 - uncomment line below
      // mFileCache.remove(key);
      FLog.w(TAG, ioe, "Exception reading from cache for %s", key.uriString)
      imageCacheStatsTracker.onDiskCacheGetFail(key)
      throw ioe
    }
  }

  /**
   * Writes to disk cache
   *
   * @throws IOException
   */
  private fun writeToDiskCache(key: CacheKey, encodedImage: EncodedImage?) {
    FLog.v(TAG, "About to write to disk-cache for key %s", key.uriString)
    try {
      fileCache.insert(key) { os ->
        val inputStream = encodedImage!!.inputStream
        checkNotNull(inputStream)
        pooledByteStreams.copy(inputStream!!, os)
      }
      imageCacheStatsTracker.onDiskCachePut(key)
      FLog.v(TAG, "Successful disk-cache write for key %s", key.uriString)
    } catch (ioe: IOException) {
      // Log failure
      // TODO: 3697790
      FLog.w(TAG, ioe, "Failed to write to disk-cache for key %s", key.uriString)
    }
  }

  companion object {
    private val TAG: Class<*> = BufferedDiskCache::class.java
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.cache

import com.facebook.cache.common.CacheKey

/**
 * Interface for stats tracking for the image cache.
 *
 * An implementation of this interface, passed to
 * [com.facebook.imagepipeline.core.ImagePipelineConfig], will be notified for each of the following
 * cache events. Use this to keep cache stats for your app.
 */
interface ImageCacheStatsTracker {

  /** Called whenever decoded images are put into the bitmap cache. */
  fun onBitmapCachePut(cacheKey: CacheKey)

  /** Called on a bitmap cache hit. */
  fun onBitmapCacheHit(cacheKey: CacheKey)

  /** Called on a bitmap cache miss. */
  fun onBitmapCacheMiss(cacheKey: CacheKey)

  /** Called whenever encoded images are put into the encoded memory cache. */
  fun onMemoryCachePut(cacheKey: CacheKey)

  /** Called on an encoded memory cache hit. */
  fun onMemoryCacheHit(cacheKey: CacheKey)

  /** Called on an encoded memory cache hit. */
  fun onMemoryCacheMiss(cacheKey: CacheKey)

  /**
   * Called on an staging area hit.
   *
   * The staging area stores encoded images. It gets the images before they are written to disk
   * cache.
   */
  fun onStagingAreaHit(cacheKey: CacheKey)

  /** Called on a staging area miss hit. */
  fun onStagingAreaMiss(cacheKey: CacheKey)

  /** Called on a disk cache hit. */
  fun onDiskCacheHit(cacheKey: CacheKey)

  /** Called on a disk cache miss. */
  fun onDiskCacheMiss(cacheKey: CacheKey)

  /** Called if an exception is thrown on a disk cache read. */
  fun onDiskCacheGetFail(cacheKey: CacheKey)

  /** called whenever new files are written to disk */
  fun onDiskCachePut(cacheKey: CacheKey)

  /**
   * Registers a bitmap cache with this tracker.
   *
   * Use this method if you need access to the cache itself to compile your stats.
   */
  fun registerBitmapMemoryCache(bitmapMemoryCache: MemoryCache<*, *>)

  /**
   * Registers an encoded memory cache with this tracker.
   *
   * Use this method if you need access to the cache itself to compile your stats.
   */
  fun registerEncodedMemoryCache(encodedMemoryCache: MemoryCache<*, *>)
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.cache

interface MemoryCacheTracker<K> {
  fun onCacheHit(cacheKey: K)

  fun onCacheMiss(cacheKey: K)

  fun onCachePut(cacheKey: K)
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

/** Implementations for the cache abstractions related to memory and disk. */
package com.facebook.imagepipeline.cache


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.core

import com.facebook.cache.disk.DiskCacheConfig
import com.facebook.cache.disk.DiskStorage

/**
 * Represents a factory for the DiskStorage to use in the ImagePipeline. Used by
 * ImagePipelineConfig/Factory
 */
fun interface DiskStorageFactory {
  fun get(diskCacheConfig: DiskCacheConfig): DiskStorage
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.core

import com.facebook.cache.disk.DiskCacheConfig
import com.facebook.cache.disk.FileCache

/**
 * Represents a factory for the FileCache to use in the ImagePipeline. Used by
 * ImagePipelineConfig/Factory
 */
fun interface FileCacheFactory {
  fun get(diskCacheConfig: DiskCacheConfig): FileCache
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.core

import android.app.ActivityManager
import android.content.Context
import android.graphics.Bitmap
import android.os.Build
import androidx.annotation.VisibleForTesting
import com.facebook.cache.common.CacheKey
import com.facebook.cache.disk.DiskCacheConfig
import com.facebook.callercontext.CallerContextVerifier
import com.facebook.common.executors.SerialExecutorService
import com.facebook.common.internal.Supplier
import com.facebook.common.internal.Suppliers
import com.facebook.common.memory.MemoryTrimmableRegistry
import com.facebook.common.memory.NoOpMemoryTrimmableRegistry
import com.facebook.common.memory.PooledByteBuffer
import com.facebook.common.webp.BitmapCreator
import com.facebook.common.webp.WebpBitmapFactory
import com.facebook.common.webp.WebpSupportStatus
import com.facebook.imagepipeline.bitmaps.HoneycombBitmapCreator
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory
import com.facebook.imagepipeline.cache.BitmapMemoryCacheFactory
import com.facebook.imagepipeline.cache.BitmapMemoryCacheTrimStrategy
import com.facebook.imagepipeline.cache.CacheKeyFactory
import com.facebook.imagepipeline.cache.CountingLruBitmapMemoryCacheFactory
import com.facebook.imagepipeline.cache.CountingMemoryCache.EntryStateObserver
import com.facebook.imagepipeline.cache.DefaultBitmapMemoryCacheParamsSupplier
import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory
import com.facebook.imagepipeline.cache.DefaultEncodedMemoryCacheParamsSupplier
import com.facebook.imagepipeline.cache.ImageCacheStatsTracker
import com.facebook.imagepipeline.cache.MemoryCache
import com.facebook.imagepipeline.cache.MemoryCache.CacheTrimStrategy
import com.facebook.imagepipeline.cache.MemoryCacheParams
import com.facebook.imagepipeline.cache.NativeMemoryCacheTrimStrategy
import com.facebook.imagepipeline.cache.NoOpImageCacheStatsTracker
import com.facebook.imagepipeline.debug.CloseableReferenceLeakTracker
import com.facebook.imagepipeline.debug.NoOpCloseableReferenceLeakTracker
import com.facebook.imagepipeline.decoder.ImageDecoder
import com.facebook.imagepipeline.decoder.ImageDecoderConfig
import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig
import com.facebook.imagepipeline.decoder.SimpleProgressiveJpegConfig
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.listener.RequestListener
import com.facebook.imagepipeline.listener.RequestListener2
import com.facebook.imagepipeline.memory.PoolConfig
import com.facebook.imagepipeline.memory.PoolFactory
import com.facebook.imagepipeline.producers.CustomProducerSequenceFactory
import com.facebook.imagepipeline.producers.HttpUrlConnectionNetworkFetcher
import com.facebook.imagepipeline.producers.NetworkFetcher
import com.facebook.imagepipeline.systrace.FrescoSystrace.beginSection
import com.facebook.imagepipeline.systrace.FrescoSystrace.endSection
import com.facebook.imagepipeline.systrace.FrescoSystrace.isTracing
import com.facebook.imagepipeline.systrace.FrescoSystrace.traceSection
import com.facebook.imagepipeline.transcoder.ImageTranscoderFactory

/**
 * Main configuration class for the image pipeline library.
 *
 * To use: ` ImagePipelineConfig config = ImagePipelineConfig.newBuilder() .setXXX(xxx) .setYYY(yyy)
 * .build(); ImagePipelineFactory factory = new ImagePipelineFactory(config); ImagePipeline pipeline
 * = factory.getImagePipeline(); ` *
 *
 * This should only be done once per process.
 */
class ImagePipelineConfig private constructor(builder: Builder) : ImagePipelineConfigInterface {

  // If a member here is marked @Nullable, it must be constructed by ImagePipelineFactory
  // on demand if needed.
  // There are a lot of parameters in this class. Please follow strict alphabetical order.
  override val bitmapConfig: Bitmap.Config
  override val bitmapMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>
  override val bitmapMemoryCacheTrimStrategy: CacheTrimStrategy
  override val encodedMemoryCacheTrimStrategy: CacheTrimStrategy
  override val bitmapMemoryCacheEntryStateObserver: EntryStateObserver<CacheKey>?
  override val cacheKeyFactory: CacheKeyFactory
  override val context: Context
  override val isDownsampleEnabled: Boolean
  override val fileCacheFactory: FileCacheFactory
  override val encodedMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>
  override val executorSupplier: ExecutorSupplier
  override val imageCacheStatsTracker: ImageCacheStatsTracker
  override val imageDecoder: ImageDecoder?
  override val imageTranscoderFactory: ImageTranscoderFactory?
  override val enableEncodedImageColorSpaceUsage: Supplier<Boolean>

  @get:ImageTranscoderType @ImageTranscoderType override val imageTranscoderType: Int?
  override val isPrefetchEnabledSupplier: Supplier<Boolean>
  override val mainDiskCacheConfig: DiskCacheConfig
  override val memoryTrimmableRegistry: MemoryTrimmableRegistry

  @get:MemoryChunkType @MemoryChunkType override val memoryChunkType: Int
  override val networkFetcher: NetworkFetcher<*>
  private val httpNetworkTimeout: Int
  override val platformBitmapFactory: PlatformBitmapFactory?
  override val poolFactory: PoolFactory
  override val progressiveJpegConfig: ProgressiveJpegConfig
  override val requestListeners: Set<RequestListener>
  override val requestListener2s: Set<RequestListener2>
  override val customProducerSequenceFactories: Set<CustomProducerSequenceFactory>
  override val isResizeAndRotateEnabledForNetwork: Boolean
  override val smallImageDiskCacheConfig: DiskCacheConfig
  override val imageDecoderConfig: ImageDecoderConfig?
  override val experiments: ImagePipelineExperiments
  override val isDiskCacheEnabled: Boolean
  override val callerContextVerifier: CallerContextVerifier?
  override val closeableReferenceLeakTracker: CloseableReferenceLeakTracker
  override val bitmapCacheOverride: MemoryCache<CacheKey, CloseableImage>?
  override val encodedMemoryCacheOverride: MemoryCache<CacheKey, PooledByteBuffer>?
  override val executorServiceForAnimatedImages: SerialExecutorService?
  override val bitmapMemoryCacheFactory: BitmapMemoryCacheFactory

  init {
    if (isTracing()) {
      beginSection("ImagePipelineConfig()")
    }
    // We have to build experiments before the rest
    experiments = builder.experimentsBuilder.build()
    bitmapMemoryCacheParamsSupplier =
        builder.bitmapMemoryCacheParamsSupplier
            ?: DefaultBitmapMemoryCacheParamsSupplier(
                (checkNotNull(builder.context.getSystemService(Context.ACTIVITY_SERVICE))
                    as ActivityManager))
    bitmapMemoryCacheTrimStrategy =
        builder.bitmapMemoryCacheTrimStrategy ?: BitmapMemoryCacheTrimStrategy()
    encodedMemoryCacheTrimStrategy =
        builder.encodedMemoryCacheTrimStrategy ?: NativeMemoryCacheTrimStrategy()
    bitmapMemoryCacheEntryStateObserver = builder.bitmapMemoryCacheEntryStateObserver
    bitmapConfig = builder.bitmapConfig ?: Bitmap.Config.ARGB_8888
    cacheKeyFactory = builder.cacheKeyFactory ?: DefaultCacheKeyFactory.getInstance()
    context = checkNotNull(builder.context)
    fileCacheFactory =
        builder.fileCacheFactory ?: DiskStorageCacheFactory(DynamicDefaultDiskStorageFactory())
    isDownsampleEnabled = builder.downsampleEnabled
    encodedMemoryCacheParamsSupplier =
        builder.encodedMemoryCacheParamsSupplier ?: DefaultEncodedMemoryCacheParamsSupplier()
    imageCacheStatsTracker =
        builder.imageCacheStatsTracker ?: NoOpImageCacheStatsTracker.getInstance()
    imageDecoder = builder.imageDecoder
    enableEncodedImageColorSpaceUsage =
        builder.enableEncodedImageColorSpaceUsage ?: Suppliers.BOOLEAN_FALSE
    imageTranscoderFactory = getImageTranscoderFactory(builder)
    imageTranscoderType = builder.imageTranscoderType
    isPrefetchEnabledSupplier = builder.isPrefetchEnabledSupplier ?: Suppliers.BOOLEAN_TRUE
    mainDiskCacheConfig =
        builder.mainDiskCacheConfig ?: getDefaultMainDiskCacheConfig(builder.context)
    memoryTrimmableRegistry =
        builder.memoryTrimmableRegistry ?: NoOpMemoryTrimmableRegistry.getInstance()
    memoryChunkType = getMemoryChunkType(builder, experiments)
    httpNetworkTimeout =
        if (builder.httpConnectionTimeout < 0) HttpUrlConnectionNetworkFetcher.HTTP_DEFAULT_TIMEOUT
        else builder.httpConnectionTimeout
    networkFetcher =
        traceSection("ImagePipelineConfig->mNetworkFetcher") {
          builder.networkFetcher ?: HttpUrlConnectionNetworkFetcher(httpNetworkTimeout)
        }
    platformBitmapFactory = builder.platformBitmapFactory
    poolFactory = builder.poolFactory ?: PoolFactory(PoolConfig.newBuilder().build())
    progressiveJpegConfig = builder.progressiveJpegConfig ?: SimpleProgressiveJpegConfig()
    requestListeners = builder.requestListeners ?: emptySet()
    requestListener2s = builder.requestListener2s ?: emptySet()
    customProducerSequenceFactories = builder.customProducerSequenceFactories ?: emptySet()
    isResizeAndRotateEnabledForNetwork = builder.resizeAndRotateEnabledForNetwork
    smallImageDiskCacheConfig = builder.smallImageDiskCacheConfig ?: mainDiskCacheConfig
    imageDecoderConfig = builder.imageDecoderConfig
    // Below this comment can't be built in alphabetical order, because of dependencies
    val numCpuBoundThreads = poolFactory.flexByteArrayPoolMaxNumThreads
    executorSupplier = builder.executorSupplier ?: DefaultExecutorSupplier(numCpuBoundThreads)
    isDiskCacheEnabled = builder.diskCacheEnabled
    callerContextVerifier = builder.callerContextVerifier
    closeableReferenceLeakTracker = builder.closeableReferenceLeakTracker
    bitmapCacheOverride = builder.bitmapMemoryCache
    bitmapMemoryCacheFactory =
        builder.bitmapMemoryCacheFactory ?: CountingLruBitmapMemoryCacheFactory()
    encodedMemoryCacheOverride = builder.encodedMemoryCache
    executorServiceForAnimatedImages = builder.serialExecutorServiceForAnimatedImages
    // Here we manage the WebpBitmapFactory implementation if any
    var webpBitmapFactory = experiments.webpBitmapFactory
    if (webpBitmapFactory != null) {
      val bitmapCreator: BitmapCreator = HoneycombBitmapCreator(poolFactory)
      setWebpBitmapFactory(webpBitmapFactory, experiments, bitmapCreator)
    } else {
      // We check using introspection only if the experiment is enabled
      if (experiments.isWebpSupportEnabled && WebpSupportStatus.sIsWebpSupportRequired) {
        webpBitmapFactory = WebpSupportStatus.loadWebpBitmapFactoryIfExists()
        if (webpBitmapFactory != null) {
          val bitmapCreator: BitmapCreator = HoneycombBitmapCreator(poolFactory)
          setWebpBitmapFactory(webpBitmapFactory, experiments, bitmapCreator)
        }
      }
    }
    if (isTracing()) {
      endSection()
    }
  }

  /** Contains default configuration that can be personalized for all the request */
  class DefaultImageRequestConfig {
    var isProgressiveRenderingEnabled = false
  }

  class Builder(context: Context) {
    var bitmapConfig: Bitmap.Config? = null
      private set

    var bitmapMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>? = null
      private set

    var bitmapMemoryCacheEntryStateObserver: EntryStateObserver<CacheKey>? = null
      private set

    var bitmapMemoryCacheTrimStrategy: CacheTrimStrategy? = null
      private set

    var encodedMemoryCacheTrimStrategy: CacheTrimStrategy? = null
      private set

    var cacheKeyFactory: CacheKeyFactory? = null
      private set

    val context: Context
    var downsampleEnabled = false
      private set

    var encodedMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>? = null
      private set

    var executorSupplier: ExecutorSupplier? = null
      private set

    var imageCacheStatsTracker: ImageCacheStatsTracker? = null
      private set

    var imageDecoder: ImageDecoder? = null
      private set

    var enableEncodedImageColorSpaceUsage: Supplier<Boolean>? = null
      private set

    var imageTranscoderFactory: ImageTranscoderFactory? = null
      private set

    @ImageTranscoderType var imageTranscoderType: Int? = null
    var isPrefetchEnabledSupplier: Supplier<Boolean>? = null
      private set

    var mainDiskCacheConfig: DiskCacheConfig? = null
      private set

    var memoryTrimmableRegistry: MemoryTrimmableRegistry? = null
      private set

    @MemoryChunkType var memoryChunkType: Int? = null
    var networkFetcher: NetworkFetcher<*>? = null
      private set

    var platformBitmapFactory: PlatformBitmapFactory? = null
      private set

    var poolFactory: PoolFactory? = null
      private set

    var progressiveJpegConfig: ProgressiveJpegConfig? = null
      private set

    var requestListeners: Set<RequestListener>? = null
      private set

    var requestListener2s: Set<RequestListener2>? = null
      private set

    var customProducerSequenceFactories: Set<CustomProducerSequenceFactory>? = null
      private set

    var resizeAndRotateEnabledForNetwork = true
      private set

    var smallImageDiskCacheConfig: DiskCacheConfig? = null
      private set

    var fileCacheFactory: FileCacheFactory? = null
      private set

    var imageDecoderConfig: ImageDecoderConfig? = null
      private set

    var httpConnectionTimeout = -1
      private set

    val experimentsBuilder = ImagePipelineExperiments.Builder(this)
    var diskCacheEnabled = true
      private set

    var callerContextVerifier: CallerContextVerifier? = null
      private set

    var closeableReferenceLeakTracker: CloseableReferenceLeakTracker =
        NoOpCloseableReferenceLeakTracker()
      private set

    var bitmapMemoryCache: MemoryCache<CacheKey, CloseableImage>? = null
      private set

    var encodedMemoryCache: MemoryCache<CacheKey, PooledByteBuffer>? = null
      private set

    var serialExecutorServiceForAnimatedImages: SerialExecutorService? = null
      private set

    var bitmapMemoryCacheFactory: BitmapMemoryCacheFactory? = null
      private set

    fun setBitmapsConfig(config: Bitmap.Config?): Builder = apply { this.bitmapConfig = config }

    fun setBitmapMemoryCacheParamsSupplier(
        bitmapMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>?
    ): Builder = apply {
      this.bitmapMemoryCacheParamsSupplier = checkNotNull(bitmapMemoryCacheParamsSupplier)
    }

    fun setBitmapMemoryCacheEntryStateObserver(
        bitmapMemoryCacheEntryStateObserver: EntryStateObserver<CacheKey>?
    ): Builder = apply {
      this.bitmapMemoryCacheEntryStateObserver = bitmapMemoryCacheEntryStateObserver
    }

    fun setBitmapMemoryCacheTrimStrategy(trimStrategy: CacheTrimStrategy?): Builder = apply {
      this.bitmapMemoryCacheTrimStrategy = trimStrategy
    }

    fun setEncodedMemoryCacheTrimStrategy(trimStrategy: CacheTrimStrategy?): Builder = apply {
      this.encodedMemoryCacheTrimStrategy = trimStrategy
    }

    fun setCacheKeyFactory(cacheKeyFactory: CacheKeyFactory?): Builder = apply {
      this.cacheKeyFactory = cacheKeyFactory
    }

    fun setHttpConnectionTimeout(httpConnectionTimeoutMs: Int): Builder = apply {
      this.httpConnectionTimeout = httpConnectionTimeoutMs
    }

    fun setFileCacheFactory(fileCacheFactory: FileCacheFactory?): Builder = apply {
      this.fileCacheFactory = fileCacheFactory
    }

    fun isDownsampleEnabled(): Boolean = this.downsampleEnabled

    fun setDownsampleEnabled(downsampleEnabled: Boolean): Builder = apply {
      this.downsampleEnabled = downsampleEnabled
    }

    fun isDiskCacheEnabled(): Boolean = this.diskCacheEnabled

    fun setDiskCacheEnabled(diskCacheEnabled: Boolean): Builder = apply {
      this.diskCacheEnabled = diskCacheEnabled
    }

    fun setEncodedMemoryCacheParamsSupplier(
        encodedMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>?
    ): Builder = apply {
      this.encodedMemoryCacheParamsSupplier = checkNotNull(encodedMemoryCacheParamsSupplier)
    }

    fun setExecutorSupplier(executorSupplier: ExecutorSupplier?): Builder = apply {
      this.executorSupplier = executorSupplier
    }

    fun setImageCacheStatsTracker(imageCacheStatsTracker: ImageCacheStatsTracker?): Builder =
        apply {
          this.imageCacheStatsTracker = imageCacheStatsTracker
        }

    fun setImageDecoder(imageDecoder: ImageDecoder?): Builder = apply {
      this.imageDecoder = imageDecoder
    }

    fun setEnableEncodedImageColorSpaceUsage(
        enableEncodedImageColorSpaceUsage: Supplier<Boolean>?
    ): Builder = apply {
      this.enableEncodedImageColorSpaceUsage = enableEncodedImageColorSpaceUsage
    }

    fun setImageTranscoderType(@ImageTranscoderType imageTranscoderType: Int): Builder = apply {
      this.imageTranscoderType = imageTranscoderType
    }

    fun setImageTranscoderFactory(imageTranscoderFactory: ImageTranscoderFactory?): Builder =
        apply {
          this.imageTranscoderFactory = imageTranscoderFactory
        }

    fun setIsPrefetchEnabledSupplier(isPrefetchEnabledSupplier: Supplier<Boolean>?): Builder =
        apply {
          this.isPrefetchEnabledSupplier = isPrefetchEnabledSupplier
        }

    fun setMainDiskCacheConfig(mainDiskCacheConfig: DiskCacheConfig?): Builder = apply {
      this.mainDiskCacheConfig = mainDiskCacheConfig
    }

    fun setMemoryTrimmableRegistry(memoryTrimmableRegistry: MemoryTrimmableRegistry?): Builder =
        apply {
          this.memoryTrimmableRegistry = memoryTrimmableRegistry
        }

    fun setMemoryChunkType(@MemoryChunkType memoryChunkType: Int): Builder = apply {
      this.memoryChunkType = memoryChunkType
    }

    fun setNetworkFetcher(networkFetcher: NetworkFetcher<*>?): Builder = apply {
      this.networkFetcher = networkFetcher
    }

    fun setPlatformBitmapFactory(platformBitmapFactory: PlatformBitmapFactory?): Builder = apply {
      this.platformBitmapFactory = platformBitmapFactory
    }

    fun setPoolFactory(poolFactory: PoolFactory?): Builder = apply {
      this.poolFactory = poolFactory
    }

    fun setProgressiveJpegConfig(progressiveJpegConfig: ProgressiveJpegConfig?): Builder = apply {
      this.progressiveJpegConfig = progressiveJpegConfig
    }

    fun setRequestListeners(requestListeners: Set<RequestListener>?): Builder = apply {
      this.requestListeners = requestListeners
    }

    fun setRequestListener2s(requestListeners: Set<RequestListener2>?): Builder = apply {
      requestListener2s = requestListeners
    }

    fun setCustomFetchSequenceFactories(
        customProducerSequenceFactories: Set<CustomProducerSequenceFactory>?
    ): Builder = apply { this.customProducerSequenceFactories = customProducerSequenceFactories }

    fun setResizeAndRotateEnabledForNetwork(resizeAndRotateEnabledForNetwork: Boolean): Builder =
        apply {
          this.resizeAndRotateEnabledForNetwork = resizeAndRotateEnabledForNetwork
        }

    fun setSmallImageDiskCacheConfig(smallImageDiskCacheConfig: DiskCacheConfig?): Builder = apply {
      this.smallImageDiskCacheConfig = smallImageDiskCacheConfig
    }

    fun setImageDecoderConfig(imageDecoderConfig: ImageDecoderConfig?): Builder = apply {
      this.imageDecoderConfig = imageDecoderConfig
    }

    fun setCallerContextVerifier(callerContextVerifier: CallerContextVerifier?): Builder = apply {
      this.callerContextVerifier = callerContextVerifier
    }

    fun setCloseableReferenceLeakTracker(
        closeableReferenceLeakTracker: CloseableReferenceLeakTracker
    ): Builder = apply { this.closeableReferenceLeakTracker = closeableReferenceLeakTracker }

    fun setBitmapMemoryCache(bitmapMemoryCache: MemoryCache<CacheKey, CloseableImage>?): Builder =
        apply {
          this.bitmapMemoryCache = bitmapMemoryCache
        }

    fun setEncodedMemoryCache(
        encodedMemoryCache: MemoryCache<CacheKey, PooledByteBuffer>?
    ): Builder = apply { this.encodedMemoryCache = encodedMemoryCache }

    fun setExecutorServiceForAnimatedImages(
        serialExecutorService: SerialExecutorService?
    ): Builder = apply { this.serialExecutorServiceForAnimatedImages = serialExecutorService }

    fun setBitmapMemoryCacheFactory(bitmapMemoryCacheFactory: BitmapMemoryCacheFactory?): Builder =
        apply {
          this.bitmapMemoryCacheFactory = bitmapMemoryCacheFactory
        }

    fun experiment(): ImagePipelineExperiments.Builder = experimentsBuilder

    fun build(): ImagePipelineConfig = ImagePipelineConfig(this)

    init {
      // Doesn't use a setter as always required.
      this.context = context
    }
  }

  companion object {
    @JvmStatic
    var defaultImageRequestConfig = DefaultImageRequestConfig()
      private set

    private fun setWebpBitmapFactory(
        webpBitmapFactory: WebpBitmapFactory,
        imagePipelineExperiments: ImagePipelineExperiments,
        bitmapCreator: BitmapCreator?
    ) {
      WebpSupportStatus.sWebpBitmapFactory = webpBitmapFactory
      val webpErrorLogger = imagePipelineExperiments.webpErrorLogger
      if (webpErrorLogger != null) {
        webpBitmapFactory.setWebpErrorLogger(webpErrorLogger)
      }
      if (bitmapCreator != null) {
        webpBitmapFactory.setBitmapCreator(bitmapCreator)
      }
    }

    private fun getDefaultMainDiskCacheConfig(context: Context): DiskCacheConfig =
        try {
          if (isTracing()) {
            beginSection("DiskCacheConfig.getDefaultMainDiskCacheConfig")
          }
          DiskCacheConfig.newBuilder(context).build()
        } finally {
          if (isTracing()) {
            endSection()
          }
        }

    @JvmStatic
    @VisibleForTesting
    fun resetDefaultRequestConfig() {
      defaultImageRequestConfig = DefaultImageRequestConfig()
    }

    @JvmStatic fun newBuilder(context: Context): Builder = Builder(context)

    private fun getImageTranscoderFactory(builder: Builder): ImageTranscoderFactory? {
      check(!(builder.imageTranscoderFactory != null && builder.imageTranscoderType != null)) {
        "You can't define a custom ImageTranscoderFactory and provide an ImageTranscoderType"
      }
      return builder.imageTranscoderFactory
      // This member will be constructed by ImagePipelineFactory
    }

    @MemoryChunkType
    private fun getMemoryChunkType(
        builder: Builder,
        imagePipelineExperiments: ImagePipelineExperiments
    ): Int =
        builder.memoryChunkType
            ?: if (imagePipelineExperiments.memoryType == MemoryChunkType.ASHMEM_MEMORY.toLong() &&
                Build.VERSION.SDK_INT >= 27) {
              MemoryChunkType.ASHMEM_MEMORY
            } else if (imagePipelineExperiments.memoryType ==
                MemoryChunkType.BUFFER_MEMORY.toLong()) {
              MemoryChunkType.BUFFER_MEMORY
            } else if (imagePipelineExperiments.memoryType ==
                MemoryChunkType.NATIVE_MEMORY.toLong()) {
              MemoryChunkType.NATIVE_MEMORY
            } else {
              MemoryChunkType.NATIVE_MEMORY
            }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.core

import android.content.Context
import android.graphics.Bitmap
import com.facebook.cache.common.CacheKey
import com.facebook.cache.disk.DiskCacheConfig
import com.facebook.callercontext.CallerContextVerifier
import com.facebook.common.executors.SerialExecutorService
import com.facebook.common.internal.Supplier
import com.facebook.common.memory.MemoryTrimmableRegistry
import com.facebook.common.memory.PooledByteBuffer
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory
import com.facebook.imagepipeline.cache.BitmapMemoryCacheFactory
import com.facebook.imagepipeline.cache.CacheKeyFactory
import com.facebook.imagepipeline.cache.CountingMemoryCache.EntryStateObserver
import com.facebook.imagepipeline.cache.ImageCacheStatsTracker
import com.facebook.imagepipeline.cache.MemoryCache
import com.facebook.imagepipeline.cache.MemoryCache.CacheTrimStrategy
import com.facebook.imagepipeline.cache.MemoryCacheParams
import com.facebook.imagepipeline.debug.CloseableReferenceLeakTracker
import com.facebook.imagepipeline.decoder.ImageDecoder
import com.facebook.imagepipeline.decoder.ImageDecoderConfig
import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.listener.RequestListener
import com.facebook.imagepipeline.listener.RequestListener2
import com.facebook.imagepipeline.memory.PoolFactory
import com.facebook.imagepipeline.producers.CustomProducerSequenceFactory
import com.facebook.imagepipeline.producers.NetworkFetcher
import com.facebook.imagepipeline.transcoder.ImageTranscoderFactory

interface ImagePipelineConfigInterface {

  val bitmapConfig: Bitmap.Config?
  val bitmapMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>
  val bitmapMemoryCacheTrimStrategy: CacheTrimStrategy
  val encodedMemoryCacheTrimStrategy: CacheTrimStrategy
  val bitmapMemoryCacheEntryStateObserver: EntryStateObserver<CacheKey>?
  val cacheKeyFactory: CacheKeyFactory
  val context: Context
  val fileCacheFactory: FileCacheFactory
  val isDownsampleEnabled: Boolean
  val isDiskCacheEnabled: Boolean
  val encodedMemoryCacheParamsSupplier: Supplier<MemoryCacheParams>
  val executorSupplier: ExecutorSupplier
  val executorServiceForAnimatedImages: SerialExecutorService?
  val imageCacheStatsTracker: ImageCacheStatsTracker
  val imageDecoder: ImageDecoder?
  val imageTranscoderFactory: ImageTranscoderFactory?

  @get:ImageTranscoderType val imageTranscoderType: Int?
  val isPrefetchEnabledSupplier: Supplier<Boolean>
  val enableEncodedImageColorSpaceUsage: Supplier<Boolean>
  val mainDiskCacheConfig: DiskCacheConfig
  val memoryTrimmableRegistry: MemoryTrimmableRegistry

  @get:MemoryChunkType val memoryChunkType: Int
  val networkFetcher: NetworkFetcher<*>
  val platformBitmapFactory: PlatformBitmapFactory?
  val poolFactory: PoolFactory
  val progressiveJpegConfig: ProgressiveJpegConfig
  val requestListeners: Set<RequestListener?>
  val requestListener2s: Set<RequestListener2?>
  val customProducerSequenceFactories: Set<CustomProducerSequenceFactory>
  val isResizeAndRotateEnabledForNetwork: Boolean
  val smallImageDiskCacheConfig: DiskCacheConfig
  val imageDecoderConfig: ImageDecoderConfig?
  val callerContextVerifier: CallerContextVerifier?
  val experiments: ImagePipelineExperiments
  val closeableReferenceLeakTracker: CloseableReferenceLeakTracker
  val bitmapCacheOverride: MemoryCache<CacheKey, CloseableImage>?
  val encodedMemoryCacheOverride: MemoryCache<CacheKey, PooledByteBuffer>?
  val bitmapMemoryCacheFactory: BitmapMemoryCacheFactory
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.imagepipeline.core

import android.content.Context
import android.graphics.Bitmap
import com.facebook.cache.common.CacheKey
import com.facebook.common.internal.Supplier
import com.facebook.common.internal.Suppliers
import com.facebook.common.memory.ByteArrayPool
import com.facebook.common.memory.PooledByteBuffer
import com.facebook.common.memory.PooledByteBufferFactory
import com.facebook.common.memory.PooledByteStreams
import com.facebook.common.webp.WebpBitmapFactory
import com.facebook.common.webp.WebpBitmapFactory.WebpErrorLogger
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory
import com.facebook.imagepipeline.cache.BufferedDiskCache
import com.facebook.imagepipeline.cache.CacheKeyFactory
import com.facebook.imagepipeline.cache.MemoryCache
import com.facebook.imagepipeline.decoder.ImageDecoder
import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imageutils.BitmapUtil
import kotlin.jvm.JvmField

/**
 * Encapsulates additional elements of the [ImagePipelineConfig] which are currently in an
 * experimental state.
 *
 * These options may often change or disappear altogether and it is not recommended to change their
 * values from their defaults.
 */
class ImagePipelineExperiments private constructor(builder: Builder) {

  val isWebpSupportEnabled: Boolean
  val webpErrorLogger: WebpErrorLogger?
  val isDecodeCancellationEnabled: Boolean
  val webpBitmapFactory: WebpBitmapFactory?
  val useDownsamplingRatioForResizing: Boolean
  val useBitmapPrepareToDraw: Boolean
  val useBalancedAnimationStrategy: Boolean
  val bitmapPrepareToDrawMinSizeBytes: Int
  val animatedCacheMemoryPercentage: Int
  val bitmapPrepareToDrawMaxSizeBytes: Int
  val bitmapPrepareToDrawForPrefetch: Boolean
  val maxBitmapSize: Int
  val isNativeCodeDisabled: Boolean
  val isPartialImageCachingEnabled: Boolean
  val producerFactoryMethod: ProducerFactoryMethod
  val isLazyDataSource: Supplier<Boolean>
  val isGingerbreadDecoderEnabled: Boolean
  val downscaleFrameToDrawableDimensions: Boolean
  val suppressBitmapPrefetchingSupplier: Supplier<Boolean>
  val isExperimentalThreadHandoffQueueEnabled: Boolean
  val memoryType: Long
  val keepCancelledFetchAsLowPriority: Boolean
  val downsampleIfLargeBitmap: Boolean
  val isEncodedCacheEnabled: Boolean
  val isEnsureTranscoderLibraryLoaded: Boolean
  val isEncodedMemoryCacheProbingEnabled: Boolean
  val isDiskCacheProbingEnabled: Boolean
  val trackedKeysSize: Int
  val allowDelay: Boolean
  val handOffOnUiThreadOnly: Boolean
  val shouldStoreCacheEntrySize: Boolean
  val shouldIgnoreCacheSizeMismatch: Boolean
  val shouldUseDecodingBufferHelper: Boolean
  val allowProgressiveOnPrefetch: Boolean
  val cancelDecodeOnCacheMiss: Boolean
  val animationRenderFpsLimit: Int
  val prefetchShortcutEnabled: Boolean

  class Builder(private val configBuilder: ImagePipelineConfig.Builder) {
    @JvmField var shouldUseDecodingBufferHelper = false
    @JvmField var webpSupportEnabled = false
    @JvmField var webpErrorLogger: WebpErrorLogger? = null
    @JvmField var decodeCancellationEnabled = false
    @JvmField var webpBitmapFactory: WebpBitmapFactory? = null
    @JvmField var useDownsamplingRatioForResizing = false
    @JvmField var useBitmapPrepareToDraw = false
    @JvmField var useBalancedAnimationStrategy = false
    @JvmField var animatedCacheMemoryPercentage = 40
    @JvmField var bitmapPrepareToDrawMinSizeBytes = 0
    @JvmField var bitmapPrepareToDrawMaxSizeBytes = 0

    @JvmField var bitmapPrepareToDrawForPrefetch = false
    @JvmField var maxBitmapSize = BitmapUtil.MAX_BITMAP_SIZE.toInt()
    @JvmField var nativeCodeDisabled = false
    @JvmField var isPartialImageCachingEnabled = false
    @JvmField var producerFactoryMethod: ProducerFactoryMethod? = null

    @JvmField var lazyDataSource: Supplier<Boolean>? = null

    @JvmField var gingerbreadDecoderEnabled = false

    @JvmField var downscaleFrameToDrawableDimensions = false

    @JvmField var suppressBitmapPrefetchingSupplier = Suppliers.of(false)

    @JvmField var experimentalThreadHandoffQueueEnabled = false

    @JvmField var memoryType: Long = 0
    @JvmField var keepCancelledFetchAsLowPriority = false

    @JvmField var downsampleIfLargeBitmap = false

    @JvmField var encodedCacheEnabled = true

    @JvmField var ensureTranscoderLibraryLoaded = true
    @JvmField var isEncodedMemoryCacheProbingEnabled = false
    @JvmField var isDiskCacheProbingEnabled = false
    @JvmField var trackedKeysSize = 20
    @JvmField var allowDelay = false
    @JvmField var handOffOnUiThreadOnly = false
    @JvmField var shouldStoreCacheEntrySize = false

    @JvmField var shouldIgnoreCacheSizeMismatch = false
    @JvmField var allowProgressiveOnPrefetch = false
    @JvmField var animationRenderFpsLimit = 30
    @JvmField var cancelDecodeOnCacheMiss = false
    @JvmField var prefetchShortcutEnabled = false

    private fun asBuilder(block: () -> Unit): ImagePipelineConfig.Builder {
      block()
      return configBuilder
    }

    fun setHandOffOnUiThreadOnly(handOffOnUiThreadOnly: Boolean) = asBuilder {
      this.handOffOnUiThreadOnly = handOffOnUiThreadOnly
    }

    fun setStoreCacheEntrySize(shouldStoreCacheEntrySize: Boolean) = asBuilder {
      this.shouldStoreCacheEntrySize = shouldStoreCacheEntrySize
    }

    fun setIgnoreCacheSizeMismatch(shouldIgnoreCacheSizeMismatch: Boolean) = asBuilder {
      this.shouldIgnoreCacheSizeMismatch = shouldIgnoreCacheSizeMismatch
    }

    fun setWebpSupportEnabled(webpSupportEnabled: Boolean) = asBuilder {
      this.webpSupportEnabled = webpSupportEnabled
    }

    fun setPrefetchShortcutEnabled(prefetchShortcutEnabled: Boolean) = asBuilder {
      this.prefetchShortcutEnabled = prefetchShortcutEnabled
    }

    fun shouldUseDecodingBufferHelper(): Boolean = shouldUseDecodingBufferHelper

    fun setShouldUseDecodingBufferHelper(shouldUseDecodingBufferHelper: Boolean) = asBuilder {
      this.shouldUseDecodingBufferHelper = shouldUseDecodingBufferHelper
    }

    fun setUseDownsampligRatioForResizing(useDownsamplingRatioForResizing: Boolean) = asBuilder {
      this.useDownsamplingRatioForResizing = useDownsamplingRatioForResizing
    }

    /**
     * Enables the caching of partial image data, for example if the request is cancelled or fails
     * after some data has been received.
     */
    fun setPartialImageCachingEnabled(partialImageCachingEnabled: Boolean) = asBuilder {
      isPartialImageCachingEnabled = partialImageCachingEnabled
    }

    /**
     * If true we cancel decoding jobs when the related request has been cancelled
     *
     * @param decodeCancellationEnabled If true the decoding of cancelled requests are cancelled
     * @return The Builder itself for chaining
     */
    fun setDecodeCancellationEnabled(decodeCancellationEnabled: Boolean) = asBuilder {
      this.decodeCancellationEnabled = decodeCancellationEnabled
    }

    fun setWebpErrorLogger(webpErrorLogger: WebpErrorLogger?) = asBuilder {
      this.webpErrorLogger = webpErrorLogger
    }

    fun setWebpBitmapFactory(webpBitmapFactory: WebpBitmapFactory?) = asBuilder {
      this.webpBitmapFactory = webpBitmapFactory
    }

    /**
     * If enabled, the pipeline will call [android.graphics.Bitmap.prepareToDraw] after decoding.
     * This potentially reduces lag on Android N+ as this step now happens async when the
     * RendererThread is idle.
     *
     * @param useBitmapPrepareToDraw set true for enabling prepareToDraw
     * @param minBitmapSizeBytes Bitmaps with a [Bitmap.getByteCount] smaller than this value are
     *   not uploaded
     * @param maxBitmapSizeBytes Bitmaps with a [Bitmap.getByteCount] larger than this value are not
     *   uploaded
     * @param preparePrefetch If this is true, also pre-fetching image requests will trigger the
     *   [android.graphics.Bitmap.prepareToDraw] call.
     * @return The Builder itself for chaining
     */
    fun setBitmapPrepareToDraw(
        useBitmapPrepareToDraw: Boolean,
        minBitmapSizeBytes: Int,
        maxBitmapSizeBytes: Int,
        preparePrefetch: Boolean
    ) = asBuilder {
      this.useBitmapPrepareToDraw = useBitmapPrepareToDraw
      this.bitmapPrepareToDrawMinSizeBytes = minBitmapSizeBytes
      this.bitmapPrepareToDrawMaxSizeBytes = maxBitmapSizeBytes
      this.bitmapPrepareToDrawForPrefetch = preparePrefetch
    }

    /** Enable balance strategy between RAM and CPU for rendering bitmap animations (WebP, Gif) */
    fun setBalancedAnimationStrategy(useBalancedAnimationStrategy: Boolean) = asBuilder {
      this.useBalancedAnimationStrategy = useBalancedAnimationStrategy
    }

    /**
     * Maximum heap memory percentage available for caching bitmaps from animated asset (WebP, Gif)
     */
    fun setAnimatedCacheMemoryPercentage(animatedCacheMemoryPercentage: Int) = asBuilder {
      this.animatedCacheMemoryPercentage = animatedCacheMemoryPercentage
    }

    /**
     * Sets the maximum bitmap size use to compute the downsampling value when decoding Jpeg images.
     */
    fun setMaxBitmapSize(maxBitmapSize: Int) = asBuilder { this.maxBitmapSize = maxBitmapSize }

    /**
     * If true, the pipeline will use alternative implementations without native code.
     *
     * @param nativeCodeDisabled set true for disabling native implementation.
     * @return The Builder itself for chaining
     */
    fun setNativeCodeDisabled(nativeCodeDisabled: Boolean) = asBuilder {
      this.nativeCodeDisabled = nativeCodeDisabled
    }

    /**
     * Stores an alternative method to instantiate the [ProducerFactory]. This allows experimenting
     * with overridden producers.
     */
    fun setProducerFactoryMethod(producerFactoryMethod: ProducerFactoryMethod?) = asBuilder {
      this.producerFactoryMethod = producerFactoryMethod
    }

    /** Stores an alternative lazy method to instantiate the data souce. */
    fun setLazyDataSource(lazyDataSource: Supplier<Boolean>?) = asBuilder {
      this.lazyDataSource = lazyDataSource
    }

    fun setGingerbreadDecoderEnabled(gingerbreadDecoderEnabled: Boolean) = asBuilder {
      this.gingerbreadDecoderEnabled = gingerbreadDecoderEnabled
    }

    fun setShouldDownscaleFrameToDrawableDimensions(downscaleFrameToDrawableDimensions: Boolean) =
        asBuilder {
          this.downscaleFrameToDrawableDimensions = downscaleFrameToDrawableDimensions
        }

    fun setSuppressBitmapPrefetchingSupplier(suppressBitmapPrefetchingSupplier: Supplier<Boolean>) =
        asBuilder {
          this.suppressBitmapPrefetchingSupplier = suppressBitmapPrefetchingSupplier
        }

    fun setExperimentalThreadHandoffQueueEnabled(experimentalThreadHandoffQueueEnabled: Boolean) =
        asBuilder {
          this.experimentalThreadHandoffQueueEnabled = experimentalThreadHandoffQueueEnabled
        }

    fun setExperimentalMemoryType(MemoryType: Long) = asBuilder { this.memoryType = MemoryType }

    fun setKeepCancelledFetchAsLowPriority(keepCancelledFetchAsLowPriority: Boolean) = asBuilder {
      this.keepCancelledFetchAsLowPriority = keepCancelledFetchAsLowPriority
    }

    fun setDownsampleIfLargeBitmap(downsampleIfLargeBitmap: Boolean) = asBuilder {
      this.downsampleIfLargeBitmap = downsampleIfLargeBitmap
    }

    fun setEncodedCacheEnabled(encodedCacheEnabled: Boolean) = asBuilder {
      this.encodedCacheEnabled = encodedCacheEnabled
    }

    fun setEnsureTranscoderLibraryLoaded(ensureTranscoderLibraryLoaded: Boolean) = asBuilder {
      this.ensureTranscoderLibraryLoaded = ensureTranscoderLibraryLoaded
    }

    fun setIsDiskCacheProbingEnabled(isDiskCacheProbingEnabled: Boolean) = asBuilder {
      this.isDiskCacheProbingEnabled = isDiskCacheProbingEnabled
    }

    fun setIsEncodedMemoryCacheProbingEnabled(isEncodedMemoryCacheProbingEnabled: Boolean) =
        asBuilder {
          this.isEncodedMemoryCacheProbingEnabled = isEncodedMemoryCacheProbingEnabled
        }

    fun setTrackedKeysSize(trackedKeysSize: Int) = asBuilder {
      this.trackedKeysSize = trackedKeysSize
    }

    fun setAllowDelay(allowDelay: Boolean) = asBuilder { this.allowDelay = allowDelay }

    fun setAllowProgressiveOnPrefetch(allowProgressiveOnPrefetch: Boolean) = asBuilder {
      this.allowProgressiveOnPrefetch = allowProgressiveOnPrefetch
    }

    fun setAnimationRenderFpsLimit(animationRenderFpsLimit: Int) = asBuilder {
      this.animationRenderFpsLimit = animationRenderFpsLimit
    }

    fun setCancelDecodeOnCacheMiss(cancelDecodeOnCacheMiss: Boolean) = asBuilder {
      this.cancelDecodeOnCacheMiss = cancelDecodeOnCacheMiss
    }

    fun build(): ImagePipelineExperiments = ImagePipelineExperiments(this)
  }

  interface ProducerFactoryMethod {
    fun createProducerFactory(
        context: Context,
        byteArrayPool: ByteArrayPool,
        imageDecoder: ImageDecoder,
        progressiveJpegConfig: ProgressiveJpegConfig,
        downsampleEnabled: Boolean,
        resizeAndRotateEnabledForNetwork: Boolean,
        decodeCancellationEnabled: Boolean,
        executorSupplier: ExecutorSupplier,
        pooledByteBufferFactory: PooledByteBufferFactory,
        pooledByteStreams: PooledByteStreams,
        bitmapMemoryCache: MemoryCache<CacheKey?, CloseableImage?>,
        encodedMemoryCache: MemoryCache<CacheKey?, PooledByteBuffer?>,
        defaultBufferedDiskCache: BufferedDiskCache,
        smallImageBufferedDiskCache: BufferedDiskCache,
        cacheKeyFactory: CacheKeyFactory,
        platformBitmapFactory: PlatformBitmapFactory,
        bitmapPrepareToDrawMinSizeBytes: Int,
        bitmapPrepareToDrawMaxSizeBytes: Int,
        bitmapPrepareToDrawForPrefetch: Boolean,
        maxBitmapSize: Int,
        closeableReferenceFactory: CloseableReferenceFactory,
        keepCancelledFetchAsLowPriority: Boolean,
        trackedKeysSize: Int
    ): ProducerFactory
  }

  class DefaultProducerFactoryMethod : ProducerFactoryMethod {
    override fun createProducerFactory(
        context: Context,
        byteArrayPool: ByteArrayPool,
        imageDecoder: ImageDecoder,
        progressiveJpegConfig: ProgressiveJpegConfig,
        downsampleEnabled: Boolean,
        resizeAndRotateEnabledForNetwork: Boolean,
        decodeCancellationEnabled: Boolean,
        executorSupplier: ExecutorSupplier,
        pooledByteBufferFactory: PooledByteBufferFactory,
        pooledByteStreams: PooledByteStreams,
        bitmapMemoryCache: MemoryCache<CacheKey?, CloseableImage?>,
        encodedMemoryCache: MemoryCache<CacheKey?, PooledByteBuffer?>,
        defaultBufferedDiskCache: BufferedDiskCache,
        smallImageBufferedDiskCache: BufferedDiskCache,
        cacheKeyFactory: CacheKeyFactory,
        platformBitmapFactory: PlatformBitmapFactory,
        bitmapPrepareToDrawMinSizeBytes: Int,
        bitmapPrepareToDrawMaxSizeBytes: Int,
        bitmapPrepareToDrawForPrefetch: Boolean,
        maxBitmapSize: Int,
        closeableReferenceFactory: CloseableReferenceFactory,
        keepCancelledFetchAsLowPriority: Boolean,
        trackedKeysSize: Int
    ): ProducerFactory =
        ProducerFactory(
            context!!,
            byteArrayPool!!,
            imageDecoder!!,
            progressiveJpegConfig!!,
            downsampleEnabled,
            resizeAndRotateEnabledForNetwork,
            decodeCancellationEnabled,
            executorSupplier!!,
            pooledByteBufferFactory!!,
            bitmapMemoryCache!!,
            encodedMemoryCache!!,
            defaultBufferedDiskCache!!,
            smallImageBufferedDiskCache!!,
            cacheKeyFactory!!,
            platformBitmapFactory!!,
            bitmapPrepareToDrawMinSizeBytes,
            bitmapPrepareToDrawMaxSizeBytes,
            bitmapPrepareToDrawForPrefetch,
            maxBitmapSize,
            closeableReferenceFactory!!,
            keepCancelledFetchAsLowPriority,
            trackedKeysSize)
  }

  init {
    isWebpSupportEnabled = builder.webpSupportEnabled
    webpErrorLogger = builder.webpErrorLogger
    isDecodeCancellationEnabled = builder.decodeCancellationEnabled
    webpBitmapFactory = builder.webpBitmapFactory
    useDownsamplingRatioForResizing = builder.useDownsamplingRatioForResizing
    useBitmapPrepareToDraw = builder.useBitmapPrepareToDraw
    useBalancedAnimationStrategy = builder.useBalancedAnimationStrategy
    animatedCacheMemoryPercentage = builder.animatedCacheMemoryPercentage
    bitmapPrepareToDrawMinSizeBytes = builder.bitmapPrepareToDrawMinSizeBytes
    bitmapPrepareToDrawMaxSizeBytes = builder.bitmapPrepareToDrawMaxSizeBytes
    bitmapPrepareToDrawForPrefetch = builder.bitmapPrepareToDrawForPrefetch
    maxBitmapSize = builder.maxBitmapSize
    isNativeCodeDisabled = builder.nativeCodeDisabled
    isPartialImageCachingEnabled = builder.isPartialImageCachingEnabled
    producerFactoryMethod = builder.producerFactoryMethod ?: DefaultProducerFactoryMethod()
    isLazyDataSource = builder.lazyDataSource ?: Suppliers.BOOLEAN_FALSE
    isGingerbreadDecoderEnabled = builder.gingerbreadDecoderEnabled
    downscaleFrameToDrawableDimensions = builder.downscaleFrameToDrawableDimensions
    suppressBitmapPrefetchingSupplier = builder.suppressBitmapPrefetchingSupplier
    isExperimentalThreadHandoffQueueEnabled = builder.experimentalThreadHandoffQueueEnabled
    memoryType = builder.memoryType
    keepCancelledFetchAsLowPriority = builder.keepCancelledFetchAsLowPriority
    downsampleIfLargeBitmap = builder.downsampleIfLargeBitmap
    isEncodedCacheEnabled = builder.encodedCacheEnabled
    isEnsureTranscoderLibraryLoaded = builder.ensureTranscoderLibraryLoaded
    isEncodedMemoryCacheProbingEnabled = builder.isEncodedMemoryCacheProbingEnabled
    isDiskCacheProbingEnabled = builder.isDiskCacheProbingEnabled
    trackedKeysSize = builder.trackedKeysSize
    allowProgressiveOnPrefetch = builder.allowProgressiveOnPrefetch
    animationRenderFpsLimit = builder.animationRenderFpsLimit
    allowDelay = builder.allowDelay
    handOffOnUiThreadOnly = builder.handOffOnUiThreadOnly
    shouldStoreCacheEntrySize = builder.shouldStoreCacheEntrySize
    shouldIgnoreCacheSizeMismatch = builder.shouldIgnoreCacheSizeMismatch
    shouldUseDecodingBufferHelper = builder.shouldUseDecodingBufferHelper
    cancelDecodeOnCacheMiss = builder.cancelDecodeOnCacheMiss
    prefetchShortcutEnabled = builder.prefetchShortcutEnabled
  }

  companion object {
    @JvmStatic
    fun newBuilder(configBuilder: ImagePipelineConfig.Builder): Builder = Builder(configBuilder)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

/** Main classes related to the Fresco API. */
package com.facebook.imagepipeline.core