diff --git a/app/build.gradle b/app/build.gradle index 7b58b1428c..0b89d83b13 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -320,22 +320,26 @@ android { dimension 'distribution' isDefault true buildConfigField "boolean", "MANAGES_APP_UPDATES", "false" - buildConfigField "String", "APK_UPDATE_URL", "null" + buildConfigField "String", "APK_UPDATE_MANIFEST_URL", "null" buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"play\"" } website { dimension 'distribution' buildConfigField "boolean", "MANAGES_APP_UPDATES", "true" - buildConfigField "String", "APK_UPDATE_URL", "\"https://updates.signal.org/android\"" + buildConfigField "String", "APK_UPDATE_MANIFEST_URL", "\"https://updates.signal.org/android/latest.json\"" buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"website\"" } nightly { + def apkUpdateManifestUrl = "" + if (project.hasProperty('nightlyApkUpdateManifestUrl')) { + apkUpdateManifestUrl = project.getProperty('nightlyApkUpdateManifestUrl') + } dimension 'distribution' versionNameSuffix "-nightly-untagged-${getDateSuffix()}" - buildConfigField "boolean", "MANAGES_APP_UPDATES", "false" - buildConfigField "String", "APK_UPDATE_URL", "null" + buildConfigField "boolean", "MANAGES_APP_UPDATES", "true" + buildConfigField "String", "APK_UPDATE_MANIFEST_URL", "\"${apkUpdateManifestUrl}\"" buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"nightly\"" } @@ -400,6 +404,9 @@ android { tag = tag.substring(1) } output.versionNameOverride = tag + output.outputFileName = output.outputFileName.replace(".apk", "-${versionNameOverride}.apk") + } else { + output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk") } } else { output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk") @@ -659,6 +666,23 @@ tasks.withType(Test) { } } +project.tasks.configureEach { task -> + if (task.name.toLowerCase().contains("nightly") && task.name != 'checkNightlyParams') { + task.dependsOn checkNightlyParams + } +} + +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!") + } + } + } +} + + def loadKeystoreProperties(filename) { def keystorePropertiesFile = file("${project.rootDir}/${filename}") if (keystorePropertiesFile.exists()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt index a29a40278c..1945561ebc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt @@ -16,6 +16,7 @@ import org.signal.core.util.getDownloadManager import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.util.Environment import org.thoughtcrime.securesms.util.FileUtils import java.io.FileInputStream import java.io.IOException @@ -86,17 +87,6 @@ object ApkUpdateInstaller { Log.d(TAG, "Beginning APK install...") val packageInstaller: PackageInstaller = context.packageManager.packageInstaller - Log.d(TAG, "Clearing inactive sessions...") - packageInstaller.mySessions - .filter { session -> !session.isActive } - .forEach { session -> - try { - packageInstaller.abandonSession(session.sessionId) - } catch (e: SecurityException) { - Log.w(TAG, "Failed to abandon inactive session!", e) - } - } - val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL).apply { // At this point, we always want to set this if possible, since we've already prompted the user with our own notification when necessary. // This lets us skip the system-generated notification. @@ -151,8 +141,7 @@ object ApkUpdateInstaller { } private fun shouldAutoUpdate(): Boolean { - // TODO Auto-updates temporarily disabled. Once we have designs for allowing users to opt-out of auto-updates, we can re-enable this - return false -// return Build.VERSION.SDK_INT >= 31 && SignalStore.apkUpdate().autoUpdate && !ApplicationDependencies.getAppForegroundObserver().isForegrounded + // TODO Auto-updates temporarily restricted to nightlies. Once we have designs for allowing users to opt-out of auto-updates, we can re-enable this + return Environment.IS_NIGHTLY && Build.VERSION.SDK_INT >= 31 && SignalStore.apkUpdate().autoUpdate && !ApplicationDependencies.getAppForegroundObserver().isForegrounded } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateNotifications.kt b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateNotifications.kt index 76dc1a26b5..0e715fd3a2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateNotifications.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateNotifications.kt @@ -66,11 +66,34 @@ object ApkUpdateNotifications { .setSmallIcon(R.drawable.ic_notification) .setColor(ContextCompat.getColor(context, R.color.core_ultramarine)) .setContentIntent(pendingIntent) + .setAutoCancel(true) .build() ServiceUtil.getNotificationManager(context).notify(NotificationIds.APK_UPDATE_FAILED_INSTALL, notification) } + fun showAutoUpdateSuccess(context: Context) { + val pendingIntent = PendingIntent.getActivity( + context, + 0, + Intent(context, MainActivity::class.java), + PendingIntentFlags.immutable() + ) + + val appVersionName = context.packageManager.getPackageInfo(context.packageName, 0).versionName + + val notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().APP_UPDATES) + .setContentTitle(context.getString(R.string.ApkUpdateNotifications_auto_update_success_title)) + .setContentText(context.getString(R.string.ApkUpdateNotifications_auto_update_success_body, appVersionName)) + .setSmallIcon(R.drawable.ic_notification) + .setColor(ContextCompat.getColor(context, R.color.core_ultramarine)) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .build() + + ServiceUtil.getNotificationManager(context).notify(NotificationIds.APK_UPDATE_SUCCESSFUL_INSTALL, notification) + } + enum class FailureReason { UNKNOWN, ABORTED, diff --git a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdatePackageInstallerReceiver.kt b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdatePackageInstallerReceiver.kt index 9deb2c4b98..c988d2c5ba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdatePackageInstallerReceiver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdatePackageInstallerReceiver.kt @@ -34,8 +34,11 @@ class ApkUpdatePackageInstallerReceiver : BroadcastReceiver() { Log.w(TAG, "[onReceive] Status: $statusCode, Message: $statusMessage") when (statusCode) { + PackageInstaller.STATUS_SUCCESS -> { + Log.i(TAG, "Update installed successfully!") + ApkUpdateNotifications.showAutoUpdateSuccess(context) + } PackageInstaller.STATUS_PENDING_USER_ACTION -> handlePendingUserAction(context, userInitiated, intent!!) - PackageInstaller.STATUS_SUCCESS -> Log.w(TAG, "Update installed successfully!") PackageInstaller.STATUS_FAILURE_ABORTED -> ApkUpdateNotifications.showInstallFailed(context, FailureReason.ABORTED) PackageInstaller.STATUS_FAILURE_BLOCKED -> ApkUpdateNotifications.showInstallFailed(context, FailureReason.BLOCKED) PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> ApkUpdateNotifications.showInstallFailed(context, FailureReason.INCOMPATIBLE) 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 846969b0c2..2e7094b87b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ApkUpdateJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ApkUpdateJob.kt @@ -63,7 +63,7 @@ class ApkUpdateJob private constructor(parameters: Parameters) : BaseJob(paramet Log.i(TAG, "Checking for APK update...") val client = OkHttpClient() - val request = Request.Builder().url("${BuildConfig.APK_UPDATE_URL}/latest.json").build() + val request = Request.Builder().url(BuildConfig.APK_UPDATE_MANIFEST_URL).build() val rawUpdateDescriptor: String = client.newCall(request).execute().use { response -> if (!response.isSuccessful || response.body() == null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java index 02b74fe1d4..7173aeb46a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java @@ -9,6 +9,7 @@ public final class NotificationIds { public static final int FCM_FAILURE = 12; public static final int APK_UPDATE_PROMPT_INSTALL = 666; public static final int APK_UPDATE_FAILED_INSTALL = 667; + public static final int APK_UPDATE_SUCCESSFUL_INSTALL = 668; public static final int PENDING_MESSAGES = 1111; public static final int MESSAGE_SUMMARY = 1338; public static final int APPLICATION_MIGRATION = 4242; diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/Environment.kt b/app/src/main/java/org/thoughtcrime/securesms/util/Environment.kt index 8e68650274..2733b10119 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/Environment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/Environment.kt @@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.BuildConfig object Environment { const val IS_STAGING: Boolean = BuildConfig.BUILD_ENVIRONMENT_TYPE == "Staging" const val IS_PNP: Boolean = BuildConfig.BUILD_ENVIRONMENT_TYPE == "Pnp" + const val IS_NIGHTLY: Boolean = BuildConfig.BUILD_DISTRIBUTION_TYPE == "nightly" object Donations { @JvmStatic diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c7c6ed3c1e..22c36b5a98 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2105,6 +2105,8 @@ A new version of Signal is available. Tap to update. Signal failed to update We will try again later. + Signal successfully updated + You were automatically updated to version %1$s. Send message? diff --git a/app/src/nightly/AndroidManifest.xml b/app/src/nightly/AndroidManifest.xml new file mode 100644 index 0000000000..613e309f7f --- /dev/null +++ b/app/src/nightly/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file