Enable auto-updates for nightly builds.

This commit is contained in:
Greyson Parrelli 2023-10-27 14:27:17 -07:00
parent c4f5110148
commit b8d229e58e
9 changed files with 91 additions and 20 deletions

View file

@ -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 = "<unset>"
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()) {

View file

@ -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
}
}

View file

@ -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,

View file

@ -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)

View file

@ -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) {

View file

@ -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;

View file

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

View file

@ -2105,6 +2105,8 @@
<string name="ApkUpdateNotifications_prompt_install_body">A new version of Signal is available. Tap to update.</string>
<string name="ApkUpdateNotifications_failed_general_title">Signal failed to update</string>
<string name="ApkUpdateNotifications_failed_general_body">We will try again later.</string>
<string name="ApkUpdateNotifications_auto_update_success_title">Signal successfully updated</string>
<string name="ApkUpdateNotifications_auto_update_success_body">You were automatically updated to version %1$s.</string>
<!-- UntrustedSendDialog -->
<string name="UntrustedSendDialog_send_message">Send message?</string>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"/>
<application>
<receiver android:name=".apkupdate.ApkUpdateRefreshListener" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".apkupdate.ApkUpdateDownloadManagerReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>
</receiver>
<receiver
android:name=".apkupdate.ApkUpdatePackageInstallerReceiver"
android:exported="true" />
<receiver
android:name=".apkupdate.ApkUpdateNotificationReceiver"
android:exported="false" />
</application>
</manifest>