build.gradle 31.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
Tiger Oakes's avatar
Tiger Oakes committed
17

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

Georg Koppen's avatar
Georg Koppen committed
20
21
22
23
24
25
26
27
def obtainTestBuildType() {
    def result = "debug";
    if (project.hasProperty("testBuildType")) {
        result = project.getProperties().get("testBuildType")
    }
    result
}

Jeff Boek's avatar
Jeff Boek committed
28
android {
Georg Koppen's avatar
Georg Koppen committed
29
    testBuildType obtainTestBuildType()
30
    compileSdkVersion Config.compileSdkVersion
31
32
33
34
35
36
37

    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
38
    defaultConfig {
Matthew Finkel's avatar
Matthew Finkel committed
39
        applicationId "org.torproject"
40
41
        minSdkVersion Config.minSdkVersion
        targetSdkVersion Config.targetSdkVersion
42
43
        versionCode 1
        versionName Config.generateDebugVersionName()
44
        vectorDrawables.useSupportLibrary = true
Kevin Brosnan's avatar
Kevin Brosnan committed
45
46
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments clearPackageData: 'true'
47
48
        resValue "bool", "IS_DEBUG", "false"
        buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false"
49
50
51
52
53
54
        // 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\""
        // This should be the base URL used to call the AMO API.
        buildConfigField "String", "AMO_SERVER_URL", "\"https://services.addons.mozilla.org\""
Matthew Finkel's avatar
Matthew Finkel committed
55
        def deepLinkSchemeValue = "torbrowser-dev"
56
        buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
57
        manifestPlaceholders = [
58
                "deepLinkScheme": deepLinkSchemeValue
59
        ]
60
61
62
63
64
65
66

        // 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"
        }
67
68

        buildConfigField "boolean", "DATA_COLLECTION_DISABLED", "true"
69
70
71
    }

    def releaseTemplate = {
72
73
74
75
        // 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")
76
        proguardFiles 'proguard-android-optimize-3.5.0-modified.txt', 'proguard-rules.pro'
77
        matchingFallbacks = ['release'] // Use on the "release" build type in dependencies (AARs)
78
79
80
81

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

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

Jeff Boek's avatar
Jeff Boek committed
88
    buildTypes {
89
        debug {
90
91
            shrinkResources false
            minifyEnabled false
Matthew Finkel's avatar
Matthew Finkel committed
92
            applicationIdSuffix ".torbrowser_debug"
93
            resValue "bool", "IS_DEBUG", "true"
94
            pseudoLocalesEnabled true
95
        }
96
        nightly releaseTemplate >> {
Matthew Finkel's avatar
Matthew Finkel committed
97
            applicationIdSuffix ".torbrowser_nightly"
98
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
Matthew Finkel's avatar
Matthew Finkel committed
99
            def deepLinkSchemeValue = "torbrowser-nightly"
100
101
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
            manifestPlaceholders = ["deepLinkScheme": deepLinkSchemeValue]
102
        }
103
        beta releaseTemplate >> {
104
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
Matthew Finkel's avatar
Matthew Finkel committed
105
106
            applicationIdSuffix ".torbrowser_alpha"
            def deepLinkSchemeValue = "torbrowser-alpha"
107
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
108
            manifestPlaceholders = [
109
                    // This release type is meant to replace Firefox (Beta channel) and therefore needs to inherit
Jeff Boek's avatar
Jeff Boek committed
110
111
112
113
114
115
                    // 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
Matthew Finkel's avatar
Matthew Finkel committed
116
                    "sharedUserId": "org.torproject.torbrowser_alpha.sharedID",
117
                    "deepLinkScheme": deepLinkSchemeValue
118
            ]
119
        }
120
        release releaseTemplate >> {
121
            buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
Matthew Finkel's avatar
Matthew Finkel committed
122
123
            applicationIdSuffix ".torbrowser"
            def deepLinkSchemeValue = "torbrowser"
124
            buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
125
126
127
128
129
130
131
132
            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
Matthew Finkel's avatar
Matthew Finkel committed
133
                    "sharedUserId": "org.torproject.torbrowser.sharedID",
134
                    "deepLinkScheme": deepLinkSchemeValue
135
136
            ]
        }
137
138
    }

139
140
141
142
143
144
    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'
145
146
147
148

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

Kevin Brosnan's avatar
Kevin Brosnan committed
151
152
    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'
153
        unitTests.includeAndroidResources = true
154
        animationsDisabled = true
Kevin Brosnan's avatar
Kevin Brosnan committed
155
156
    }

157
    flavorDimensions "engine"
158

Isabel Rios's avatar
Isabel Rios committed
159
160
    sourceSets {
        androidTest {
Jeff Boek's avatar
Jeff Boek committed
161
            resources.srcDirs += ['src/androidTest/resources']
Isabel Rios's avatar
Isabel Rios committed
162
        }
163
164
        debug {
            java.srcDirs = ['src/geckoNightly/java']
165
        }
166
167
        nightly {
            java.srcDirs = ['src/geckoNightly/java']
168
        }
169
170
        beta {
            java.srcDirs = ['src/migration/java', 'src/geckoBeta/java']
171
172
            manifest.srcFile "src/migration/AndroidManifest.xml"
        }
173
174
175
        release {
            java.srcDirs = ['src/migration/java', 'src/geckoRelease/java']
            manifest.srcFile "src/migration/AndroidManifest.xml"
176
        }
177
178
179
180
181
182
183
184
185
    }

    splits {
        abi {
            enable true

            reset()

            include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
186
        }
187
188
    }

189
190
191
192
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
193
194
195

    lintOptions {
        lintConfig file("lint.xml")
196
        baseline file("lint-baseline.xml")
197
    }
198
199
200
201

    packagingOptions {
        exclude 'META-INF/atomicfu.kotlin_module'
    }
202
203
204

    testOptions {
        unitTests.returnDefaultValues = true
205
206
207
208
209
210
211
212
213
214
215

        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"
        }
216
    }
217
218
}

219
android.applicationVariants.all { variant ->
220
221
222
223
224

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

225
    boolean hasTest = gradle.startParameter.taskNames.find { it.contains("test") || it.contains("Test") } != null
226
227
228
    if (hasTest) {
        apply plugin: 'kotlin-allopen'
        allOpen {
229
            annotation("org.mozilla.fenix.utils.OpenClass")
230
231
232
        }
    }

233
234
235
236
// -------------------------------------------------------------------------------------------------
// Generate version codes for builds
// -------------------------------------------------------------------------------------------------

237
    def isDebug = variant.buildType.resValues['IS_DEBUG']?.value ?: false
238
239
    def isDataCollectionDisabled = variant.buildType.buildConfigFields['DATA_COLLECTION_DISABLED']?.value ?: true
    def isDebugOrDCD = isDebug || isDataCollectionDisabled
240
    def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false
241
242
    def versionName = Config.releaseVersionName(project)

243
244
245
246
247
    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)
248
    println("Telemetry enabled: " + !isDebugOrDCD)
249

250
    if (useReleaseVersioning) {
251
252
253
254
        // 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.

255
256
        variant.outputs.each { output ->
            def abi = output.getFilter(OutputFile.ABI)
257
258
259
            // 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)
260
261

            println("versionCode for $abi = $versionCodeOverride")
262
263
264

            output.versionNameOverride = versionName
            output.versionCodeOverride = versionCodeOverride
265
        }
266
267
    }

268
269
270
271
// -------------------------------------------------------------------------------------------------
// BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
// -------------------------------------------------------------------------------------------------

272
    buildConfigField 'String', 'SENTRY_TOKEN', 'null'
273
    if (!isDebugOrDCD) {
274
        buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
275
276
277
278
279
        // 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) {}
280
281
282
283
    } else {
        buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
    }

284
    if (!isDebugOrDCD) {
285
286
287
288
289
290
        buildConfigField 'boolean', 'TELEMETRY', 'true'
    } else {
        buildConfigField 'boolean', 'TELEMETRY', 'false'
    }

    def buildDate = Config.generateBuildDate()
291
292
293
294
295
296
297
    // 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
298

299
// -------------------------------------------------------------------------------------------------
Jeff Boek's avatar
Jeff Boek committed
300
// Adjust: Read token from local file if it exists (Only release builds)
301
302
303
304
// -------------------------------------------------------------------------------------------------

    print("Adjust token: ")

305
    if (!isDebugOrDCD) {
306
307
308
309
310
311
312
313
314
315
316
317
        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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

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

338
339
340
341
342
343
344
345
346
347
348
349
350
351
// -------------------------------------------------------------------------------------------------
// 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")
    }
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

// -------------------------------------------------------------------------------------------------
// 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("--")
    }
Jeff Boek's avatar
Jeff Boek committed
376
377
}

378
379
380
381
androidExtensions {
    experimental = true
}

382
383
384
385
386
// 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"

387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
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
408
dependencies {
409
410
411
    jnaForTest Deps.jna
    testImplementation files(configurations.jnaForTest.copyRecursive().files)

Georg Koppen's avatar
Georg Koppen committed
412
    debugImplementation Deps.mozilla_browser_engine_gecko_beta
413

Georg Koppen's avatar
Georg Koppen committed
414
    nightlyImplementation Deps.mozilla_browser_engine_gecko_beta
415
416
    betaImplementation Deps.mozilla_browser_engine_gecko_beta
    releaseImplementation Deps.mozilla_browser_engine_gecko_release
417

418
    implementation Deps.kotlin_stdlib
419
    implementation Deps.kotlin_coroutines
420
    implementation Deps.kotlin_coroutines_android
421
    testImplementation Deps.kotlin_coroutines_test
422
423
    implementation Deps.androidx_appcompat
    implementation Deps.androidx_constraintlayout
Emily Kager's avatar
Emily Kager committed
424
    implementation Deps.androidx_coordinatorlayout
425

426
    implementation Deps.sentry
Jeff Boek's avatar
Jeff Boek committed
427

428
429
430
    implementation Deps.leanplum_core
    implementation Deps.leanplum_fcm

431
    implementation Deps.mozilla_concept_base
432
    implementation Deps.mozilla_concept_engine
Tiger Oakes's avatar
Tiger Oakes committed
433
    implementation Deps.mozilla_concept_menu
434
    implementation Deps.mozilla_concept_push
435
    implementation Deps.mozilla_concept_storage
436
    implementation Deps.mozilla_concept_sync
437
    implementation Deps.mozilla_concept_toolbar
438
    implementation Deps.mozilla_concept_tabstray
439

Jeff Boek's avatar
Jeff Boek committed
440
    implementation Deps.mozilla_browser_awesomebar
441
    implementation Deps.mozilla_feature_downloads
442
    implementation Deps.mozilla_browser_domains
443
    implementation Deps.mozilla_browser_icons
444
    implementation Deps.mozilla_browser_menu
445
    implementation Deps.mozilla_browser_menu2
446
    implementation Deps.mozilla_browser_search
447
    implementation Deps.mozilla_browser_session
448
    implementation Deps.mozilla_browser_session_storage
449
    implementation Deps.mozilla_browser_state
450
    implementation Deps.mozilla_browser_storage_sync
451
452
    implementation Deps.mozilla_browser_tabstray
    implementation Deps.mozilla_browser_thumbnails
Jeff Boek's avatar
Jeff Boek committed
453
454
    implementation Deps.mozilla_browser_toolbar

Gabriel Luong's avatar
Gabriel Luong committed
455
456
457
    implementation Deps.mozilla_support_extensions
    implementation Deps.mozilla_feature_addons

458
    implementation Deps.mozilla_feature_accounts
459
    implementation Deps.mozilla_feature_app_links
460
    implementation Deps.mozilla_feature_awesomebar
461
    implementation Deps.mozilla_feature_contextmenu
462
    implementation Deps.mozilla_feature_customtabs
463
    implementation Deps.mozilla_feature_downloads
464
    implementation Deps.mozilla_feature_intent
465
    implementation Deps.mozilla_feature_media
466
    implementation Deps.mozilla_feature_prompts
467
    implementation Deps.mozilla_feature_push
468
    implementation Deps.mozilla_feature_privatemode
469
    implementation Deps.mozilla_feature_pwa
Colin Lee's avatar
Colin Lee committed
470
    implementation Deps.mozilla_feature_qr
471
    implementation Deps.mozilla_feature_search
472
    implementation Deps.mozilla_feature_session
473
    implementation Deps.mozilla_feature_syncedtabs
474
    implementation Deps.mozilla_feature_toolbar
475
    implementation Deps.mozilla_feature_tabs
476
    implementation Deps.mozilla_feature_findinpage
477
    implementation Deps.mozilla_feature_logins
478
    implementation Deps.mozilla_feature_site_permissions
479
    implementation Deps.mozilla_feature_readerview
480
    implementation Deps.mozilla_feature_tab_collections
ekager's avatar
ekager committed
481
    implementation Deps.mozilla_feature_recentlyclosed
482
    implementation Deps.mozilla_feature_top_sites
Mihai Branescu's avatar
Mihai Branescu committed
483
    implementation Deps.mozilla_feature_share
484
    implementation Deps.mozilla_feature_accounts_push
485
    implementation Deps.mozilla_feature_webcompat
486
    implementation Deps.mozilla_feature_webnotifications
487
    implementation Deps.mozilla_feature_webcompat_reporter
488

Tiger Oakes's avatar
Tiger Oakes committed
489
    implementation Deps.mozilla_service_digitalassetlinks
ekager's avatar
ekager committed
490
    implementation Deps.mozilla_service_sync_logins
491
    implementation Deps.mozilla_service_firefox_accounts
492
    implementation Deps.mozilla_service_glean
493
    implementation Deps.mozilla_service_location
jhugman's avatar
jhugman committed
494
    implementation Deps.mozilla_service_nimbus
495

496
    implementation Deps.mozilla_support_base
497
    implementation Deps.mozilla_support_images
498
    implementation Deps.mozilla_support_ktx
499
    implementation Deps.mozilla_support_rustlog
500
    implementation Deps.mozilla_support_utils
501
    implementation Deps.mozilla_support_locale
502

503
    implementation Deps.mozilla_support_migration
504

505
506
    implementation Deps.mozilla_ui_colors
    implementation Deps.mozilla_ui_icons
507
    implementation Deps.mozilla_lib_publicsuffixlist
508
    implementation Deps.mozilla_ui_widgets
509
    implementation Deps.mozilla_ui_tabcounter
510

511
    implementation Deps.mozilla_lib_crash
512
    implementation Deps.mozilla_lib_push_firebase
513
    implementation Deps.mozilla_lib_dataprotect
514
    debugImplementation Deps.leakcanary
515

516
    implementation Deps.androidx_legacy
517
    implementation Deps.androidx_biometric
518
    implementation Deps.androidx_paging
519
    implementation Deps.androidx_preference
520
    implementation Deps.androidx_fragment
ekager's avatar
ekager committed
521
522
    implementation Deps.androidx_navigation_fragment
    implementation Deps.androidx_navigation_ui
ekager's avatar
ekager committed
523
    implementation Deps.androidx_recyclerview
Tiger Oakes's avatar
Tiger Oakes committed
524
    implementation Deps.androidx_lifecycle_livedata
525
526
    implementation Deps.androidx_lifecycle_runtime
    implementation Deps.androidx_lifecycle_viewmodel
527
    implementation Deps.androidx_core
528
    implementation Deps.androidx_core_ktx
529
    implementation Deps.androidx_transition
530
    implementation Deps.androidx_work_ktx
531
    implementation Deps.google_material
Colin Lee's avatar
Colin Lee committed
532

533
534
535
    implementation Deps.adjust
    implementation Deps.installreferrer // Required by Adjust

536
537
    implementation Deps.google_play_store // Required for in-app reviews

Kevin Brosnan's avatar
Kevin Brosnan committed
538
    androidTestImplementation Deps.uiautomator
539
// Removed pending AndroidX fixes
540
    androidTestImplementation "tools.fastlane:screengrab:2.0.0"
541
//    androidTestImplementation "br.com.concretesolutions:kappuccino:1.2.1"
542

Kevin Brosnan's avatar
Kevin Brosnan committed
543
544
545
546
547
548
549
550
551
552
553
554
555
    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'
    }

556
    androidTestImplementation Deps.androidx_test_core
Kevin Brosnan's avatar
Kevin Brosnan committed
557
    androidTestImplementation Deps.espresso_idling_resources
558
    androidTestImplementation Deps.espresso_intents
559

560
    androidTestImplementation Deps.tools_test_runner
Kevin Brosnan's avatar
Kevin Brosnan committed
561
562
563
564
565
    androidTestImplementation Deps.tools_test_rules
    androidTestUtil Deps.orchestrator
    androidTestImplementation Deps.espresso_core, {
        exclude group: 'com.android.support', module: 'support-annotations'
    }
566

567
568
    androidTestImplementation Deps.androidx_junit
    androidTestImplementation Deps.androidx_work_testing
569
    androidTestImplementation Deps.mockwebserver
Denys M's avatar
Denys M committed
570
    testImplementation Deps.mozilla_support_test
571
    testImplementation Deps.mozilla_support_test_libstate
Denys M's avatar
Denys M committed
572
    testImplementation Deps.androidx_junit
573
    testImplementation Deps.androidx_work_testing
574
575
576
577
578
    testImplementation (Deps.robolectric) {
        exclude group: 'org.apache.maven'
    }

    testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3'
579
    implementation Deps.mozilla_support_rusthttp
580
581

    testImplementation Deps.mockk
582
583
584

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

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

Colin Lee's avatar
Colin Lee committed
590
if (project.hasProperty("coverage")) {
Tiger Oakes's avatar
Tiger Oakes committed
591
    tasks.withType(Test).configureEach {
Colin Lee's avatar
Colin Lee committed
592
593
594
595
        jacoco.includeNoLocationClasses = true
    }

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

Colin Lee's avatar
Colin Lee committed
599
600
601
602
603
604
605
606
607
608
609
610
            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"

611
612
613
614
615
616
            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
617
618
619
620
621
622
623
624
625
626
627
628
        }
    }

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

629
// -------------------------------------------------------------------------------------------------
630
// Task for printing APK information for the requested variant
631
// Usage: "./gradlew printVariants
632
// -------------------------------------------------------------------------------------------------
Tiger Oakes's avatar
Tiger Oakes committed
633
tasks.register('printVariants') {
634
    doLast {
635
636
637
638
639
640
641
        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,
642
        ]}
Johan Lorenzo's avatar
Johan Lorenzo committed
643
644
645
646
        // AndroidTest is a special case not included above
        variants.add([
            apks: [[
                abi: 'noarch',
647
                fileName: 'app-debug-androidTest.apk',
Johan Lorenzo's avatar
Johan Lorenzo committed
648
649
650
651
            ]],
            build_type: 'androidTest',
            name: 'androidTest',
        ])
Tiger Oakes's avatar
Tiger Oakes committed
652
        println 'variants: ' + JsonOutput.toJson(variants)
653
654
655
    }
}

656
task buildTranslationArray {
Tiger Oakes's avatar
Tiger Oakes committed
657
658
    // 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
659
    def foundLocales = new StringBuilder()
Georg Koppen's avatar
Georg Koppen committed
660
    def languageCodes = []
661
662
663
    foundLocales.append("new String[]{")

    fileTree("src/main/res").visit { FileVisitDetails details ->
Georg Koppen's avatar
Georg Koppen committed
664
        if(details.file.path.endsWith("${File.separator}torbrowser_strings.xml")){
665
            def languageCode = details.file.parent.tokenize(File.separator).last().replaceAll('values-','').replaceAll('-r','-')
666
            languageCode = (languageCode == "values") ? "en-US" : languageCode
Georg Koppen's avatar
Georg Koppen committed
667
            languageCodes.add(languageCode)
668
669
        }
    }
Georg Koppen's avatar
Georg Koppen committed
670
671
672
673
674
675
    // 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(",")
    }
676
677
678
679
680
    foundLocales.append("}")
    def foundLocalesString = foundLocales.toString().replaceAll(',}','}')
    android.defaultConfig.buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", foundLocalesString
}

681
afterEvaluate {
682
683

    // Format test output. Ported from AC #2401
Tiger Oakes's avatar
Tiger Oakes committed
684
    tasks.withType(Test).configureEach {
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
        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("")
        }
    }
724
}
725
726
727
728
729
730
731
732

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"
}
733
734
735
736
737

if (gradle.hasProperty('localProperties.autoPublish.android-components.dir')) {
    ext.acSrcDir = gradle."localProperties.autoPublish.android-components.dir"
    apply from: "../${acSrcDir}/substitute-local-ac.gradle"
}
738
739
740
741
742

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"
}
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757

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

Georg Koppen's avatar
Georg Koppen committed
758
759
760
761
762
763
764
        def systemEnvBuildDate = System.getenv('MOZ_BUILD_DATE')
        // MOZ_BUILD_DATE is in the yyyyMMddHHmmss format. Thus, we only use a
        // substring of it if it is available.
        def values = ['version': AndroidComponents.VERSION + "." +
                      (systemEnvBuildDate != null ?
                       systemEnvBuildDate.substring(4) :
                       new Date().format('MMddHHmmss'))]
765
766
767
768
769
770
771
772
773
774
775
776
777
        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
778
779
preBuild.dependsOn "updateAdsExtensionVersion"
preBuild.dependsOn "updateCookiesExtensionVersion"