build.gradle 32.5 KB
Newer Older
1
2
3
4
plugins {
    id "com.jetbrains.python.envs" version "0.0.26"
}

Jeff Boek's avatar
Jeff Boek committed
5
6
7
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
Colin Lee's avatar
Colin Lee committed
8
apply plugin: 'jacoco'
9
apply plugin: 'androidx.navigation.safeargs.kotlin'
10
apply plugin: 'com.google.android.gms.oss-licenses-plugin'
Jeff Boek's avatar
Jeff Boek committed
11

Tiger Oakes's avatar
Tiger Oakes committed
12
13

import com.android.build.OutputFile
Tiger Oakes's avatar
Tiger Oakes committed
14
import groovy.json.JsonOutput
15
16
import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory
Tiger Oakes's avatar
Tiger Oakes committed
17

18
import static org.gradle.api.tasks.testing.TestResult.ResultType
19

Jeff Boek's avatar
Jeff Boek committed
20
android {
21
    compileSdkVersion Config.compileSdkVersion
22
23
24
25
26
27
28

    if (project.hasProperty("testBuildType")) {
        // Allowing to configure the test build type via command line flag (./gradlew -PtestBuildType=beta ..)
        // in order to run UI tests against other build variants than debug in automation.
        testBuildType project.property("testBuildType")
    }

Jeff Boek's avatar
Jeff Boek committed
29
    defaultConfig {
30
        applicationId "org.mozilla"
31
32
        minSdkVersion Config.minSdkVersion
        targetSdkVersion Config.targetSdkVersion
33
34
        versionCode 1
        versionName Config.generateDebugVersionName()
35
        vectorDrawables.useSupportLibrary = true
Kevin Brosnan's avatar
Kevin Brosnan committed
36
37
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments clearPackageData: 'true'
38
39
        resValue "bool", "IS_DEBUG", "false"
        buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false"
40
41
42
43
        // This should be the "public" base URL of AMO.
        buildConfigField "String", "AMO_BASE_URL", "\"https://addons.mozilla.org\""
        buildConfigField "String", "AMO_COLLECTION_NAME", "\"7dfae8669acc4312a65e8ba5553036\""
        buildConfigField "String", "AMO_COLLECTION_USER", "\"mozilla\""
44
45
46
47
48
49
50
51
52
53
54
55
        // These add-ons should be excluded for Mozilla Online builds.
        buildConfigField "String[]", "MOZILLA_ONLINE_ADDON_EXCLUSIONS",
                "{" +
                        "\"uBlock0@raymondhill.net\"," +
                        "\"firefox@ghostery.com\"," +
                        "\"jid1-MnnxcxisBPnSXQ@jetpack\"," +
                        "\"adguardadblocker@adguard.com\"," +
                        "\"foxyproxy@eric.h.jung\"," +
                        "\"{73a6fe31-595d-460b-a920-fcc0f8843232}\"," +
                        "\"jid1-BoFifL9Vbdl2zQ@jetpack\"," +
                        "\"woop-NoopscooPsnSXQ@jetpack\"" +
                "}"
56
57
        // This should be the base URL used to call the AMO API.
        buildConfigField "String", "AMO_SERVER_URL", "\"https://services.addons.mozilla.org\""
58
59
        def deepLinkSchemeValue = "fenix-dev"
        buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
60
        manifestPlaceholders = [
61
62
                "deepLinkScheme": deepLinkSchemeValue,
                "requestLegacyExternalStorage": true
63
        ]
64
65
66
67
68
69
70

        // Build flag for "Mozilla Online" variants. See `Config.isMozillaOnline`.
        if (project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")) {
            buildConfigField "boolean", "MOZILLA_ONLINE", "true"
        } else {
            buildConfigField "boolean", "MOZILLA_ONLINE", "false"
        }
71
72
73
    }

    def releaseTemplate = {
74
75
76
77
        // We allow disabling optimization by passing `-PdisableOptimization` to gradle. This is used
        // in automation for UI testing non-debug builds.
        shrinkResources !project.hasProperty("disableOptimization")
        minifyEnabled !project.hasProperty("disableOptimization")
78
        proguardFiles 'proguard-android-optimize-3.5.0-modified.txt', 'proguard-rules.pro'
79
        matchingFallbacks = ['release'] // Use on the "release" build type in dependencies (AARs)
80
81
82
83

        if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) {
            signingConfig signingConfigs.debug
        }
84
85
86
87

        if (gradle.hasProperty("localProperties.debuggable")) {
            debuggable true
        }
Jeff Boek's avatar
Jeff Boek committed
88
    }
89

Jeff Boek's avatar
Jeff Boek committed
90
    buildTypes {
91
        debug {
92
93
            shrinkResources false
            minifyEnabled false
94
            applicationIdSuffix ".fenix.debug"
95
            resValue "bool", "IS_DEBUG", "true"
96
            pseudoLocalesEnabled true
97
98
99
100
101
102
            def deepLinkSchemeValue = "fenix-dev"
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders = [
                    "deepLinkScheme": deepLinkSchemeValue,
                    "requestLegacyExternalStorage": false
            ]
103
        }
104
        nightly releaseTemplate >> {
105
            applicationIdSuffix ".fenix"
106
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
107
            def deepLinkSchemeValue = "fenix-nightly"
108
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
109
            manifestPlaceholders = ["deepLinkScheme": deepLinkSchemeValue, "requestLegacyExternalStorage": false]
110
        }
111
        beta releaseTemplate >> {
112
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
113
114
            applicationIdSuffix ".firefox_beta"
            def deepLinkSchemeValue = "fenix-beta"
115
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
116
            manifestPlaceholders = [
117
                    // This release type is meant to replace Firefox (Beta channel) and therefore needs to inherit
Jeff Boek's avatar
Jeff Boek committed
118
119
120
121
122
123
                    // its sharedUserId for all eternity. See:
                    // https://searchfox.org/mozilla-central/search?q=moz_android_shared_id&case=false&regexp=false&path=
                    // Shipping an app update without sharedUserId can have
                    // fatal consequences. For example see:
                    //  - https://issuetracker.google.com/issues/36924841
                    //  - https://issuetracker.google.com/issues/36905922
124
                    "sharedUserId": "org.mozilla.firefox.sharedID",
125
126
                    "deepLinkScheme": deepLinkSchemeValue,
                    "requestLegacyExternalStorage": true
127
            ]
128
        }
129
        release releaseTemplate >> {
130
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
131
132
            applicationIdSuffix ".firefox"
            def deepLinkSchemeValue = "fenix"
133
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
134
135
136
137
138
139
140
141
            manifestPlaceholders = [
                    // This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
                    // its sharedUserId for all eternity. See:
                    // https://searchfox.org/mozilla-central/search?q=moz_android_shared_id&case=false&regexp=false&path=
                    // Shipping an app update without sharedUserId can have
                    // fatal consequences. For example see:
                    //  - https://issuetracker.google.com/issues/36924841
                    //  - https://issuetracker.google.com/issues/36905922
142
                    "sharedUserId": "org.mozilla.firefox.sharedID",
143
144
                    "deepLinkScheme": deepLinkSchemeValue,
                    "requestLegacyExternalStorage": true
145
146
            ]
        }
147
148
    }

149
150
151
152
153
154
    aaptOptions {
        // All JavaScript code used internally by GeckoView is packaged in a
        // file called omni.ja. If this file is compressed in the APK,
        // GeckoView must uncompress it before it can do anything else which
        // causes a significant delay on startup.
        noCompress 'ja'
155
156
157
158

        // manifest.template.json is converted to manifest.json at build time.
        // No need to package the template in the APK.
        ignoreAssetsPattern "manifest.template.json"
159
160
    }

Kevin Brosnan's avatar
Kevin Brosnan committed
161
162
    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'
163
        unitTests.includeAndroidResources = true
164
        animationsDisabled = true
Kevin Brosnan's avatar
Kevin Brosnan committed
165
166
    }

167
    flavorDimensions "engine"
168

Isabel Rios's avatar
Isabel Rios committed
169
170
    sourceSets {
        androidTest {
Jeff Boek's avatar
Jeff Boek committed
171
            resources.srcDirs += ['src/androidTest/resources']
Isabel Rios's avatar
Isabel Rios committed
172
        }
173
174
        debug {
            java.srcDirs = ['src/geckoNightly/java']
175
        }
176
177
        nightly {
            java.srcDirs = ['src/geckoNightly/java']
178
        }
179
180
        beta {
            java.srcDirs = ['src/migration/java', 'src/geckoBeta/java']
181
182
            manifest.srcFile "src/migration/AndroidManifest.xml"
        }
183
184
185
        release {
            java.srcDirs = ['src/migration/java', 'src/geckoRelease/java']
            manifest.srcFile "src/migration/AndroidManifest.xml"
186
        }
187
188
189
190
191
192
193
194
195
    }

    splits {
        abi {
            enable true

            reset()

            include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
196
        }
197
198
    }

199
200
201
202
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
203
204
205

    lintOptions {
        lintConfig file("lint.xml")
206
        baseline file("lint-baseline.xml")
207
    }
208
209
210
211

    packagingOptions {
        exclude 'META-INF/atomicfu.kotlin_module'
    }
212
213
214

    testOptions {
        unitTests.returnDefaultValues = true
215
216
217
218
219
220
221
222
223
224
225

        unitTests.all {
            // We keep running into memory issues when running our tests. With this config we
            // reserve more memory and also create a new process after every 80 test classes. This
            // is a band-aid solution and eventually we should try to find and fix the leaks
            // instead. :)
            maxParallelForks = 2
            forkEvery = 80
            maxHeapSize = "2048m"
            minHeapSize = "1024m"
        }
226
    }
227
228
}

229
android.applicationVariants.all { variant ->
230
231
232
233
234

// -------------------------------------------------------------------------------------------------
// Set up kotlin-allopen plugin for writing tests
// -------------------------------------------------------------------------------------------------

235
    boolean hasTest = gradle.startParameter.taskNames.find { it.contains("test") || it.contains("Test") } != null
236
237
238
    if (hasTest) {
        apply plugin: 'kotlin-allopen'
        allOpen {
239
            annotation("org.mozilla.fenix.utils.OpenClass")
240
241
242
        }
    }

243
244
245
246
// -------------------------------------------------------------------------------------------------
// Generate version codes for builds
// -------------------------------------------------------------------------------------------------

247
248
    def isDebug = variant.buildType.resValues['IS_DEBUG']?.value ?: false
    def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false
249
250
    def versionName = Config.releaseVersionName(project)

251
252
253
254
255
256
257
    println("----------------------------------------------")
    println("Variant name:      " + variant.name)
    println("Application ID:    " + [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join())
    println("Build type:        " + variant.buildType.name)
    println("Flavor:            " + variant.flavorName)
    println("Telemetry enabled: " + !isDebug)

258
    if (useReleaseVersioning) {
259
260
261
262
        // The Google Play Store does not allow multiple APKs for the same app that all have the
        // same version code. Therefore we need to have different version codes for our ARM and x86
        // builds.

263
264
        variant.outputs.each { output ->
            def abi = output.getFilter(OutputFile.ABI)
265
266
267
            // We use the same version code generator, that we inherited from Fennec, across all channels - even on
            // channels that never shipped a Fennec build.
            def versionCodeOverride = Config.generateFennecVersionCode(abi)
268
269

            println("versionCode for $abi = $versionCodeOverride")
270
271
272

            output.versionNameOverride = versionName
            output.versionCodeOverride = versionCodeOverride
273
        }
274
275
    }

276
277
278
279
// -------------------------------------------------------------------------------------------------
// BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
// -------------------------------------------------------------------------------------------------

280
281
    buildConfigField 'String', 'SENTRY_TOKEN', 'null'
    if (!isDebug) {
282
        buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
283
284
285
286
287
        // Reading sentry token from local file (if it exists). In a release task on taskcluster it will be available.
        try {
            def token = new File("${rootDir}/.sentry_token").text.trim()
            buildConfigField 'String', 'SENTRY_TOKEN', '"' + token + '"'
        } catch (FileNotFoundException ignored) {}
288
289
290
291
    } else {
        buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
    }

292
    if (!isDebug) {
293
294
295
296
297
298
        buildConfigField 'boolean', 'TELEMETRY', 'true'
    } else {
        buildConfigField 'boolean', 'TELEMETRY', 'false'
    }

    def buildDate = Config.generateBuildDate()
299
300
301
302
303
304
305
    // Setting buildDate with every build changes the generated BuildConfig, which slows down the
    // build. Only do this for non-debug builds, to speed-up builds produced during local development.
    if (isDebug) {
        buildConfigField 'String', 'BUILD_DATE', '"debug build"'
    } else {
        buildConfigField 'String', 'BUILD_DATE', '"' + buildDate + '"'
    }
Jeff Boek's avatar
Jeff Boek committed
306

307
// -------------------------------------------------------------------------------------------------
Jeff Boek's avatar
Jeff Boek committed
308
// Adjust: Read token from local file if it exists (Only release builds)
309
310
311
312
// -------------------------------------------------------------------------------------------------

    print("Adjust token: ")

313
    if (!isDebug) {
314
315
316
317
318
319
320
321
322
323
324
325
        try {
            def token = new File("${rootDir}/.adjust_token").text.trim()
            buildConfigField 'String', 'ADJUST_TOKEN', '"' + token + '"'
            println "(Added from .adjust_token file)"
        } catch (FileNotFoundException ignored) {
            buildConfigField 'String', 'ADJUST_TOKEN', 'null'
            println("X_X")
        }
    } else {
        buildConfigField 'String', 'ADJUST_TOKEN', 'null'
        println("--")
    }
Jeff Boek's avatar
Jeff Boek committed
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344

// -------------------------------------------------------------------------------------------------
// Leanplum: Read token from local file if it exists
// -------------------------------------------------------------------------------------------------

    print("Leanplum token: ")

    try {
        def parts = new File("${rootDir}/.leanplum_token").text.trim().split(":")
        def id = parts[0]
        def key = parts[1]
        buildConfigField 'String', 'LEANPLUM_ID', '"' + id + '"'
        buildConfigField 'String', 'LEANPLUM_TOKEN', '"' + key + '"'
        println "(Added from .leanplum_token file)"
    } catch (FileNotFoundException ignored) {
        buildConfigField 'String', 'LEANPLUM_ID', 'null'
        buildConfigField 'String', 'LEANPLUM_TOKEN', 'null'
        println("X_X")
    }
345

346
347
348
349
350
351
352
353
354
355
356
357
358
359
// -------------------------------------------------------------------------------------------------
// MLS: Read token from local file if it exists
// -------------------------------------------------------------------------------------------------

    print("MLS token: ")

    try {
        def token = new File("${rootDir}/.mls_token").text.trim()
        buildConfigField 'String', 'MLS_TOKEN', '"' + token + '"'
        println "(Added from .mls_token file)"
    } catch (FileNotFoundException ignored) {
        buildConfigField 'String', 'MLS_TOKEN', '""'
        println("X_X")
    }
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383

// -------------------------------------------------------------------------------------------------
// Nimbus: Read endpoint from local.properties of a local file if it exists
// -------------------------------------------------------------------------------------------------

    print("Nimbus endpoint: ")

    if (!isDebug) {
        try {
            def url = new File("${rootDir}/.nimbus").text.trim()
            buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
            println "(Added from .nimbus file)"
        } catch (FileNotFoundException ignored) {
            buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
            println("X_X")
        }
    } else if (gradle.hasProperty("localProperties.nimbus.remote-settings.url")) {
        def url=gradle.getProperty("localProperties.nimbus.remote-settings.url")
        buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
        println "(Added from local.properties file)"
    } else {
        buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
        println("--")
    }
384
385
386
387
388
389
390
391
392
393

// -------------------------------------------------------------------------------------------------
// BuildConfig: Set flag for official builds; similar to MOZILLA_OFFICIAL in mozilla-central.
// -------------------------------------------------------------------------------------------------

    if (project.hasProperty("official") || gradle.hasProperty("localProperties.official")) {
        buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'true'
    } else {
        buildConfigField 'Boolean', 'MOZILLA_OFFICIAL', 'false'
    }
Jeff Boek's avatar
Jeff Boek committed
394
395
}

396
397
398
399
androidExtensions {
    experimental = true
}

400
401
402
403
404
// Generate Kotlin code and markdown docs for the Fenix Glean metrics.
ext.gleanGenerateMarkdownDocs = true
ext.gleanDocsDirectory = "$rootDir/docs"
apply plugin: "org.mozilla.telemetry.glean-gradle-plugin"

405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
configurations {
    // There's an interaction between Gradle's resolution of dependencies with different types
    // (@jar, @aar) for `implementation` and `testImplementation` and with Android Studio's built-in
    // JUnit test runner.  The runtime classpath in the built-in JUnit test runner gets the
    // dependency from the `implementation`, which is type @aar, and therefore the JNA dependency
    // doesn't provide the JNI dispatch libraries in the correct Java resource directories.  I think
    // what's happening is that @aar type in `implementation` resolves to the @jar type in
    // `testImplementation`, and that it wins the dependency resolution battle.
    //
    // A workaround is to add a new configuration which depends on the @jar type and to reference
    // the underlying JAR file directly in `testImplementation`.  This JAR file doesn't resolve to
    // the @aar type in `implementation`.  This works when invoked via `gradle`, but also sets the
    // correct runtime classpath when invoked with Android Studio's built-in JUnit test runner.
    // Success!
    jnaForTest
    // Robolectric, through `com.google.android.apps.common.testing.accessibility.framework`
    // depends on an old version of protobuf that conflict with the Application Services one.
    // See: https://github.com/mozilla/application-services/issues/2952
    all*.exclude group: 'com.google.protobuf', module: 'protobuf-java'
}

Jeff Boek's avatar
Jeff Boek committed
426
dependencies {
427
428
429
    jnaForTest Deps.jna
    testImplementation files(configurations.jnaForTest.copyRecursive().files)

430
431
432
433
434
    debugImplementation Deps.mozilla_browser_engine_gecko_nightly

    nightlyImplementation Deps.mozilla_browser_engine_gecko_nightly
    betaImplementation Deps.mozilla_browser_engine_gecko_beta
    releaseImplementation Deps.mozilla_browser_engine_gecko_release
435

436
    implementation Deps.kotlin_stdlib
437
    implementation Deps.kotlin_coroutines
438
    implementation Deps.kotlin_coroutines_android
439
    testImplementation Deps.kotlin_coroutines_test
440
441
    implementation Deps.androidx_appcompat
    implementation Deps.androidx_constraintlayout
Emily Kager's avatar
Emily Kager committed
442
    implementation Deps.androidx_coordinatorlayout
443

444
    implementation Deps.sentry
Jeff Boek's avatar
Jeff Boek committed
445

446
447
448
    implementation Deps.leanplum_core
    implementation Deps.leanplum_fcm

449
    implementation Deps.mozilla_concept_base
450
    implementation Deps.mozilla_concept_engine
Tiger Oakes's avatar
Tiger Oakes committed
451
    implementation Deps.mozilla_concept_menu
452
    implementation Deps.mozilla_concept_push
453
    implementation Deps.mozilla_concept_storage
454
    implementation Deps.mozilla_concept_sync
455
    implementation Deps.mozilla_concept_toolbar
456
    implementation Deps.mozilla_concept_tabstray
457

Jeff Boek's avatar
Jeff Boek committed
458
    implementation Deps.mozilla_browser_awesomebar
459
    implementation Deps.mozilla_feature_downloads
460
    implementation Deps.mozilla_browser_domains
461
    implementation Deps.mozilla_browser_icons
462
    implementation Deps.mozilla_browser_menu
463
    implementation Deps.mozilla_browser_menu2
464
    implementation Deps.mozilla_browser_search
465
    implementation Deps.mozilla_browser_session
466
    implementation Deps.mozilla_browser_session_storage
467
    implementation Deps.mozilla_browser_state
468
    implementation Deps.mozilla_browser_storage_sync
469
470
    implementation Deps.mozilla_browser_tabstray
    implementation Deps.mozilla_browser_thumbnails
Jeff Boek's avatar
Jeff Boek committed
471
472
    implementation Deps.mozilla_browser_toolbar

Gabriel Luong's avatar
Gabriel Luong committed
473
474
475
    implementation Deps.mozilla_support_extensions
    implementation Deps.mozilla_feature_addons

476
    implementation Deps.mozilla_feature_accounts
477
    implementation Deps.mozilla_feature_app_links
478
    implementation Deps.mozilla_feature_awesomebar
479
    implementation Deps.mozilla_feature_contextmenu
480
    implementation Deps.mozilla_feature_customtabs
481
    implementation Deps.mozilla_feature_downloads
482
    implementation Deps.mozilla_feature_intent
483
    implementation Deps.mozilla_feature_media
484
    implementation Deps.mozilla_feature_prompts
485
    implementation Deps.mozilla_feature_push
486
    implementation Deps.mozilla_feature_privatemode
487
    implementation Deps.mozilla_feature_pwa
Colin Lee's avatar
Colin Lee committed
488
    implementation Deps.mozilla_feature_qr
489
    implementation Deps.mozilla_feature_search
490
    implementation Deps.mozilla_feature_session
491
    implementation Deps.mozilla_feature_syncedtabs
492
    implementation Deps.mozilla_feature_toolbar
493
    implementation Deps.mozilla_feature_tabs
494
    implementation Deps.mozilla_feature_findinpage
495
    implementation Deps.mozilla_feature_logins
496
    implementation Deps.mozilla_feature_site_permissions
497
    implementation Deps.mozilla_feature_readerview
498
    implementation Deps.mozilla_feature_tab_collections
ekager's avatar
ekager committed
499
    implementation Deps.mozilla_feature_recentlyclosed
500
    implementation Deps.mozilla_feature_top_sites
Mihai Branescu's avatar
Mihai Branescu committed
501
    implementation Deps.mozilla_feature_share
502
    implementation Deps.mozilla_feature_accounts_push
503
    implementation Deps.mozilla_feature_webauthn
504
    implementation Deps.mozilla_feature_webcompat
505
    implementation Deps.mozilla_feature_webnotifications
506
    implementation Deps.mozilla_feature_webcompat_reporter
507

Tiger Oakes's avatar
Tiger Oakes committed
508
    implementation Deps.mozilla_service_digitalassetlinks
ekager's avatar
ekager committed
509
    implementation Deps.mozilla_service_sync_logins
510
    implementation Deps.mozilla_service_firefox_accounts
511
    implementation Deps.mozilla_service_glean
512
    implementation Deps.mozilla_service_location
jhugman's avatar
jhugman committed
513
    implementation Deps.mozilla_service_nimbus
514

515
    implementation Deps.mozilla_support_base
516
    implementation Deps.mozilla_support_images
517
    implementation Deps.mozilla_support_ktx
518
    implementation Deps.mozilla_support_rustlog
519
    implementation Deps.mozilla_support_utils
520
    implementation Deps.mozilla_support_locale
521

522
    implementation Deps.mozilla_support_migration
523

524
525
    implementation Deps.mozilla_ui_colors
    implementation Deps.mozilla_ui_icons
526
    implementation Deps.mozilla_lib_publicsuffixlist
527
    implementation Deps.mozilla_ui_widgets
528
    implementation Deps.mozilla_ui_tabcounter
529

530
    implementation Deps.mozilla_lib_crash
531
    implementation Deps.mozilla_lib_push_firebase
532
    implementation Deps.mozilla_lib_dataprotect
533
    debugImplementation Deps.leakcanary
534

535
    implementation Deps.androidx_legacy
536
    implementation Deps.androidx_biometric
537
    implementation Deps.androidx_paging
538
    implementation Deps.androidx_preference
539
    implementation Deps.androidx_fragment
ekager's avatar
ekager committed
540
541
    implementation Deps.androidx_navigation_fragment
    implementation Deps.androidx_navigation_ui
ekager's avatar
ekager committed
542
    implementation Deps.androidx_recyclerview
Tiger Oakes's avatar
Tiger Oakes committed
543
    implementation Deps.androidx_lifecycle_livedata
544
545
    implementation Deps.androidx_lifecycle_runtime
    implementation Deps.androidx_lifecycle_viewmodel
546
    implementation Deps.androidx_core
547
    implementation Deps.androidx_core_ktx
548
    implementation Deps.androidx_transition
549
    implementation Deps.androidx_work_ktx
550
    implementation Deps.google_material
Colin Lee's avatar
Colin Lee committed
551

552
553
554
    implementation Deps.adjust
    implementation Deps.installreferrer // Required by Adjust

555
556
    implementation Deps.google_ads_id // Required for the Google Advertising ID

557
558
    implementation Deps.google_play_store // Required for in-app reviews

Kevin Brosnan's avatar
Kevin Brosnan committed
559
    androidTestImplementation Deps.uiautomator
560
// Removed pending AndroidX fixes
561
    androidTestImplementation "tools.fastlane:screengrab:2.0.0"
562
//    androidTestImplementation "br.com.concretesolutions:kappuccino:1.2.1"
563

Kevin Brosnan's avatar
Kevin Brosnan committed
564
565
566
567
568
569
570
571
572
573
574
575
576
    androidTestImplementation Deps.espresso_core, {
        exclude group: 'com.android.support', module: 'support-annotations'
    }

    androidTestImplementation(Deps.espresso_contrib) {
        exclude module: 'appcompat-v7'
        exclude module: 'support-v4'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'design'
        exclude module: 'espresso-core'
    }

577
    androidTestImplementation Deps.androidx_test_core
Kevin Brosnan's avatar
Kevin Brosnan committed
578
    androidTestImplementation Deps.espresso_idling_resources
579
    androidTestImplementation Deps.espresso_intents
580

581
    androidTestImplementation Deps.tools_test_runner
Kevin Brosnan's avatar
Kevin Brosnan committed
582
583
584
585
586
    androidTestImplementation Deps.tools_test_rules
    androidTestUtil Deps.orchestrator
    androidTestImplementation Deps.espresso_core, {
        exclude group: 'com.android.support', module: 'support-annotations'
    }
587

588
589
    androidTestImplementation Deps.androidx_junit
    androidTestImplementation Deps.androidx_work_testing
590
    androidTestImplementation Deps.mockwebserver
Denys M's avatar
Denys M committed
591
    testImplementation Deps.mozilla_support_test
592
    testImplementation Deps.mozilla_support_test_libstate
Denys M's avatar
Denys M committed
593
    testImplementation Deps.androidx_junit
594
    testImplementation Deps.androidx_work_testing
595
596
597
598
599
    testImplementation (Deps.robolectric) {
        exclude group: 'org.apache.maven'
    }

    testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3'
600
    implementation Deps.mozilla_support_rusthttp
601
602

    testImplementation Deps.mockk
603
604
605

    // For the initial release of Glean 19, we require consumer applications to
    // depend on a separate library for unit tests. This will be removed in future releases.
606
    testImplementation "org.mozilla.telemetry:glean-forUnitTests:${project.ext.glean_version}"
607
608

    lintChecks project(":mozilla-lint-rules")
Jeff Boek's avatar
Jeff Boek committed
609
}
610

Colin Lee's avatar
Colin Lee committed
611
if (project.hasProperty("coverage")) {
Tiger Oakes's avatar
Tiger Oakes committed
612
    tasks.withType(Test).configureEach {
Colin Lee's avatar
Colin Lee committed
613
614
615
616
        jacoco.includeNoLocationClasses = true
    }

    android.applicationVariants.all { variant ->
617
618
619
        tasks.register("jacoco${variant.name.capitalize()}TestReport", JacocoReport) {
            dependsOn "test${variant.name.capitalize()}UnitTest"

Colin Lee's avatar
Colin Lee committed
620
621
622
623
624
625
626
627
628
629
630
631
            reports {
                xml.enabled = true
                html.enabled = true
            }

            def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
                              '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
            def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/${variant.name}", excludes: fileFilter)
            def javaDebugTree = fileTree(dir: "$project.buildDir/intermediates/classes/${variant.flavorName}/${variant.buildType.name}",
                    excludes: fileFilter)
            def mainSrc = "$project.projectDir/src/main/java"

632
633
634
635
636
637
            sourceDirectories.setFrom(files([mainSrc]))
            classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
            executionData.setFrom(fileTree(dir: project.buildDir, includes: [
                "jacoco/test${variant.name.capitalize()}UnitTest.exec",
                'outputs/code-coverage/connected/*coverage.ec'
            ]))
Colin Lee's avatar
Colin Lee committed
638
639
640
641
642
643
644
645
646
647
648
649
        }
    }

    android {
        buildTypes {
            debug {
                testCoverageEnabled true
            }
        }
    }
}

650
// -------------------------------------------------------------------------------------------------
651
// Task for printing APK information for the requested variant
652
// Usage: "./gradlew printVariants
653
// -------------------------------------------------------------------------------------------------
Tiger Oakes's avatar
Tiger Oakes committed
654
tasks.register('printVariants') {
655
    doLast {
656
657
658
659
660
661
662
        def variants = android.applicationVariants.collect { variant -> [
            apks: variant.outputs.collect { output -> [
                abi: output.getFilter(com.android.build.VariantOutput.FilterType.ABI),
                fileName: output.outputFile.name
            ]},
            build_type: variant.buildType.name,
            name: variant.name,
663
        ]}
Johan Lorenzo's avatar
Johan Lorenzo committed
664
665
666
667
        // AndroidTest is a special case not included above
        variants.add([
            apks: [[
                abi: 'noarch',
668
                fileName: 'app-debug-androidTest.apk',
Johan Lorenzo's avatar
Johan Lorenzo committed
669
670
671
672
            ]],
            build_type: 'androidTest',
            name: 'androidTest',
        ])
Tiger Oakes's avatar
Tiger Oakes committed
673
        println 'variants: ' + JsonOutput.toJson(variants)
674
675
676
    }
}

677
task buildTranslationArray {
Tiger Oakes's avatar
Tiger Oakes committed
678
679
    // This isn't running as a task, instead the array is build when the gradle file is parsed.
    // https://github.com/mozilla-mobile/fenix/issues/14175
680
681
682
683
    def foundLocales = new StringBuilder()
    foundLocales.append("new String[]{")

    fileTree("src/main/res").visit { FileVisitDetails details ->
684
685
        if(details.file.path.endsWith("${File.separator}strings.xml")){
            def languageCode = details.file.parent.tokenize(File.separator).last().replaceAll('values-','').replaceAll('-r','-')
686
687
688
689
690
691
692
693
694
695
            languageCode = (languageCode == "values") ? "en-US" : languageCode
            foundLocales.append("\"").append(languageCode).append("\"").append(",")
        }
    }

    foundLocales.append("}")
    def foundLocalesString = foundLocales.toString().replaceAll(',}','}')
    android.defaultConfig.buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", foundLocalesString
}

696
afterEvaluate {
697
698

    // Format test output. Ported from AC #2401
Tiger Oakes's avatar
Tiger Oakes committed
699
    tasks.withType(Test).configureEach {
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
        systemProperty "robolectric.logging", "stdout"
        systemProperty "logging.test-mode", "true"

        testLogging.events = []

        def out = services.get(StyledTextOutputFactory).create("tests")

        beforeSuite { descriptor ->
            if (descriptor.getClassName() != null) {
                out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
            }
        }

        beforeTest { descriptor ->
            out.style(Style.Description).println("  TEST: " + descriptor.getName())
        }

        onOutput { descriptor, event ->
            logger.lifecycle("    " + event.message.trim())
        }

        afterTest { descriptor, result ->
            switch (result.getResultType()) {
                case ResultType.SUCCESS:
                    out.style(Style.Success).println("  SUCCESS")
                    break

                case ResultType.FAILURE:
                    out.style(Style.Failure).println("  FAILURE")
                    logger.lifecycle("", result.getException())
                    break

                case ResultType.SKIPPED:
                    out.style(Style.Info).println("  SKIPPED")
                    break
            }
            logger.lifecycle("")
        }
    }
739
}
740
741
742
743
744
745
746
747

if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
    if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
        ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
    }
    ext.topsrcdir = gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir"
    apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
}
748
749
750
751
752

if (gradle.hasProperty('localProperties.autoPublish.android-components.dir')) {
    ext.acSrcDir = gradle."localProperties.autoPublish.android-components.dir"
    apply from: "../${acSrcDir}/substitute-local-ac.gradle"
}
753
754
755
756
757

if (gradle.hasProperty('localProperties.autoPublish.application-services.dir')) {
    ext.appServicesSrcDir = gradle."localProperties.autoPublish.application-services.dir"
    apply from: "../${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
}
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

// Define a reusable task for updating the versions of our built-in web extensions. We automate this
// to make sure we never forget to update the version, either in local development or for releases.
// In both cases, we want to make sure the latest version of all extensions (including their latest
// changes) are installed on first start-up.
// We're using the A-C version here as we want to uplift all built-in extensions to A-C (Once that's
// done we can also remove the task below):
// https://github.com/mozilla-mobile/android-components/issues/7249
ext.updateExtensionVersion = { task, extDir ->
    configure(task) {
        from extDir
        include 'manifest.template.json'
        rename { 'manifest.json' }
        into extDir

        def values = ['version': AndroidComponents.VERSION + "." + new Date().format('MMddHHmmss')]
        inputs.properties(values)
        expand(values)
    }
}

tasks.register("updateAdsExtensionVersion", Copy) { task ->
    updateExtensionVersion(task, 'src/main/assets/extensions/ads')
}

tasks.register("updateCookiesExtensionVersion", Copy) { task ->
    updateExtensionVersion(task, 'src/main/assets/extensions/cookies')
}

Tiger Oakes's avatar
Tiger Oakes committed
787
788
preBuild.dependsOn "updateAdsExtensionVersion"
preBuild.dependsOn "updateCookiesExtensionVersion"