Compare commits

..

2 Commits

Author SHA1 Message Date
Greyson Parrelli
6978ba7090 Bump version to 7.32.3 2025-02-07 15:08:10 -05:00
Alex Hart
18bb0e0739 Fix fullscreen call notifications. 2025-02-07 15:38:36 -04:00
5278 changed files with 130477 additions and 443527 deletions

View File

@@ -18,16 +18,3 @@ ktlint_standard_statement-wrapping = disabled
internal:ktlint-suppression = disabled
ktlint_standard_unnecessary-parentheses-before-trailing-lambda = disabled
ktlint_standard_value-parameter-comment = disabled
ktlint_standard_class-signature = disabled
ktlint_standard_function-expression-body = disabled
# Disable ktlint on generated source code, see
# https://github.com/JLLeitschuh/ktlint-gradle/issues/746
[**/build/generated/source/**]
ktlint = disabled
[build/generated/*/main/**]
ktlint = disabled
[**/build/generated-sources/**]
ktlint = disabled

View File

@@ -16,19 +16,19 @@ jobs:
runs-on: ubuntu-latest-8-cores
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 17
cache: gradle
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v5
uses: gradle/wrapper-validation-action@v1
- name: Build with Gradle
run: ./gradlew qa

View File

@@ -8,7 +8,7 @@ permissions:
pull-requests: write # to comment on PR
env:
NDK_VERSION: '28.0.13004108'
NDK_VERSION: '27.0.12077973'
jobs:
assemble-base:
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest-8-cores
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
ref: ${{ github.event.pull_request.base.sha }}
@@ -32,11 +32,11 @@ jobs:
run: echo "y" | ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --install "ndk;${{ env.NDK_VERSION }}"
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v5
uses: gradle/wrapper-validation-action@v1
- name: Cache base apk
id: cache-base
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: diffuse-base.apk
key: diffuse-${{ github.event.pull_request.base.sha }}
@@ -49,7 +49,7 @@ jobs:
if: steps.cache-base.outputs.cache-hit != 'true'
run: mv app/build/outputs/apk/playProd/release/*arm64*.apk diffuse-base.apk
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
clean: 'false'

View File

@@ -1,20 +1,21 @@
name: Check reproducible-build Dockerfile
name: Reproducible Build Check
on:
schedule:
- cron: "0 5 * * *"
- cron: '0 5 * * *'
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Build image
run: |
cd reproducible-builds
docker build -t signal-android .
- name: Test build
run: docker run --memory=12g --rm -v "$(pwd)":/project -w /project signal-android ./gradlew --no-daemon --max-workers=1 -Dorg.gradle.jvmargs="-Xmx4g -XX:MaxMetaspaceSize=512m" -Dkotlin.compiler.execution.strategy=in-process bundlePlayProdRelease
- uses: actions/checkout@v3
- name: Build image
run: cd reproducible-builds && docker build -t signal-android . && cd ..
- name: Test build
run: docker run --rm -v $(pwd):/project -w /project signal-android ./gradlew clean assemblePlayProdRelease

1
.gitignore vendored
View File

@@ -32,4 +32,3 @@ maps.key
/local/
kls_database.db
.kotlin
lefthook-local.yml

View File

@@ -16,7 +16,6 @@
<option name="ALIGN_MULTILINE_TEXT_BLOCKS" value="true" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="false" module="true" />
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="false" />

View File

@@ -1,2 +1 @@
java openjdk-17.0.2
uv latest
java 17.0.2

View File

@@ -17,6 +17,7 @@ Truths which we believe to be self-evident:
## Building
1. You'll need to get the `libwebp` submodule after checking out the repository with `git submodule init && git submodule update`
1. Most things are pretty straightforward, and opening the project in Android Studio should get you most of the way there.
1. Depending on your configuration, you'll also likely need to install additional SDK Tool components, namely the versions of NDK and CMake we are currently using in our [Docker](https://github.com/signalapp/Signal-Android/blob/main/reproducible-builds/Dockerfile#L30) configuration.
@@ -62,7 +63,7 @@ You will need to [sign our CLA](https://signal.org/cla/) before your pull reques
### Follow the Code Style Guidelines
Ensure that your code adheres to the [Code Style Guidelines](https://github.com/signalapp/Signal-Android/wiki/Code-Style-Guidelines) before submitting a pull request.
You can run `./gradlew format` to automatically format your code. See `lefthook.yml` for instructions on how to run this as a git hook.
You can run `./gradlew format` to automatically check conformance with some of these guidelines.
### Submit finished and well-tested pull requests
Please do not submit pull requests that are still a work in progress. Pull requests should be thoroughly tested and ready to merge before they are submitted.

View File

@@ -1,18 +1,14 @@
# Signal Android
Signal is a simple, powerful, and secure messenger that uses your phone's data connection (WiFi/3G/4G/5G) to communicate securely.
Signal is a simple, powerful, and secure messenger.
Millions of people use Signal every day for free and instantaneous communication anywhere in the world. Send and receive high-fidelity messages, participate in HD voice/video calls, and explore a growing set of new features that help you stay connected.
Signal uses your phone's data connection (WiFi/3G/4G/5G) to communicate securely. Millions of people use Signal every day for free and instantaneous communication anywhere in the world. Send and receive high-fidelity messages, participate in HD voice/video calls, and explore a growing set of new features that help you stay connected. Signals advanced privacy-preserving technology is always enabled, so you can focus on sharing the moments that matter with the people who matter to you.
Signals advanced privacy-preserving technology is always enabled, so you can focus on sharing the moments that matter with the people who matter to you.
Currently available on the [Play Store](https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms) and [signal.org](https://signal.org/android/apk/).
Currently available on the Play Store and [signal.org](https://signal.org/android/apk/).
<a href='https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height='80px'/></a>
Also available on [iOS](https://github.com/signalapp/signal-ios) and [Desktop](https://github.com/signalapp/signal-desktop).
## Contributing Bug Reports
## Contributing Bug reports
We use GitHub for bug tracking. Please search the existing issues for your bug and create a new one if the issue is not yet tracked!
https://github.com/signalapp/Signal-Android/issues
@@ -25,11 +21,6 @@ https://play.google.com/apps/testing/org.thoughtcrime.securesms
If you're interested in a life of peace and tranquility, stick with the standard releases.
## Contributing Translations
Interested in helping translate Signal? Contribute here:
https://community.signalusers.org/c/translation-feedback/
## Contributing Code
If you're new to the Signal codebase, we recommend going through our issues and picking out a simple bug to fix in order to get yourself familiar. Also please have a look at the [CONTRIBUTING.md](https://github.com/signalapp/Signal-Android/blob/main/CONTRIBUTING.md), that might answer some of your questions.
@@ -63,7 +54,7 @@ The form and manner of this distribution makes it eligible for export under the
## License
Copyright 2013-2025 Signal Messenger, LLC
Copyright 2013-2024 Signal Messenger, LLC
Licensed under the GNU AGPLv3: https://www.gnu.org/licenses/agpl-3.0.html

View File

@@ -1,7 +1,9 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.api.dsl.ManagedVirtualDevice
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import java.io.ByteArrayOutputStream
import java.io.FileInputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Properties
plugins {
@@ -9,8 +11,6 @@ plugins {
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.ktlint)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlinx.serialization)
alias(benchmarkLibs.plugins.baselineprofile)
id("androidx.navigation.safeargs")
id("kotlin-parcelize")
id("com.squareup.wire")
@@ -20,37 +20,14 @@ plugins {
apply(from = "static-ips.gradle.kts")
val canonicalVersionCode = 1654
val canonicalVersionName = "8.0.2"
val currentHotfixVersion = 0
val canonicalVersionCode = 1509
val canonicalVersionName = "7.32.3"
val currentHotfixVersion = 1
val maxHotfixVersions = 100
// We don't want versions to ever end in 0 so that they don't conflict with nightly versions
val possibleHotfixVersions = (0 until maxHotfixVersions).toList().filter { it % 10 != 0 }
val debugKeystorePropertiesProvider = providers.of(PropertiesFileValueSource::class.java) {
parameters.file.set(rootProject.layout.projectDirectory.file("keystore.debug.properties"))
}
val languagesProvider = providers.of(LanguageListValueSource::class.java) {
parameters.resDir.set(layout.projectDirectory.dir("src/main/res"))
}
val languagesForBuildConfigProvider = languagesProvider.map { languages ->
languages.joinToString(separator = ", ") { language -> "\"$language\"" }
}
val localPropertiesFile = File(rootProject.projectDir, "local.properties")
val localProperties: Properties? = if (localPropertiesFile.exists()) {
Properties().apply { localPropertiesFile.inputStream().use { load(it) } }
} else {
null
}
val quickstartCredentialsDir: String? = localProperties?.getProperty("quickstart.credentials.dir")
val keystores: Map<String, Properties?> = mapOf("debug" to loadKeystoreProperties("keystore.debug.properties"))
val selectableVariants = listOf(
"nightlyBackupRelease",
"nightlyBackupSpinner",
"nightlyProdSpinner",
"nightlyProdPerf",
"nightlyProdRelease",
@@ -59,8 +36,6 @@ val selectableVariants = listOf(
"playProdSpinner",
"playProdCanary",
"playProdPerf",
"playProdMocked",
"playProdNonMinifiedMocked",
"playProdBenchmark",
"playProdInstrumentation",
"playProdRelease",
@@ -70,14 +45,18 @@ val selectableVariants = listOf(
"playStagingPerf",
"playStagingInstrumentation",
"playStagingRelease",
"playProdQuickstart",
"playStagingQuickstart",
"websiteProdSpinner",
"websiteProdRelease",
"githubProdSpinner",
"githubProdRelease"
"websiteProdRelease"
)
val signalBuildToolsVersion: String by rootProject.extra
val signalCompileSdkVersion: String by rootProject.extra
val signalTargetSdkVersion: Int by rootProject.extra
val signalMinSdkVersion: Int by rootProject.extra
val signalNdkVersion: String by rootProject.extra
val signalJavaVersion: JavaVersion by rootProject.extra
val signalKotlinJvmTarget: String by rootProject.extra
wire {
kotlin {
javaInterop = true
@@ -88,22 +67,20 @@ wire {
}
protoPath {
srcDir("${project.rootDir}/lib/libsignal-service/src/main/protowire")
srcDir("${project.rootDir}/libsignal-service/src/main/protowire")
}
// Handled by libsignal
prune("signalservice.DecryptionErrorMessage")
}
ktlint {
version.set("1.5.0")
version.set("1.2.1")
}
android {
namespace = "org.thoughtcrime.securesms"
buildToolsVersion = libs.versions.buildTools.get()
compileSdkVersion = libs.versions.compileSdk.get()
ndkVersion = libs.versions.ndk.get()
buildToolsVersion = signalBuildToolsVersion
compileSdkVersion = signalCompileSdkVersion
ndkVersion = signalNdkVersion
flavorDimensions += listOf("distribution", "environment")
testBuildType = "instrumentation"
@@ -111,12 +88,11 @@ android {
android.bundle.language.enableSplit = false
kotlinOptions {
jvmTarget = libs.versions.kotlinJvmTarget.get()
jvmTarget = signalKotlinJvmTarget
freeCompilerArgs = listOf("-Xjvm-default=all")
suppressWarnings = true
}
debugKeystorePropertiesProvider.orNull?.let { properties ->
keystores["debug"]?.let { properties ->
signingConfigs.getByName("debug").apply {
storeFile = file("${project.rootDir}/${properties.getProperty("storeFile")}")
storePassword = properties.getProperty("storePassword")
@@ -156,8 +132,8 @@ android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.toVersion(libs.versions.javaVersion.get())
targetCompatibility = JavaVersion.toVersion(libs.versions.javaVersion.get())
sourceCompatibility = signalJavaVersion
targetCompatibility = signalJavaVersion
}
packaging {
@@ -179,8 +155,7 @@ android {
"META-INF/LICENSE-notice.md",
"META-INF/proguard/androidx-annotations.pro",
"**/*.dylib",
"**/*.dll",
"**/*.proto"
"**/*.dll"
)
}
}
@@ -196,14 +171,11 @@ android {
}
defaultConfig {
if (currentHotfixVersion >= maxHotfixVersions) {
throw AssertionError("Hotfix version offset is too large!")
}
versionCode = (canonicalVersionCode * maxHotfixVersions) + possibleHotfixVersions[currentHotfixVersion]
versionCode = (canonicalVersionCode * maxHotfixVersions) + currentHotfixVersion
versionName = canonicalVersionName
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.targetSdk.get().toInt()
minSdk = signalMinSdkVersion
targetSdk = signalTargetSdkVersion
vectorDrawables.useSupportLibrary = true
project.ext.set("archivesBaseName", "Signal")
@@ -236,13 +208,13 @@ android {
buildConfigField("String[]", "SIGNAL_CDSI_IPS", rootProject.extra["cdsi_ips"] as String)
buildConfigField("String[]", "SIGNAL_SVR2_IPS", rootProject.extra["svr2_ips"] as String)
buildConfigField("String", "SIGNAL_AGENT", "\"OWA\"")
buildConfigField("String", "SVR2_MRENCLAVE_LEGACY", "\"29cd63c87bea751e3bfd0fbd401279192e2e5c99948b4ee9437eafc4968355fb\"")
buildConfigField("String", "SVR2_MRENCLAVE", "\"1240acbd4aa26974184844c8a46b1022d3957ac8a76c1fd8f5b1a15141ee0708\"")
buildConfigField("String[]", "UNIDENTIFIED_SENDER_TRUST_ROOTS", "new String[]{ \"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\", \"BUkY0I+9+oPgDCn4+Ac6Iu813yvqkDr/ga8DzLxFxuk6\"}")
buildConfigField("String", "SVR2_MRENCLAVE_LEGACY", "\"a6622ad4656e1abcd0bc0ff17c229477747d2ded0495c4ebee7ed35c1789fa97\"")
buildConfigField("String", "SVR2_MRENCLAVE", "\"9314436a9a144992bb3680770ea5fd7934a7ffd29257844a33763a238903d570\"")
buildConfigField("String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\"")
buildConfigField("String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXTLfN0/vLt98KDPnxwAQL9j5V1jGOY8jQl6MLxEs56cwXN0dqCnImzVH3TZT1cJ8SW1BRX6qIVxEzjsSGx3yxF3suAilPMqGRp4ffyopjMD1JXiKR2RwLKzizUe5e8XyGOy9fplzhw3jVzTRyUZTRSZKkMLWcQ/gv0E4aONNqs4P+NameAZYOD12qRkxosQQP5uux6B2nRyZ7sAV54DgFyLiRcq1FvwKw2EPQdk4HDoePrO/RNUbyNddnM/mMgj4FW65xCoT1LmjrIjsv/Ggdlx46ueczhMgtBunx1/w8k8V+l8LVZ8gAT6wkU5J+DPQalQguMg12Jzug3q4TbdHiGCmD9EunCwOmsLuLJkz6EcSYXtrlDEnAM+hicw7iergYLLlMXpfTdGxJCWJmP4zqUFeTTmsmhsjGBt7NiEB/9pFFEB3pSbf4iiUukw63Eo8Aqnf4iwob6X1QviCWuc8t0LUlT9vALgh/f2DPVOOmR0RW6bgRvc7DSF20V/omg+YBw==\"")
buildConfigField("String", "GENERIC_SERVER_PUBLIC_PARAMS", "\"AByD873dTilmOSG0TjKrvpeaKEsUmIO8Vx9BeMmftwUs9v7ikPwM8P3OHyT0+X3EUMZrSe9VUp26Wai51Q9I8mdk0hX/yo7CeFGJyzoOqn8e/i4Ygbn5HoAyXJx5eXfIbqpc0bIxzju4H/HOQeOpt6h742qii5u/cbwOhFZCsMIbElZTaeU+BWMBQiZHIGHT5IE0qCordQKZ5iPZom0HeFa8Yq0ShuEyAl0WINBiY6xE3H/9WnvzXBbMuuk//eRxXgzO8ieCeK8FwQNxbfXqZm6Ro1cMhCOF3u7xoX83QhpN\"")
buildConfigField("String", "BACKUP_SERVER_PUBLIC_PARAMS", "\"AJwNSU55fsFCbgaxGRD11wO1juAs8Yr5GF8FPlGzzvdJJIKH5/4CC7ZJSOe3yL2vturVaRU2Cx0n751Vt8wkj1bozK3CBV1UokxV09GWf+hdVImLGjXGYLLhnI1J2TWEe7iWHyb553EEnRb5oxr9n3lUbNAJuRmFM7hrr0Al0F0wrDD4S8lo2mGaXe0MJCOM166F8oYRQqpFeEHfiLnxA1O8ZLh7vMdv4g9jI5phpRBTsJ5IjiJrWeP0zdIGHEssUeprDZ9OUJ14m0v61eYJMKsf59Bn+mAT2a7YfB+Don9O\"")
buildConfigField("String[]", "LANGUAGES", "new String[]{ ${languagesForBuildConfigProvider.get()} }")
buildConfigField("String[]", "LANGUAGES", "new String[]{ ${languageList().map { "\"$it\"" }.joinToString(separator = ", ")} }")
buildConfigField("int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode")
buildConfigField("String", "DEFAULT_CURRENCIES", "\"EUR,AUD,GBP,CAD,CNY\"")
buildConfigField("String", "GIPHY_API_KEY", "\"3o6ZsYH6U6Eri53TXy\"")
@@ -258,8 +230,7 @@ android {
buildConfigField("String", "STRIPE_BASE_URL", "\"https://api.stripe.com/v1\"")
buildConfigField("String", "STRIPE_PUBLISHABLE_KEY", "\"pk_live_6cmGZopuTsV8novGgJJW9JpC00vLIgtQ1D\"")
buildConfigField("boolean", "TRACING_ENABLED", "false")
buildConfigField("boolean", "LINK_DEVICE_UX_ENABLED", "false")
buildConfigField("boolean", "USE_STRING_ID", "false")
buildConfigField("boolean", "MESSAGE_BACKUP_RESTORE_ENABLED", "false")
ndk {
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
@@ -281,7 +252,7 @@ android {
buildTypes {
getByName("debug") {
if (debugKeystorePropertiesProvider.orNull != null) {
if (keystores["debug"] != null) {
signingConfig = signingConfigs["debug"]
}
isDefault = true
@@ -314,7 +285,6 @@ android {
manifestPlaceholders["mapsKey"] = getMapsKey()
buildConfigField("String", "BUILD_VARIANT_TYPE", "\"Debug\"")
buildConfigField("boolean", "LINK_DEVICE_UX_ENABLED", "true")
}
getByName("release") {
@@ -358,25 +328,8 @@ android {
isDebuggable = false
isMinifyEnabled = true
matchingFallbacks += "debug"
applicationIdSuffix = ".benchmark"
buildConfigField("String", "BUILD_VARIANT_TYPE", "\"Benchmark\"")
buildConfigField("boolean", "TRACING_ENABLED", "true")
buildConfigField("String[]", "UNIDENTIFIED_SENDER_TRUST_ROOTS", "new String[]{ \"BVT/2gHqbrG1xzuIypLIOjFgMtihrMld1/5TGADL6Dhv\"}")
manifestPlaceholders["applicationClass"] = "org.thoughtcrime.securesms.BenchmarkApplicationContext"
}
create("mocked") {
initWith(getByName("debug"))
isDefault = false
isDebuggable = false
isMinifyEnabled = true
matchingFallbacks += "debug"
buildConfigField("String", "BUILD_VARIANT_TYPE", "\"Benchmark\"")
buildConfigField("boolean", "TRACING_ENABLED", "true")
manifestPlaceholders["applicationClass"] = "org.thoughtcrime.securesms.ApplicationContext"
}
create("canary") {
@@ -386,14 +339,6 @@ android {
matchingFallbacks += "debug"
buildConfigField("String", "BUILD_VARIANT_TYPE", "\"Canary\"")
}
create("quickstart") {
initWith(getByName("debug"))
isDefault = false
isMinifyEnabled = false
matchingFallbacks += "debug"
buildConfigField("String", "BUILD_VARIANT_TYPE", "\"Quickstart\"")
}
}
productFlavors {
@@ -412,20 +357,18 @@ android {
buildConfigField("String", "BUILD_DISTRIBUTION_TYPE", "\"website\"")
}
create("github") {
dimension = "distribution"
buildConfigField("boolean", "MANAGES_APP_UPDATES", "false")
buildConfigField("String", "APK_UPDATE_MANIFEST_URL", "null")
buildConfigField("String", "BUILD_DISTRIBUTION_TYPE", "\"github\"")
}
create("nightly") {
val apkUpdateManifestUrl = if (file("${project.rootDir}/nightly-url.txt").exists()) {
file("${project.rootDir}/nightly-url.txt").readText().trim()
} else {
"<unset>"
}
dimension = "distribution"
versionNameSuffix = "-nightly-untagged-${getGitHash()}"
buildConfigField("boolean", "MANAGES_APP_UPDATES", "false")
buildConfigField("String", "APK_UPDATE_MANIFEST_URL", "null")
versionNameSuffix = "-nightly-untagged-${getDateSuffix()}"
buildConfigField("boolean", "MANAGES_APP_UPDATES", "true")
buildConfigField("String", "APK_UPDATE_MANIFEST_URL", "\"${apkUpdateManifestUrl}\"")
buildConfigField("String", "BUILD_DISTRIBUTION_TYPE", "\"nightly\"")
buildConfigField("boolean", "LINK_DEVICE_UX_ENABLED", "true")
}
create("prod") {
@@ -449,9 +392,9 @@ android {
buildConfigField("String", "SIGNAL_CDN3_URL", "\"https://cdn3-staging.signal.org\"")
buildConfigField("String", "SIGNAL_CDSI_URL", "\"https://cdsi.staging.signal.org\"")
buildConfigField("String", "SIGNAL_SVR2_URL", "\"https://svr2.staging.signal.org\"")
buildConfigField("String", "SVR2_MRENCLAVE_LEGACY", "\"a75542d82da9f6914a1e31f8a7407053b99cc99a0e7291d8fbd394253e19b036\"")
buildConfigField("String", "SVR2_MRENCLAVE", "\"97f151f6ed078edbbfd72fa9cae694dcc08353f1f5e8d9ccd79a971b10ffc535\"")
buildConfigField("String[]", "UNIDENTIFIED_SENDER_TRUST_ROOTS", "new String[]{\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\", \"BYhU6tPjqP46KGZEzRs1OL4U39V5dlPJ/X09ha4rErkm\"}")
buildConfigField("String", "SVR2_MRENCLAVE_LEGACY", "\"acb1973aa0bbbd14b3b4e06f145497d948fd4a98efc500fcce363b3b743ec482\"")
buildConfigField("String", "SVR2_MRENCLAVE", "\"38e01eff4fe357dc0b0e8ef7a44b4abc5489fbccba3a78780f3872c277f62bf3\"")
buildConfigField("String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\"")
buildConfigField("String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXZSSsOZ6s7M1+rTJN0bI5CKY2PX29y5Ok3jSWufIKcgKOnWoP67d5b2du2ZVJjpjfibNIHbT/cegy/sBLoFwtHogVYUewANUAXIaMPyCLRArsKhfJ5wBtTminG/PAvuBdJ70Z/bXVPf8TVsR292zQ65xwvWTejROW6AZX6aqucUjlENAErBme1YHmOSpU6tr6doJ66dPzVAWIanmO/5mgjNEDeK7DDqQdB1xd03HT2Qs2TxY3kCK8aAb/0iM0HQiXjxZ9HIgYhbtvGEnDKW5ILSUydqH/KBhW4Pb0jZWnqN/YgbWDKeJxnDbYcUob5ZY5Lt5ZCMKuaGUvCJRrCtuugSMaqjowCGRempsDdJEt+cMaalhZ6gczklJB/IbdwENW9KeVFPoFNFzhxWUIS5ML9riVYhAtE6JE5jX0xiHNVIIPthb458cfA8daR0nYfYAUKogQArm0iBezOO+mPk5vCNWI+wwkyFCqNDXz/qxl1gAntuCJtSfq9OC3NkdhQlgYQ==\"")
buildConfigField("String", "GENERIC_SERVER_PUBLIC_PARAMS", "\"AHILOIrFPXX9laLbalbA9+L1CXpSbM/bTJXZGZiuyK1JaI6dK5FHHWL6tWxmHKYAZTSYmElmJ5z2A5YcirjO/yfoemE03FItyaf8W1fE4p14hzb5qnrmfXUSiAIVrhaXVwIwSzH6RL/+EO8jFIjJ/YfExfJ8aBl48CKHgu1+A6kWynhttonvWWx6h7924mIzW0Czj2ROuh4LwQyZypex4GuOPW8sgIT21KNZaafgg+KbV7XM1x1tF3XA17B4uGUaDbDw2O+nR1+U5p6qHPzmJ7ggFjSN6Utu+35dS1sS0P9N\"")
buildConfigField("String", "BACKUP_SERVER_PUBLIC_PARAMS", "\"AHYrGb9IfugAAJiPKp+mdXUx+OL9zBolPYHYQz6GI1gWjpEu5me3zVNSvmYY4zWboZHif+HG1sDHSuvwFd0QszSwuSF4X4kRP3fJREdTZ5MCR0n55zUppTwfHRW2S4sdQ0JGz7YDQIJCufYSKh0pGNEHL6hv79Agrdnr4momr3oXdnkpVBIp3HWAQ6IbXQVSG18X36GaicI1vdT0UFmTwU2KTneluC2eyL9c5ff8PcmiS+YcLzh0OKYQXB5ZfQ06d6DiINvDQLy75zcfUOniLAj0lGJiHxGczin/RXisKSR8\"")
@@ -463,17 +406,7 @@ android {
buildConfigField("String", "BUILD_ENVIRONMENT_TYPE", "\"Staging\"")
buildConfigField("String", "STRIPE_PUBLISHABLE_KEY", "\"pk_test_sngOd8FnXNkpce9nPXawKrJD00kIDngZkD\"")
}
create("backup") {
initWith(getByName("staging"))
dimension = "environment"
applicationIdSuffix = ".backup"
buildConfigField("boolean", "MANAGES_APP_UPDATES", "true")
buildConfigField("String", "BUILD_ENVIRONMENT_TYPE", "\"Backup\"")
buildConfigField("boolean", "MESSAGE_BACKUP_RESTORE_ENABLED", "true")
}
}
@@ -481,64 +414,43 @@ android {
abortOnError = true
baseline = file("lint-baseline.xml")
checkReleaseBuilds = false
ignoreWarnings = true
quiet = true
disable += "LintError"
lintConfig = rootProject.file("lint.xml")
}
applicationVariants.all {
outputs
.map { it as com.android.build.gradle.internal.api.ApkVariantOutputImpl }
.forEach { output ->
if (output.baseName.contains("nightly")) {
var tag = getCurrentGitTag()
if (!tag.isNullOrEmpty()) {
if (tag.startsWith("v")) {
tag = tag.substring(1)
}
output.versionNameOverride = tag
output.outputFileName = output.outputFileName.replace(".apk", "-${output.versionNameOverride}.apk")
} else {
output.outputFileName = output.outputFileName.replace(".apk", "-$versionName.apk")
}
} else {
output.outputFileName = output.outputFileName.replace(".apk", "-$versionName.apk")
if (currentHotfixVersion >= maxHotfixVersions) {
throw AssertionError("Hotfix version is too large!")
}
}
}
}
androidComponents {
beforeVariants { variant ->
variant.enable = variant.name in selectableVariants
}
onVariants(selector().all()) { variant: com.android.build.api.variant.ApplicationVariant ->
onVariants { variant ->
// Include the test-only library on debug builds.
if (variant.buildType != "instrumentation") {
variant.packaging.jniLibs.excludes.add("**/libsignal_jni_testing.so")
}
// Starting with minSdk 23, Android leaves native libraries uncompressed, which is fine for the Play Store, but not for our self-distributed APKs.
// This reverts it to the legacy behavior, compressing the native libraries, and drastically reducing the APK file size.
if (variant.name.contains("website", ignoreCase = true) || variant.name.contains("github", ignoreCase = true)) {
variant.packaging.jniLibs.useLegacyPackaging.set(true)
}
// Version overrides
if (variant.name.contains("nightly", ignoreCase = true)) {
var tag = getNightlyTagForCurrentCommit()
if (!tag.isNullOrEmpty()) {
if (tag.startsWith("v")) {
tag = tag.substring(1)
}
// We add a multiple of maxHotfixVersions to nightlies to ensure we're always at least that many versions ahead
val nightlyBuffer = (5 * maxHotfixVersions)
val nightlyVersionCode = (canonicalVersionCode * maxHotfixVersions) + (getNightlyBuildNumber(tag) * 10) + nightlyBuffer
variant.outputs.forEach { output ->
output.versionName.set(tag)
output.versionCode.set(nightlyVersionCode)
}
}
}
}
onVariants(selector().withBuildType("quickstart")) { variant ->
val environment = variant.flavorName?.let { name ->
when {
name.contains("staging", ignoreCase = true) -> "staging"
name.contains("prod", ignoreCase = true) -> "prod"
else -> "prod"
}
} ?: "prod"
val taskProvider = tasks.register<CopyQuickstartCredentialsTask>("copyQuickstartCredentials${variant.name.capitalize()}") {
if (quickstartCredentialsDir != null) {
inputDir.set(File(quickstartCredentialsDir))
}
filePrefix.set("${environment}_")
}
variant.sources.assets?.addGeneratedSourceDirectory(taskProvider) { it.outputDir }
}
}
@@ -551,40 +463,6 @@ android {
java.srcDir(path)
}
}
sourceSets {
getByName("mocked") {
java.srcDir("$projectDir/src/benchmarkShared/java")
manifest.srcFile("$projectDir/src/benchmarkShared/AndroidManifest.xml")
}
getByName("benchmark") {
java.srcDir("$projectDir/src/benchmarkShared/java")
manifest.srcFile("$projectDir/src/benchmarkShared/AndroidManifest.xml")
}
}
applicationVariants.configureEach {
outputs.configureEach {
if (this is com.android.build.gradle.internal.api.BaseVariantOutputImpl) {
outputFileName = outputFileName.replace(".apk", "-$versionName.apk")
}
}
}
}
baselineProfile {
warnings {
disabledVariants = false
}
mergeIntoMain = true
variants.create("mocked") {
from(project(":baseline-profile"))
}
dexLayoutOptimization = false
}
dependencies {
@@ -592,27 +470,22 @@ dependencies {
ktlintRuleset(libs.ktlint.twitter.compose)
coreLibraryDesugaring(libs.android.tools.desugar)
implementation(project(":lib:libsignal-service"))
implementation(project(":lib:paging"))
implementation(project(":core:util"))
implementation(project(":lib:glide"))
implementation(project(":lib:video"))
implementation(project(":lib:device-transfer"))
implementation(project(":lib:image-editor"))
implementation(project(":lib:donations"))
implementation(project(":lib:debuglogs-viewer"))
implementation(project(":lib:contacts"))
implementation(project(":lib:qr"))
implementation(project(":lib:sticky-header-grid"))
implementation(project(":lib:photoview"))
implementation(project(":lib:blurhash"))
implementation(project(":core:ui"))
implementation(project(":core:models"))
implementation(project(":core:models-jvm"))
implementation(project(":feature:camera"))
implementation(project(":feature:registration"))
implementation(project(":libsignal-service"))
implementation(project(":paging"))
implementation(project(":core-util"))
implementation(project(":glide-config"))
implementation(project(":video"))
implementation(project(":device-transfer"))
implementation(project(":image-editor"))
implementation(project(":donations"))
implementation(project(":contacts"))
implementation(project(":qr"))
implementation(project(":sticky-header-grid"))
implementation(project(":photoview"))
implementation(project(":core-ui"))
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.fragment.compose)
implementation(libs.androidx.appcompat) {
version {
strictly("1.6.1")
@@ -634,8 +507,6 @@ dependencies {
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.navigation3.runtime)
implementation(libs.androidx.navigation3.ui)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.process)
@@ -664,7 +535,6 @@ dependencies {
}
implementation(libs.google.play.services.maps)
implementation(libs.google.play.services.auth)
implementation(libs.google.signin)
implementation(libs.bundles.media3)
implementation(libs.conscrypt.android)
implementation(libs.signal.aesgcmprovider)
@@ -691,7 +561,6 @@ dependencies {
implementation(libs.lottie.compose)
implementation(libs.signal.android.database.sqlcipher)
implementation(libs.androidx.sqlite)
testImplementation(libs.androidx.sqlite.framework)
implementation(libs.google.ez.vcard) {
exclude(group = "com.fasterxml.jackson.core")
exclude(group = "org.freemarker")
@@ -708,14 +577,11 @@ dependencies {
implementation(libs.rxjava3.rxandroid)
implementation(libs.rxjava3.rxkotlin)
implementation(libs.rxdogtag)
implementation(libs.androidx.credentials)
implementation(libs.androidx.credentials.compat)
implementation(libs.kotlinx.serialization.json)
implementation(project(":lib:billing"))
implementation(project(":feature:media-send"))
"playImplementation"(project(":billing"))
"nightlyImplementation"(project(":billing"))
"spinnerImplementation"(project(":lib:spinner"))
"spinnerImplementation"(project(":spinner"))
"canaryImplementation"(libs.square.leakcanary)
@@ -741,12 +607,8 @@ dependencies {
}
testImplementation(testLibs.conscrypt.openjdk.uber)
testImplementation(testLibs.mockk)
testImplementation(testFixtures(project(":lib:libsignal-service")))
testImplementation(testFixtures(project(":libsignal-service")))
testImplementation(testLibs.espresso.core)
testImplementation(testLibs.kotlinx.coroutines.test)
testImplementation(libs.androidx.compose.ui.test.junit4)
"perfImplementation"(libs.androidx.compose.ui.test.manifest)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
@@ -757,11 +619,63 @@ dependencies {
androidTestImplementation(testLibs.androidx.test.ext.junit.ktx)
androidTestImplementation(testLibs.assertk)
androidTestImplementation(testLibs.mockk.android)
androidTestImplementation(testLibs.square.okhttp.mockserver)
androidTestImplementation(testLibs.diff.utils)
androidTestUtil(testLibs.androidx.test.orchestrator)
}
fun assertIsGitRepo() {
if (!file("${project.rootDir}/.git").exists()) {
throw IllegalStateException("Must be a git repository to guarantee reproducible builds! (git hash is part of APK)")
}
}
fun getLastCommitTimestamp(): String {
assertIsGitRepo()
ByteArrayOutputStream().use { os ->
exec {
executable = "git"
args = listOf("log", "-1", "--pretty=format:%ct")
standardOutput = os
}
return os.toString() + "000"
}
}
fun getGitHash(): String {
assertIsGitRepo()
val stdout = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "rev-parse", "HEAD")
standardOutput = stdout
}
return stdout.toString().trim().substring(0, 12)
}
fun getCurrentGitTag(): String? {
assertIsGitRepo()
val stdout = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "tag", "--points-at", "HEAD")
standardOutput = stdout
}
val output: String = stdout.toString().trim()
return if (output.isNotEmpty()) {
val tags = output.split("\n").toList()
tags.firstOrNull { it.contains("nightly") } ?: tags[0]
} else {
null
}
}
tasks.withType<Test>().configureEach {
testLogging {
events("failed")
@@ -772,131 +686,59 @@ tasks.withType<Test>().configureEach {
}
}
fun getLastCommitTimestamp(): String {
return providers.exec {
commandLine("git", "log", "-1", "--pretty=format:%ct")
}.standardOutput.asText.get() + "000"
project.tasks.configureEach {
if (name.lowercase().contains("nightly") && name != "checkNightlyParams") {
dependsOn(tasks.getByName("checkNightlyParams"))
}
}
fun getGitHash(): String {
return providers.exec {
commandLine("git", "rev-parse", "HEAD")
}.standardOutput.asText.get().trim().substring(0, 12)
tasks.register("checkNightlyParams") {
doFirst {
if (project.gradle.startParameter.taskNames.any { it.lowercase().contains("nightly") }) {
if (!file("${project.rootDir}/nightly-url.txt").exists()) {
throw GradleException("Cannot find 'nightly-url.txt' for nightly build! It must exist in the root of this project and contain the location of the nightly manifest.")
}
}
}
}
fun getNightlyTagForCurrentCommit(): String? {
val output = providers.exec {
commandLine("git", "tag", "--points-at", "HEAD")
}.standardOutput.asText.get().trim()
fun loadKeystoreProperties(filename: String): Properties? {
val keystorePropertiesFile = file("${project.rootDir}/$filename")
return if (output.isNotEmpty()) {
val tags = output.split("\n").toList()
tags.firstOrNull { it.contains("nightly") } ?: tags[0]
return if (keystorePropertiesFile.exists()) {
val keystoreProperties = Properties()
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
keystoreProperties
} else {
null
}
}
fun getNightlyBuildNumber(tag: String?): Int {
if (tag == null) {
return 0
}
val match = Regex("-(\\d{3})$").find(tag)
return match?.groupValues?.get(1)?.toIntOrNull() ?: 0
fun getDateSuffix(): String {
return SimpleDateFormat("yyyy-MM-dd-HH:mm").format(Date())
}
fun getMapsKey(): String {
return providers
.gradleProperty("mapsKey")
.orElse(providers.environmentVariable("MAPS_KEY"))
.orElse("AIzaSyCSx9xea86GwDKGznCAULE9Y5a8b-TfN9U")
.get()
}
val mapKey = file("${project.rootDir}/maps.key")
abstract class LanguageListValueSource : ValueSource<List<String>, LanguageListValueSource.Params> {
interface Params : ValueSourceParameters {
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)
val resDir: DirectoryProperty
}
override fun obtain(): List<String> {
// In API 35, language codes for Hebrew and Indonesian now use the ISO 639-1 code ("he" and "id").
// However, the value resources still only support the outdated code ("iw" and "in") so we have
// to manually indicate that we support these languages.
val updatedLanguageCodes = listOf("he", "id")
val resRoot = parameters.resDir.asFile.get()
val languages = resRoot
.walkTopDown()
.filter { it.isFile && it.name == "strings.xml" }
.mapNotNull { stringFile -> stringFile.parentFile?.name }
.map { valuesFolderName -> valuesFolderName.removePrefix("values-") }
.filter { valuesFolderName -> valuesFolderName != "values" }
.map { languageCode -> languageCode.replace("-r", "_") }
.toList()
.distinct()
.sorted()
return languages + updatedLanguageCodes + "en"
return if (mapKey.exists()) {
mapKey.readLines()[0]
} else {
"AIzaSyCSx9xea86GwDKGznCAULE9Y5a8b-TfN9U"
}
}
abstract class PropertiesFileValueSource : ValueSource<Properties?, PropertiesFileValueSource.Params> {
interface Params : ValueSourceParameters {
@get:InputFile
@get:Optional
@get:PathSensitive(PathSensitivity.RELATIVE)
val file: RegularFileProperty
}
override fun obtain(): Properties? {
val f: File = parameters.file.asFile.get()
if (!f.exists()) return null
return Properties().apply {
f.inputStream().use { load(it) }
}
}
fun Project.languageList(): List<String> {
return fileTree("src/main/res") { include("**/strings.xml") }
.map { stringFile -> stringFile.parentFile.name }
.map { valuesFolderName -> valuesFolderName.replace("values-", "") }
.filter { valuesFolderName -> valuesFolderName != "values" }
.map { languageCode -> languageCode.replace("-r", "_") }
.distinct()
.sorted() + "en"
}
fun String.capitalize(): String {
return this.replaceFirstChar { it.uppercase() }
}
abstract class CopyQuickstartCredentialsTask : DefaultTask() {
@get:InputDirectory
@get:Optional
abstract val inputDir: DirectoryProperty
@get:Input
abstract val filePrefix: Property<String>
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@TaskAction
fun copy() {
if (!inputDir.isPresent) {
throw GradleException("quickstart.credentials.dir is not set in local.properties. This is required for quickstart builds.")
}
val prefix = filePrefix.get()
val candidates = inputDir.get().asFile.listFiles()
?.filter { it.extension == "json" && it.name.startsWith(prefix) }
?: emptyList()
if (candidates.isEmpty()) {
throw GradleException("No credential files matching '$prefix*.json' found in ${inputDir.get().asFile}. Add files like '${prefix}account1.json' to your credentials directory.")
}
val chosen = candidates.random()
logger.lifecycle("Selected quickstart credential: ${chosen.name}")
val dest = outputDir.get().asFile.resolve("quickstart")
dest.mkdirs()
chosen.copyTo(dest.resolve(chosen.name), overwrite = true)
}
}

File diff suppressed because one or more lines are too long

View File

@@ -22,9 +22,7 @@
<issue id="CanvasSize" severity="error" />
<issue id="HardcodedText" severity="error" />
<issue id="VectorRaster" severity="error">
<ignore path="*/donate_with_googlepay_button_content.xml" /> <!-- Externally provided by Google -->
</issue>
<issue id="VectorRaster" severity="error" />
<issue id="ButtonOrder" severity="error" />
<issue id="ExtraTranslation" severity="warning" />
<issue id="UnspecifiedImmutableFlag" severity="error" />
@@ -45,8 +43,4 @@
</issue>
<issue id="OptionalUsedAsFieldOrParameterType" severity="ignore" />
<issue id="SameParameterValue" severity="ignore" />
<!-- Disables check for digital asset linking in manifest. It's not needed, since we are not using CredentialManager for passkey support. -->
<issue id="CredManMissingDal" severity="ignore" />
</lint>

Some files were not shown because too many files have changed in this diff Show More