1 import org.apache.tools.ant.util.StringUtils
4 id "com.jetbrains.python.envs" version "$python_envs_plugin"
5 id "com.google.protobuf" version "$protobuf_plugin"
8 apply plugin: 'com.android.application'
9 apply plugin: 'kotlin-android'
10 apply plugin: 'kotlin-parcelize'
11 apply plugin: 'jacoco'
12 apply plugin: 'androidx.navigation.safeargs.kotlin'
13 apply plugin: 'com.google.android.gms.oss-licenses-plugin'
15 import com.android.build.OutputFile
16 import groovy.json.JsonOutput
17 import org.gradle.internal.logging.text.StyledTextOutput.Style
18 import org.gradle.internal.logging.text.StyledTextOutputFactory
20 import static org.gradle.api.tasks.testing.TestResult.ResultType
22 apply from: 'benchmark.gradle'
25 compileSdkVersion config.compileSdkVersion
27 project.maybeConfigForJetpackBenchmark(it)
28 if (project.hasProperty("testBuildType")) {
29 // Allowing to configure the test build type via command line flag (./gradlew -PtestBuildType=beta ..)
30 // in order to run UI tests against other build variants than debug in automation.
31 testBuildType project.property("testBuildType")
35 applicationId "org.mozilla"
36 minSdkVersion config.minSdkVersion
37 targetSdkVersion config.targetSdkVersion
39 versionName Config.generateDebugVersionName()
40 vectorDrawables.useSupportLibrary = true
41 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
42 testInstrumentationRunnerArguments clearPackageData: 'true'
43 resValue "bool", "IS_DEBUG", "false"
44 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false"
45 buildConfigField "String", "GIT_HASH", "\"\"" // see override in release builds for why it's blank.
46 // This should be the "public" base URL of AMO.
47 buildConfigField "String", "AMO_BASE_URL", "\"https://addons.mozilla.org\""
48 buildConfigField "String", "AMO_COLLECTION_NAME", "\"Extensions-for-Android\""
49 buildConfigField "String", "AMO_COLLECTION_USER", "\"mozilla\""
50 // These add-ons should be excluded for Mozilla Online builds.
51 buildConfigField "String[]", "MOZILLA_ONLINE_ADDON_EXCLUSIONS",
53 "\"uBlock0@raymondhill.net\"," +
54 "\"firefox@ghostery.com\"," +
55 "\"jid1-MnnxcxisBPnSXQ@jetpack\"," +
56 "\"adguardadblocker@adguard.com\"," +
57 "\"foxyproxy@eric.h.jung\"," +
58 "\"{73a6fe31-595d-460b-a920-fcc0f8843232}\"," +
59 "\"jid1-BoFifL9Vbdl2zQ@jetpack\"," +
60 "\"woop-NoopscooPsnSXQ@jetpack\"," +
61 "\"adnauseam@rednoise.org\"" +
63 // This should be the base URL used to call the AMO API.
64 buildConfigField "String", "AMO_SERVER_URL", "\"https://services.addons.mozilla.org\""
66 def deepLinkSchemeValue = "fenix-dev"
67 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
69 // This allows overriding the target activity for MozillaOnline builds, which happens
70 // as part of the defaultConfig below.
71 def targetActivity = "HomeActivity"
73 // Build flag for "Mozilla Online" variants. See `Config.isMozillaOnline`.
74 if (project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")) {
75 buildConfigField "boolean", "MOZILLA_ONLINE", "true"
76 targetActivity = "MozillaOnlineHomeActivity"
78 buildConfigField "boolean", "MOZILLA_ONLINE", "false"
81 manifestPlaceholders = [
82 "targetActivity": targetActivity,
83 "deepLinkScheme": deepLinkSchemeValue
87 def releaseTemplate = {
88 // We allow disabling optimization by passing `-PdisableOptimization` to gradle. This is used
89 // in automation for UI testing non-debug builds.
90 shrinkResources !project.hasProperty("disableOptimization")
91 minifyEnabled !project.hasProperty("disableOptimization")
92 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
93 matchingFallbacks = ['release'] // Use on the "release" build type in dependencies (AARs)
95 // Changing the build config can cause files that depend on BuildConfig.java to recompile
96 // so we only set the git hash in release builds to avoid possible recompilation in debug builds.
97 buildConfigField "String", "GIT_HASH", "\"${Config.getGitHash()}\""
99 if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) {
100 signingConfig signingConfigs.debug
103 if (gradle.hasProperty("localProperties.debuggable")) {
110 shrinkResources false
112 applicationIdSuffix ".fenix.debug"
113 resValue "bool", "IS_DEBUG", "true"
114 pseudoLocalesEnabled true
116 nightly releaseTemplate >> {
117 applicationIdSuffix ".fenix"
118 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
119 def deepLinkSchemeValue = "fenix-nightly"
120 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
121 manifestPlaceholders.putAll([
122 "deepLinkScheme": deepLinkSchemeValue
125 beta releaseTemplate >> {
126 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
127 applicationIdSuffix ".firefox_beta"
128 def deepLinkSchemeValue = "fenix-beta"
129 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
130 manifestPlaceholders.putAll([
131 // This release type is meant to replace Firefox (Beta channel) and therefore needs to inherit
132 // its sharedUserId for all eternity. See:
133 // https://searchfox.org/mozilla-esr68/search?q=moz_android_shared_id&case=false®exp=false&path=
134 // Shipping an app update without sharedUserId can have
135 // fatal consequences. For example see:
136 // - https://issuetracker.google.com/issues/36924841
137 // - https://issuetracker.google.com/issues/36905922
138 "sharedUserId": "org.mozilla.firefox.sharedID",
139 "deepLinkScheme": deepLinkSchemeValue,
142 release releaseTemplate >> {
143 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
144 applicationIdSuffix ".firefox"
145 def deepLinkSchemeValue = "fenix"
146 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
147 manifestPlaceholders.putAll([
148 // This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
149 // its sharedUserId for all eternity. See:
150 // https://searchfox.org/mozilla-esr68/search?q=moz_android_shared_id&case=false®exp=false&path=
151 // Shipping an app update without sharedUserId can have
152 // fatal consequences. For example see:
153 // - https://issuetracker.google.com/issues/36924841
154 // - https://issuetracker.google.com/issues/36905922
155 "sharedUserId": "org.mozilla.firefox.sharedID",
156 "deepLinkScheme": deepLinkSchemeValue,
159 benchmark releaseTemplate >> {
160 initWith buildTypes.nightly
161 applicationIdSuffix ".fenix"
171 // All JavaScript code used internally by GeckoView is packaged in a
172 // file called omni.ja. If this file is compressed in the APK,
173 // GeckoView must uncompress it before it can do anything else which
174 // causes a significant delay on startup.
177 // manifest.template.json is converted to manifest.json at build time.
178 // No need to package the template in the APK.
179 ignoreAssetsPattern "manifest.template.json"
183 execution 'ANDROIDX_TEST_ORCHESTRATOR'
184 unitTests.includeAndroidResources = true
185 animationsDisabled = true
188 flavorDimensions "engine"
190 flavorDimensions "product"
200 resources.srcDirs += ['src/androidTest/resources']
210 include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
215 sourceCompatibility JavaVersion.VERSION_17
216 targetCompatibility JavaVersion.VERSION_17
220 lintConfig file("lint.xml")
221 baseline file("lint-baseline.xml")
225 excludes += ['META-INF/atomicfu.kotlin_module', 'META-INF/AL2.0', 'META-INF/LGPL2.1',
226 'META-INF/LICENSE.md', 'META-INF/LICENSE-notice.md']
232 unitTests.returnDefaultValues = true
235 // We keep running into memory issues when running our tests. With this config we
236 // reserve more memory and also create a new process after every 80 test classes. This
237 // is a band-aid solution and eventually we should try to find and fix the leaks
240 maxHeapSize = "3072m"
241 minHeapSize = "1024m"
250 kotlinCompilerExtensionVersion = Versions.compose_compiler
253 namespace 'org.mozilla.fenix'
256 android.applicationVariants.all { variant ->
258 // -------------------------------------------------------------------------------------------------
259 // Generate version codes for builds
260 // -------------------------------------------------------------------------------------------------
262 def isDebug = variant.buildType.resValues['bool/IS_DEBUG']?.value ?: false
263 def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false
265 println("----------------------------------------------")
266 println("Variant name: " + variant.name)
267 println("Application ID: " + [variant.applicationId, variant.buildType.applicationIdSuffix].findAll().join())
268 println("Build type: " + variant.buildType.name)
269 println("Flavor: " + variant.flavorName)
270 println("Telemetry enabled: " + !isDebug)
272 if (useReleaseVersioning) {
273 // The Google Play Store does not allow multiple APKs for the same app that all have the
274 // same version code. Therefore we need to have different version codes for our ARM and x86
277 def versionName = variant.buildType.name == 'nightly' ? Config.nightlyVersionName() : Config.releaseVersionName(project)
278 println("versionName override: $versionName")
280 variant.outputs.each { output ->
281 def isMozillaOnline = project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")
282 def abi = output.getFilter(OutputFile.ABI)
283 // If it is a Mozilla Online build, use a unified version code of armeabi-v7a
284 def arch = (isMozillaOnline) ? "armeabi-v7a" : abi
285 // We use the same version code generator, that we inherited from Fennec, across all channels - even on
286 // channels that never shipped a Fennec build.
287 def versionCodeOverride = Config.generateFennecVersionCode(arch)
289 println("versionCode for $abi = $versionCodeOverride, isMozillaOnline = $isMozillaOnline")
291 if (versionName != null) {
292 output.versionNameOverride = versionName
294 output.versionCodeOverride = versionCodeOverride
296 } else if (gradle.hasProperty("localProperties.branchBuild.fenix.version")) {
297 def versionName = gradle.getProperty("localProperties.branchBuild.fenix.version")
298 println("versionName override: $versionName")
299 variant.outputs.each { output ->
300 output.versionNameOverride = versionName
304 // -------------------------------------------------------------------------------------------------
305 // BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
306 // -------------------------------------------------------------------------------------------------
308 buildConfigField 'String', 'SENTRY_TOKEN', 'null'
310 buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
311 // Reading sentry token from local file (if it exists). In a release task on taskcluster it will be available.
313 def token = new File("${rootDir}/.sentry_token").text.trim()
314 buildConfigField 'String', 'SENTRY_TOKEN', '"' + token + '"'
315 } catch (FileNotFoundException ignored) {}
317 buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
321 buildConfigField 'boolean', 'TELEMETRY', 'true'
323 buildConfigField 'boolean', 'TELEMETRY', 'false'
326 def buildDate = Config.generateBuildDate()
327 // Setting buildDate with every build changes the generated BuildConfig, which slows down the
328 // build. Only do this for non-debug builds, to speed-up builds produced during local development.
330 buildConfigField 'String', 'BUILD_DATE', '"debug build"'
332 buildConfigField 'String', 'BUILD_DATE', '"' + buildDate + '"'
335 // -------------------------------------------------------------------------------------------------
336 // Adjust: Read token from local file if it exists (Only release builds)
337 // -------------------------------------------------------------------------------------------------
339 print("Adjust token: ")
343 def token = new File("${rootDir}/.adjust_token").text.trim()
344 buildConfigField 'String', 'ADJUST_TOKEN', '"' + token + '"'
345 println "(Added from .adjust_token file)"
346 } catch (FileNotFoundException ignored) {
347 buildConfigField 'String', 'ADJUST_TOKEN', 'null'
351 buildConfigField 'String', 'ADJUST_TOKEN', 'null'
355 // -------------------------------------------------------------------------------------------------
356 // MLS: Read token from local file if it exists
357 // -------------------------------------------------------------------------------------------------
362 def token = new File("${rootDir}/.mls_token").text.trim()
363 buildConfigField 'String', 'MLS_TOKEN', '"' + token + '"'
364 println "(Added from .mls_token file)"
365 } catch (FileNotFoundException ignored) {
366 buildConfigField 'String', 'MLS_TOKEN', '""'
370 // -------------------------------------------------------------------------------------------------
371 // Nimbus: Read endpoint from local.properties of a local file if it exists
372 // -------------------------------------------------------------------------------------------------
374 print("Nimbus endpoint: ")
378 def url = new File("${rootDir}/.nimbus").text.trim()
379 buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
380 println "(Added from .nimbus file)"
381 } catch (FileNotFoundException ignored) {
382 buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
385 } else if (gradle.hasProperty("localProperties.nimbus.remote-settings.url")) {
386 def url=gradle.getProperty("localProperties.nimbus.remote-settings.url")
387 buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
388 println "(Added from local.properties file)"
390 buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
394 // -------------------------------------------------------------------------------------------------
395 // Glean: Read custom server URL from local.properties of a local file if it exists
396 // -------------------------------------------------------------------------------------------------
398 print("Glean custom server URL: ")
400 if (gradle.hasProperty("localProperties.glean.custom.server.url")) {
401 def url=gradle.getProperty("localProperties.glean.custom.server.url")
402 buildConfigField 'String', 'GLEAN_CUSTOM_URL', url
403 println "(Added from local.properties file)"
405 buildConfigField 'String', 'GLEAN_CUSTOM_URL', 'null'
409 // -------------------------------------------------------------------------------------------------
410 // BuildConfig: Set flag for official builds; similar to MOZILLA_OFFICIAL in mozilla-central.
411 // -------------------------------------------------------------------------------------------------
413 if (project.hasProperty("official") || gradle.hasProperty("localProperties.official")) {
414 buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'true'
416 buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'false'
419 // -------------------------------------------------------------------------------------------------
420 // BuildConfig: Set remote wallpaper URL using local file if it exists
421 // -------------------------------------------------------------------------------------------------
423 print("Wallpaper URL: ")
426 def token = new File("${rootDir}/.wallpaper_url").text.trim()
427 buildConfigField 'String', 'WALLPAPER_URL', '"' + token + '"'
428 println "(Added from .wallpaper_url file)"
429 } catch (FileNotFoundException ignored) {
430 buildConfigField 'String', 'WALLPAPER_URL', '""'
434 // -------------------------------------------------------------------------------------------------
435 // BuildConfig: Set the Pocket consumer key from a local file if it exists
436 // -------------------------------------------------------------------------------------------------
438 print("Pocket consumer key: ")
441 def token = new File("${rootDir}/.pocket_consumer_key").text.trim()
442 buildConfigField 'String', 'POCKET_CONSUMER_KEY', '"' + token + '"'
443 println "(Added from .pocket_consumer_key file)"
444 } catch (FileNotFoundException ignored) {
445 buildConfigField 'String', 'POCKET_CONSUMER_KEY', '""'
450 // Generate Kotlin code for the Fenix Glean metrics.
451 apply plugin: "org.mozilla.telemetry.glean-gradle-plugin"
452 apply plugin: "org.mozilla.appservices.nimbus-gradle-plugin"
455 // The path to the Nimbus feature manifest file
456 manifestFile = "nimbus.fml.yaml"
457 // The fully qualified class name for the generated features.
458 // Map from the variant name to the channel as experimenter and nimbus understand it.
459 // If nimbus's channels were accurately set up well for this project, then this
460 // shouldn't be needed.
462 fenixDebug: "developer",
463 fenixNightly: "nightly",
465 fenixRelease: "release",
466 fenixBenchmark: "developer",
468 // This is generated by the FML and should be checked into git.
469 // It will be fetched by Experimenter (the Nimbus experiment website)
470 // and used to inform experiment configuration.
471 experimenterManifest = ".experimenter.yaml"
474 tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
476 freeCompilerArgs += [
477 "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
483 implementation project(':browser-engine-gecko')
485 implementation ComponentsDependencies.kotlin_coroutines
486 testImplementation ComponentsDependencies.testing_coroutines
487 implementation ComponentsDependencies.androidx_appcompat
488 implementation ComponentsDependencies.androidx_constraintlayout
489 implementation ComponentsDependencies.androidx_coordinatorlayout
490 implementation FenixDependencies.google_accompanist_drawablepainter
492 implementation ComponentsDependencies.thirdparty_sentry_latest
494 implementation project(':compose-awesomebar')
495 implementation project(':compose-cfr')
497 implementation project(':concept-awesomebar')
498 implementation project(':concept-base')
499 implementation project(':concept-engine')
500 implementation project(':concept-menu')
501 implementation project(':concept-push')
502 implementation project(':concept-storage')
503 implementation project(':concept-sync')
504 implementation project(':concept-toolbar')
505 implementation project(':concept-tabstray')
507 implementation project(':browser-domains')
508 implementation project(':browser-icons')
509 implementation project(':browser-menu')
510 implementation project(':browser-menu2')
511 implementation project(':browser-session-storage')
512 implementation project(':browser-state')
513 implementation project(':browser-storage-sync')
514 implementation project(':browser-tabstray')
515 implementation project(':browser-thumbnails')
516 implementation project(':browser-toolbar')
518 implementation project(':feature-addons')
519 implementation project(':feature-accounts')
520 implementation project(':feature-app-links')
521 implementation project(':feature-autofill')
522 implementation project(':feature-awesomebar')
523 implementation project(':feature-contextmenu')
524 implementation project(':feature-customtabs')
525 implementation project(':feature-downloads')
526 implementation project(':feature-intent')
527 implementation project(':feature-media')
528 implementation project(':feature-prompts')
529 implementation project(':feature-push')
530 implementation project(':feature-privatemode')
531 implementation project(':feature-pwa')
532 implementation project(':feature-qr')
533 implementation project(':feature-search')
534 implementation project(':feature-session')
535 implementation project(':feature-syncedtabs')
536 implementation project(':feature-toolbar')
537 implementation project(':feature-tabs')
538 implementation project(':feature-findinpage')
539 implementation project(':feature-logins')
540 implementation project(':feature-sitepermissions')
541 implementation project(':feature-readerview')
542 implementation project(':feature-tab-collections')
543 implementation project(':feature-recentlyclosed')
544 implementation project(':feature-top-sites')
545 implementation project(':feature-share')
546 implementation project(':feature-accounts-push')
547 implementation project(':feature-webauthn')
548 implementation project(':feature-webcompat')
549 implementation project(':feature-webnotifications')
550 implementation project(':feature-webcompat-reporter')
552 implementation project(':service-pocket')
553 implementation project(':service-contile')
554 implementation project(':service-digitalassetlinks')
555 implementation project(':service-sync-autofill')
556 implementation project(':service-sync-logins')
557 implementation project(':service-firefox-accounts')
558 implementation project(':service-glean')
559 implementation project(':service-location')
560 implementation project(':service-nimbus')
562 implementation project(':support-webextensions')
563 implementation project(':support-base')
564 implementation project(':support-rusterrors')
565 implementation project(':support-images')
566 implementation project(':support-ktx')
567 implementation project(':support-rustlog')
568 implementation project(':support-utils')
569 implementation project(':support-locale')
571 implementation project(':ui-colors')
572 implementation project(':ui-icons')
573 implementation project(':lib-publicsuffixlist')
574 implementation project(':ui-widgets')
575 implementation project(':ui-tabcounter')
577 implementation project(':lib-crash')
578 implementation project(':lib-crash-sentry')
579 implementation project(':lib-push-firebase')
580 implementation project(':lib-state')
581 implementation project(':lib-dataprotect')
583 debugImplementation ComponentsDependencies.leakcanary
584 debugImplementation ComponentsDependencies.androidx_compose_ui_tooling
586 implementation ComponentsDependencies.androidx_activity_compose
587 implementation FenixDependencies.androidx_activity_ktx
588 implementation ComponentsDependencies.androidx_annotation
589 implementation ComponentsDependencies.androidx_compose_ui
590 implementation ComponentsDependencies.androidx_compose_ui_tooling_preview
591 implementation ComponentsDependencies.androidx_compose_foundation
592 implementation ComponentsDependencies.androidx_compose_material
593 implementation FenixDependencies.androidx_legacy
594 implementation ComponentsDependencies.androidx_biometric
595 implementation FenixDependencies.androidx_paging
596 implementation ComponentsDependencies.androidx_preferences
597 implementation ComponentsDependencies.androidx_fragment
598 implementation FenixDependencies.androidx_navigation_fragment
599 implementation FenixDependencies.androidx_navigation_ui
600 implementation ComponentsDependencies.androidx_recyclerview
601 implementation FenixDependencies.androidx_lifecycle_common
602 implementation ComponentsDependencies.androidx_lifecycle_livedata
603 implementation ComponentsDependencies.androidx_lifecycle_process
604 implementation ComponentsDependencies.androidx_lifecycle_runtime
606 implementation ComponentsDependencies.androidx_lifecycle_viewmodel
607 implementation ComponentsDependencies.androidx_core
608 implementation ComponentsDependencies.androidx_core_ktx
609 implementation FenixDependencies.androidx_core_splashscreen
610 implementation FenixDependencies.androidx_transition
611 implementation ComponentsDependencies.androidx_work_runtime
612 implementation FenixDependencies.androidx_datastore
613 implementation ComponentsDependencies.androidx_data_store_preferences
614 implementation FenixDependencies.protobuf_javalite
615 implementation ComponentsDependencies.google_material
617 implementation FenixDependencies.adjust
618 implementation FenixDependencies.installreferrer // Required by Adjust
620 implementation FenixDependencies.google_ads_id // Required for the Google Advertising ID
622 // Required for in-app reviews
623 implementation FenixDependencies.google_play_review
624 implementation FenixDependencies.google_play_review_ktx
626 implementation FenixDependencies.androidx_profileinstaller
628 androidTestImplementation ComponentsDependencies.androidx_test_uiautomator
629 androidTestImplementation FenixDependencies.fastlane
630 // This Falcon version is added to maven central now required for Screengrab
631 androidTestImplementation FenixDependencies.falcon
633 androidTestImplementation ComponentsDependencies.androidx_compose_ui_test
635 androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
636 exclude group: 'com.android.support', module: 'support-annotations'
639 androidTestImplementation(FenixDependencies.espresso_contrib) {
640 exclude module: 'appcompat-v7'
641 exclude module: 'support-v4'
642 exclude module: 'support-annotations'
643 exclude module: 'recyclerview-v7'
644 exclude module: 'design'
645 exclude module: 'espresso-core'
646 exclude module: 'protobuf-lite'
649 androidTestImplementation ComponentsDependencies.androidx_test_core
650 androidTestImplementation FenixDependencies.espresso_idling_resources
651 androidTestImplementation FenixDependencies.espresso_intents
653 androidTestImplementation ComponentsDependencies.androidx_test_runner
654 androidTestImplementation ComponentsDependencies.androidx_test_rules
655 androidTestUtil FenixDependencies.orchestrator
656 androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
657 exclude group: 'com.android.support', module: 'support-annotations'
660 androidTestImplementation ComponentsDependencies.androidx_test_junit
661 androidTestImplementation ComponentsDependencies.androidx_work_testing
662 androidTestImplementation FenixDependencies.androidx_benchmark_junit4
663 androidTestImplementation FenixDependencies.mockwebserver
664 testImplementation project(':support-test')
665 testImplementation project(':support-test-libstate')
666 testImplementation ComponentsDependencies.androidx_test_junit
667 testImplementation ComponentsDependencies.androidx_work_testing
668 testImplementation (ComponentsDependencies.testing_robolectric) {
669 exclude group: 'org.apache.maven'
672 testImplementation ComponentsDependencies.testing_maven_ant_tasks
673 implementation project(':support-rusthttp')
675 androidTestImplementation FenixDependencies.mockk_android
676 testImplementation FenixDependencies.mockk
678 // For the initial release of Glean 19, we require consumer applications to
679 // depend on a separate library for unit tests. This will be removed in future releases.
680 testImplementation "org.mozilla.telemetry:glean-native-forUnitTests:${project.ext.glean_version}"
682 lintChecks project(":mozilla-lint-rules")
687 artifact = FenixDependencies.protobuf_compiler
690 // Generates the java Protobuf-lite code for the Protobufs in this project. See
691 // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
692 // for more information.
704 if (project.hasProperty("coverage")) {
705 tasks.withType(Test).configureEach {
706 jacoco.includeNoLocationClasses = true
707 jacoco.excludes = ['jdk.internal.*']
711 toolVersion = Versions.jacoco
714 android.applicationVariants.all { variant ->
715 tasks.register("jacoco${variant.name.capitalize()}TestReport", JacocoReport) {
716 dependsOn "test${variant.name.capitalize()}UnitTest"
723 def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
724 '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
725 def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/${variant.name}", excludes: fileFilter)
726 def javaDebugTree = fileTree(dir: "$project.buildDir/intermediates/classes/${variant.flavorName}/${variant.buildType.name}",
727 excludes: fileFilter)
728 def mainSrc = "$project.projectDir/src/main/java"
730 sourceDirectories.setFrom(files([mainSrc]))
731 classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
732 executionData.setFrom(fileTree(dir: project.buildDir, includes: [
733 "jacoco/test${variant.name.capitalize()}UnitTest.exec",
734 'outputs/code-coverage/connected/*coverage.ec'
742 testCoverageEnabled true
748 // -------------------------------------------------------------------------------------------------
749 // Task for printing APK information for the requested variant
750 // Usage: "./gradlew printVariants
751 // -------------------------------------------------------------------------------------------------
752 tasks.register('printVariants') {
754 def variants = android.applicationVariants.collect { variant -> [
755 apks: variant.outputs.collect { output -> [
756 abi: output.getFilter(com.android.build.VariantOutput.FilterType.ABI),
757 fileName: output.outputFile.name
759 build_type: variant.buildType.name,
762 // AndroidTest is a special case not included above
766 fileName: 'app-debug-androidTest.apk',
768 build_type: 'androidTest',
771 println 'variants: ' + JsonOutput.toJson(variants)
775 task buildTranslationArray {
776 // This isn't running as a task, instead the array is build when the gradle file is parsed.
777 // https://github.com/mozilla-mobile/fenix/issues/14175
778 def foundLocales = new StringBuilder()
779 foundLocales.append("new String[]{")
781 fileTree("src/main/res").visit { FileVisitDetails details ->
782 if(details.file.path.endsWith("${File.separator}strings.xml")){
783 def languageCode = details.file.parent.tokenize(File.separator).last().replaceAll('values-','').replaceAll('-r','-')
784 languageCode = (languageCode == "values") ? "en-US" : languageCode
785 foundLocales.append("\"").append(languageCode).append("\"").append(",")
789 foundLocales.append("}")
790 def foundLocalesString = foundLocales.toString().replaceAll(',}','}')
791 android.defaultConfig.buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", foundLocalesString
796 // Format test output. Ported from AC #2401
797 tasks.withType(Test).configureEach {
798 systemProperty "robolectric.logging", "stdout"
799 systemProperty "logging.test-mode", "true"
801 testLogging.events = []
803 def out = services.get(StyledTextOutputFactory).create("tests")
805 beforeSuite { descriptor ->
806 if (descriptor.getClassName() != null) {
807 out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
811 beforeTest { descriptor ->
812 out.style(Style.Description).println(" TEST: " + descriptor.getName())
815 onOutput { descriptor, event ->
816 logger.lifecycle(" " + event.message.trim())
819 afterTest { descriptor, result ->
820 switch (result.getResultType()) {
821 case ResultType.SUCCESS:
822 out.style(Style.Success).println(" SUCCESS")
825 case ResultType.FAILURE:
826 out.style(Style.Failure).println(" FAILURE")
827 logger.lifecycle("", result.getException())
830 case ResultType.SKIPPED:
831 out.style(Style.Info).println(" SKIPPED")
839 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
840 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
841 ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
843 ext.topsrcdir = StringUtils.removeSuffix(gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir", File.separator)
844 apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
847 if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
848 ext.gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
849 apply from: "../${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
852 android.applicationVariants.all { variant ->
853 tasks.register("apkSize${variant.name.capitalize()}", ApkSizeTask) {
854 variantName = variant.name
855 apks = variant.outputs.collect { output -> output.outputFile.name }
856 dependsOn "package${variant.name.capitalize()}"
860 // Enable expiration by major version.
861 ext.gleanExpireByVersion = Config.majorVersion()