1 import com.android.build.api.variant.FilterConfiguration
2 import org.apache.tools.ant.util.StringUtils
5 id "com.jetbrains.python.envs" version "$python_envs_plugin"
6 id "com.google.protobuf" version "$protobuf_plugin"
9 if (findProject(":geckoview") != null) {
10 buildDir "${topobjdir}/gradle/build/mobile/android/fenix"
13 apply plugin: 'com.android.application'
14 apply plugin: 'kotlin-android'
15 apply plugin: 'kotlin-parcelize'
16 apply plugin: 'jacoco'
17 apply plugin: 'androidx.navigation.safeargs.kotlin'
18 apply plugin: 'com.google.android.gms.oss-licenses-plugin'
20 if (findProject(":geckoview") != null) {
21 apply from: "${topsrcdir}/mobile/android/gradle/product_flavors.gradle"
24 import groovy.json.JsonOutput
25 import org.gradle.internal.logging.text.StyledTextOutput.Style
26 import org.gradle.internal.logging.text.StyledTextOutputFactory
27 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
29 import static org.gradle.api.tasks.testing.TestResult.ResultType
31 apply from: 'benchmark.gradle'
34 project.maybeConfigForJetpackBenchmark(it)
35 if (project.hasProperty("testBuildType")) {
36 // Allowing to configure the test build type via command line flag (./gradlew -PtestBuildType=beta ..)
37 // in order to run UI tests against other build variants than debug in automation.
38 testBuildType project.property("testBuildType")
42 applicationId "org.mozilla"
43 minSdkVersion config.minSdkVersion
44 compileSdk config.compileSdkVersion
45 targetSdkVersion config.targetSdkVersion
47 versionName Config.generateDebugVersionName()
48 vectorDrawables.useSupportLibrary = true
49 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
50 testInstrumentationRunnerArguments clearPackageData: 'true'
51 resValue "bool", "IS_DEBUG", "false"
52 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false"
53 buildConfigField "String", "VCS_HASH", "\"\"" // see override in release builds for why it's blank.
54 // This should be the "public" base URL of AMO.
55 buildConfigField "String", "AMO_BASE_URL", "\"https://addons.mozilla.org\""
56 buildConfigField "String", "AMO_COLLECTION_NAME", "\"Extensions-for-Android\""
57 buildConfigField "String", "AMO_COLLECTION_USER", "\"mozilla\""
58 // These add-ons should be excluded for Mozilla Online builds.
59 buildConfigField "String[]", "MOZILLA_ONLINE_ADDON_EXCLUSIONS",
61 "\"uBlock0@raymondhill.net\"," +
62 "\"firefox@ghostery.com\"," +
63 "\"jid1-MnnxcxisBPnSXQ@jetpack\"," +
64 "\"adguardadblocker@adguard.com\"," +
65 "\"foxyproxy@eric.h.jung\"," +
66 "\"{73a6fe31-595d-460b-a920-fcc0f8843232}\"," +
67 "\"jid1-BoFifL9Vbdl2zQ@jetpack\"," +
68 "\"woop-NoopscooPsnSXQ@jetpack\"," +
69 "\"adnauseam@rednoise.org\"" +
71 // This should be the base URL used to call the AMO API.
72 buildConfigField "String", "AMO_SERVER_URL", "\"https://services.addons.mozilla.org\""
74 def deepLinkSchemeValue = "fenix-dev"
75 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
77 // This allows overriding the target activity for MozillaOnline builds, which happens
78 // as part of the defaultConfig below.
79 def targetActivity = "HomeActivity"
81 // Build flag for "Mozilla Online" variants. See `Config.isMozillaOnline`.
82 if (project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")) {
83 buildConfigField "boolean", "MOZILLA_ONLINE", "true"
84 targetActivity = "MozillaOnlineHomeActivity"
86 buildConfigField "boolean", "MOZILLA_ONLINE", "false"
89 manifestPlaceholders = [
90 "targetActivity": targetActivity,
91 "deepLinkScheme": deepLinkSchemeValue
94 buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", getSupportedLocales()
97 def releaseTemplate = {
98 // We allow disabling optimization by passing `-PdisableOptimization` to gradle. This is used
99 // in automation for UI testing non-debug builds.
100 shrinkResources !project.hasProperty("disableOptimization")
101 minifyEnabled !project.hasProperty("disableOptimization")
102 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
103 matchingFallbacks = ['release'] // Use on the "release" build type in dependencies (AARs)
105 // Changing the build config can cause files that depend on BuildConfig.java to recompile
106 // so we only set the vcs hash in release builds to avoid possible recompilation in debug builds.
107 buildConfigField "String", "VCS_HASH", "\"${Config.getVcsHash()}\""
109 if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) {
110 signingConfig signingConfigs.debug
113 if (gradle.hasProperty("localProperties.debuggable")) {
120 shrinkResources false
122 applicationIdSuffix ".fenix.debug"
123 resValue "bool", "IS_DEBUG", "true"
124 pseudoLocalesEnabled true
126 nightly releaseTemplate >> {
127 applicationIdSuffix ".fenix"
128 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
129 def deepLinkSchemeValue = "fenix-nightly"
130 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
131 manifestPlaceholders.putAll([
132 "deepLinkScheme": deepLinkSchemeValue
135 beta releaseTemplate >> {
136 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
137 applicationIdSuffix ".firefox_beta"
138 def deepLinkSchemeValue = "fenix-beta"
139 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
140 manifestPlaceholders.putAll([
141 // This release type is meant to replace Firefox (Beta channel) and therefore needs to inherit
142 // its sharedUserId for all eternity. See:
143 // https://searchfox.org/mozilla-esr68/search?q=moz_android_shared_id&case=false®exp=false&path=
144 // Shipping an app update without sharedUserId can have
145 // fatal consequences. For example see:
146 // - https://issuetracker.google.com/issues/36924841
147 // - https://issuetracker.google.com/issues/36905922
148 "sharedUserId": "org.mozilla.firefox.sharedID",
149 "deepLinkScheme": deepLinkSchemeValue,
152 release releaseTemplate >> {
153 buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
154 applicationIdSuffix ".firefox"
155 def deepLinkSchemeValue = "fenix"
156 buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
157 manifestPlaceholders.putAll([
158 // This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
159 // its sharedUserId for all eternity. See:
160 // https://searchfox.org/mozilla-esr68/search?q=moz_android_shared_id&case=false®exp=false&path=
161 // Shipping an app update without sharedUserId can have
162 // fatal consequences. For example see:
163 // - https://issuetracker.google.com/issues/36924841
164 // - https://issuetracker.google.com/issues/36905922
165 "sharedUserId": "org.mozilla.firefox.sharedID",
166 "deepLinkScheme": deepLinkSchemeValue,
169 benchmark releaseTemplate >> {
170 initWith buildTypes.nightly
171 applicationIdSuffix ".fenix"
182 // All JavaScript code used internally by GeckoView is packaged in a
183 // file called omni.ja. If this file is compressed in the APK,
184 // GeckoView must uncompress it before it can do anything else which
185 // causes a significant delay on startup.
188 // manifest.template.json is converted to manifest.json at build time.
189 // No need to package the template in the APK.
190 ignoreAssetsPattern "manifest.template.json"
194 execution 'ANDROIDX_TEST_ORCHESTRATOR'
195 unitTests.includeAndroidResources = true
196 animationsDisabled = true
199 if (findProject(":geckoview") != null) {
200 project.configureProductFlavors.delegate = it
201 project.configureProductFlavors()
204 flavorDimensions.add("product")
214 resources.srcDirs += ['src/androidTest/resources']
224 // As gradle is unable to pick the right apk to install when multiple apks are generated
225 // while running benchmark tests or generating baseline profiles. To circumvent this,
226 // this flag is passed to make sure only one apk is generated so gradle can pick that one.
227 if (project.hasProperty("benchmarkTest")) {
230 include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
236 // Profiler issues require us to temporarily package native code compressed to
237 // match the previous APK packaging.
238 // https://bugzilla.mozilla.org/show_bug.cgi?id=1865634
241 it.useLegacyPackaging = true
246 // Because we have runtime language selection we will keep all strings and languages
253 lintConfig file("lint.xml")
254 baseline file("lint-baseline.xml")
258 excludes += ['META-INF/atomicfu.kotlin_module', 'META-INF/AL2.0', 'META-INF/LGPL2.1',
259 'META-INF/LICENSE.md', 'META-INF/LICENSE-notice.md']
262 useLegacyPackaging true
268 unitTests.returnDefaultValues = true
271 // We keep running into memory issues when running our tests. With this config we
272 // reserve more memory and also create a new process after every 80 test classes. This
273 // is a band-aid solution and eventually we should try to find and fix the leaks
276 maxHeapSize = "3072m"
277 minHeapSize = "1024m"
286 kotlinCompilerExtensionVersion = Versions.compose_compiler
289 namespace 'org.mozilla.fenix'
292 android.applicationVariants.configureEach { variant ->
294 // -------------------------------------------------------------------------------------------------
295 // Generate version codes for builds
296 // -------------------------------------------------------------------------------------------------
298 def isDebug = variant.buildType.resValues['bool/IS_DEBUG']?.value ?: false
299 def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false
301 println("----------------------------------------------")
302 println("Variant name: " + variant.name)
303 println("Application ID: " + [variant.applicationId, variant.buildType.applicationIdSuffix].findAll().join())
304 println("Build type: " + variant.buildType.name)
305 println("Flavor: " + variant.flavorName)
306 println("Telemetry enabled: " + !isDebug)
308 if (useReleaseVersioning) {
309 // The Google Play Store does not allow multiple APKs for the same app that all have the
310 // same version code. Therefore we need to have different version codes for our ARM and x86
313 def versionName = variant.buildType.name == 'nightly' ? Config.nightlyVersionName(project) : Config.releaseVersionName(project)
314 println("versionName override: $versionName")
316 variant.outputs.each { output ->
317 def isMozillaOnline = project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")
318 def abi = output.getFilter(FilterConfiguration.FilterType.ABI.name())
319 // If it is a Mozilla Online build, use a unified version code of armeabi-v7a
320 def arch = (isMozillaOnline) ? "armeabi-v7a" : abi
321 def aab = project.hasProperty("aab")
322 // We use the same version code generator, that we inherited from Fennec, across all channels - even on
323 // channels that never shipped a Fennec build.
324 def versionCodeOverride = Config.generateFennecVersionCode(arch, aab)
326 println("versionCode for $abi = $versionCodeOverride, isMozillaOnline = $isMozillaOnline")
328 if (versionName != null) {
329 output.versionNameOverride = versionName
331 output.versionCodeOverride = versionCodeOverride
333 } else if (gradle.hasProperty("localProperties.branchBuild.fenix.version")) {
334 def versionName = gradle.getProperty("localProperties.branchBuild.fenix.version")
335 println("versionName override: $versionName")
336 variant.outputs.each { output ->
337 output.versionNameOverride = versionName
341 // -------------------------------------------------------------------------------------------------
342 // BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
343 // -------------------------------------------------------------------------------------------------
345 buildConfigField 'String', 'SENTRY_TOKEN', 'null'
347 buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
348 // Reading sentry token from local file (if it exists). In a release task on taskcluster it will be available.
350 def token = new File("${rootDir}/.sentry_token").text.trim()
351 buildConfigField 'String', 'SENTRY_TOKEN', '"' + token + '"'
352 } catch (FileNotFoundException ignored) {}
354 buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
358 buildConfigField 'boolean', 'TELEMETRY', 'true'
360 buildConfigField 'boolean', 'TELEMETRY', 'false'
363 def buildDate = Config.generateBuildDate()
364 // Setting buildDate with every build changes the generated BuildConfig, which slows down the
365 // build. Only do this for non-debug builds, to speed-up builds produced during local development.
367 buildConfigField 'String', 'BUILD_DATE', '"debug build"'
369 buildConfigField 'String', 'BUILD_DATE', '"' + buildDate + '"'
372 // -------------------------------------------------------------------------------------------------
373 // Adjust: Read token from local file if it exists (Only release builds)
374 // -------------------------------------------------------------------------------------------------
376 print("Adjust token: ")
380 def token = new File("${rootDir}/.adjust_token").text.trim()
381 buildConfigField 'String', 'ADJUST_TOKEN', '"' + token + '"'
382 println "(Added from .adjust_token file)"
383 } catch (FileNotFoundException ignored) {
384 buildConfigField 'String', 'ADJUST_TOKEN', 'null'
388 buildConfigField 'String', 'ADJUST_TOKEN', 'null'
392 // -------------------------------------------------------------------------------------------------
393 // MLS: Read token from local file if it exists
394 // -------------------------------------------------------------------------------------------------
399 def token = new File("${rootDir}/.mls_token").text.trim()
400 buildConfigField 'String', 'MLS_TOKEN', '"' + token + '"'
401 println "(Added from .mls_token file)"
402 } catch (FileNotFoundException ignored) {
403 buildConfigField 'String', 'MLS_TOKEN', '""'
407 // -------------------------------------------------------------------------------------------------
408 // Nimbus: Read endpoint from local.properties of a local file if it exists
409 // -------------------------------------------------------------------------------------------------
411 print("Nimbus endpoint: ")
415 def url = new File("${rootDir}/.nimbus").text.trim()
416 buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
417 println "(Added from .nimbus file)"
418 } catch (FileNotFoundException ignored) {
419 buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
422 } else if (gradle.hasProperty("localProperties.nimbus.remote-settings.url")) {
423 def url=gradle.getProperty("localProperties.nimbus.remote-settings.url")
424 buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
425 println "(Added from local.properties file)"
427 buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
431 // -------------------------------------------------------------------------------------------------
432 // Glean: Read custom server URL from local.properties of a local file if it exists
433 // -------------------------------------------------------------------------------------------------
435 print("Glean custom server URL: ")
437 if (gradle.hasProperty("localProperties.glean.custom.server.url")) {
438 def url=gradle.getProperty("localProperties.glean.custom.server.url")
439 buildConfigField 'String', 'GLEAN_CUSTOM_URL', url
440 println "(Added from local.properties file)"
442 buildConfigField 'String', 'GLEAN_CUSTOM_URL', 'null'
446 // -------------------------------------------------------------------------------------------------
447 // BuildConfig: Set flag for official builds; similar to MOZILLA_OFFICIAL in mozilla-central.
448 // -------------------------------------------------------------------------------------------------
450 if (project.hasProperty("official") || gradle.hasProperty("localProperties.official")) {
451 buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'true'
453 buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'false'
456 // -------------------------------------------------------------------------------------------------
457 // BuildConfig: Set remote wallpaper URL using local file if it exists
458 // -------------------------------------------------------------------------------------------------
460 print("Wallpaper URL: ")
463 def token = new File("${rootDir}/.wallpaper_url").text.trim()
464 buildConfigField 'String', 'WALLPAPER_URL', '"' + token + '"'
465 println "(Added from .wallpaper_url file)"
466 } catch (FileNotFoundException ignored) {
467 buildConfigField 'String', 'WALLPAPER_URL', '""'
471 // -------------------------------------------------------------------------------------------------
472 // BuildConfig: Set the Pocket consumer key from a local file if it exists
473 // -------------------------------------------------------------------------------------------------
475 print("Pocket consumer key: ")
478 def token = new File("${rootDir}/.pocket_consumer_key").text.trim()
479 buildConfigField 'String', 'POCKET_CONSUMER_KEY', '"' + token + '"'
480 println "(Added from .pocket_consumer_key file)"
481 } catch (FileNotFoundException ignored) {
482 buildConfigField 'String', 'POCKET_CONSUMER_KEY', '""'
486 // -------------------------------------------------------------------------------------------------
487 // BuildConfig: Set flag to disable LeakCanary in debug (on CI builds)
488 // -------------------------------------------------------------------------------------------------
491 if (project.hasProperty("disableLeakCanary") || gradle.hasProperty("localProperties.disableLeakCanary")) {
492 buildConfigField "boolean", "LEAKCANARY", "false"
493 println("LeakCanary enabled in debug: false")
495 buildConfigField "boolean", "LEAKCANARY", "true"
496 println("LeakCanary enabled in debug: true")
499 buildConfigField "boolean", "LEAKCANARY", "false"
503 // Generate Kotlin code for the Fenix Glean metrics.
504 apply plugin: "org.mozilla.telemetry.glean-gradle-plugin"
505 apply plugin: "org.mozilla.appservices.nimbus-gradle-plugin"
508 // The path to the Nimbus feature manifest file
509 manifestFile = "nimbus.fml.yaml"
510 // The fully qualified class name for the generated features.
511 // Map from the variant name to the channel as experimenter and nimbus understand it.
512 // If nimbus's channels were accurately set up well for this project, then this
513 // shouldn't be needed.
515 fenixDebug: "developer",
516 fenixNightly: "nightly",
518 fenixRelease: "release",
519 fenixBenchmark: "developer",
520 withGeckoBinariesFenixDebug: "developer",
521 withGeckoBinariesFenixNightly: "nightly",
522 withGeckoBinariesFenixBeta: "beta",
523 withGeckoBinariesFenixRelease: "release",
524 withGeckoBinariesFenixBenchmark: "developer",
525 withoutGeckoBinariesFenixDebug: "developer",
526 withoutGeckoBinariesFenixNightly: "nightly",
527 withoutGeckoBinariesFenixBeta: "beta",
528 withoutGeckoBinariesFenixRelease: "release",
529 withoutGeckoBinariesFenixBenchmark: "developer",
531 // This is generated by the FML and should be checked into git.
532 // It will be fetched by Experimenter (the Nimbus experiment website)
533 // and used to inform experiment configuration.
534 experimenterManifest = ".experimenter.yaml"
535 applicationServicesDir = gradle.hasProperty('localProperties.autoPublish.application-services.dir')
536 ? gradle.getProperty('localProperties.autoPublish.application-services.dir') : null
539 tasks.withType(KotlinCompile).configureEach {
540 kotlinOptions.freeCompilerArgs += "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
544 implementation platform(ComponentsDependencies.androidx_compose_bom)
545 androidTestImplementation platform(ComponentsDependencies.androidx_compose_bom)
547 implementation project(':browser-engine-gecko')
549 implementation ComponentsDependencies.kotlin_coroutines
550 testImplementation ComponentsDependencies.testing_coroutines
551 implementation ComponentsDependencies.androidx_appcompat
552 implementation ComponentsDependencies.androidx_constraintlayout
553 implementation ComponentsDependencies.androidx_coordinatorlayout
554 implementation FenixDependencies.google_accompanist_drawablepainter
556 implementation ComponentsDependencies.thirdparty_sentry
558 implementation project(':compose-awesomebar')
559 implementation project(':compose-cfr')
561 implementation project(':concept-awesomebar')
562 implementation project(':concept-base')
563 implementation project(':concept-engine')
564 implementation project(':concept-menu')
565 implementation project(':concept-push')
566 implementation project(':concept-storage')
567 implementation project(':concept-sync')
568 implementation project(':concept-toolbar')
569 implementation project(':concept-tabstray')
571 implementation project(':browser-domains')
572 implementation project(':browser-icons')
573 implementation project(':browser-menu')
574 implementation project(':browser-menu2')
575 implementation project(':browser-session-storage')
576 implementation project(':browser-state')
577 implementation project(':browser-storage-sync')
578 implementation project(':browser-tabstray')
579 implementation project(':browser-thumbnails')
580 implementation project(':browser-toolbar')
582 implementation project(':feature-addons')
583 implementation project(':feature-accounts')
584 implementation project(':feature-app-links')
585 implementation project(':feature-autofill')
586 implementation project(':feature-awesomebar')
587 implementation project(':feature-contextmenu')
588 implementation project(':feature-customtabs')
589 implementation project(':feature-downloads')
590 implementation project(':feature-fxsuggest')
591 implementation project(':feature-intent')
592 implementation project(':feature-media')
593 implementation project(':feature-prompts')
594 implementation project(':feature-push')
595 implementation project(':feature-privatemode')
596 implementation project(':feature-pwa')
597 implementation project(':feature-qr')
598 implementation project(':feature-search')
599 implementation project(':feature-session')
600 implementation project(':feature-syncedtabs')
601 implementation project(':feature-toolbar')
602 implementation project(':feature-tabs')
603 implementation project(':feature-findinpage')
604 implementation project(':feature-logins')
605 implementation project(':feature-sitepermissions')
606 implementation project(':feature-readerview')
607 implementation project(':feature-tab-collections')
608 implementation project(':feature-recentlyclosed')
609 implementation project(':feature-top-sites')
610 implementation project(':feature-share')
611 implementation project(':feature-accounts-push')
612 implementation project(':feature-webauthn')
613 implementation project(':feature-webcompat')
614 implementation project(':feature-webnotifications')
615 implementation project(':feature-webcompat-reporter')
617 implementation project(':service-pocket')
618 implementation project(':service-contile')
619 implementation project(':service-digitalassetlinks')
620 implementation project(':service-sync-autofill')
621 implementation project(':service-sync-logins')
622 implementation project(':service-firefox-accounts')
623 implementation project(':service-glean')
624 implementation project(':service-location')
625 implementation project(':service-nimbus')
627 implementation project(':support-webextensions')
628 implementation project(':support-base')
629 implementation project(':support-rusterrors')
630 implementation project(':support-images')
631 implementation project(':support-ktx')
632 implementation project(':support-rustlog')
633 implementation project(':support-utils')
634 implementation project(':support-locale')
636 implementation project(':ui-colors')
637 implementation project(':ui-icons')
638 implementation project(':lib-publicsuffixlist')
639 implementation project(':ui-widgets')
640 implementation project(':ui-tabcounter')
642 implementation project(':lib-crash')
643 implementation project(':lib-crash-sentry')
644 implementation project(':lib-push-firebase')
645 implementation project(':lib-state')
646 implementation project(':lib-dataprotect')
647 testImplementation project(':support-test-fakes')
649 debugImplementation ComponentsDependencies.leakcanary
650 debugImplementation ComponentsDependencies.androidx_compose_ui_tooling
652 implementation ComponentsDependencies.androidx_activity_compose
653 implementation FenixDependencies.androidx_activity_ktx
654 implementation ComponentsDependencies.androidx_annotation
655 implementation ComponentsDependencies.androidx_compose_ui
656 implementation ComponentsDependencies.androidx_compose_ui_tooling_preview
657 implementation ComponentsDependencies.androidx_compose_animation
658 implementation ComponentsDependencies.androidx_compose_foundation
659 implementation ComponentsDependencies.androidx_compose_material
660 implementation FenixDependencies.androidx_legacy
661 implementation ComponentsDependencies.androidx_biometric
662 implementation ComponentsDependencies.androidx_paging
663 implementation ComponentsDependencies.androidx_preferences
664 implementation ComponentsDependencies.androidx_fragment
665 implementation ComponentsDependencies.androidx_navigation_fragment
666 implementation ComponentsDependencies.androidx_navigation_ui
667 implementation ComponentsDependencies.androidx_compose_navigation
668 implementation ComponentsDependencies.androidx_recyclerview
670 implementation ComponentsDependencies.androidx_lifecycle_common
671 implementation ComponentsDependencies.androidx_lifecycle_livedata
672 implementation ComponentsDependencies.androidx_lifecycle_process
673 implementation ComponentsDependencies.androidx_lifecycle_runtime
674 implementation ComponentsDependencies.androidx_lifecycle_viewmodel
675 implementation ComponentsDependencies.androidx_lifecycle_service
677 implementation ComponentsDependencies.androidx_core
678 implementation ComponentsDependencies.androidx_core_ktx
679 implementation FenixDependencies.androidx_core_splashscreen
680 implementation FenixDependencies.androidx_transition
681 implementation ComponentsDependencies.androidx_work_runtime
682 implementation FenixDependencies.androidx_datastore
683 implementation ComponentsDependencies.androidx_data_store_preferences
684 implementation FenixDependencies.protobuf_javalite
685 implementation ComponentsDependencies.google_material
687 implementation FenixDependencies.adjust
688 implementation FenixDependencies.installreferrer // Required by Adjust
690 implementation FenixDependencies.google_ads_id // Required for the Google Advertising ID
692 // Required for in-app reviews
693 implementation FenixDependencies.google_play_review
694 implementation FenixDependencies.google_play_review_ktx
696 implementation FenixDependencies.androidx_profileinstaller
698 androidTestImplementation ComponentsDependencies.androidx_test_uiautomator
699 androidTestImplementation FenixDependencies.fastlane
700 // This Falcon version is added to maven central now required for Screengrab
701 androidTestImplementation FenixDependencies.falcon
703 androidTestImplementation ComponentsDependencies.androidx_compose_ui_test
705 androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
706 exclude group: 'com.android.support', module: 'support-annotations'
709 androidTestImplementation(FenixDependencies.espresso_contrib) {
710 exclude module: 'appcompat-v7'
711 exclude module: 'support-v4'
712 exclude module: 'support-annotations'
713 exclude module: 'recyclerview-v7'
714 exclude module: 'design'
715 exclude module: 'espresso-core'
716 exclude module: 'protobuf-lite'
719 androidTestImplementation ComponentsDependencies.androidx_test_core
720 androidTestImplementation FenixDependencies.espresso_idling_resources
721 androidTestImplementation FenixDependencies.espresso_intents
723 androidTestImplementation ComponentsDependencies.androidx_test_runner
724 androidTestImplementation ComponentsDependencies.androidx_test_rules
725 androidTestUtil FenixDependencies.orchestrator
726 androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
727 exclude group: 'com.android.support', module: 'support-annotations'
730 androidTestImplementation ComponentsDependencies.androidx_test_junit
731 androidTestImplementation ComponentsDependencies.androidx_work_testing
732 androidTestImplementation FenixDependencies.androidx_benchmark_junit4
733 androidTestImplementation ComponentsDependencies.testing_mockwebserver
734 testImplementation project(':support-test')
735 testImplementation project(':support-test-libstate')
736 testImplementation ComponentsDependencies.androidx_test_junit
737 testImplementation ComponentsDependencies.androidx_work_testing
738 testImplementation (ComponentsDependencies.testing_robolectric) {
739 exclude group: 'org.apache.maven'
742 testImplementation ComponentsDependencies.testing_maven_ant_tasks
743 implementation project(':support-rusthttp')
745 androidTestImplementation FenixDependencies.mockk_android
746 testImplementation FenixDependencies.mockk
748 // For the initial release of Glean 19, we require consumer applications to
749 // depend on a separate library for unit tests. This will be removed in future releases.
750 testImplementation "org.mozilla.telemetry:glean-native-forUnitTests:${project.ext.glean_version}"
752 lintChecks project(":mozilla-lint-rules")
753 lintChecks project(':tooling-lint')
758 artifact = FenixDependencies.protobuf_compiler
761 // Generates the java Protobuf-lite code for the Protobufs in this project. See
762 // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
763 // for more information.
775 if (project.hasProperty("coverage")) {
776 tasks.withType(Test).configureEach {
777 jacoco.includeNoLocationClasses = true
778 jacoco.excludes = ['jdk.internal.*']
782 toolVersion = Versions.jacoco
785 android.applicationVariants.configureEach { variant ->
786 tasks.register("jacoco${variant.name.capitalize()}TestReport", JacocoReport) {
787 dependsOn "test${variant.name.capitalize()}UnitTest"
794 def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
795 '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
796 def kotlinDebugTree = fileTree(dir: "$project.layout.buildDirectory/tmp/kotlin-classes/${variant.name}", excludes: fileFilter)
797 def javaDebugTree = fileTree(dir: "$project.layout.buildDirectory/intermediates/classes/${variant.flavorName}/${variant.buildType.name}",
798 excludes: fileFilter)
799 def mainSrc = "$project.projectDir/src/main/java"
801 sourceDirectories.setFrom(files([mainSrc]))
802 classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
803 executionData.setFrom(fileTree(dir: project.layout.buildDirectory, includes: [
804 "jacoco/test${variant.name.capitalize()}UnitTest.exec",
805 'outputs/code-coverage/connected/*coverage.ec'
813 testCoverageEnabled true
819 // -------------------------------------------------------------------------------------------------
820 // Task for printing APK information for the requested variant
821 // Usage: "./gradlew printVariants
822 // -------------------------------------------------------------------------------------------------
823 tasks.register('printVariants') {
825 def variants = android.applicationVariants.collect { variant -> [
826 apks: variant.outputs.collect { output -> [
827 abi: output.getFilter(FilterConfiguration.FilterType.ABI.name()),
828 fileName: output.outputFile.name
830 build_type: variant.buildType.name,
833 // AndroidTest is a special case not included above
837 fileName: 'app-debug-androidTest.apk',
839 build_type: 'androidTest',
842 println 'variants: ' + JsonOutput.toJson(variants)
848 // Format test output. Ported from AC #2401
849 tasks.withType(Test).configureEach {
850 systemProperty "robolectric.logging", "stdout"
851 systemProperty "logging.test-mode", "true"
853 testLogging.events = []
855 def out = services.get(StyledTextOutputFactory).create("tests")
857 beforeSuite { descriptor ->
858 if (descriptor.getClassName() != null) {
859 out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
863 beforeTest { descriptor ->
864 out.style(Style.Description).println(" TEST: " + descriptor.getName())
867 onOutput { descriptor, event ->
868 logger.lifecycle(" " + event.message.trim())
871 afterTest { descriptor, result ->
872 switch (result.getResultType()) {
873 case ResultType.SUCCESS:
874 out.style(Style.Success).println(" SUCCESS")
877 case ResultType.FAILURE:
878 out.style(Style.Failure).println(" FAILURE")
879 logger.lifecycle("", result.getException())
882 case ResultType.SKIPPED:
883 out.style(Style.Info).println(" SKIPPED")
891 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
892 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
893 ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
895 ext.topsrcdir = StringUtils.removeSuffix(gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir", File.separator)
896 apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
899 if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
900 ext.gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
901 apply from: "../${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
904 android.applicationVariants.configureEach { variant ->
905 tasks.register("apkSize${variant.name.capitalize()}", ApkSizeTask) {
906 variantName = variant.name
907 apks = variant.outputs.collect { output -> output.outputFile.name }
908 dependsOn "package${variant.name.capitalize()}"
912 def getSupportedLocales() {
913 // This isn't running as a task, instead the array is build when the gradle file is parsed.
914 // https://github.com/mozilla-mobile/fenix/issues/14175
915 def foundLocales = new StringBuilder()
916 foundLocales.append("new String[]{")
918 fileTree("src/main/res").visit { FileVisitDetails details ->
919 if (details.file.path.endsWith("${File.separator}strings.xml")) {
920 def languageCode = details.file.parent.tokenize(File.separator).last().replaceAll('values-', '').replaceAll('-r', '-')
921 languageCode = (languageCode == "values") ? "en-US" : languageCode
922 foundLocales.append("\"").append(languageCode).append("\"").append(",")
926 foundLocales.append("}")
927 def foundLocalesString = foundLocales.toString().replaceAll(',}', '}')
928 return foundLocalesString
931 // Enable expiration by major version.
932 ext.gleanExpireByVersion = Config.majorVersion(project)