Add deprecation notification when build expires.

This commit is contained in:
lisa-signal
2025-06-18 11:13:33 -04:00
committed by Michelle Tang
parent 4f6a5de227
commit b826352ce7
4 changed files with 98 additions and 3 deletions

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.jobs
import android.app.PendingIntent
import android.content.Intent
import android.net.Uri
import androidx.core.app.NotificationCompat
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.notifications.NotificationChannels
import org.thoughtcrime.securesms.notifications.NotificationIds
import org.thoughtcrime.securesms.util.ServiceUtil
import kotlin.time.Duration.Companion.days
/**
* Notifies users that their build expired and redirects to the download page on click.
*/
class DeprecatedNotificationJob private constructor(parameters: Parameters) : Job(parameters) {
companion object {
const val KEY: String = "DeprecatedNotificationJob"
private val TAG = Log.tag(DeprecatedNotificationJob::class.java)
@JvmStatic
fun enqueue() {
AppDependencies.jobManager.add(DeprecatedNotificationJob())
}
}
private constructor() : this(
Parameters.Builder()
.setQueue("DeprecatedNotificationJob")
.setLifespan(7.days.inWholeMilliseconds)
.setMaxAttempts(Parameters.UNLIMITED)
.build()
)
override fun serialize(): ByteArray? = null
override fun getFactoryKey(): String = KEY
override fun run(): Result {
if (NotificationChannels.getInstance().areNotificationsEnabled()) {
val intent: Intent
if (BuildConfig.MANAGES_APP_UPDATES) {
Log.d(TAG, "Showing deprecated notification for website APK")
intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://signal.org/android/apk"))
} else {
Log.d(TAG, "Showing deprecated notification for PlayStore")
val packageName = context.packageName
intent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName"))
}
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val builder = NotificationCompat.Builder(context, NotificationChannels.getInstance().APP_ALERTS)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(context.getString(R.string.DeprecatedNotificationJob_update_signal))
.setContentText(context.getString(R.string.DeprecatedNotificationJob_this_version_of_signal_has_expired))
.setContentIntent(pendingIntent)
ServiceUtil.getNotificationManager(context).notify(NotificationIds.APK_UPDATE_PROMPT_INSTALL, builder.build())
}
return Result.success()
}
override fun onFailure() = Unit
class Factory : Job.Factory<DeprecatedNotificationJob> {
override fun create(parameters: Parameters, serializedData: ByteArray?): DeprecatedNotificationJob {
return DeprecatedNotificationJob(parameters)
}
}
}

View File

@@ -151,7 +151,7 @@ public final class JobManagerFactories {
put(CopyAttachmentToArchiveJob.KEY, new CopyAttachmentToArchiveJob.Factory());
put(CreateReleaseChannelJob.KEY, new CreateReleaseChannelJob.Factory());
put(DeleteAbandonedAttachmentsJob.KEY, new DeleteAbandonedAttachmentsJob.Factory());
put(NewLinkedDeviceNotificationJob.KEY, new NewLinkedDeviceNotificationJob.Factory());
put(DeprecatedNotificationJob.KEY, new DeprecatedNotificationJob.Factory());
put(DeviceNameChangeJob.KEY, new DeviceNameChangeJob.Factory());
put(DirectoryRefreshJob.KEY, new DirectoryRefreshJob.Factory());
put(DownloadLatestEmojiDataJob.KEY, new DownloadLatestEmojiDataJob.Factory());
@@ -207,6 +207,7 @@ public final class JobManagerFactories {
put(MultiDeviceVerifiedUpdateJob.KEY, new MultiDeviceVerifiedUpdateJob.Factory());
put(MultiDeviceViewOnceOpenJob.KEY, new MultiDeviceViewOnceOpenJob.Factory());
put(MultiDeviceViewedUpdateJob.KEY, new MultiDeviceViewedUpdateJob.Factory());
put(NewLinkedDeviceNotificationJob.KEY, new NewLinkedDeviceNotificationJob.Factory());
put(NullMessageSendJob.KEY, new NullMessageSendJob.Factory());
put(OptimizeMediaJob.KEY, new OptimizeMediaJob.Factory());
put(OptimizeMessageSearchIndexJob.KEY, new OptimizeMessageSearchIndexJob.Factory());

View File

@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.keyvalue
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.UsernameQrCodeColorScheme
import org.thoughtcrime.securesms.database.model.databaseprotos.PendingChangeNumberMetadata
import org.thoughtcrime.securesms.jobmanager.impl.ChangeNumberConstraintObserver
import org.thoughtcrime.securesms.jobs.DeprecatedNotificationJob
import org.thoughtcrime.securesms.keyvalue.protos.LeastActiveLinkedDevice
class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) {
@@ -69,9 +70,16 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
var lastProfileRefreshTime by longValue(LAST_PROFILE_REFRESH_TIME, 0)
/**
* Whether or not the client is currently in a 'deprecated' state, disallowing network access.
* Whether or not the client is currently in a 'deprecated' state, disallowing network access. Send a notification if the client changes from not deprecated to deprecated state.
*/
var isClientDeprecated: Boolean by booleanValue(CLIENT_DEPRECATED, false)
var isClientDeprecated: Boolean
get() = getBoolean(CLIENT_DEPRECATED, false)
set(isDeprecated) {
if (isDeprecated && !isClientDeprecated) {
DeprecatedNotificationJob.enqueue()
}
putBoolean(CLIENT_DEPRECATED, isDeprecated)
}
/**
* Whether or not we've locked the device after they've transferred to a new one.

View File

@@ -1177,6 +1177,11 @@
<string name="ExpiredBuildReminder_this_version_of_signal_has_expired">This version of Signal has expired. Update now to send and receive messages.</string>
<string name="ExpiredBuildReminder_update_now">Update now</string>
<!-- Title of notification telling users to update Signal -->
<string name="DeprecatedNotificationJob_update_signal">Update Signal</string>
<!-- Message body of notification telling users that this current version of Signal has expired. If pressed, we will direct them to the website APK or PlayStore page -->
<string name="DeprecatedNotificationJob_this_version_of_signal_has_expired">This version of Signal has expired. Tap to update to send and receive messages.</string>
<!-- PendingGroupJoinRequestsReminder -->
<plurals name="PendingGroupJoinRequestsReminder_d_pending_member_requests">
<item quantity="one">%d pending member request.</item>