plugins {
    id 'org.sonarqube'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
// rules to allow test running with a real android jar implementation of URI, Uri.Builder for group link encoding
apply plugin: 'de.mobilej.unmock'
unMock {
    keepStartingWith "android.net.Uri"
    keep "android.net.Uri"
    keepAndRename "java.nio.charset.Charsets" to "xjava.nio.charset.Charsets"
    keepStartingWith "libcore."
}

// only apply the plugin if we are dealing with a AppGallery build
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Hms")) {
    println "enabling hms plugin"
    apply plugin: 'com.huawei.agconnect'
}

// version codes
def app_version = "4.67"
def beta_suffix = "" // with leading dash

/**
 * Return the git hash, if git is installed.
 */
def getGitHash = { ->
    def stdout = new ByteArrayOutputStream()
    def stderr = new ByteArrayOutputStream()
    try {
        exec {
            commandLine 'git', 'rev-parse', '--short', 'HEAD'
            standardOutput = stdout
            errorOutput = stderr
            ignoreExitValue true
        }
    } catch (ignored) { /* If git binary is not found, carry on */ }
    def hash = stdout.toString().trim()
    return (hash.isEmpty()) ? "?" : hash
}

/**
 * Look up the keystore with the specified name in a `keystore` directory
 * adjacent to this project directory. If it exists, return a signing config.
 * Otherwise, return null.
 */
def findKeystore = { name ->
    def basePath = "${projectDir.getAbsolutePath()}/../../keystore"
    def storePath = "${basePath}/${name}.keystore"
    def storeFile = new File(storePath)
    if (storeFile.exists() && storeFile.isFile()) {
        def propertiesPath = "${basePath}/${name}.properties"
        def propertiesFile = new File(propertiesPath)
        if (propertiesFile.exists() && propertiesFile.isFile()) {
            Properties props = new Properties()
            propertiesFile.withInputStream { props.load(it) }
            return [
                storeFile: storePath,
                storePassword: props.storePassword,
                keyAlias: props.keyAlias,
                keyPassword: props.keyPassword,
            ]
        } else {
            return [
                storeFile: storePath,
                storePassword: null,
                keyAlias: null,
                keyPassword: null,
            ]
        }
    }
}

/**
 * Map with keystore paths (if found).
 */
def keystores = [
    debug: findKeystore("debug"),
    release: findKeystore("threema"),
    hms_release: findKeystore("threema_hms"),
    onprem_release: findKeystore("onprem"),
    red_release: findKeystore("red"),
]

android {
    // NOTE: When adjusting compileSdkVersion, buildToolsVersion or ndkVersion,
    //       make sure to adjust them in `scripts/Dockerfile` and
    //       `.gitlab-ci.yml` as well!
    compileSdkVersion 30
    buildToolsVersion '30.0.3'
    ndkVersion '21.1.6352462'

    defaultConfig {
        minSdkVersion 21
        //noinspection OldTargetApi
        targetSdkVersion 30
        vectorDrawables.useSupportLibrary = true
        applicationId "ch.threema.app"
        testApplicationId 'ch.threema.app.test'
        versionCode 721
        versionName "${app_version}${beta_suffix}"
        resValue "string", "app_name", "Threema"
        // package name used for sync adapter - needs to match mime types below
        resValue "string", "package_name", applicationId
        resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.profile"
        resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.call"
        buildConfigField "int", "MAX_GROUP_SIZE", "256"
        buildConfigField "String", "CHAT_SERVER_PREFIX", "\"g-\""
        buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.g-\""
        buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.threema.ch\""
        buildConfigField "int[]", "CHAT_SERVER_PORTS", "{5222, 443}"
        buildConfigField "String", "MEDIA_PATH", "\"Threema\""
        buildConfigField "boolean", "CHAT_SERVER_GROUPS", "true"
        buildConfigField "boolean", "DISABLE_CERT_PINNING", "false"
        buildConfigField "boolean", "VIDEO_CALLS_ENABLED", "true"
        buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x45, (byte) 0x0b, (byte) 0x97, (byte) 0x57, (byte) 0x35, (byte) 0x27, (byte) 0x9f, (byte) 0xde, (byte) 0xcb, (byte) 0x33, (byte) 0x13, (byte) 0x64, (byte) 0x8f, (byte) 0x5f, (byte) 0xc6, (byte) 0xee, (byte) 0x9f, (byte) 0xf4, (byte) 0x36, (byte) 0x0e, (byte) 0xa9, (byte) 0x2a, (byte) 0x8c, (byte) 0x17, (byte) 0x51, (byte) 0xc6, (byte) 0x61, (byte) 0xe4, (byte) 0xc0, (byte) 0xd8, (byte) 0xc9, (byte) 0x09 }"
        buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0xda, (byte) 0x7c, (byte) 0x73, (byte) 0x79, (byte) 0x8f, (byte) 0x97, (byte) 0xd5, (byte) 0x87, (byte) 0xc3, (byte) 0xa2, (byte) 0x5e, (byte) 0xbe, (byte) 0x0a, (byte) 0x91, (byte) 0x41, (byte) 0x7f, (byte) 0x76, (byte) 0xdb, (byte) 0xcc, (byte) 0xcd, (byte) 0xda, (byte) 0x29, (byte) 0x30, (byte) 0xe6, (byte) 0xa9, (byte) 0x09, (byte) 0x0a, (byte) 0xf6, (byte) 0x2e, (byte) 0xba, (byte) 0x6f, (byte) 0x15 }"
        buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\""
        buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.threema.ch/\""
        buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.threema.ch/\""
        buildConfigField "String", "WORK_SERVER_URL", "null"
        buildConfigField "String", "WORK_SERVER_IPV6_URL", "null"
        buildConfigField "String", "BLOB_SERVER_DOWNLOAD_URL", "\"https://blobp-{blobIdPrefix}.threema.ch/{blobId}\""
        buildConfigField "String", "BLOB_SERVER_DOWNLOAD_IPV6_URL", "\"https://ds-blobp-{blobIdPrefix}.threema.ch/{blobId}\""
        buildConfigField "String", "BLOB_SERVER_DONE_URL", "\"https://blobp-{blobIdPrefix}.threema.ch/{blobId}/done\""
        buildConfigField "String", "BLOB_SERVER_DONE_IPV6_URL", "\"https://ds-blobp-{blobIdPrefix}.threema.ch/{blobId}/done\""
        buildConfigField "String", "BLOB_SERVER_UPLOAD_URL", "\"https://blobp-upload.threema.ch/upload\""
        buildConfigField "String", "BLOB_SERVER_UPLOAD_IPV6_URL", "\"https://ds-blobp-upload.threema.ch/upload\""
        buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.threema.ch/\""
        buildConfigField "String", "SAFE_SERVER_URL", "\"https://safe-%h.threema.ch/\""
        buildConfigField "String", "WEB_SERVER_URL", "\"https://web.threema.ch/\""
        buildConfigField "String", "ONPREM_ID_PREFIX", "\"O\""

        buildConfigField "String[]", "ONPREM_CONFIG_TRUSTED_PUBLIC_KEYS", "null"
        buildConfigField "boolean", "SEND_CONSUMED_DELIVERY_RECEIPTS", "false"

        // config fields for action URLs / deep links
        buildConfigField "String", "uriScheme", "\"threema\""
        buildConfigField "String", "actionUrl", "\"go.threema.ch\""
        buildConfigField "String", "contactActionUrl", "\"threema.id\""
        buildConfigField "String", "groupLinkActionUrl", "\"threema.group\""

        // duplicated for manifest
        manifestPlaceholders = [
            uriScheme: "threema",
            contactActionUrl: "threema.id",
            groupLinkActionUrl: "threema.group",
            actionUrl: "go.threema.ch"
        ]

        ndk {
            abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }

        testInstrumentationRunner 'ch.threema.app.ThreemaTestRunner'
        testInstrumentationRunnerArgument 'notAnnotation', 'ch.threema.app.TestFastlaneOnly,ch.threema.app.DangerousTest'
        testInstrumentationRunnerArgument 'disableAnalytics', 'true' // https://developer.android.com/training/testing/espresso/setup#analytics
    }

    splits {
        abi {
            enable true
            reset()
            include 'armeabi-v7a', 'x86', "arm64-v8a", "x86_64"
            exclude 'armeabi', 'mips', 'mips64'
            universalApk true
        }
    }

    // Assign different version code for each output
    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
    android.applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.versionCodeOverride =
                    project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
        }
    }

    flavorDimensions "default"
    productFlavors {
        none { }
        store_google { }
        store_threema {
            resValue "string", "shop_download_filename", "Threema-update.apk"
        }
        store_google_work {
            versionName "${app_version}k${beta_suffix}"
            applicationId "ch.threema.app.work"
            testApplicationId 'ch.threema.app.work.test'
            resValue "string", "app_name", "Threema Work"
            resValue "string", "package_name", applicationId
            resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile"
            resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call"
            buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
            buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
            buildConfigField "String", "MEDIA_PATH", "\"ThreemaWork\""
            buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.threema.ch/\""
            buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.threema.ch/\""

            // config fields for action URLs / deep links
            buildConfigField "String", "uriScheme", "\"threemawork\""
            buildConfigField "String", "actionUrl", "\"work.threema.ch\""

            manifestPlaceholders = [
                uriScheme: "threemawork",
                actionUrl: "work.threema.ch",
            ]
        }
        sandbox {
            applicationId "ch.threema.app.sandbox"
            testApplicationId 'ch.threema.app.sandbox.test'
            resValue "string", "app_name", "Threema Sandbox"
            resValue "string", "package_name", applicationId
            resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.profile"
            resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.call"
            buildConfigField "String", "MEDIA_PATH", "\"ThreemaSandbox\""
            buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
            buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
            buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
            buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.test.threema.ch/\""
            buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.test.threema.ch/\""
            buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.test.threema.ch/\""
        }
        sandbox_work {
            versionName "${app_version}k${beta_suffix}"
            applicationId "ch.threema.app.sandbox.work"
            testApplicationId 'ch.threema.app.sandbox.work.test'
            resValue "string", "app_name", "Threema Sandbox Work"
            resValue "string", "package_name", applicationId
            resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.work.profile"
            resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.work.call"
            buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
            buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
            buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
            buildConfigField "String", "MEDIA_PATH", "\"ThreemaWorkSandbox\""
            buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
            buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"

            buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.test.threema.ch/\""
            buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.test.threema.ch/\""
            buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.test.threema.ch/\""
            buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.test.threema.ch/\""
            buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.test.threema.ch/\""

            // config fields for action URLs / deep links
            buildConfigField "String", "uriScheme", "\"threemawork\""
            buildConfigField "String", "actionUrl", "\"work.threema.ch\""

            manifestPlaceholders = [
                uriScheme       : "threemawork",
                actionUrl       : "work.threema.ch",
            ]
        }
        onprem {
            versionName "${app_version}o${beta_suffix}"
            applicationId "ch.threema.app.onprem"
            testApplicationId 'ch.threema.app.onprem.test'
            resValue "string", "app_name", "Threema OnPrem"
            resValue "string", "package_name", applicationId
            resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.onprem.profile"
            resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.onprem.call"
            buildConfigField "int", "MAX_GROUP_SIZE", "256"
            buildConfigField "String", "CHAT_SERVER_PREFIX", "\"\""
            buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"\""
            buildConfigField "String", "CHAT_SERVER_SUFFIX", "null"
            buildConfigField "String", "MEDIA_PATH", "\"ThreemaOnPrem\""
            buildConfigField "boolean", "CHAT_SERVER_GROUPS", "false"

            buildConfigField "byte[]", "SERVER_PUBKEY", "null"
            buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "null"
            buildConfigField "String", "DIRECTORY_SERVER_URL", "null"
            buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "null"
            buildConfigField "String", "BLOB_SERVER_DOWNLOAD_URL", "null"
            buildConfigField "String", "BLOB_SERVER_DOWNLOAD_IPV6_URL", "null"
            buildConfigField "String", "BLOB_SERVER_DONE_URL", "null"
            buildConfigField "String", "BLOB_SERVER_DONE_IPV6_URL", "null"
            buildConfigField "String", "BLOB_SERVER_UPLOAD_URL", "null"
            buildConfigField "String", "BLOB_SERVER_UPLOAD_IPV6_URL", "null"
            buildConfigField "String[]", "ONPREM_CONFIG_TRUSTED_PUBLIC_KEYS", "new String[] {\"ek1qBp4DyRmLL9J5sCmsKSfwbsiGNB4veDAODjkwe/k=\", \"Hrk8aCjwKkXySubI7CZ3y9Sx+oToEHjNkGw98WSRneU=\", \"5pEn1T/5bhecNWrp9NgUQweRfgVtu/I8gRb3VxGP7k4=\"}"

            // config fields for action URLs / deep links
            buildConfigField "String", "uriScheme", "\"threemaonprem\""
            buildConfigField "String", "actionUrl", "\"onprem.threema.ch\""

            manifestPlaceholders = [
                uriScheme: "threemaonprem",
                actionUrl: "onprem.threema.ch",
            ]
        }

        red { // Essentially like sandbox work, but with a different icon and accent color, used for internal testing
            versionName "${app_version}r${beta_suffix}"
            applicationId "ch.threema.app.red"
            testApplicationId 'ch.threema.app.red.test'
            resValue "string", "app_name", "Threema Red"
            resValue "string", "package_name", applicationId
            resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.red.profile"
            resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.red.call"

            buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
            buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
            buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
            buildConfigField "String", "MEDIA_PATH", "\"ThreemaRed\""
            buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
            buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
            buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.test.threema.ch/\""
            buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.test.threema.ch/\""
            buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.test.threema.ch/\""
            buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.test.threema.ch/\""
            buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.test.threema.ch/\""

            buildConfigField "boolean", "SEND_CONSUMED_DELIVERY_RECEIPTS", "true"

            // config fields for action URLs / deep links
            buildConfigField "String", "uriScheme", "\"threemared\""
            buildConfigField "String", "actionUrl", "\"red.threema.ch\""

            manifestPlaceholders = [
                uriScheme: "threemared",
                actionUrl: "red.threema.ch",
            ]
        }
        hms {
            applicationId "ch.threema.app.hms"
        }
        hms_work {
            versionName "${app_version}k${beta_suffix}"
            applicationId "ch.threema.app.work.hms"
            testApplicationId 'ch.threema.app.work.test.hms'
            resValue "string", "app_name", "Threema Work"
            resValue "string", "package_name", "ch.threema.app.work"
            resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile"
            resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call"
            buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
            buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
            buildConfigField "String", "MEDIA_PATH", "\"ThreemaWork\""
            buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.threema.ch/\""
            buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.threema.ch/\""

            // config fields for action URLs / deep links
            buildConfigField "String", "uriScheme", "\"threemawork\""
            buildConfigField "String", "actionUrl", "\"work.threema.ch\""

            manifestPlaceholders = [
                uriScheme: "threemawork",
                actionUrl: "work.threema.ch",
            ]
        }
    }

    signingConfigs {
        // Debug config
        if (keystores.debug != null) {
            debug {
                storeFile file(keystores.debug.storeFile)
            }
        } else {
            logger.warn("No debug keystore found. Falling back to locally generated keystore.")
        }

        // Release config
        if (keystores.release != null) {
            release {
                storeFile file(keystores.release.storeFile)
                storePassword keystores.release.storePassword
                keyAlias keystores.release.keyAlias
                keyPassword keystores.release.keyPassword
            }
        } else {
            logger.warn("No release keystore found. Falling back to locally generated keystore.")
        }

        // Release config
        if (keystores.hms_release != null) {
            hms_release {
                storeFile file(keystores.hms_release.storeFile)
                storePassword keystores.hms_release.storePassword
                keyAlias keystores.hms_release.keyAlias
                keyPassword keystores.hms_release.keyPassword
            }
        } else {
            logger.warn("No hms keystore found. Falling back to locally generated keystore.")
        }

        // Onprem release config
        if (keystores.onprem_release != null) {
            onprem_release {
                storeFile file(keystores.onprem_release.storeFile)
                storePassword keystores.onprem_release.storePassword
                keyAlias keystores.onprem_release.keyAlias
                keyPassword keystores.onprem_release.keyPassword
            }
        } else {
            logger.warn("No onprem keystore found. Falling back to locally generated keystore.")
        }

        // Red release config
        if (keystores.red_release != null) {
            red_release {
                storeFile file(keystores.red_release.storeFile)
                storePassword keystores.red_release.storePassword
                keyAlias keystores.red_release.keyAlias
                keyPassword keystores.red_release.keyPassword
            }
        } else {
            logger.warn("No red keystore found. Falling back to locally generated keystore.")
        }
    }

    sourceSets {
        main {
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }
        none {
            java.srcDir 'src/google_services_based/java'
        }
        store_google {
            java.srcDir 'src/google_services_based/java'
        }
        store_google_work {
            java.srcDir 'src/google_services_based/java'
        }
        store_threema {
            java.srcDir 'src/google_services_based/java'
        }
        hms {
            java.srcDir 'src/hms_services_based/java'
        }
        hms_work {
            java.srcDir 'src/hms_services_based/java'
            res.srcDir 'src/store_google_work/res'
        }
        onprem {
            java.srcDir 'src/google_services_based/java'
        }
        sandbox {
            java.srcDir 'src/google_services_based/java'
            manifest.srcFile 'src/store_google/AndroidManifest.xml'
        }
        sandbox_work {
            java.srcDirs = ['src/store_google_work/java', 'src/google_services_based/java']
            res.srcDir 'src/store_google_work/res'
            manifest.srcFile 'src/store_google_work/AndroidManifest.xml'
        }
        red {
            java.srcDir 'src/google_services_based/java'
            res.srcDir 'src/red/res'
        }
    }

    buildTypes {
        debug {
            debuggable true
            jniDebuggable false
            multiDexEnabled true
            multiDexKeepProguard file('multidex-keep.pro')
            testCoverageEnabled false

            if (keystores['debug'] != null) {
                signingConfig signingConfigs.debug
            }
        }
        release {
            debuggable false
            jniDebuggable false
            minifyEnabled true
            shrinkResources false // Caused inconsistencies between local and CI builds
            zipAlignEnabled true
            multiDexEnabled true
            multiDexKeepProguard file('multidex-keep.pro')
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-project.txt'

            if (keystores['release'] != null) {
                productFlavors.store_google.signingConfig signingConfigs.release
                productFlavors.store_google_work.signingConfig signingConfigs.release
                productFlavors.store_threema.signingConfig signingConfigs.release
                productFlavors.sandbox.signingConfig signingConfigs.release
                productFlavors.sandbox_work.signingConfig signingConfigs.release
                productFlavors.none.signingConfig signingConfigs.release
            }

            if (keystores['hms_release'] != null) {
                productFlavors.hms.signingConfig signingConfigs.hms_release
                productFlavors.hms_work.signingConfig signingConfigs.hms_release
            }

            if (keystores['onprem_release'] != null) {
                productFlavors.onprem.signingConfig signingConfigs.onprem_release
            }

            if (keystores['red_release'] != null) {
                productFlavors.red.signingConfig signingConfigs.red_release
            }
        }
    }

    // Only build relevant buildType / flavor combinations
    variantFilter { variant ->
        def names = variant.flavors*.name

        if (
            variant.buildType.name == "release" && (
                names.contains("sandbox") || names.contains("sandbox_work")
            )
        ) {
            setIgnore(true)
        }
    }


    externalNativeBuild {
        ndkBuild {
            path 'jni/Android.mk'
        }
    }

    lintOptions {
        // set to true to have all release builds run lint on issues with severity=fatal
        // and abort the build (controlled by abortOnError above) if fatal issues are found
        checkReleaseBuilds true
        // set to true to turn off analysis progress reporting by lint
        // quiet true
        // if true, stop the gradle build if errors are found
        abortOnError true
        // if true, only report errors
        ignoreWarnings false
        // if true, emit full/absolute paths to files with errors (true by default)
        //absolutePaths true
        // if true, check all issues, including those that are off by default
        checkAllWarnings true
        // if true, treat all warnings as errors
        warningsAsErrors false
        // turn off checking the given issue id's
        disable 'TypographyFractions', 'TypographyQuotes'
        // turn on the given issue id's
        disable 'RtlHardcoded', 'RtlCompat', 'RtlEnabled'
        // check *only* the given issue id's
        // check 'NewApi', 'InlinedApi'
        // if true, don't include source code lines in the error output
        noLines false
        // if true, show all locations for an error, do not truncate lists, etc.
        showAll true
        // if true, generate an XML report for use by for example Jenkins
        xmlReport true
        // file to write report to (if not specified, defaults to lint-results.xml)
        xmlOutput file("lint-report.xml")

        // Set the severity of the given issues to fatal (which means they will be
        // checked during release builds (even if the lint target is not included)
        fatal 'NewApi', 'InlinedApi'
        // Set the severity of the given issues to error
        error 'Wakelock', 'TextViewEdits', 'ResourceAsColor'
        // Set the severity of the given issues to warning
        warning 'MissingTranslation'
        // Set the severity of the given issues to ignore (same as disabling the check)
        ignore 'TypographyQuotes'
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
        exclude '**/*.proto'
        // fix https://stackoverflow.com/questions/42739916/aarch64-linux-android-strip-file-missing
        doNotStrip '*/mips/*.so'
        doNotStrip '*/mips64/*.so'
        doNotStrip '*/armeabi/*.so'
    }

    testOptions {
        // Disable animations in instrumentation tests
        animationsDisabled true

        unitTests {
            all {
                // All the usual Gradle options.
                testLogging {
                    events "passed", "skipped", "failed", "standardOut", "standardError"
                    outputs.upToDateWhen { false }
                    exceptionFormat = 'full'
                }
            }
            // By default, local unit tests throw an exception any time the code you are testing tries to access
            // Android platform APIs (unless you mock Android dependencies yourself or with a testing
            // framework like Mockito). However, you can enable the following property so that the test
            // returns either null or zero when accessing platform APIs, rather than throwing an exception.
            returnDefaultValues true
        }
    }

    compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
    }

    aaptOptions {
        noCompress 'png'
    }
}

dependencies {
    configurations.all {
        // Prefer modules that are part of this build (multi-project or composite build)
        // over external modules
        resolutionStrategy.preferProjectModules()

        // Alternatively, we can fail eagerly on version conflict to see the conflicts
        //resolutionStrategy.failOnVersionConflict()
    }

    implementation project(':domain')

    implementation 'net.zetetic:android-database-sqlcipher:4.5.0'

    implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
    implementation 'net.sf.opencsv:opencsv:2.3'
    implementation 'net.lingala.zip4j:zip4j:2.9.1'
    implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.2'
    implementation 'org.maplibre.gl:android-sdk:9.5.2'
    // commons-io >2.6 requires android 8
    implementation 'commons-io:commons-io:2.6'
    implementation "org.slf4j:slf4j-api:$slf4j_version"
    implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.23'
    implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
    implementation 'com.datatheorem.android.trustkit:trustkit:1.1.5'
    implementation 'com.takisoft.preferencex:preferencex:1.1.0'
    implementation 'me.zhanghai.android.fastscroll:library:1.1.5'

    // AndroidX / Jetpack support libraries
    implementation "androidx.core:core:1.6.0"
    implementation "androidx.preference:preference:1.1.1"
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    implementation 'androidx.palette:palette:1.0.0'
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
    implementation 'androidx.biometric:biometric:1.1.0'
    implementation "androidx.work:work-runtime:2.6.0"
    implementation 'androidx.fragment:fragment:1.3.6'
    implementation 'androidx.activity:activity:1.3.1'
    implementation 'androidx.sqlite:sqlite:2.1.0'
    implementation "androidx.concurrent:concurrent-futures:1.1.0"
    implementation "androidx.camera:camera-camera2:1.0.2"
    implementation "androidx.camera:camera-lifecycle:1.0.2"
    // camera-view >1.0.0-alpha25 requires compileSDK 30
    implementation "androidx.camera:camera-view:1.0.0-alpha25"
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.1"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
    implementation "androidx.lifecycle:lifecycle-livedata:2.3.1"
    implementation "androidx.lifecycle:lifecycle-runtime:2.3.1"
    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1"
    implementation "androidx.lifecycle:lifecycle-service:2.3.1"
    implementation "androidx.lifecycle:lifecycle-process:2.3.1"
    implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation "androidx.paging:paging-runtime:3.0.1"
    implementation "androidx.sharetarget:sharetarget:1.1.0"

    implementation 'com.google.android.material:material:1.4.0'
    implementation 'com.google.android.exoplayer:exoplayer-core:2.15.1'
    implementation 'com.google.android.exoplayer:exoplayer-ui:2.15.1'
    implementation 'com.google.zxing:core:3.3.3' // zxing 3.4 crashes on kitkat
    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.41' // make sure to update this in domain's build.gradle as well

    // webclient dependencies
    implementation 'org.msgpack:msgpack-core:0.8.22!!'
    implementation 'com.neovisionaries:nv-websocket-client:2.9'

    // Backport of Streams and CompletableFuture. Remove once API level 24 is supported.
    implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.2'

    // Google Assistant Voice Action verification library
    implementation(name: 'libgsaverification-client', ext: 'aar')

    implementation('org.saltyrtc:saltyrtc-client:0.14.2') {
        exclude group: 'org.json'
    }

    implementation 'org.saltyrtc:chunked-dc:1.0.1'
    implementation 'ch.threema:webrtc-android:94.0.0'
    implementation('org.saltyrtc:saltyrtc-task-webrtc:0.18.1') {
        exclude module: 'saltyrtc-client'
    }

    // Glide components
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

    // kotlin
    implementation "androidx.core:core-ktx:1.3.2"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"

    // use leak canary in debug builds
//    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'

    // test dependencies
    testImplementation 'junit:junit:4.12'
    testImplementation(testFixtures(project(":domain")))

    // use powermock instead of mockito. it support mocking static classes.
    def mockitoVersion = '2.0.7'
    testImplementation "org.powermock:powermock-api-mockito2:${mockitoVersion}"
    testImplementation "org.powermock:powermock-module-junit4-rule-agent:${mockitoVersion}"
    testImplementation "org.powermock:powermock-module-junit4-rule:${mockitoVersion}"
    testImplementation "org.powermock:powermock-module-junit4:${mockitoVersion}"

    // add JSON support to tests without mocking
    testImplementation 'org.json:json:20160212'

    testImplementation 'com.tngtech.archunit:archunit-junit4:0.18.0'

    androidTestImplementation(testFixtures(project(":domain")))
    androidTestImplementation 'androidx.test:rules:1.2.0'
    androidTestImplementation 'tools.fastlane:screengrab:2.0.0', {
        exclude group: 'androidx.annotation', module: 'annotation'
    }
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0', {
        exclude group: 'androidx.annotation', module: 'annotation'
    }
    androidTestImplementation 'androidx.test:runner:1.1.0', {
        exclude group: 'androidx.annotation', module: 'annotation'
    }
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.0', {
        exclude group: 'androidx.annotation', module: 'annotation'
        exclude group: 'androidx.appcompat', module: 'appcompat'
        exclude group: 'androidx.legacy', module: 'legacy-support-v4'
        exclude group: 'com.google.android.material', module: 'material'
        exclude group: 'androidx.recyclerview', module: 'recyclerview'
    }
    androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0', {
        exclude group: 'androidx.annotation', module: 'annotation'
    }
    androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'

    // Google Play Services and related libraries
    def googleDependencies = [
        // Play services
        'com.google.android.gms:play-services-base:16.1.0': [],

        // Firebase push
        //
        // Note: Do not upgrade to a higher version of firebase-messaging,
        //       as we do not want the Firebase Installations API in our app
        'com.google.firebase:firebase-messaging:20.1.0': [
            [group: 'com.google.firebase', module: 'firebase-core'],
            [group: 'com.google.firebase', module: 'firebase-analytics'],
            [group: 'com.google.firebase', module: 'firebase-measurement-connector'],
        ],
    ]
    googleDependencies.each {
        def dependency = it.key
        def excludes = it.value
        noneImplementation(dependency) { excludes.each { exclude it } }
        store_googleImplementation(dependency) { excludes.each { exclude it } }
        store_google_workImplementation(dependency) { excludes.each { exclude it } }
        store_threemaImplementation(dependency) { excludes.each { exclude it } }
        onpremImplementation(dependency) { excludes.each { exclude it } }
        sandboxImplementation(dependency) { excludes.each { exclude it } }
        sandbox_workImplementation(dependency) { excludes.each { exclude it } }
        redImplementation(dependency) { excludes.each { exclude it } }
    }

    // Huawei related libraries (only for hms* build variants)
    def huaweiDependencies = [
        // HMS push
        'com.huawei.hms:push:5.0.4.302': [
            // Exclude agconnect dependency, we'll replace it with the vendored version below
            [group: 'com.huawei.agconnect'],
        ],
    ]
    huaweiDependencies.each {
        def dependency = it.key
        def excludes = it.value
        hmsImplementation(dependency) { excludes.each { exclude it } }
        hms_workImplementation(dependency) { excludes.each { exclude it } }
    }
    hmsImplementation(name: 'agconnect-core-1.4.0.300', ext: 'aar')
    hms_workImplementation(name: 'agconnect-core-1.4.0.300', ext: 'aar')
}

sonarqube {
    properties {
        property "sonar.sources", "src/main/, ../scripts/, ../scripts-internal/"
        property "sonar.exclusions", "src/main/java/ch/threema/localcrypto/**, src/test/java/ch/threema/localcrypto/**"
        property "sonar.tests", "src/testNoneDebug/"
        property "sonar.sourceEncoding", "UTF-8"
        property "sonar.verbose", "true"
        property 'sonar.projectKey', 'android-client'
        property 'sonar.projectName', 'Threema for Android'
    }
}

// Set up Gradle tasks to fetch screenshots on UI test failures
// See https://medium.com/stepstone-tech/how-to-capture-screenshots-for-failed-ui-tests-9927eea6e1e4
def reportsDirectory = "$buildDir/reports/androidTests/connected"
def screenshotsDirectory = "/sdcard/testfailures/screenshots/"
def clearScreenshotsTask = task('clearScreenshots', type: Exec) {
    executable "${android.getAdbExe().toString()}"
    args 'shell', 'rm', '-r', screenshotsDirectory
}
def createScreenshotsDirectoryTask = task('createScreenshotsDirectory', type: Exec, group: 'reporting') {
    executable "${android.getAdbExe().toString()}"
    args 'shell', 'mkdir', '-p', screenshotsDirectory
}
def fetchScreenshotsTask = task('fetchScreenshots', type: Exec, group: 'reporting') {
    executable "${android.getAdbExe().toString()}"
    args 'pull', screenshotsDirectory + '.', reportsDirectory
    finalizedBy {
        clearScreenshotsTask
    }
    dependsOn {
        createScreenshotsDirectoryTask
    }
    doFirst {
        new File(reportsDirectory).mkdirs()
    }
}
tasks.whenTaskAdded { task ->
    if (task.name == 'connectedDebugAndroidTest') {
        task.finalizedBy {
            fetchScreenshotsTask
        }
    }
}
