diff options
Diffstat (limited to 'mobile/android/fenix/app/build.gradle')
-rw-r--r-- | mobile/android/fenix/app/build.gradle | 934 |
1 files changed, 934 insertions, 0 deletions
diff --git a/mobile/android/fenix/app/build.gradle b/mobile/android/fenix/app/build.gradle new file mode 100644 index 0000000000..a3e5442372 --- /dev/null +++ b/mobile/android/fenix/app/build.gradle @@ -0,0 +1,934 @@ +import com.android.build.api.variant.FilterConfiguration +import org.apache.tools.ant.util.StringUtils + +plugins { + id "com.jetbrains.python.envs" version "$python_envs_plugin" + id "com.google.protobuf" version "$protobuf_plugin" +} + +if (findProject(":geckoview") != null) { + buildDir "${topobjdir}/gradle/build/mobile/android/fenix" +} + +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' + +if (findProject(":geckoview") != null) { + apply from: "${topsrcdir}/mobile/android/gradle/product_flavors.gradle" +} + +import groovy.json.JsonOutput +import org.gradle.internal.logging.text.StyledTextOutput.Style +import org.gradle.internal.logging.text.StyledTextOutputFactory +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +import static org.gradle.api.tasks.testing.TestResult.ResultType + +apply from: 'benchmark.gradle' + +android { + 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 "org.mozilla" + minSdkVersion config.minSdkVersion + compileSdk config.compileSdkVersion + 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", "VCS_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 + ] + + buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", getSupportedLocales() + } + + 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 vcs hash in release builds to avoid possible recompilation in debug builds. + buildConfigField "String", "VCS_HASH", "\"${Config.getVcsHash()}\"" + + 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®exp=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®exp=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, + ]) + } + benchmark releaseTemplate >> { + initWith buildTypes.nightly + applicationIdSuffix ".fenix" + debuggable false + } + } + + buildFeatures { + viewBinding true + buildConfig 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 + } + + if (findProject(":geckoview") != null) { + project.configureProductFlavors.delegate = it + project.configureProductFlavors() + } + + flavorDimensions.add("product") + + productFlavors { + fenix { + dimension "product" + } + } + + sourceSets { + androidTest { + resources.srcDirs += ['src/androidTest/resources'] + } + } + + splits { + abi { + enable true + + reset() + + // As gradle is unable to pick the right apk to install when multiple apks are generated + // while running benchmark tests or generating baseline profiles. To circumvent this, + // this flag is passed to make sure only one apk is generated so gradle can pick that one. + if (project.hasProperty("benchmarkTest")) { + include "arm64-v8a" + } else { + include "x86", "armeabi-v7a", "arm64-v8a", "x86_64" + } + } + } + + bundle { + // Profiler issues require us to temporarily package native code compressed to + // match the previous APK packaging. + // https://bugzilla.mozilla.org/show_bug.cgi?id=1865634 + packagingOptions { + jniLibs { + it.useLegacyPackaging = true + } + } + + language { + // Because we have runtime language selection we will keep all strings and languages + // in the base APKs. + enableSplit = false + } + } + + 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'] + } + jniLibs { + useLegacyPackaging true + } + } + + + 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.configureEach { 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(project)}" : + "${Config.releaseVersionName(project)}" + println("versionName override: $versionName") + + variant.outputs.each { output -> + def isMozillaOnline = project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline") + def abi = output.getFilter(FilterConfiguration.FilterType.ABI.name()) + // If it is a Mozilla Online build, use a unified version code of armeabi-v7a + def arch = (isMozillaOnline) ? "armeabi-v7a" : abi + def aab = project.hasProperty("aab") + // 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, aab) + + 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', 'true' + // 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', 'true' + } 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() + 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("--") + } + +// ------------------------------------------------------------------------------------------------- +// BuildConfig: Set flag to disable LeakCanary in debug (on CI builds) +// ------------------------------------------------------------------------------------------------- + + if (isDebug) { + if (project.hasProperty("disableLeakCanary") || gradle.hasProperty("localProperties.disableLeakCanary")) { + buildConfigField "boolean", "LEAKCANARY", "false" + println("LeakCanary enabled in debug: false") + } else { + buildConfigField "boolean", "LEAKCANARY", "true" + println("LeakCanary enabled in debug: true") + } + } else { + buildConfigField "boolean", "LEAKCANARY", "false" + } +} + +// 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", + fenixBenchmark: "developer", + withGeckoBinariesFenixDebug: "developer", + withGeckoBinariesFenixNightly: "nightly", + withGeckoBinariesFenixBeta: "beta", + withGeckoBinariesFenixRelease: "release", + withGeckoBinariesFenixBenchmark: "developer", + withoutGeckoBinariesFenixDebug: "developer", + withoutGeckoBinariesFenixNightly: "nightly", + withoutGeckoBinariesFenixBeta: "beta", + withoutGeckoBinariesFenixRelease: "release", + withoutGeckoBinariesFenixBenchmark: "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" + applicationServicesDir = gradle.hasProperty('localProperties.autoPublish.application-services.dir') + ? gradle.getProperty('localProperties.autoPublish.application-services.dir') : null +} + +tasks.withType(KotlinCompile).configureEach { + kotlinOptions.freeCompilerArgs += "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" +} + +dependencies { + implementation platform(ComponentsDependencies.androidx_compose_bom) + androidTestImplementation platform(ComponentsDependencies.androidx_compose_bom) + + 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 + + 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-fxsuggest') + 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-push-firebase') + implementation project(':lib-state') + implementation project(':lib-dataprotect') + testImplementation project(':support-test-fakes') + + debugImplementation 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 ComponentsDependencies.androidx_biometric + implementation ComponentsDependencies.androidx_paging + implementation ComponentsDependencies.androidx_preferences + implementation ComponentsDependencies.androidx_fragment + implementation ComponentsDependencies.androidx_navigation_fragment + implementation ComponentsDependencies.androidx_navigation_ui + implementation ComponentsDependencies.androidx_compose_navigation + implementation ComponentsDependencies.androidx_recyclerview + implementation ComponentsDependencies.androidx_swiperefreshlayout + + implementation ComponentsDependencies.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_lifecycle_service + + 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 + + implementation FenixDependencies.adjust + implementation FenixDependencies.installreferrer // Required by Adjust + + implementation FenixDependencies.google_ads_id // Required for the Google Advertising ID + + // Required for in-app reviews + implementation FenixDependencies.google_play_review + implementation FenixDependencies.google_play_review_ktx + + implementation FenixDependencies.androidx_profileinstaller + + 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 ComponentsDependencies.testing_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") + lintChecks project(':tooling-lint') +} + +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.configureEach { variant -> + tasks.register("jacoco${variant.name.capitalize()}TestReport", JacocoReport) { + dependsOn "test${variant.name.capitalize()}UnitTest" + + reports { + xml.required = true + html.required = true + } + + def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', + '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*'] + def kotlinDebugTree = fileTree(dir: "$project.layout.buildDirectory/tmp/kotlin-classes/${variant.name}", excludes: fileFilter) + def javaDebugTree = fileTree(dir: "$project.layout.buildDirectory/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.layout.buildDirectory, includes: [ + "jacoco/test${variant.name.capitalize()}UnitTest.exec", + 'outputs/code-coverage/connected/*coverage.ec' + ])) + } + } + + android { + buildTypes { + debug { + 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(FilterConfiguration.FilterType.ABI.name()), + 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) + } +} + +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: + def testId = descriptor.getClassName() + "." + descriptor.getName() + out.style(Style.Failure).println(" TEST-UNEXPECTED-FAIL | " + testId + " | " + 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.configureEach { variant -> + tasks.register("apkSize${variant.name.capitalize()}", ApkSizeTask) { + variantName = variant.name + apks = variant.outputs.collect { output -> output.outputFile.name } + dependsOn "package${variant.name.capitalize()}" + } +} + +def getSupportedLocales() { + // 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(',}', '}') + return foundLocalesString +} + +// Enable expiration by major version. +ext.gleanExpireByVersion = Config.majorVersion(project) |