build.gradle 27.9 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
17
import org.mozilla.fenix.gradle.tasks.LintUnitTestRunner
Tiger Oakes's avatar
Tiger Oakes committed
18

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

Jeff Boek's avatar
Jeff Boek committed
21
android {
22
    compileSdkVersion Config.compileSdkVersion
Jeff Boek's avatar
Jeff Boek committed
23
    defaultConfig {
24
        applicationId "org.torproject"
25
26
        minSdkVersion Config.minSdkVersion
        targetSdkVersion Config.targetSdkVersion
27
28
        versionCode 1
        versionName Config.generateDebugVersionName()
29
        vectorDrawables.useSupportLibrary = true
Kevin Brosnan's avatar
Kevin Brosnan committed
30
31
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments clearPackageData: 'true'
32
33
        resValue "bool", "IS_DEBUG", "false"
        buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false"
34
        buildConfigField "String", "AMO_COLLECTION", "\"83a9cccfe6e24a34bd7b155ff9ee32\""
35
        def deepLinkSchemeValue = "torbrowser-dev"
36
        buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
37
        manifestPlaceholders = [
38
                "deepLinkScheme": deepLinkSchemeValue
39
        ]
40
        buildConfigField "boolean", "DATA_COLLECTION_DISABLED", "true"
41
42
43
44
45
    }

    def releaseTemplate = {
        shrinkResources true
        minifyEnabled true
46
        proguardFiles 'proguard-android-optimize-3.5.0-modified.txt', 'proguard-rules.pro'
47
        matchingFallbacks = ['release'] // Use on the "release" build type in dependencies (AARs)
48
49
50
51

        if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) {
            signingConfig signingConfigs.debug
        }
52
53
54
55

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

Jeff Boek's avatar
Jeff Boek committed
58
    buildTypes {
59
        debug {
60
61
            shrinkResources false
            minifyEnabled false
62
            applicationIdSuffix ".torbrowser_debug"
63
            resValue "bool", "IS_DEBUG", "true"
64
            pseudoLocalesEnabled true
65
        }
66
        nightly releaseTemplate >> {
67
            applicationIdSuffix ".torbrowser_nightly"
68
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
69
            def deepLinkSchemeValue = "torbrowser-nightly"
70
71
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders = ["deepLinkScheme": deepLinkSchemeValue]
72
        }
73
        beta releaseTemplate >> {
74
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
75
            applicationIdSuffix ".torbrowser_alpha"
76
            def deepLinkSchemeValue = "torbrowser-alpha"
77
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
78
            manifestPlaceholders = [
79
                    // This release type is meant to replace Firefox (Beta channel) and therefore needs to inherit
Jeff Boek's avatar
Jeff Boek committed
80
81
82
83
84
85
                    // 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
86
                    "sharedUserId": "org.torproject.torbrowser_alpha.sharedID",
87
                    "deepLinkScheme": deepLinkSchemeValue
88
            ]
89
        }
90
        release releaseTemplate >> {
91
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
92
            applicationIdSuffix ".torbrowser"
93
            def deepLinkSchemeValue = "torbrowser"
94
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
95
96
97
98
99
100
101
102
            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
103
                    "sharedUserId": "org.torproject.torbrowser.sharedID",
104
                    "deepLinkScheme": deepLinkSchemeValue
105
106
            ]
        }
107
108
    }

109
110
111
112
113
114
    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'
115
116
117
118

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

Kevin Brosnan's avatar
Kevin Brosnan committed
121
122
    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'
123
        unitTests.includeAndroidResources = true
124
        animationsDisabled = true
Kevin Brosnan's avatar
Kevin Brosnan committed
125
126
    }

127
    flavorDimensions "engine"
128

Isabel Rios's avatar
Isabel Rios committed
129
130
    sourceSets {
        androidTest {
Jeff Boek's avatar
Jeff Boek committed
131
            resources.srcDirs += ['src/androidTest/resources']
Isabel Rios's avatar
Isabel Rios committed
132
        }
133
134
        debug {
            java.srcDirs = ['src/geckoNightly/java']
135
        }
136
137
        nightly {
            java.srcDirs = ['src/geckoNightly/java']
138
        }
139
140
        beta {
            java.srcDirs = ['src/migration/java', 'src/geckoBeta/java']
141
142
            manifest.srcFile "src/migration/AndroidManifest.xml"
        }
143
144
145
        release {
            java.srcDirs = ['src/migration/java', 'src/geckoRelease/java']
            manifest.srcFile "src/migration/AndroidManifest.xml"
146
        }
147
148
149
150
151
152
153
154
155
    }

    splits {
        abi {
            enable true

            reset()

            include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
156
        }
157
158
    }

159
160
161
162
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
163
164
165
166

    lintOptions {
        lintConfig file("lint.xml")
    }
167
168
169
170

    packagingOptions {
        exclude 'META-INF/atomicfu.kotlin_module'
    }
171
172
173
174

    testOptions {
        unitTests.returnDefaultValues = true
    }
175
176
}

177
android.applicationVariants.all { variant ->
178
179
180
181
182

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

183
    boolean hasTest = gradle.startParameter.taskNames.find { it.contains("test") || it.contains("Test") } != null
184
185
186
    if (hasTest) {
        apply plugin: 'kotlin-allopen'
        allOpen {
187
            annotation("org.mozilla.fenix.utils.OpenClass")
188
189
190
        }
    }

191
192
193
194
// -------------------------------------------------------------------------------------------------
// Generate version codes for builds
// -------------------------------------------------------------------------------------------------

195
    def isDebug = variant.buildType.resValues['IS_DEBUG']?.value ?: false
196
197
    def isDataCollectionDisabled = variant.buildType.buildConfigFields['DATA_COLLECTION_DISABLED']?.value ?: true
    def isDebugOrDCD = isDebug || isDataCollectionDisabled
198
    def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false
199
200
    def versionName = Config.releaseVersionName(project)

201
202
203
204
205
    def disableTor = false
    if (project.hasProperty("disableTor")) {
        disableTor = project.getProperty("disableTor")
    }

206
207
208
209
210
    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)
211
    println("Telemetry enabled: " + !isDebugOrDCD)
212
213
214
    println("Tor is disabled:   " + disableTor)

    buildConfigField "boolean", "DISABLE_TOR", "$disableTor"
215

216
    if (useReleaseVersioning) {
217
218
219
220
        // 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.

221
222
        variant.outputs.each { output ->
            def abi = output.getFilter(OutputFile.ABI)
223
224
225
            // 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)
226
227

            println("versionCode for $abi = $versionCodeOverride")
228
229
230

            output.versionNameOverride = versionName
            output.versionCodeOverride = versionCodeOverride
231
        }
232
233
    }

234
235
236
237
// -------------------------------------------------------------------------------------------------
// BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
// -------------------------------------------------------------------------------------------------

238
    buildConfigField 'String', 'SENTRY_TOKEN', 'null'
239
    if (!isDebugOrDCD) {
240
        buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
241
242
243
244
245
        // 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) {}
246
247
248
249
    } else {
        buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
    }

250
    if (!isDebugOrDCD) {
251
252
253
254
255
256
        buildConfigField 'boolean', 'TELEMETRY', 'true'
    } else {
        buildConfigField 'boolean', 'TELEMETRY', 'false'
    }

    def buildDate = Config.generateBuildDate()
257
258
259
260
261
262
263
    // 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
264

265
// -------------------------------------------------------------------------------------------------
Jeff Boek's avatar
Jeff Boek committed
266
// Adjust: Read token from local file if it exists (Only release builds)
267
268
269
270
// -------------------------------------------------------------------------------------------------

    print("Adjust token: ")

271
    if (!isDebugOrDCD) {
272
273
274
275
276
277
278
279
280
281
282
283
        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
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302

// -------------------------------------------------------------------------------------------------
// 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")
    }
303

304
305
306
307
308
309
310
311
312
313
314
315
316
317
// -------------------------------------------------------------------------------------------------
// 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")
    }
Jeff Boek's avatar
Jeff Boek committed
318
319
}

320
321
322
323
androidExtensions {
    experimental = true
}

324
325
326
327
328
// 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"

Jeff Boek's avatar
Jeff Boek committed
329
dependencies {
330
    debugImplementation Deps.mozilla_browser_engine_gecko_beta
331

332
    nightlyImplementation Deps.mozilla_browser_engine_gecko_beta
333
334
    betaImplementation Deps.mozilla_browser_engine_gecko_beta
    releaseImplementation Deps.mozilla_browser_engine_gecko_release
335

336
    implementation Deps.kotlin_stdlib
337
    implementation Deps.kotlin_coroutines
338
    implementation Deps.kotlin_coroutines_android
339
    testImplementation Deps.kotlin_coroutines_test
340
341
    implementation Deps.androidx_appcompat
    implementation Deps.androidx_constraintlayout
Emily Kager's avatar
Emily Kager committed
342
    implementation Deps.androidx_coordinatorlayout
343

344
    implementation Deps.sentry
Jeff Boek's avatar
Jeff Boek committed
345

346
347
348
    implementation Deps.leanplum_core
    implementation Deps.leanplum_fcm

349
    implementation Deps.mozilla_concept_engine
Tiger Oakes's avatar
Tiger Oakes committed
350
    implementation Deps.mozilla_concept_menu
351
    implementation Deps.mozilla_concept_push
352
    implementation Deps.mozilla_concept_storage
353
    implementation Deps.mozilla_concept_sync
354
    implementation Deps.mozilla_concept_toolbar
355
    implementation Deps.mozilla_concept_tabstray
356

Jeff Boek's avatar
Jeff Boek committed
357
    implementation Deps.mozilla_browser_awesomebar
358
    implementation Deps.mozilla_feature_downloads
359
    implementation Deps.mozilla_browser_domains
360
    implementation Deps.mozilla_browser_icons
361
    implementation Deps.mozilla_browser_menu
362
    implementation Deps.mozilla_browser_menu2
363
    implementation Deps.mozilla_browser_search
364
    implementation Deps.mozilla_browser_session
365
    implementation Deps.mozilla_browser_state
366
    implementation Deps.mozilla_browser_storage_sync
367
368
    implementation Deps.mozilla_browser_tabstray
    implementation Deps.mozilla_browser_thumbnails
Jeff Boek's avatar
Jeff Boek committed
369
370
    implementation Deps.mozilla_browser_toolbar

Gabriel Luong's avatar
Gabriel Luong committed
371
372
373
    implementation Deps.mozilla_support_extensions
    implementation Deps.mozilla_feature_addons

374
    implementation Deps.mozilla_feature_accounts
375
    implementation Deps.mozilla_feature_app_links
376
    implementation Deps.mozilla_feature_awesomebar
377
    implementation Deps.mozilla_feature_contextmenu
378
    implementation Deps.mozilla_feature_customtabs
379
    implementation Deps.mozilla_feature_downloads
380
    implementation Deps.mozilla_feature_intent
381
    implementation Deps.mozilla_feature_media
382
    implementation Deps.mozilla_feature_prompts
383
    implementation Deps.mozilla_feature_push
384
    implementation Deps.mozilla_feature_privatemode
385
    implementation Deps.mozilla_feature_pwa
Colin Lee's avatar
Colin Lee committed
386
    implementation Deps.mozilla_feature_qr
387
    implementation Deps.mozilla_feature_search
388
    implementation Deps.mozilla_feature_session
389
    implementation Deps.mozilla_feature_syncedtabs
390
    implementation Deps.mozilla_feature_toolbar
391
    implementation Deps.mozilla_feature_tabs
392
    implementation Deps.mozilla_feature_findinpage
393
    implementation Deps.mozilla_feature_logins
394
    implementation Deps.mozilla_feature_site_permissions
395
    implementation Deps.mozilla_feature_readerview
396
    implementation Deps.mozilla_feature_tab_collections
ekager's avatar
ekager committed
397
    implementation Deps.mozilla_feature_recentlyclosed
398
    implementation Deps.mozilla_feature_top_sites
Mihai Branescu's avatar
Mihai Branescu committed
399
    implementation Deps.mozilla_feature_share
400
    implementation Deps.mozilla_feature_accounts_push
401
    implementation Deps.mozilla_feature_webcompat
402
    implementation Deps.mozilla_feature_webnotifications
403
    implementation Deps.mozilla_feature_webcompat_reporter
404

Tiger Oakes's avatar
Tiger Oakes committed
405
    implementation Deps.mozilla_service_digitalassetlinks
406
    implementation Deps.mozilla_service_experiments
ekager's avatar
ekager committed
407
    implementation Deps.mozilla_service_sync_logins
408
    implementation Deps.mozilla_service_firefox_accounts
409
    implementation Deps.mozilla_service_glean
410
411
    implementation Deps.mozilla_service_location

412
    implementation Deps.mozilla_support_base
413
    implementation Deps.mozilla_support_images
414
    implementation Deps.mozilla_support_ktx
415
    implementation Deps.mozilla_support_rustlog
416
    implementation Deps.mozilla_support_utils
417
    implementation Deps.mozilla_support_locale
418

419
    implementation Deps.mozilla_support_migration
420

421
422
    implementation Deps.mozilla_ui_colors
    implementation Deps.mozilla_ui_icons
423
    implementation Deps.mozilla_lib_publicsuffixlist
424
    implementation Deps.mozilla_ui_widgets
425

426
    implementation Deps.mozilla_lib_crash
427
    implementation Deps.mozilla_lib_push_firebase
428
    implementation Deps.mozilla_lib_dataprotect
429
    debugImplementation Deps.leakcanary
430

431
    implementation Deps.androidx_legacy
432
    implementation Deps.androidx_biometric
433
    implementation Deps.androidx_paging
434
    implementation Deps.androidx_preference
435
    implementation Deps.androidx_fragment
ekager's avatar
ekager committed
436
437
    implementation Deps.androidx_navigation_fragment
    implementation Deps.androidx_navigation_ui
ekager's avatar
ekager committed
438
    implementation Deps.androidx_recyclerview
Tiger Oakes's avatar
Tiger Oakes committed
439
    implementation Deps.androidx_lifecycle_livedata
440
441
    implementation Deps.androidx_lifecycle_runtime
    implementation Deps.androidx_lifecycle_viewmodel
442
    implementation Deps.androidx_core
443
    implementation Deps.androidx_core_ktx
444
    implementation Deps.androidx_transition
445
    implementation Deps.androidx_work_ktx
446
    implementation Deps.google_material
Colin Lee's avatar
Colin Lee committed
447

448
449
    implementation Deps.lottie

450
451
452
    implementation Deps.adjust
    implementation Deps.installreferrer // Required by Adjust

453
454
    implementation Deps.google_play_store // Required for in-app reviews

Kevin Brosnan's avatar
Kevin Brosnan committed
455
    androidTestImplementation Deps.uiautomator
456
// Removed pending AndroidX fixes
457
    androidTestImplementation "tools.fastlane:screengrab:2.0.0"
458
//    androidTestImplementation "br.com.concretesolutions:kappuccino:1.2.1"
459

Kevin Brosnan's avatar
Kevin Brosnan committed
460
461
462
463
464
465
466
467
468
469
470
471
472
    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'
    }

473
    androidTestImplementation Deps.androidx_test_core
Kevin Brosnan's avatar
Kevin Brosnan committed
474
    androidTestImplementation Deps.espresso_idling_resources
475
    androidTestImplementation Deps.espresso_intents
476

477
    androidTestImplementation Deps.tools_test_runner
Kevin Brosnan's avatar
Kevin Brosnan committed
478
479
480
481
482
    androidTestImplementation Deps.tools_test_rules
    androidTestUtil Deps.orchestrator
    androidTestImplementation Deps.espresso_core, {
        exclude group: 'com.android.support', module: 'support-annotations'
    }
483

484
485
    androidTestImplementation Deps.androidx_junit
    androidTestImplementation Deps.androidx_work_testing
486
    androidTestImplementation Deps.mockwebserver
Denys M's avatar
Denys M committed
487
488
    testImplementation Deps.mozilla_support_test
    testImplementation Deps.androidx_junit
489
    testImplementation Deps.androidx_work_testing
490
491
492
493
494
    testImplementation (Deps.robolectric) {
        exclude group: 'org.apache.maven'
    }

    testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3'
495
    implementation Deps.mozilla_support_rusthttp
496
497

    testImplementation Deps.mockk
498
499
500

    // 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.
501
    testImplementation "org.mozilla.telemetry:glean-forUnitTests:${project.ext.glean_version}"
502
503

    lintChecks project(":mozilla-lint-rules")
504
505
506
507
508
509
510
511
512
513
514
515

    // Tor Android Services Dependencies
    implementation 'net.freehaven.tor.control:jtorctl:0.2'
    implementation 'org.slf4j:slf4j-api:1.7.25'
    implementation 'org.slf4j:slf4j-android:1.7.25'

    // Tor Android Services.
    implementation files('service-release.aar')

    // Tor Onion Proxy Library.
    implementation files('universal-0.0.3.jar')
    implementation files('android-release.aar')
Jeff Boek's avatar
Jeff Boek committed
516
}
517

Colin Lee's avatar
Colin Lee committed
518
if (project.hasProperty("coverage")) {
Tiger Oakes's avatar
Tiger Oakes committed
519
    tasks.withType(Test).configureEach {
Colin Lee's avatar
Colin Lee committed
520
521
522
523
        jacoco.includeNoLocationClasses = true
    }

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

Colin Lee's avatar
Colin Lee committed
527
528
529
530
531
532
533
534
535
536
537
538
            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"

539
540
541
542
543
544
            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
545
546
547
548
549
550
551
552
553
554
555
556
        }
    }

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

557
// -------------------------------------------------------------------------------------------------
558
// Task for printing APK information for the requested variant
559
// Usage: "./gradlew printVariants
560
// -------------------------------------------------------------------------------------------------
Tiger Oakes's avatar
Tiger Oakes committed
561
tasks.register('printVariants') {
562
    doLast {
563
        def variants = android.applicationVariants.collect {[
Jeff Boek's avatar
Jeff Boek committed
564
565
566
567
568
569
                apks: it.variantData.outputScope.apkDatas.collect {[
                        abi: it.filters.find { it.filterType == 'ABI' }.identifier,
                        fileName: it.outputFileName,
                ]},
                build_type: it.buildType.name,
                name: it.name,
570
        ]}
Johan Lorenzo's avatar
Johan Lorenzo committed
571
572
573
574
        // AndroidTest is a special case not included above
        variants.add([
            apks: [[
                abi: 'noarch',
575
                fileName: 'app-debug-androidTest.apk',
Johan Lorenzo's avatar
Johan Lorenzo committed
576
577
578
579
            ]],
            build_type: 'androidTest',
            name: 'androidTest',
        ])
Tiger Oakes's avatar
Tiger Oakes committed
580
        println 'variants: ' + JsonOutput.toJson(variants)
581
582
583
    }
}

584
task buildTranslationArray {
Tiger Oakes's avatar
Tiger Oakes committed
585
586
    // 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
587
    def foundLocales = new StringBuilder()
588
    def languageCodes = []
589
590
591
592
593
594
    foundLocales.append("new String[]{")

    fileTree("src/main/res").visit { FileVisitDetails details ->
        if(details.file.path.endsWith("/strings.xml")){
            def languageCode = details.file.parent.tokenize('/').last().replaceAll('values-','').replaceAll('-r','-')
            languageCode = (languageCode == "values") ? "en-US" : languageCode
595
            languageCodes.add(languageCode)
596
597
        }
    }
598
599
600
601
602
603
    // The order of files in a `FileTree` is not stable, even on a single
    // computer. Thus we need to sort the `languageCode`s. See: fenix#40083.
    languageCodes.sort()
    languageCodes.each {
        foundLocales.append("\"").append(it).append("\"").append(",")
    }
604
605
606
607
608
    foundLocales.append("}")
    def foundLocalesString = foundLocales.toString().replaceAll(',}','}')
    android.defaultConfig.buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", foundLocalesString
}

Tiger Oakes's avatar
Tiger Oakes committed
609
tasks.register('lintUnitTestRunner', LintUnitTestRunner)
610

611
afterEvaluate {
612
613

    // Format test output. Ported from AC #2401
Tiger Oakes's avatar
Tiger Oakes committed
614
    tasks.withType(Test).configureEach {
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
        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("")
        }
    }
654
}
655
656
657
658
659
660
661
662

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"
}
663
664
665
666
667

if (gradle.hasProperty('localProperties.autoPublish.android-components.dir')) {
    ext.acSrcDir = gradle."localProperties.autoPublish.android-components.dir"
    apply from: "../${acSrcDir}/substitute-local-ac.gradle"
}
668
669
670
671
672

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"
}
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687

// 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

688
        def systemEnvBuildDate = System.getenv('MOZ_BUILD_DATE')
689
690
        // MOZ_BUILD_DATE is in the yyyyMMddHHmmss format. Thus, we only use a
        // substring of it if it is available.
691
        def values = ['version': AndroidComponents.VERSION + "." +
692
693
694
                      (systemEnvBuildDate != null ?
                       systemEnvBuildDate.substring(4) :
                       new Date().format('MMddHHmmss'))]
695
696
697
698
699
700
701
702
703
704
705
706
707
        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
708
709
preBuild.dependsOn "updateAdsExtensionVersion"
preBuild.dependsOn "updateCookiesExtensionVersion"