import org.apache.tools.ant.util.StringUtils

plugins {
    id "com.jetbrains.python.envs" version "$python_envs_plugin"
    id "com.google.protobuf" version "$protobuf_plugin"
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'jacoco'
apply plugin: 'androidx.navigation.safeargs.kotlin'
apply plugin: 'com.google.android.gms.oss-licenses-plugin'

import com.android.build.OutputFile
import groovy.json.JsonOutput
import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory

import static org.gradle.api.tasks.testing.TestResult.ResultType

apply from: 'benchmark.gradle'

android {
    compileSdkVersion config.compileSdkVersion

    project.maybeConfigForJetpackBenchmark(it)
    if (project.hasProperty("testBuildType")) {
        // Allowing to configure the test build type via command line flag (./gradlew -PtestBuildType=beta ..)
        // in order to run UI tests against other build variants than debug in automation.
        testBuildType project.property("testBuildType")
    }

    defaultConfig {
        applicationId "io.github.forkmaintainers"
        minSdkVersion config.minSdkVersion
        targetSdkVersion config.targetSdkVersion
        versionCode 1
        versionName Config.generateDebugVersionName()
        vectorDrawables.useSupportLibrary = true
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments clearPackageData: 'true'
        resValue "bool", "IS_DEBUG", "false"
        buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false"
        buildConfigField "String", "GIT_HASH", "\"\"" // see override in release builds for why it's blank.
        // This should be the "public" base URL of AMO.
        buildConfigField "String", "AMO_BASE_URL", "\"https://addons.mozilla.org\""
        buildConfigField "String", "AMO_COLLECTION_NAME", "\"Extensions-for-Android\""
        buildConfigField "String", "AMO_COLLECTION_USER", "\"mozilla\""
        // These add-ons should be excluded for Mozilla Online builds.
        buildConfigField "String[]", "MOZILLA_ONLINE_ADDON_EXCLUSIONS",
                "{" +
                        "\"uBlock0@raymondhill.net\"," +
                        "\"firefox@ghostery.com\"," +
                        "\"jid1-MnnxcxisBPnSXQ@jetpack\"," +
                        "\"adguardadblocker@adguard.com\"," +
                        "\"foxyproxy@eric.h.jung\"," +
                        "\"{73a6fe31-595d-460b-a920-fcc0f8843232}\"," +
                        "\"jid1-BoFifL9Vbdl2zQ@jetpack\"," +
                        "\"woop-NoopscooPsnSXQ@jetpack\"," +
                        "\"adnauseam@rednoise.org\"" +
                "}"
        // This should be the base URL used to call the AMO API.
        buildConfigField "String", "AMO_SERVER_URL", "\"https://services.addons.mozilla.org\""

        def deepLinkSchemeValue = "fenix-dev"
        buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""

        // This allows overriding the target activity for MozillaOnline builds, which happens
        // as part of the defaultConfig below.
        def targetActivity = "HomeActivity"

        // Build flag for "Mozilla Online" variants. See `Config.isMozillaOnline`.
        if (project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")) {
            buildConfigField "boolean", "MOZILLA_ONLINE", "true"
            targetActivity = "MozillaOnlineHomeActivity"
        } else {
            buildConfigField "boolean", "MOZILLA_ONLINE", "false"
        }

        manifestPlaceholders = [
                "targetActivity": targetActivity,
                "deepLinkScheme": deepLinkSchemeValue
        ]
    }

    def releaseTemplate = {
        // We allow disabling optimization by passing `-PdisableOptimization` to gradle. This is used
        // in automation for UI testing non-debug builds.
        shrinkResources !project.hasProperty("disableOptimization")
        minifyEnabled !project.hasProperty("disableOptimization")
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        matchingFallbacks = ['release'] // Use on the "release" build type in dependencies (AARs)

        // Changing the build config can cause files that depend on BuildConfig.java to recompile
        // so we only set the git hash in release builds to avoid possible recompilation in debug builds.
        buildConfigField "String", "GIT_HASH", "\"${Config.getGitHash()}\""

        if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) {
            signingConfig signingConfigs.debug
        }

        if (gradle.hasProperty("localProperties.debuggable")) {
            debuggable true
        }
    }

    buildTypes {
        debug {
            shrinkResources false
            minifyEnabled false
            applicationIdSuffix ".fenix.debug"
            resValue "bool", "IS_DEBUG", "true"
            pseudoLocalesEnabled true
        }
        nightly releaseTemplate >> {
            applicationIdSuffix ".fenix"
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
            def deepLinkSchemeValue = "fenix-nightly"
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders.putAll([
                    "deepLinkScheme": deepLinkSchemeValue
            ])
        }
        beta releaseTemplate >> {
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
            applicationIdSuffix ".firefox_beta"
            def deepLinkSchemeValue = "fenix-beta"
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders.putAll([
                    // This release type is meant to replace Firefox (Beta channel) and therefore needs to inherit
                    // its sharedUserId for all eternity. See:
                    // https://searchfox.org/mozilla-esr68/search?q=moz_android_shared_id&case=false&regexp=false&path=
                    // Shipping an app update without sharedUserId can have
                    // fatal consequences. For example see:
                    //  - https://issuetracker.google.com/issues/36924841
                    //  - https://issuetracker.google.com/issues/36905922
                    "sharedUserId": "org.mozilla.firefox.sharedID",
                    "deepLinkScheme": deepLinkSchemeValue,
            ])
        }
        release releaseTemplate >> {
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
            applicationIdSuffix ".firefox"
            def deepLinkSchemeValue = "fenix"
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders.putAll([
                    // This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
                    // its sharedUserId for all eternity. See:
                    // https://searchfox.org/mozilla-esr68/search?q=moz_android_shared_id&case=false&regexp=false&path=
                    // Shipping an app update without sharedUserId can have
                    // fatal consequences. For example see:
                    //  - https://issuetracker.google.com/issues/36924841
                    //  - https://issuetracker.google.com/issues/36905922
                    "sharedUserId": "org.mozilla.firefox.sharedID",
                    "deepLinkScheme": deepLinkSchemeValue,
            ])
        }
        forkDebug {
            shrinkResources false
            minifyEnabled false
            applicationIdSuffix ".iceraven.debug"
            pseudoLocalesEnabled true
            // Need to replicate default debug config features
            signingConfig signingConfigs.debug
            debuggable true
            def deepLinkSchemeValue = "iceraven-debug"
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders.putAll([
                    "sharedUserId": "io.github.forkmaintainers.iceraven.sharedID",
                    "deepLinkScheme": deepLinkSchemeValue,
            ])
            // Use custom default allowed addon list
            buildConfigField "String", "AMO_COLLECTION_USER", "\"16201230\""
            buildConfigField "String", "AMO_COLLECTION_NAME", "\"What-I-want-on-Fenix\""
            resValue "bool", "IS_DEBUG", "true"
            matchingFallbacks = ['debug']
        }
        forkRelease releaseTemplate >> {
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
            applicationIdSuffix ".iceraven"
            def deepLinkSchemeValue = "iceraven"
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders.putAll([
                    "sharedUserId": "io.github.forkmaintainers.iceraven.sharedID",
                    "deepLinkScheme": deepLinkSchemeValue,
            ])
            // Use custom default allowed addon list
            buildConfigField "String", "AMO_COLLECTION_USER", "\"16201230\""
            buildConfigField "String", "AMO_COLLECTION_NAME", "\"What-I-want-on-Fenix\""
        }
        benchmark releaseTemplate >> {
            initWith buildTypes.nightly
            applicationIdSuffix ".fenix"
            debuggable false
        }
    }

    buildFeatures {
        viewBinding true
    }

    androidResources {
        // All JavaScript code used internally by GeckoView is packaged in a
        // file called omni.ja. If this file is compressed in the APK,
        // GeckoView must uncompress it before it can do anything else which
        // causes a significant delay on startup.
        noCompress 'ja'

        // manifest.template.json is converted to manifest.json at build time.
        // No need to package the template in the APK.
        ignoreAssetsPattern "manifest.template.json"
    }

    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'
        unitTests.includeAndroidResources = true
        animationsDisabled = true
    }

    flavorDimensions "engine"

    flavorDimensions "product"

    productFlavors {
        fenix {
            dimension "product"
        }
    }

    sourceSets {
        androidTest {
            resources.srcDirs += ['src/androidTest/resources']
        }
    }

    splits {
        abi {
            enable true

            reset()

            include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    lint {
        lintConfig file("lint.xml")
        baseline file("lint-baseline.xml")
    }
    packagingOptions {
        resources {
            excludes += ['META-INF/atomicfu.kotlin_module', 'META-INF/AL2.0', 'META-INF/LGPL2.1',
                         'META-INF/LICENSE.md', 'META-INF/LICENSE-notice.md']
        }
    }


    testOptions {
        unitTests.returnDefaultValues = true

        unitTests.all {
            // We keep running into memory issues when running our tests. With this config we
            // reserve more memory and also create a new process after every 80 test classes. This
            // is a band-aid solution and eventually we should try to find and fix the leaks
            // instead. :)
            forkEvery = 80
            maxHeapSize = "3072m"
            minHeapSize = "1024m"
        }
    }

    buildFeatures {
        compose true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = Versions.compose_compiler
    }

    namespace 'org.mozilla.fenix'
}

android.applicationVariants.all { variant ->

// -------------------------------------------------------------------------------------------------
// Generate version codes for builds
// -------------------------------------------------------------------------------------------------

    def isDebug = variant.buildType.resValues['bool/IS_DEBUG']?.value ?: false
    def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false

    println("----------------------------------------------")
    println("Variant name:      " + variant.name)
    println("Application ID:    " + [variant.applicationId, variant.buildType.applicationIdSuffix].findAll().join())
    println("Build type:        " + variant.buildType.name)
    println("Flavor:            " + variant.flavorName)
    println("Telemetry enabled: " + !isDebug)

    if (useReleaseVersioning) {
        // The Google Play Store does not allow multiple APKs for the same app that all have the
        // same version code. Therefore we need to have different version codes for our ARM and x86
        // builds.

        def versionName = variant.buildType.name == 'nightly' ? Config.nightlyVersionName() : Config.releaseVersionName(project)
        println("versionName override: $versionName")

        variant.outputs.each { output ->
            def isMozillaOnline = project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")
            def abi = output.getFilter(OutputFile.ABI)
            // If it is a Mozilla Online build, use a unified version code of armeabi-v7a
            def arch = (isMozillaOnline) ? "armeabi-v7a" : abi
            // We use the same version code generator, that we inherited from Fennec, across all channels - even on
            // channels that never shipped a Fennec build.
            def versionCodeOverride = Config.generateFennecVersionCode(arch)

            println("versionCode for $abi = $versionCodeOverride, isMozillaOnline = $isMozillaOnline")

            if (versionName != null) {
                output.versionNameOverride = versionName
            }
            output.versionCodeOverride = versionCodeOverride
        }
    } else if (gradle.hasProperty("localProperties.branchBuild.fenix.version")) {
        def versionName = gradle.getProperty("localProperties.branchBuild.fenix.version")
        println("versionName override: $versionName")
        variant.outputs.each { output ->
            output.versionNameOverride = versionName
        }
    }

// -------------------------------------------------------------------------------------------------
// BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
// -------------------------------------------------------------------------------------------------

    buildConfigField 'String', 'SENTRY_TOKEN', 'null'
    if (!isDebug) {
        buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
        // Reading sentry token from local file (if it exists). In a release task on taskcluster it will be available.
        try {
            def token = new File("${rootDir}/.sentry_token").text.trim()
            buildConfigField 'String', 'SENTRY_TOKEN', '"' + token + '"'
        } catch (FileNotFoundException ignored) {}
    } else {
        buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
    }

    if (!isDebug) {
        buildConfigField 'boolean', 'TELEMETRY', 'false'
    } else {
        buildConfigField 'boolean', 'TELEMETRY', 'false'
    }

    def buildDate = Config.generateBuildDate()
    // Setting buildDate with every build changes the generated BuildConfig, which slows down the
    // build. Only do this for non-debug builds, to speed-up builds produced during local development.
    if (isDebug) {
        buildConfigField 'String', 'BUILD_DATE', '"debug build"'
    } else {
        buildConfigField 'String', 'BUILD_DATE', '"' + buildDate + '"'
    }

// -------------------------------------------------------------------------------------------------
// Adjust: Read token from local file if it exists (Only release builds)
// -------------------------------------------------------------------------------------------------

    print("Adjust token: ")

    if (!isDebug) {
        try {
            def token = new File("${rootDir}/.adjust_token").text.trim()
            buildConfigField 'String', 'ADJUST_TOKEN', '"' + token + '"'
            println "(Added from .adjust_token file)"
        } catch (FileNotFoundException ignored) {
            buildConfigField 'String', 'ADJUST_TOKEN', 'null'
            println("X_X")
        }
    } else {
        buildConfigField 'String', 'ADJUST_TOKEN', 'null'
        println("--")
    }

// -------------------------------------------------------------------------------------------------
// MLS: Read token from local file if it exists
// -------------------------------------------------------------------------------------------------

    print("MLS token: ")

    try {
        def token = new File("${rootDir}/.mls_token").text.trim()
        buildConfigField 'String', 'MLS_TOKEN', '"' + token + '"'
        println "(Added from .mls_token file)"
    } catch (FileNotFoundException ignored) {
        buildConfigField 'String', 'MLS_TOKEN', '""'
        println("X_X")
    }

// -------------------------------------------------------------------------------------------------
// Nimbus: Read endpoint from local.properties of a local file if it exists
// -------------------------------------------------------------------------------------------------

    print("Nimbus endpoint: ")

    if (!isDebug) {
        try {
            def url = new File("${rootDir}/.nimbus").text.trim()
            buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
            println "(Added from .nimbus file)"
        } catch (FileNotFoundException ignored) {
            buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
            println("X_X")
        }
    } else if (gradle.hasProperty("localProperties.nimbus.remote-settings.url")) {
        def url=gradle.getProperty("localProperties.nimbus.remote-settings.url")
        buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
        println "(Added from local.properties file)"
    } else {
        buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
        println("--")
    }

// -------------------------------------------------------------------------------------------------
// Glean: Read custom server URL from local.properties of a local file if it exists
// -------------------------------------------------------------------------------------------------

    print("Glean custom server URL: ")

    if (gradle.hasProperty("localProperties.glean.custom.server.url")) {
        def url=gradle.getProperty("localProperties.glean.custom.server.url")
        buildConfigField 'String', 'GLEAN_CUSTOM_URL', url
        println "(Added from local.properties file)"
    } else {
        buildConfigField 'String', 'GLEAN_CUSTOM_URL', 'null'
        println("--")
    }

// -------------------------------------------------------------------------------------------------
// BuildConfig: Set flag for official builds; similar to MOZILLA_OFFICIAL in mozilla-central.
// -------------------------------------------------------------------------------------------------

    if (project.hasProperty("official") || gradle.hasProperty("localProperties.official")) {
        buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'true'
    } else {
        buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'false'
    }

// -------------------------------------------------------------------------------------------------
// BuildConfig: Set remote wallpaper URL using local file if it exists
// -------------------------------------------------------------------------------------------------

    print("Wallpaper URL: ")

    try {
        // def token = new File("${rootDir}/.wallpaper_url").text.trim()
        def token = "https://assets.mozilla.net/mobile-wallpapers/android"
        buildConfigField 'String', 'WALLPAPER_URL', '"' + token + '"'
        println "(Added from .wallpaper_url file)"
    } catch (FileNotFoundException ignored) {
        buildConfigField 'String', 'WALLPAPER_URL', '""'
        println("--")
    }

// -------------------------------------------------------------------------------------------------
// BuildConfig: Set the Pocket consumer key from a local file if it exists
// -------------------------------------------------------------------------------------------------

    print("Pocket consumer key: ")

    try {
        def token = new File("${rootDir}/.pocket_consumer_key").text.trim()
        buildConfigField 'String', 'POCKET_CONSUMER_KEY', '"' + token + '"'
        println "(Added from .pocket_consumer_key file)"
    } catch (FileNotFoundException ignored) {
        buildConfigField 'String', 'POCKET_CONSUMER_KEY', '""'
        println("--")
    }
}

// Generate Kotlin code for the Fenix Glean metrics.
apply plugin: "org.mozilla.telemetry.glean-gradle-plugin"
apply plugin: "org.mozilla.appservices.nimbus-gradle-plugin"

nimbus {
    // The path to the Nimbus feature manifest file
    manifestFile = "nimbus.fml.yaml"
    // The fully qualified class name for the generated features.
    // Map from the variant name to the channel as experimenter and nimbus understand it.
    // If nimbus's channels were accurately set up well for this project, then this
    // shouldn't be needed.
    channels = [
            fenixDebug: "developer",
            fenixNightly: "nightly",
            fenixBeta: "beta",
            fenixRelease: "release",
            fenixForkDebug: "forkDebug",
            fenixForkRelease: "forkRelease",
            fenixBenchmark: "developer"
    ]
    // This is generated by the FML and should be checked into git.
    // It will be fetched by Experimenter (the Nimbus experiment website)
    // and used to inform experiment configuration.
    experimenterManifest = ".experimenter.yaml"
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
    kotlinOptions {
        freeCompilerArgs += [
                "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
        ]
    }
}

dependencies {
    implementation project(':browser-engine-gecko')

    implementation ComponentsDependencies.kotlin_coroutines
    testImplementation ComponentsDependencies.testing_coroutines
    implementation ComponentsDependencies.androidx_appcompat
    implementation ComponentsDependencies.androidx_constraintlayout
    implementation ComponentsDependencies.androidx_coordinatorlayout
    implementation FenixDependencies.google_accompanist_drawablepainter

    implementation ComponentsDependencies.thirdparty_sentry_latest

    implementation project(':compose-awesomebar')
    implementation project(':compose-cfr')

    implementation project(':concept-awesomebar')
    implementation project(':concept-base')
    implementation project(':concept-engine')
    implementation project(':concept-menu')
    implementation project(':concept-push')
    implementation project(':concept-storage')
    implementation project(':concept-sync')
    implementation project(':concept-toolbar')
    implementation project(':concept-tabstray')

    implementation project(':browser-domains')
    implementation project(':browser-icons')
    implementation project(':browser-menu')
    implementation project(':browser-menu2')
    implementation project(':browser-session-storage')
    implementation project(':browser-state')
    implementation project(':browser-storage-sync')
    implementation project(':browser-tabstray')
    implementation project(':browser-thumbnails')
    implementation project(':browser-toolbar')

    implementation project(':feature-addons')
    implementation project(':feature-accounts')
    implementation project(':feature-app-links')
    implementation project(':feature-autofill')
    implementation project(':feature-awesomebar')
    implementation project(':feature-contextmenu')
    implementation project(':feature-customtabs')
    implementation project(':feature-downloads')
    implementation project(':feature-intent')
    implementation project(':feature-media')
    implementation project(':feature-prompts')
    implementation project(':feature-push')
    implementation project(':feature-privatemode')
    implementation project(':feature-pwa')
    implementation project(':feature-qr')
    implementation project(':feature-search')
    implementation project(':feature-session')
    implementation project(':feature-syncedtabs')
    implementation project(':feature-toolbar')
    implementation project(':feature-tabs')
    implementation project(':feature-findinpage')
    implementation project(':feature-logins')
    implementation project(':feature-sitepermissions')
    implementation project(':feature-readerview')
    implementation project(':feature-tab-collections')
    implementation project(':feature-recentlyclosed')
    implementation project(':feature-top-sites')
    implementation project(':feature-share')
    implementation project(':feature-accounts-push')
    implementation project(':feature-webauthn')
    implementation project(':feature-webcompat')
    implementation project(':feature-webnotifications')
    implementation project(':feature-webcompat-reporter')

    implementation project(':service-pocket')
    implementation project(':service-contile')
    implementation project(':service-digitalassetlinks')
    implementation project(':service-sync-autofill')
    implementation project(':service-sync-logins')
    implementation project(':service-firefox-accounts')
    implementation project(':service-glean')
    implementation project(':service-location')
    implementation project(':service-nimbus')

    implementation project(':support-webextensions')
    implementation project(':support-base')
    implementation project(':support-rusterrors')
    implementation project(':support-images')
    implementation project(':support-ktx')
    implementation project(':support-rustlog')
    implementation project(':support-utils')
    implementation project(':support-locale')

    implementation project(':ui-colors')
    implementation project(':ui-icons')
    implementation project(':lib-publicsuffixlist')
    implementation project(':ui-widgets')
    implementation project(':ui-tabcounter')

    implementation project(':lib-crash')
    implementation project(':lib-crash-sentry')
    implementation project(':lib-state')
    implementation project(':lib-dataprotect')

    debugImplementation ComponentsDependencies.leakcanary
    forkDebugImplementation ComponentsDependencies.leakcanary
    debugImplementation ComponentsDependencies.androidx_compose_ui_tooling

    implementation ComponentsDependencies.androidx_activity_compose
    implementation FenixDependencies.androidx_activity_ktx
    implementation ComponentsDependencies.androidx_annotation
    implementation ComponentsDependencies.androidx_compose_ui
    implementation ComponentsDependencies.androidx_compose_ui_tooling_preview
    implementation ComponentsDependencies.androidx_compose_animation
    implementation ComponentsDependencies.androidx_compose_foundation
    implementation ComponentsDependencies.androidx_compose_material
    implementation FenixDependencies.androidx_legacy
    implementation ComponentsDependencies.androidx_biometric
    implementation ComponentsDependencies.androidx_paging
    implementation ComponentsDependencies.androidx_preferences
    implementation ComponentsDependencies.androidx_fragment
    implementation FenixDependencies.androidx_navigation_fragment
    implementation FenixDependencies.androidx_navigation_ui
    implementation ComponentsDependencies.androidx_recyclerview
    implementation FenixDependencies.androidx_lifecycle_common
    implementation ComponentsDependencies.androidx_lifecycle_livedata
    implementation ComponentsDependencies.androidx_lifecycle_process
    implementation ComponentsDependencies.androidx_lifecycle_runtime

    implementation ComponentsDependencies.androidx_lifecycle_viewmodel
    implementation ComponentsDependencies.androidx_core
    implementation ComponentsDependencies.androidx_core_ktx
    implementation FenixDependencies.androidx_core_splashscreen
    implementation FenixDependencies.androidx_transition
    implementation ComponentsDependencies.androidx_work_runtime
    implementation FenixDependencies.androidx_datastore
    implementation ComponentsDependencies.androidx_data_store_preferences
    implementation FenixDependencies.protobuf_javalite
    implementation ComponentsDependencies.google_material

    androidTestImplementation ComponentsDependencies.androidx_test_uiautomator
    androidTestImplementation FenixDependencies.fastlane
    // This Falcon version is added to maven central now required for Screengrab
    androidTestImplementation FenixDependencies.falcon

    androidTestImplementation ComponentsDependencies.androidx_compose_ui_test

    androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
        exclude group: 'com.android.support', module: 'support-annotations'
    }

    androidTestImplementation(FenixDependencies.espresso_contrib) {
        exclude module: 'appcompat-v7'
        exclude module: 'support-v4'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'design'
        exclude module: 'espresso-core'
        exclude module: 'protobuf-lite'
    }

    androidTestImplementation ComponentsDependencies.androidx_test_core
    androidTestImplementation FenixDependencies.espresso_idling_resources
    androidTestImplementation FenixDependencies.espresso_intents

    androidTestImplementation ComponentsDependencies.androidx_test_runner
    androidTestImplementation ComponentsDependencies.androidx_test_rules
    androidTestUtil FenixDependencies.orchestrator
    androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
        exclude group: 'com.android.support', module: 'support-annotations'
    }

    androidTestImplementation ComponentsDependencies.androidx_test_junit
    androidTestImplementation ComponentsDependencies.androidx_work_testing
    androidTestImplementation FenixDependencies.androidx_benchmark_junit4
    androidTestImplementation FenixDependencies.mockwebserver
    testImplementation project(':support-test')
    testImplementation project(':support-test-libstate')
    testImplementation ComponentsDependencies.androidx_test_junit
    testImplementation ComponentsDependencies.androidx_work_testing
    testImplementation (ComponentsDependencies.testing_robolectric) {
        exclude group: 'org.apache.maven'
    }

    testImplementation ComponentsDependencies.testing_maven_ant_tasks
    implementation project(':support-rusthttp')

    androidTestImplementation FenixDependencies.mockk_android
    testImplementation FenixDependencies.mockk

    // For the initial release of Glean 19, we require consumer applications to
    // depend on a separate library for unit tests. This will be removed in future releases.
    testImplementation "org.mozilla.telemetry:glean-native-forUnitTests:${project.ext.glean_version}"

    lintChecks project(":mozilla-lint-rules")
}

protobuf {
    protoc {
        artifact = FenixDependencies.protobuf_compiler
    }

    // Generates the java Protobuf-lite code for the Protobufs in this project. See
    // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
    // for more information.
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java {
                    option 'lite'
                }
            }
        }
    }
}

if (project.hasProperty("coverage")) {
    tasks.withType(Test).configureEach {
        jacoco.includeNoLocationClasses = true
        jacoco.excludes = ['jdk.internal.*']
    }

    jacoco {
        toolVersion = Versions.jacoco
    }

    android.applicationVariants.all { variant ->
        tasks.register("jacoco${variant.name.capitalize()}TestReport", JacocoReport) {
            dependsOn "test${variant.name.capitalize()}UnitTest"

            reports {
                xml.enabled = true
                html.enabled = true
            }

            def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
                              '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
            def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/${variant.name}", excludes: fileFilter)
            def javaDebugTree = fileTree(dir: "$project.buildDir/intermediates/classes/${variant.flavorName}/${variant.buildType.name}",
                    excludes: fileFilter)
            def mainSrc = "$project.projectDir/src/main/java"

            sourceDirectories.setFrom(files([mainSrc]))
            classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
            executionData.setFrom(fileTree(dir: project.buildDir, includes: [
                "jacoco/test${variant.name.capitalize()}UnitTest.exec",
                'outputs/code-coverage/connected/*coverage.ec'
            ]))
        }
    }

    android {
        buildTypes {
            debug {
                testCoverageEnabled true
            }
            forkDebug {
                testCoverageEnabled true
            }
        }
    }
}

// -------------------------------------------------------------------------------------------------
// Task for printing APK information for the requested variant
// Usage: "./gradlew printVariants
// -------------------------------------------------------------------------------------------------
tasks.register('printVariants') {
    doLast {
        def variants = android.applicationVariants.collect { variant -> [
            apks: variant.outputs.collect { output -> [
                abi: output.getFilter(com.android.build.VariantOutput.FilterType.ABI),
                fileName: output.outputFile.name
            ]},
            build_type: variant.buildType.name,
            name: variant.name,
        ]}
        // AndroidTest is a special case not included above
        variants.add([
            apks: [[
                abi: 'noarch',
                fileName: 'app-debug-androidTest.apk',
            ]],
            build_type: 'androidTest',
            name: 'androidTest',
        ])
        println 'variants: ' + JsonOutput.toJson(variants)
    }
}

task buildTranslationArray {
    // This isn't running as a task, instead the array is build when the gradle file is parsed.
    // https://github.com/mozilla-mobile/fenix/issues/14175
    def foundLocales = new StringBuilder()
    foundLocales.append("new String[]{")

    fileTree("src/main/res").visit { FileVisitDetails details ->
        if(details.file.path.endsWith("${File.separator}strings.xml")){
            def languageCode = details.file.parent.tokenize(File.separator).last().replaceAll('values-','').replaceAll('-r','-')
            languageCode = (languageCode == "values") ? "en-US" : languageCode
            foundLocales.append("\"").append(languageCode).append("\"").append(",")
        }
    }

    foundLocales.append("}")
    def foundLocalesString = foundLocales.toString().replaceAll(',}','}')
    android.defaultConfig.buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", foundLocalesString
}

afterEvaluate {

    // Format test output. Ported from AC #2401
    tasks.withType(Test).configureEach {
        systemProperty "robolectric.logging", "stdout"
        systemProperty "logging.test-mode", "true"

        testLogging.events = []

        def out = services.get(StyledTextOutputFactory).create("tests")

        beforeSuite { descriptor ->
            if (descriptor.getClassName() != null) {
                out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
            }
        }

        beforeTest { descriptor ->
            out.style(Style.Description).println("  TEST: " + descriptor.getName())
        }

        onOutput { descriptor, event ->
            logger.lifecycle("    " + event.message.trim())
        }

        afterTest { descriptor, result ->
            switch (result.getResultType()) {
                case ResultType.SUCCESS:
                    out.style(Style.Success).println("  SUCCESS")
                    break

                case ResultType.FAILURE:
                    out.style(Style.Failure).println("  FAILURE")
                    logger.lifecycle("", result.getException())
                    break

                case ResultType.SKIPPED:
                    out.style(Style.Info).println("  SKIPPED")
                    break
            }
            logger.lifecycle("")
        }
    }
}

if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
    if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
        ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
    }
    ext.topsrcdir = StringUtils.removeSuffix(gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir", File.separator)
    apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
}

if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
    ext.gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
    apply from: "../${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
}

android.applicationVariants.all { variant ->
    tasks.register("apkSize${variant.name.capitalize()}", ApkSizeTask) {
        variantName = variant.name
        apks = variant.outputs.collect { output -> output.outputFile.name }
        dependsOn "package${variant.name.capitalize()}"
    }
}

// Enable expiration by major version.
ext.gleanExpireByVersion = Config.majorVersion()
