diff --git a/.gitignore b/.gitignore index 97aa4650e5..dd90f84809 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ captures/ project.properties keystore.debug.properties keystore.staging.properties +nightly-url.txt .project .settings bin/ @@ -28,4 +29,4 @@ jni/libspeex/.deps/ pkcs11.password dev.keystore maps.key -local/ \ No newline at end of file +local/ diff --git a/app/build.gradle b/app/build.gradle index 9eda125251..85deffe5bc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -333,8 +333,8 @@ android { nightly { def apkUpdateManifestUrl = "" - if (project.hasProperty('nightlyApkUpdateManifestUrl')) { - apkUpdateManifestUrl = project.getProperty('nightlyApkUpdateManifestUrl') + if (file("${project.rootDir}/nightly-url.txt").exists()) { + apkUpdateManifestUrl = file("${project.rootDir}/nightly-url.txt").text.trim() } dimension 'distribution' versionNameSuffix "-nightly-untagged-${getDateSuffix()}" @@ -675,8 +675,9 @@ project.tasks.configureEach { task -> tasks.register('checkNightlyParams') { doFirst { if (project.gradle.startParameter.taskNames.any { it.toLowerCase().contains("nightly") }) { - if (!project.hasProperty('nightlyApkUpdateManifestUrl')) { - throw new GradleException("Required command-line parameter 'nightlyApkUpdateManifestUrl' not found for nightly build!") + + if (!file("${project.rootDir}/nightly-url.txt").exists()) { + throw new GradleException("Cannot fine 'nightly-url.txt' for nightly build! It must exist in the root of this project and contain the location of the nightly manifest.") } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt index 39d6ae5bb1..3f3dcae30d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt @@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity +import org.thoughtcrime.securesms.util.Environment import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.PlayStoreUtil import org.thoughtcrime.securesms.util.Util @@ -232,6 +233,16 @@ class AppSettingsFragment : DSLSettingsFragment( } ) + if (Environment.IS_NIGHTLY) { + clickPref( + title = DSLSettingsText.from("App updates"), + icon = DSLSettingsIcon.from(R.drawable.symbol_calendar_24), + onClick = { + findNavController().safeNavigate(R.id.action_appSettingsFragment_to_appUpdatesSettingsFragment) + } + ) + } + dividerPref() if (SignalStore.paymentsValues().paymentsAvailability.showPaymentsMenu()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/updates/AppUpdatesSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/updates/AppUpdatesSettingsFragment.kt new file mode 100644 index 0000000000..8f6d0808cf --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/updates/AppUpdatesSettingsFragment.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.components.settings.app.updates + +import android.os.Build +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.settings.DSLConfiguration +import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment +import org.thoughtcrime.securesms.components.settings.DSLSettingsText +import org.thoughtcrime.securesms.components.settings.configure +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies +import org.thoughtcrime.securesms.jobs.ApkUpdateJob +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +/** + * Settings around app updates. Only shown for builds that manage their own app updates. + */ +class AppUpdatesSettingsFragment : DSLSettingsFragment(R.string.preferences_app_updates__title) { + + override fun bindAdapter(adapter: MappingAdapter) { + adapter.submitList(getConfiguration().toMappingModelList()) + } + + private fun getConfiguration(): DSLConfiguration { + return configure { + if (Build.VERSION.SDK_INT >= 31) { + switchPref( + title = DSLSettingsText.from("Automatic updates"), + summary = DSLSettingsText.from("Automatically download and install app updates"), + isChecked = SignalStore.apkUpdate().autoUpdate, + onClick = { + SignalStore.apkUpdate().autoUpdate = !SignalStore.apkUpdate().autoUpdate + } + ) + } + + clickPref( + title = DSLSettingsText.from("Check for updates"), + summary = DSLSettingsText.from("Last checked on: $lastSuccessfulUpdateString"), + onClick = { + ApplicationDependencies.getJobManager().add(ApkUpdateJob()) + } + ) + } + } + + private val lastSuccessfulUpdateString: String + get() { + val lastUpdateTime = SignalStore.apkUpdate().lastSuccessfulCheck + + return if (lastUpdateTime > 0) { + val dateFormat = SimpleDateFormat("MMMM dd, yyyy 'at' h:mma", Locale.US) + dateFormat.format(Date(lastUpdateTime)) + } else { + "Never" + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ApkUpdateJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ApkUpdateJob.kt index 2e7094b87b..c63568a89d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ApkUpdateJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ApkUpdateJob.kt @@ -60,7 +60,7 @@ class ApkUpdateJob private constructor(parameters: Parameters) : BaseJob(paramet return } - Log.i(TAG, "Checking for APK update...") + Log.d(TAG, "Checking for APK update at ${BuildConfig.APK_UPDATE_MANIFEST_URL}") val client = OkHttpClient() val request = Request.Builder().url(BuildConfig.APK_UPDATE_MANIFEST_URL).build() @@ -78,10 +78,11 @@ class ApkUpdateJob private constructor(parameters: Parameters) : BaseJob(paramet Log.w(TAG, "Invalid update descriptor! $updateDescriptor") return } else { - Log.i(TAG, "Got descriptor: $updateDescriptor") + Log.d(TAG, "Got descriptor: $updateDescriptor") } if (updateDescriptor.versionCode > getCurrentAppVersionCode()) { + Log.i(TAG, "Newer version code available. Current: ${getCurrentAppVersionCode()}, Update: ${updateDescriptor.versionCode}") val digest: ByteArray = Hex.fromStringCondensed(updateDescriptor.digest) val downloadStatus: DownloadStatus = getDownloadStatus(updateDescriptor.url, digest) @@ -94,7 +95,11 @@ class ApkUpdateJob private constructor(parameters: Parameters) : BaseJob(paramet Log.i(TAG, "Download status missing, starting download...") handleDownloadStart(updateDescriptor.url, updateDescriptor.versionName, digest) } + } else { + Log.d(TAG, "Version code is the same or older than our own. Current: ${getCurrentAppVersionCode()}, Update: ${updateDescriptor.versionCode}") } + + SignalStore.apkUpdate().lastSuccessfulCheck = System.currentTimeMillis() } public override fun onShouldRetry(e: Exception): Boolean { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ApkUpdateValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ApkUpdateValues.kt index a86e07201a..e54bb9a963 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ApkUpdateValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ApkUpdateValues.kt @@ -10,6 +10,7 @@ internal class ApkUpdateValues(store: KeyValueStore) : SignalStoreValues(store) private const val DOWNLOAD_ID = "apk_update.download_id" private const val DIGEST = "apk_update.digest" private const val AUTO_UPDATE = "apk_update.auto_update" + private const val LAST_SUCCESSFUL_CHECK = "apk_update.last_successful_check" } override fun onFirstEverAppLaunch() = Unit @@ -17,7 +18,8 @@ internal class ApkUpdateValues(store: KeyValueStore) : SignalStoreValues(store) val downloadId: Long by longValue(DOWNLOAD_ID, -2) val digest: ByteArray? get() = store.getBlob(DIGEST, null) - val autoUpdate: Boolean by booleanValue(AUTO_UPDATE, true) + var autoUpdate: Boolean by booleanValue(AUTO_UPDATE, true) + var lastSuccessfulCheck: Long by longValue(LAST_SUCCESSFUL_CHECK, 0) fun setDownloadAttributes(id: Long, digest: ByteArray?) { store diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java index d5c12cb11b..9b702cfe21 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java @@ -91,6 +91,9 @@ public class LogSectionSystemInfo implements LogSection { builder.append("User-Agent : ").append(StandardUserAgentInterceptor.USER_AGENT).append("\n"); builder.append("SlowNotifications : ").append(SlowNotificationHeuristics.isHavingDelayedNotifications()).append("\n"); builder.append("PotentiallyBattery: ").append(SlowNotificationHeuristics.isPotentiallyCausedByBatteryOptimizations()).append("\n"); + if (BuildConfig.MANAGES_APP_UPDATES) { + builder.append("ApkManifestUrl : ").append(BuildConfig.APK_UPDATE_MANIFEST_URL).append("\n"); + } builder.append("App : "); try { diff --git a/app/src/main/res/navigation/app_settings.xml b/app/src/main/res/navigation/app_settings.xml index ae43f0d79f..69cba73bf9 100644 --- a/app/src/main/res/navigation/app_settings.xml +++ b/app/src/main/res/navigation/app_settings.xml @@ -106,6 +106,13 @@ app:exitAnim="@anim/fragment_open_exit" app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> + + + + + Payments Chats + App updates Manage storage Use less data for calls Never