Bug 1864078 - Create debug drawer navigation UI
[gecko.git] / mobile / android / fenix / app / build.gradle
blobde18512c7e482c7d63faab836e6078e749ae7c8c
1 import com.android.build.api.variant.FilterConfiguration
2 import org.apache.tools.ant.util.StringUtils
4 plugins {
5     id "com.jetbrains.python.envs" version "$python_envs_plugin"
6     id "com.google.protobuf" version "$protobuf_plugin"
9 apply plugin: 'com.android.application'
10 apply plugin: 'kotlin-android'
11 apply plugin: 'kotlin-parcelize'
12 apply plugin: 'jacoco'
13 apply plugin: 'androidx.navigation.safeargs.kotlin'
14 apply plugin: 'com.google.android.gms.oss-licenses-plugin'
16 import groovy.json.JsonOutput
17 import org.gradle.internal.logging.text.StyledTextOutput.Style
18 import org.gradle.internal.logging.text.StyledTextOutputFactory
19 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
21 import static org.gradle.api.tasks.testing.TestResult.ResultType
23 apply from: 'benchmark.gradle'
25 android {
26     project.maybeConfigForJetpackBenchmark(it)
27     if (project.hasProperty("testBuildType")) {
28         // Allowing to configure the test build type via command line flag (./gradlew -PtestBuildType=beta ..)
29         // in order to run UI tests against other build variants than debug in automation.
30         testBuildType project.property("testBuildType")
31     }
33     defaultConfig {
34         applicationId "org.mozilla"
35         minSdkVersion config.minSdkVersion
36         compileSdk config.compileSdkVersion
37         targetSdkVersion config.targetSdkVersion
38         versionCode 1
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",
52                 "{" +
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\"" +
62                 "}"
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"
77         } else {
78             buildConfigField "boolean", "MOZILLA_ONLINE", "false"
79         }
81         manifestPlaceholders = [
82                 "targetActivity": targetActivity,
83                 "deepLinkScheme": deepLinkSchemeValue
84         ]
85     }
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
101         }
103         if (gradle.hasProperty("localProperties.debuggable")) {
104             debuggable true
105         }
106     }
108     buildTypes {
109         debug {
110             shrinkResources false
111             minifyEnabled false
112             applicationIdSuffix ".fenix.debug"
113             resValue "bool", "IS_DEBUG", "true"
114             pseudoLocalesEnabled true
115         }
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
123             ])
124         }
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&regexp=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,
140             ])
141         }
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&regexp=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,
157             ])
158         }
159         benchmark releaseTemplate >> {
160             initWith buildTypes.nightly
161             applicationIdSuffix ".fenix"
162             debuggable false
163         }
164     }
166     buildFeatures {
167         viewBinding true
168         buildConfig true
169     }
171     androidResources {
172         // All JavaScript code used internally by GeckoView is packaged in a
173         // file called omni.ja. If this file is compressed in the APK,
174         // GeckoView must uncompress it before it can do anything else which
175         // causes a significant delay on startup.
176         noCompress 'ja'
178         // manifest.template.json is converted to manifest.json at build time.
179         // No need to package the template in the APK.
180         ignoreAssetsPattern "manifest.template.json"
181     }
183     testOptions {
184         execution 'ANDROIDX_TEST_ORCHESTRATOR'
185         unitTests.includeAndroidResources = true
186         animationsDisabled = true
187     }
189     flavorDimensions.add("product")
191     productFlavors {
192         fenix {
193             dimension "product"
194         }
195     }
197     sourceSets {
198         androidTest {
199             resources.srcDirs += ['src/androidTest/resources']
200         }
201     }
203     splits {
204         abi {
205             enable true
207             reset()
209             include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
210         }
211     }
213     compileOptions {
214         sourceCompatibility JavaVersion.VERSION_17
215         targetCompatibility JavaVersion.VERSION_17
216     }
218     bundle {
219         // Profiler issues require us to temporarily package native code compressed to
220         // match the previous APK packaging.
221         // https://bugzilla.mozilla.org/show_bug.cgi?id=1865634
222         packagingOptions {
223             jniLibs {
224                 it.useLegacyPackaging = true
225             }
226         }
228         language {
229             // Because we have runtime language selection we will keep all strings and languages
230             // in the base APKs.
231             enableSplit = false
232         }
233     }
235     lint {
236         lintConfig file("lint.xml")
237         baseline file("lint-baseline.xml")
238     }
239     packagingOptions {
240         resources {
241             excludes += ['META-INF/atomicfu.kotlin_module', 'META-INF/AL2.0', 'META-INF/LGPL2.1',
242                          'META-INF/LICENSE.md', 'META-INF/LICENSE-notice.md']
243         }
244         jniLibs {
245             useLegacyPackaging true
246         }
247     }
250     testOptions {
251         unitTests.returnDefaultValues = true
253         unitTests.all {
254             // We keep running into memory issues when running our tests. With this config we
255             // reserve more memory and also create a new process after every 80 test classes. This
256             // is a band-aid solution and eventually we should try to find and fix the leaks
257             // instead. :)
258             forkEvery = 80
259             maxHeapSize = "3072m"
260             minHeapSize = "1024m"
261         }
262     }
264     buildFeatures {
265         compose true
266     }
268     composeOptions {
269         kotlinCompilerExtensionVersion = Versions.compose_compiler
270     }
272     namespace 'org.mozilla.fenix'
275 android.applicationVariants.configureEach { variant ->
277 // -------------------------------------------------------------------------------------------------
278 // Generate version codes for builds
279 // -------------------------------------------------------------------------------------------------
281     def isDebug = variant.buildType.resValues['bool/IS_DEBUG']?.value ?: false
282     def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false
284     println("----------------------------------------------")
285     println("Variant name:      " + variant.name)
286     println("Application ID:    " + [variant.applicationId, variant.buildType.applicationIdSuffix].findAll().join())
287     println("Build type:        " + variant.buildType.name)
288     println("Flavor:            " + variant.flavorName)
289     println("Telemetry enabled: " + !isDebug)
291     if (useReleaseVersioning) {
292         // The Google Play Store does not allow multiple APKs for the same app that all have the
293         // same version code. Therefore we need to have different version codes for our ARM and x86
294         // builds.
296         def versionName = variant.buildType.name == 'nightly' ? Config.nightlyVersionName() : Config.releaseVersionName(project)
297         println("versionName override: $versionName")
299         variant.outputs.each { output ->
300             def isMozillaOnline = project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")
301             def abi = output.getFilter(FilterConfiguration.FilterType.ABI.name())
302             // If it is a Mozilla Online build, use a unified version code of armeabi-v7a
303             def arch = (isMozillaOnline) ? "armeabi-v7a" : abi
304             def aab = project.hasProperty("aab")
305             // We use the same version code generator, that we inherited from Fennec, across all channels - even on
306             // channels that never shipped a Fennec build.
307             def versionCodeOverride = Config.generateFennecVersionCode(arch, aab)
309             println("versionCode for $abi = $versionCodeOverride, isMozillaOnline = $isMozillaOnline")
311             if (versionName != null) {
312                 output.versionNameOverride = versionName
313             }
314             output.versionCodeOverride = versionCodeOverride
315         }
316     } else if (gradle.hasProperty("localProperties.branchBuild.fenix.version")) {
317         def versionName = gradle.getProperty("localProperties.branchBuild.fenix.version")
318         println("versionName override: $versionName")
319         variant.outputs.each { output ->
320             output.versionNameOverride = versionName
321         }
322     }
324 // -------------------------------------------------------------------------------------------------
325 // BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
326 // -------------------------------------------------------------------------------------------------
328     buildConfigField 'String', 'SENTRY_TOKEN', 'null'
329     if (!isDebug) {
330         buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
331         // Reading sentry token from local file (if it exists). In a release task on taskcluster it will be available.
332         try {
333             def token = new File("${rootDir}/.sentry_token").text.trim()
334             buildConfigField 'String', 'SENTRY_TOKEN', '"' + token + '"'
335         } catch (FileNotFoundException ignored) {}
336     } else {
337         buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
338     }
340     if (!isDebug) {
341         buildConfigField 'boolean', 'TELEMETRY', 'true'
342     } else {
343         buildConfigField 'boolean', 'TELEMETRY', 'false'
344     }
346     def buildDate = Config.generateBuildDate()
347     // Setting buildDate with every build changes the generated BuildConfig, which slows down the
348     // build. Only do this for non-debug builds, to speed-up builds produced during local development.
349     if (isDebug) {
350         buildConfigField 'String', 'BUILD_DATE', '"debug build"'
351     } else {
352         buildConfigField 'String', 'BUILD_DATE', '"' + buildDate + '"'
353     }
355 // -------------------------------------------------------------------------------------------------
356 // Adjust: Read token from local file if it exists (Only release builds)
357 // -------------------------------------------------------------------------------------------------
359     print("Adjust token: ")
361     if (!isDebug) {
362         try {
363             def token = new File("${rootDir}/.adjust_token").text.trim()
364             buildConfigField 'String', 'ADJUST_TOKEN', '"' + token + '"'
365             println "(Added from .adjust_token file)"
366         } catch (FileNotFoundException ignored) {
367             buildConfigField 'String', 'ADJUST_TOKEN', 'null'
368             println("X_X")
369         }
370     } else {
371         buildConfigField 'String', 'ADJUST_TOKEN', 'null'
372         println("--")
373     }
375 // -------------------------------------------------------------------------------------------------
376 // MLS: Read token from local file if it exists
377 // -------------------------------------------------------------------------------------------------
379     print("MLS token: ")
381     try {
382         def token = new File("${rootDir}/.mls_token").text.trim()
383         buildConfigField 'String', 'MLS_TOKEN', '"' + token + '"'
384         println "(Added from .mls_token file)"
385     } catch (FileNotFoundException ignored) {
386         buildConfigField 'String', 'MLS_TOKEN', '""'
387         println("X_X")
388     }
390 // -------------------------------------------------------------------------------------------------
391 // Nimbus: Read endpoint from local.properties of a local file if it exists
392 // -------------------------------------------------------------------------------------------------
394     print("Nimbus endpoint: ")
396     if (!isDebug) {
397         try {
398             def url = new File("${rootDir}/.nimbus").text.trim()
399             buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
400             println "(Added from .nimbus file)"
401         } catch (FileNotFoundException ignored) {
402             buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
403             println("X_X")
404         }
405     } else if (gradle.hasProperty("localProperties.nimbus.remote-settings.url")) {
406         def url=gradle.getProperty("localProperties.nimbus.remote-settings.url")
407         buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
408         println "(Added from local.properties file)"
409     } else {
410         buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
411         println("--")
412     }
414 // -------------------------------------------------------------------------------------------------
415 // Glean: Read custom server URL from local.properties of a local file if it exists
416 // -------------------------------------------------------------------------------------------------
418     print("Glean custom server URL: ")
420     if (gradle.hasProperty("localProperties.glean.custom.server.url")) {
421         def url=gradle.getProperty("localProperties.glean.custom.server.url")
422         buildConfigField 'String', 'GLEAN_CUSTOM_URL', url
423         println "(Added from local.properties file)"
424     } else {
425         buildConfigField 'String', 'GLEAN_CUSTOM_URL', 'null'
426         println("--")
427     }
429 // -------------------------------------------------------------------------------------------------
430 // BuildConfig: Set flag for official builds; similar to MOZILLA_OFFICIAL in mozilla-central.
431 // -------------------------------------------------------------------------------------------------
433     if (project.hasProperty("official") || gradle.hasProperty("localProperties.official")) {
434         buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'true'
435     } else {
436         buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'false'
437     }
439 // -------------------------------------------------------------------------------------------------
440 // BuildConfig: Set remote wallpaper URL using local file if it exists
441 // -------------------------------------------------------------------------------------------------
443     print("Wallpaper URL: ")
445     try {
446         def token = new File("${rootDir}/.wallpaper_url").text.trim()
447         buildConfigField 'String', 'WALLPAPER_URL', '"' + token + '"'
448         println "(Added from .wallpaper_url file)"
449     } catch (FileNotFoundException ignored) {
450         buildConfigField 'String', 'WALLPAPER_URL', '""'
451         println("--")
452     }
454 // -------------------------------------------------------------------------------------------------
455 // BuildConfig: Set the Pocket consumer key from a local file if it exists
456 // -------------------------------------------------------------------------------------------------
458     print("Pocket consumer key: ")
460     try {
461         def token = new File("${rootDir}/.pocket_consumer_key").text.trim()
462         buildConfigField 'String', 'POCKET_CONSUMER_KEY', '"' + token + '"'
463         println "(Added from .pocket_consumer_key file)"
464     } catch (FileNotFoundException ignored) {
465         buildConfigField 'String', 'POCKET_CONSUMER_KEY', '""'
466         println("--")
467     }
469 // -------------------------------------------------------------------------------------------------
470 // BuildConfig: Set flag to disable LeakCanary in debug (on CI builds)
471 // -------------------------------------------------------------------------------------------------
473     if (isDebug) {
474         if (project.hasProperty("disableLeakCanary") || gradle.hasProperty("localProperties.disableLeakCanary")) {
475             buildConfigField "boolean", "LEAKCANARY", "false"
476             println("LeakCanary enabled in debug: false")
477         } else {
478             buildConfigField "boolean", "LEAKCANARY", "true"
479             println("LeakCanary enabled in debug: true")
480         }
481     } else {
482         buildConfigField "boolean", "LEAKCANARY", "false"
483     }
487 // Generate Kotlin code for the Fenix Glean metrics.
488 apply plugin: "org.mozilla.telemetry.glean-gradle-plugin"
489 apply plugin: "org.mozilla.appservices.nimbus-gradle-plugin"
491 nimbus {
492     // The path to the Nimbus feature manifest file
493     manifestFile = "nimbus.fml.yaml"
494     // The fully qualified class name for the generated features.
495     // Map from the variant name to the channel as experimenter and nimbus understand it.
496     // If nimbus's channels were accurately set up well for this project, then this
497     // shouldn't be needed.
498     channels = [
499             fenixDebug: "developer",
500             fenixNightly: "nightly",
501             fenixBeta: "beta",
502             fenixRelease: "release",
503             fenixBenchmark: "developer",
504     ]
505     // This is generated by the FML and should be checked into git.
506     // It will be fetched by Experimenter (the Nimbus experiment website)
507     // and used to inform experiment configuration.
508     experimenterManifest = ".experimenter.yaml"
509     applicationServicesDir = gradle.hasProperty('localProperties.autoPublish.application-services.dir')
510             ? gradle.getProperty('localProperties.autoPublish.application-services.dir') : null
513 tasks.withType(KotlinCompile).configureEach {
514     kotlinOptions.freeCompilerArgs += "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
517 dependencies {
518     implementation project(':browser-engine-gecko')
520     implementation ComponentsDependencies.kotlin_coroutines
521     testImplementation ComponentsDependencies.testing_coroutines
522     implementation ComponentsDependencies.androidx_appcompat
523     implementation ComponentsDependencies.androidx_constraintlayout
524     implementation ComponentsDependencies.androidx_coordinatorlayout
525     implementation FenixDependencies.google_accompanist_drawablepainter
527     implementation ComponentsDependencies.thirdparty_sentry
529     implementation project(':compose-awesomebar')
530     implementation project(':compose-cfr')
532     implementation project(':concept-awesomebar')
533     implementation project(':concept-base')
534     implementation project(':concept-engine')
535     implementation project(':concept-menu')
536     implementation project(':concept-push')
537     implementation project(':concept-storage')
538     implementation project(':concept-sync')
539     implementation project(':concept-toolbar')
540     implementation project(':concept-tabstray')
542     implementation project(':browser-domains')
543     implementation project(':browser-icons')
544     implementation project(':browser-menu')
545     implementation project(':browser-menu2')
546     implementation project(':browser-session-storage')
547     implementation project(':browser-state')
548     implementation project(':browser-storage-sync')
549     implementation project(':browser-tabstray')
550     implementation project(':browser-thumbnails')
551     implementation project(':browser-toolbar')
553     implementation project(':feature-addons')
554     implementation project(':feature-accounts')
555     implementation project(':feature-app-links')
556     implementation project(':feature-autofill')
557     implementation project(':feature-awesomebar')
558     implementation project(':feature-contextmenu')
559     implementation project(':feature-customtabs')
560     implementation project(':feature-downloads')
561     implementation project(':feature-fxsuggest')
562     implementation project(':feature-intent')
563     implementation project(':feature-media')
564     implementation project(':feature-prompts')
565     implementation project(':feature-push')
566     implementation project(':feature-privatemode')
567     implementation project(':feature-pwa')
568     implementation project(':feature-qr')
569     implementation project(':feature-search')
570     implementation project(':feature-session')
571     implementation project(':feature-syncedtabs')
572     implementation project(':feature-toolbar')
573     implementation project(':feature-tabs')
574     implementation project(':feature-findinpage')
575     implementation project(':feature-logins')
576     implementation project(':feature-sitepermissions')
577     implementation project(':feature-readerview')
578     implementation project(':feature-tab-collections')
579     implementation project(':feature-recentlyclosed')
580     implementation project(':feature-top-sites')
581     implementation project(':feature-share')
582     implementation project(':feature-accounts-push')
583     implementation project(':feature-webauthn')
584     implementation project(':feature-webcompat')
585     implementation project(':feature-webnotifications')
586     implementation project(':feature-webcompat-reporter')
588     implementation project(':service-pocket')
589     implementation project(':service-contile')
590     implementation project(':service-digitalassetlinks')
591     implementation project(':service-sync-autofill')
592     implementation project(':service-sync-logins')
593     implementation project(':service-firefox-accounts')
594     implementation project(':service-glean')
595     implementation project(':service-location')
596     implementation project(':service-nimbus')
598     implementation project(':support-webextensions')
599     implementation project(':support-base')
600     implementation project(':support-rusterrors')
601     implementation project(':support-images')
602     implementation project(':support-ktx')
603     implementation project(':support-rustlog')
604     implementation project(':support-utils')
605     implementation project(':support-locale')
607     implementation project(':ui-colors')
608     implementation project(':ui-icons')
609     implementation project(':lib-publicsuffixlist')
610     implementation project(':ui-widgets')
611     implementation project(':ui-tabcounter')
613     implementation project(':lib-crash')
614     implementation project(':lib-crash-sentry')
615     implementation project(':lib-push-firebase')
616     implementation project(':lib-state')
617     implementation project(':lib-dataprotect')
619     debugImplementation ComponentsDependencies.leakcanary
620     debugImplementation ComponentsDependencies.androidx_compose_ui_tooling
622     implementation ComponentsDependencies.androidx_activity_compose
623     implementation FenixDependencies.androidx_activity_ktx
624     implementation ComponentsDependencies.androidx_annotation
625     implementation ComponentsDependencies.androidx_compose_ui
626     implementation ComponentsDependencies.androidx_compose_ui_tooling_preview
627     implementation ComponentsDependencies.androidx_compose_animation
628     implementation ComponentsDependencies.androidx_compose_foundation
629     implementation ComponentsDependencies.androidx_compose_material
630     implementation FenixDependencies.androidx_legacy
631     implementation ComponentsDependencies.androidx_biometric
632     implementation ComponentsDependencies.androidx_paging
633     implementation ComponentsDependencies.androidx_preferences
634     implementation ComponentsDependencies.androidx_fragment
635     implementation FenixDependencies.androidx_navigation_fragment
636     implementation FenixDependencies.androidx_navigation_ui
637     implementation ComponentsDependencies.androidx_compose_navigation
638     implementation ComponentsDependencies.androidx_recyclerview
639     implementation ComponentsDependencies.androidx_lifecycle_common
640     implementation ComponentsDependencies.androidx_lifecycle_livedata
641     implementation ComponentsDependencies.androidx_lifecycle_process
642     implementation ComponentsDependencies.androidx_lifecycle_runtime
644     implementation ComponentsDependencies.androidx_lifecycle_viewmodel
645     implementation ComponentsDependencies.androidx_core
646     implementation ComponentsDependencies.androidx_core_ktx
647     implementation FenixDependencies.androidx_core_splashscreen
648     implementation FenixDependencies.androidx_transition
649     implementation ComponentsDependencies.androidx_work_runtime
650     implementation FenixDependencies.androidx_datastore
651     implementation ComponentsDependencies.androidx_data_store_preferences
652     implementation FenixDependencies.protobuf_javalite
653     implementation ComponentsDependencies.google_material
655     implementation FenixDependencies.adjust
656     implementation FenixDependencies.installreferrer // Required by Adjust
658     implementation FenixDependencies.google_ads_id // Required for the Google Advertising ID
660     // Required for in-app reviews
661     implementation FenixDependencies.google_play_review
662     implementation FenixDependencies.google_play_review_ktx
664     implementation FenixDependencies.androidx_profileinstaller
666     androidTestImplementation ComponentsDependencies.androidx_test_uiautomator
667     androidTestImplementation FenixDependencies.fastlane
668     // This Falcon version is added to maven central now required for Screengrab
669     androidTestImplementation FenixDependencies.falcon
671     androidTestImplementation ComponentsDependencies.androidx_compose_ui_test
673     androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
674         exclude group: 'com.android.support', module: 'support-annotations'
675     }
677     androidTestImplementation(FenixDependencies.espresso_contrib) {
678         exclude module: 'appcompat-v7'
679         exclude module: 'support-v4'
680         exclude module: 'support-annotations'
681         exclude module: 'recyclerview-v7'
682         exclude module: 'design'
683         exclude module: 'espresso-core'
684         exclude module: 'protobuf-lite'
685     }
687     androidTestImplementation ComponentsDependencies.androidx_test_core
688     androidTestImplementation FenixDependencies.espresso_idling_resources
689     androidTestImplementation FenixDependencies.espresso_intents
691     androidTestImplementation ComponentsDependencies.androidx_test_runner
692     androidTestImplementation ComponentsDependencies.androidx_test_rules
693     androidTestUtil FenixDependencies.orchestrator
694     androidTestImplementation ComponentsDependencies.androidx_espresso_core, {
695         exclude group: 'com.android.support', module: 'support-annotations'
696     }
698     androidTestImplementation ComponentsDependencies.androidx_test_junit
699     androidTestImplementation ComponentsDependencies.androidx_work_testing
700     androidTestImplementation FenixDependencies.androidx_benchmark_junit4
701     androidTestImplementation ComponentsDependencies.testing_mockwebserver
702     testImplementation project(':support-test')
703     testImplementation project(':support-test-libstate')
704     testImplementation ComponentsDependencies.androidx_test_junit
705     testImplementation ComponentsDependencies.androidx_work_testing
706     testImplementation (ComponentsDependencies.testing_robolectric) {
707         exclude group: 'org.apache.maven'
708     }
710     testImplementation ComponentsDependencies.testing_maven_ant_tasks
711     implementation project(':support-rusthttp')
713     androidTestImplementation FenixDependencies.mockk_android
714     testImplementation FenixDependencies.mockk
716     // For the initial release of Glean 19, we require consumer applications to
717     // depend on a separate library for unit tests. This will be removed in future releases.
718     testImplementation "org.mozilla.telemetry:glean-native-forUnitTests:${project.ext.glean_version}"
720     lintChecks project(":mozilla-lint-rules")
723 protobuf {
724     protoc {
725         artifact = FenixDependencies.protobuf_compiler
726     }
728     // Generates the java Protobuf-lite code for the Protobufs in this project. See
729     // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
730     // for more information.
731     generateProtoTasks {
732         all().each { task ->
733             task.builtins {
734                 java {
735                     option 'lite'
736                 }
737             }
738         }
739     }
742 if (project.hasProperty("coverage")) {
743     tasks.withType(Test).configureEach {
744         jacoco.includeNoLocationClasses = true
745         jacoco.excludes = ['jdk.internal.*']
746     }
748     jacoco {
749         toolVersion = Versions.jacoco
750     }
752     android.applicationVariants.configureEach { variant ->
753         tasks.register("jacoco${variant.name.capitalize()}TestReport", JacocoReport) {
754             dependsOn "test${variant.name.capitalize()}UnitTest"
756             reports {
757                 xml.required = true
758                 html.required = true
759             }
761             def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
762                               '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
763             def kotlinDebugTree = fileTree(dir: "$project.layout.buildDirectory/tmp/kotlin-classes/${variant.name}", excludes: fileFilter)
764             def javaDebugTree = fileTree(dir: "$project.layout.buildDirectory/intermediates/classes/${variant.flavorName}/${variant.buildType.name}",
765                     excludes: fileFilter)
766             def mainSrc = "$project.projectDir/src/main/java"
768             sourceDirectories.setFrom(files([mainSrc]))
769             classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
770             executionData.setFrom(fileTree(dir: project.layout.buildDirectory, includes: [
771                 "jacoco/test${variant.name.capitalize()}UnitTest.exec",
772                 'outputs/code-coverage/connected/*coverage.ec'
773             ]))
774         }
775     }
777     android {
778         buildTypes {
779             debug {
780                 testCoverageEnabled true
781             }
782         }
783     }
786 // -------------------------------------------------------------------------------------------------
787 // Task for printing APK information for the requested variant
788 // Usage: "./gradlew printVariants
789 // -------------------------------------------------------------------------------------------------
790 tasks.register('printVariants') {
791     doLast {
792         def variants = android.applicationVariants.collect { variant -> [
793             apks: variant.outputs.collect { output -> [
794                 abi: output.getFilter(FilterConfiguration.FilterType.ABI.name()),
795                 fileName: output.outputFile.name
796             ]},
797             build_type: variant.buildType.name,
798             name: variant.name,
799         ]}
800         // AndroidTest is a special case not included above
801         variants.add([
802             apks: [[
803                 abi: 'noarch',
804                 fileName: 'app-debug-androidTest.apk',
805             ]],
806             build_type: 'androidTest',
807             name: 'androidTest',
808         ])
809         println 'variants: ' + JsonOutput.toJson(variants)
810     }
813 tasks.register('buildTranslationArray') {
814     // This isn't running as a task, instead the array is build when the gradle file is parsed.
815     // https://github.com/mozilla-mobile/fenix/issues/14175
816     def foundLocales = new StringBuilder()
817     foundLocales.append("new String[]{")
819     fileTree("src/main/res").visit { FileVisitDetails details ->
820         if (details.file.path.endsWith("${File.separator}strings.xml")) {
821             def languageCode = details.file.parent.tokenize(File.separator).last().replaceAll('values-', '').replaceAll('-r', '-')
822             languageCode = (languageCode == "values") ? "en-US" : languageCode
823             foundLocales.append("\"").append(languageCode).append("\"").append(",")
824         }
825     }
827     foundLocales.append("}")
828     def foundLocalesString = foundLocales.toString().replaceAll(',}', '}')
829     android.defaultConfig.buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", foundLocalesString
832 afterEvaluate {
834     // Format test output. Ported from AC #2401
835     tasks.withType(Test).configureEach {
836         systemProperty "robolectric.logging", "stdout"
837         systemProperty "logging.test-mode", "true"
839         testLogging.events = []
841         def out = services.get(StyledTextOutputFactory).create("tests")
843         beforeSuite { descriptor ->
844             if (descriptor.getClassName() != null) {
845                 out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
846             }
847         }
849         beforeTest { descriptor ->
850             out.style(Style.Description).println("  TEST: " + descriptor.getName())
851         }
853         onOutput { descriptor, event ->
854             logger.lifecycle("    " + event.message.trim())
855         }
857         afterTest { descriptor, result ->
858             switch (result.getResultType()) {
859                 case ResultType.SUCCESS:
860                     out.style(Style.Success).println("  SUCCESS")
861                     break
863                 case ResultType.FAILURE:
864                     out.style(Style.Failure).println("  FAILURE")
865                     logger.lifecycle("", result.getException())
866                     break
868                 case ResultType.SKIPPED:
869                     out.style(Style.Info).println("  SKIPPED")
870                     break
871             }
872             logger.lifecycle("")
873         }
874     }
877 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
878     if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
879         ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
880     }
881     ext.topsrcdir = StringUtils.removeSuffix(gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir", File.separator)
882     apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
885 if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
886     ext.gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
887     apply from: "../${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
890 android.applicationVariants.configureEach { variant ->
891     tasks.register("apkSize${variant.name.capitalize()}", ApkSizeTask) {
892         variantName = variant.name
893         apks = variant.outputs.collect { output -> output.outputFile.name }
894         dependsOn "package${variant.name.capitalize()}"
895     }
898 // Enable expiration by major version.
899 ext.gleanExpireByVersion = Config.majorVersion()