mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Update target SDK to 35.
This commit is contained in:
@@ -736,13 +736,18 @@ fun getMapsKey(): String {
|
||||
}
|
||||
|
||||
fun Project.languageList(): 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")
|
||||
|
||||
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"
|
||||
.sorted() + updatedLanguageCodes + "en"
|
||||
}
|
||||
|
||||
fun String.capitalize(): String {
|
||||
|
||||
@@ -85,8 +85,8 @@ class AttachmentProgressService : SafeForegroundService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun stop(context: Context) {
|
||||
stop(context, AttachmentProgressService::class.java)
|
||||
private fun stop(context: Context, fromTimeout: Boolean = false) {
|
||||
stop(context, AttachmentProgressService::class.java, fromTimeout)
|
||||
}
|
||||
|
||||
private fun onControllersChanged(context: Context) {
|
||||
@@ -139,6 +139,17 @@ class AttachmentProgressService : SafeForegroundService() {
|
||||
listeners -= listener
|
||||
}
|
||||
|
||||
override fun onTimeout(startId: Int, fgsType: Int) {
|
||||
Log.w(TAG, "AttachmentProgressService has timed out. Removing all controllers. startId: $startId, foregroundServiceType: $fgsType")
|
||||
|
||||
controllerLock.withLock {
|
||||
controllers.forEach { it.closeFromTimeout() }
|
||||
stop(context = this, fromTimeout = true)
|
||||
}
|
||||
|
||||
listeners -= listener
|
||||
}
|
||||
|
||||
class Controller(private val context: Context, title: String) : AutoCloseable {
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
private val progressFlow = MutableSharedFlow<Float>(replay = 0, extraBufferCapacity = 1)
|
||||
@@ -178,6 +189,13 @@ class AttachmentProgressService : SafeForegroundService() {
|
||||
progressFlow.tryEmit(progress)
|
||||
}
|
||||
|
||||
fun closeFromTimeout() {
|
||||
controllerLock.withLock {
|
||||
coroutineScope.cancel()
|
||||
controllers.remove(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
controllerLock.withLock {
|
||||
coroutineScope.cancel()
|
||||
|
||||
@@ -57,8 +57,8 @@ class BackupProgressService : SafeForegroundService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun stop(context: Context) {
|
||||
SafeForegroundService.stop(context, BackupProgressService::class.java)
|
||||
private fun stop(context: Context, fromTimeout: Boolean = false) {
|
||||
SafeForegroundService.stop(context, BackupProgressService::class.java, fromTimeout)
|
||||
controllerLock.withLock {
|
||||
controller = null
|
||||
}
|
||||
@@ -82,6 +82,11 @@ class BackupProgressService : SafeForegroundService() {
|
||||
return getForegroundNotification(this)
|
||||
}
|
||||
|
||||
override fun onTimeout(startId: Int, fgsType: Int) {
|
||||
Log.w(TAG, "BackupProgressService has timed out. startId: $startId, foregroundServiceType: $fgsType")
|
||||
stop(context = this, fromTimeout = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to update notification progress/state.
|
||||
*/
|
||||
|
||||
@@ -27,6 +27,7 @@ class GenericForegroundService : Service() {
|
||||
private val allActiveMessages = LinkedHashMap<Int, Entry>()
|
||||
private val lock = ReentrantLock()
|
||||
|
||||
var hasTimedOut = false
|
||||
private var lastPosted: Entry? = null
|
||||
|
||||
companion object {
|
||||
@@ -175,6 +176,16 @@ class GenericForegroundService : Service() {
|
||||
super.onTrimMemory(level)
|
||||
}
|
||||
|
||||
override fun onTimeout(startId: Int, foregroundServiceType: Int) {
|
||||
Log.i(TAG, "[onTimeout] startId: $startId, fgsType: $foregroundServiceType")
|
||||
lock.withLock {
|
||||
hasTimedOut = true
|
||||
allActiveMessages.clear()
|
||||
}
|
||||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
fun replaceTitle(id: Int, title: String) {
|
||||
lock.withLock {
|
||||
updateEntry(id) { oldEntry ->
|
||||
|
||||
@@ -58,7 +58,12 @@ class NotificationController internal constructor(private val context: Context,
|
||||
} else {
|
||||
Log.w(TAG, "[close] Service was not bound at the time of close()...")
|
||||
}
|
||||
stopForegroundTask(context, id)
|
||||
|
||||
if (service.get()?.hasTimedOut == true) {
|
||||
Log.w(TAG, "[close] Service has timed out, skipping stop foreground task.")
|
||||
} else {
|
||||
stopForegroundTask(context, id)
|
||||
}
|
||||
} catch (e: IllegalStateException) {
|
||||
Log.w(TAG, "[close] Failed to unbind service...", e)
|
||||
} catch (e: UnableToStartException) {
|
||||
|
||||
@@ -34,6 +34,7 @@ abstract class SafeForegroundService : Service() {
|
||||
private const val ACTION_START = "start"
|
||||
private const val ACTION_UPDATE = "update"
|
||||
private const val ACTION_STOP = "stop"
|
||||
private const val ACTION_TIMEOUT = "timeout"
|
||||
|
||||
private var states: MutableMap<Class<out SafeForegroundService>, State> = mutableMapOf()
|
||||
private val stateLock = ReentrantLock()
|
||||
@@ -86,9 +87,11 @@ abstract class SafeForegroundService : Service() {
|
||||
* Safely stops the service by starting it with an action to stop itself.
|
||||
* This is done to prevent scenarios where you stop the service while
|
||||
* a start is pending, preventing the posting of a foreground notification.
|
||||
*
|
||||
* @param fromTimeout - Whether we are stopping due to system timeout (limit is 6hr in 24hr)
|
||||
* @return true if service was running previously
|
||||
*/
|
||||
fun stop(context: Context, serviceClass: Class<out SafeForegroundService>): Boolean {
|
||||
fun stop(context: Context, serviceClass: Class<out SafeForegroundService>, fromTimeout: Boolean = false): Boolean {
|
||||
stateLock.withLock {
|
||||
val state = currentState(serviceClass)
|
||||
|
||||
@@ -98,10 +101,11 @@ abstract class SafeForegroundService : Service() {
|
||||
State.STARTING -> {
|
||||
Log.d(TAG, "[stop] Stopping service.")
|
||||
states[serviceClass] = State.STOPPING
|
||||
val stopAction = if (fromTimeout) ACTION_TIMEOUT else ACTION_STOP
|
||||
try {
|
||||
ForegroundServiceUtil.startWhenCapable(
|
||||
context = context,
|
||||
intent = Intent(context, serviceClass).apply { action = ACTION_STOP }
|
||||
intent = Intent(context, serviceClass).apply { action = stopAction }
|
||||
)
|
||||
} catch (e: UnableToStartException) {
|
||||
Log.w(TAG, "Failed to start service class $serviceClass", e)
|
||||
@@ -182,7 +186,9 @@ abstract class SafeForegroundService : Service() {
|
||||
|
||||
Log.d(tag, "[onStartCommand] action: ${intent.action}")
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 30 && serviceType != 0) {
|
||||
if (intent.action == ACTION_TIMEOUT) {
|
||||
Log.i(TAG, "Time limit for foreground services has been met. Skipping starting a foreground.")
|
||||
} else if (Build.VERSION.SDK_INT >= 30 && serviceType != 0) {
|
||||
startForeground(notificationId, getForegroundNotification(intent), serviceType)
|
||||
} else {
|
||||
startForeground(notificationId, getForegroundNotification(intent))
|
||||
@@ -192,6 +198,7 @@ abstract class SafeForegroundService : Service() {
|
||||
ACTION_START -> {
|
||||
onServiceStartCommandReceived(intent)
|
||||
}
|
||||
ACTION_TIMEOUT,
|
||||
ACTION_STOP -> {
|
||||
onServiceStopCommandReceived(intent)
|
||||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
||||
|
||||
@@ -155,7 +155,7 @@ class ActiveCallManager(
|
||||
AppDependencies.unauthWebSocket.registerKeepAliveToken(WEBSOCKET_KEEP_ALIVE_TOKEN)
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
fun shutdown(fromTimeout: Boolean = false) {
|
||||
Log.v(TAG, "shutdown")
|
||||
|
||||
previousNotificationDisposable.dispose()
|
||||
@@ -172,7 +172,7 @@ class ActiveCallManager(
|
||||
AppDependencies.authWebSocket.removeKeepAliveToken(WEBSOCKET_KEEP_ALIVE_TOKEN)
|
||||
AppDependencies.unauthWebSocket.removeKeepAliveToken(WEBSOCKET_KEEP_ALIVE_TOKEN)
|
||||
|
||||
if (!ActiveCallForegroundService.stop(application) && previousNotificationId != -1) {
|
||||
if (!ActiveCallForegroundService.stop(application, fromTimeout) && previousNotificationId != -1) {
|
||||
NotificationManagerCompat.from(application).cancel(previousNotificationId)
|
||||
}
|
||||
}
|
||||
@@ -290,8 +290,8 @@ class ActiveCallManager(
|
||||
}
|
||||
}
|
||||
|
||||
fun stop(context: Context): Boolean {
|
||||
return SafeForegroundService.stop(context, ActiveCallForegroundService::class.java)
|
||||
fun stop(context: Context, fromTimeout: Boolean = false): Boolean {
|
||||
return SafeForegroundService.stop(context, ActiveCallForegroundService::class.java, fromTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +348,15 @@ class ActiveCallManager(
|
||||
notificationDisposable.dispose()
|
||||
}
|
||||
|
||||
override fun onTimeout(startId: Int, fgsType: Int) {
|
||||
Log.w(TAG, "ActiveCallForegroundService has timed out. Hanging up. startId: $startId, foregroundServiceType: $fgsType")
|
||||
AppDependencies.signalCallManager.localHangup()
|
||||
activeCallManagerLock.withLock {
|
||||
activeCallManager?.shutdown(fromTimeout = true)
|
||||
activeCallManager = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@
|
||||
<style name="TextSecure.BaseLightTheme" parent="@style/Theme.Material3.Light">
|
||||
<item name="theme_type">light</item>
|
||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
|
||||
|
||||
<!-- Material 3 -->
|
||||
<item name="colorPrimary">@color/signal_colorPrimary</item>
|
||||
@@ -239,6 +240,7 @@
|
||||
<style name="TextSecure.BaseDarkTheme" parent="@style/Theme.Material3.Dark">
|
||||
<item name="theme_type">dark</item>
|
||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
|
||||
|
||||
<!-- Material 3 -->
|
||||
<item name="colorPrimary">@color/signal_colorPrimary</item>
|
||||
|
||||
@@ -37,6 +37,9 @@ public final class LanguageResourcesTest {
|
||||
public void language_options_matches_available_resources() {
|
||||
Set<String> languageEntries = languageEntries();
|
||||
Set<String> foundResources = buildConfigResources();
|
||||
Set<String> manuallyAddedResources = Set.of("id", "he"); // With API 35, we had to manually add certain supported languages
|
||||
foundResources.removeAll(manuallyAddedResources);
|
||||
|
||||
if (!languageEntries.equals(foundResources)) {
|
||||
assertSubset(foundResources, languageEntries, "Missing language_entries for resources");
|
||||
assertSubset(languageEntries, foundResources, "Missing resources for language_entries");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
val signalBuildToolsVersion by extra("35.0.0")
|
||||
val signalCompileSdkVersion by extra("android-35")
|
||||
val signalTargetSdkVersion by extra(34)
|
||||
val signalTargetSdkVersion by extra(35)
|
||||
val signalMinSdkVersion by extra(21)
|
||||
val signalNdkVersion by extra("28.0.13004108")
|
||||
val signalJavaVersion by extra(JavaVersion.VERSION_17)
|
||||
|
||||
Reference in New Issue
Block a user