Improve FetchPushForegroundService's reliability (#6757)
* Improve `FetchPushForegroundService`'s reliability - Don't use DI, we can just create the notification channel. This should speed up the creation of the service and reduce the number of `ForegroundServiceDidNotStartInTimeException` received. Also use `MainScope` instead of the app's coroutine scope. - Move the wakelock releasing mechanism to `onDestroy` so it's always used. Previously, this would only happen when `stopService` was called, which would only happen when `stopSelf()` is called, but not when the OS or the service manager stops the service. * Add fallback value for the notification channel title * Replace the wrong string for the notification/channel title --------- Co-authored-by: Benoit Marty <benoitm@element.io>
This commit is contained in:
parent
11476c73cf
commit
77b444581d
22 changed files with 60 additions and 62 deletions
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.di
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import io.element.android.libraries.push.impl.push.FetchPushForegroundService
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface PushBindings {
|
||||
fun inject(fetchPushForegroundService: FetchPushForegroundService)
|
||||
}
|
||||
|
|
@ -13,17 +13,14 @@ import android.content.pm.ServiceInfo
|
|||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import androidx.core.app.NotificationChannelCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.ServiceCompat
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.push.impl.di.PushBindings
|
||||
import io.element.android.libraries.push.impl.notifications.channels.NotificationChannels
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -34,6 +31,12 @@ private const val NOTIFICATION_ID = 1001
|
|||
// This kind of foreground service can only last up to 3 minutes before onTimeout is called
|
||||
private val wakelockTimeout = 3.minutes.inWholeMilliseconds
|
||||
|
||||
// The channel ID to use for the notification of the foreground service.
|
||||
private const val CHANNEL_ID = "fetch_push_notification_channel"
|
||||
|
||||
// The tag to use for the wakelock, this is used for debugging purposes and should be unique to this service.
|
||||
private const val WAKELOCK_TAG = "FetchPushService:WakeLock"
|
||||
|
||||
/**
|
||||
* Foreground service used to ensure the device stays awake while we handle the pushes and schedule and run the work to fetch the notification content.
|
||||
*/
|
||||
|
|
@ -42,28 +45,35 @@ class FetchPushForegroundService : Service() {
|
|||
return null
|
||||
}
|
||||
|
||||
@Inject lateinit var notificationChannels: NotificationChannels
|
||||
@Inject @AppCoroutineScope lateinit var coroutineScope: CoroutineScope
|
||||
|
||||
private val wakelock: PowerManager.WakeLock by lazy {
|
||||
val powerManager = getSystemService(POWER_SERVICE) as PowerManager
|
||||
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "FetchPushService:WakeLock").apply {
|
||||
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG).apply {
|
||||
setReferenceCounted(false)
|
||||
}
|
||||
}
|
||||
|
||||
private var isOnForeground = false
|
||||
|
||||
private fun ensureNotificationChannelExists() {
|
||||
NotificationManagerCompat.from(this).createNotificationChannelsCompat(
|
||||
listOf(
|
||||
NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_LOW)
|
||||
.setName(getString(CommonStrings.common_fetching_notifications_title_android).ifEmpty { "Syncing notifications…" })
|
||||
.setVibrationEnabled(false)
|
||||
.setSound(null, null)
|
||||
.build()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
Timber.d("Creating FetchPushForegroundService")
|
||||
Timber.i("Creating FetchPushForegroundService to handle incoming push, acquiring wakelock for up to $wakelockTimeout ms")
|
||||
ensureNotificationChannelExists()
|
||||
|
||||
bindings<PushBindings>().inject(this)
|
||||
|
||||
Timber.d("Starting FetchPushForegroundService with wakelock timeout of $wakelockTimeout ms")
|
||||
// Start the foreground service as soon as possible
|
||||
val notificationCompat = NotificationCompat.Builder(this, notificationChannels.getSilentChannelId())
|
||||
val notificationCompat = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setSmallIcon(CommonDrawables.ic_notification)
|
||||
.setContentTitle(getString(CommonStrings.common_android_fetching_notifications_title))
|
||||
.setContentTitle(getString(CommonStrings.common_fetching_notifications_title_android).ifEmpty { "Syncing notifications…" })
|
||||
.setProgress(0, 0, true)
|
||||
.setVibrate(longArrayOf(0))
|
||||
.setSound(null)
|
||||
|
|
@ -103,7 +113,7 @@ class FetchPushForegroundService : Service() {
|
|||
|
||||
// The timeout is not automatic before Android 15, so we need to schedule it ourselves
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
coroutineScope.launch {
|
||||
MainScope().launch {
|
||||
delay(wakelockTimeout)
|
||||
onTimeoutAction(calledByTheSystem = false)
|
||||
}
|
||||
|
|
@ -112,13 +122,18 @@ class FetchPushForegroundService : Service() {
|
|||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun stopService(intent: Intent?): Boolean {
|
||||
if (isOnForeground) {
|
||||
wakelock.release()
|
||||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
||||
}
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
return super.stopService(intent)
|
||||
if (isOnForeground) {
|
||||
Timber.i("Destroying FetchPushForegroundService, releasing wakelock and stopping foreground")
|
||||
if (wakelock.isHeld) {
|
||||
wakelock.release()
|
||||
}
|
||||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
||||
} else {
|
||||
Timber.w("Destroying FetchPushForegroundService that was not running in foreground, this is unexpected")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTimeout(startId: Int) {
|
||||
|
|
@ -127,9 +142,9 @@ class FetchPushForegroundService : Service() {
|
|||
}
|
||||
|
||||
private fun onTimeoutAction(calledByTheSystem: Boolean) {
|
||||
Timber.d("onTimeoutAction, calledByTheSystem: $calledByTheSystem, isOnForeground: $isOnForeground")
|
||||
Timber.w("onTimeoutAction, calledByTheSystem: $calledByTheSystem, isOnForeground: $isOnForeground")
|
||||
if (isOnForeground) {
|
||||
Timber.d("Wakelock timeout reached, stopping FetchPushForegroundService")
|
||||
Timber.w("Wakelock timeout reached, stopping FetchPushForegroundService")
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,7 +198,6 @@
|
|||
<string name="common_advanced_settings">"Pokročilá nastavení"</string>
|
||||
<string name="common_an_image">"obrázek"</string>
|
||||
<string name="common_analytics">"Analytika"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Synchronizace oznámení…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Opustili jste místnost"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Byli jste odhlášeni z relace"</string>
|
||||
<string name="common_appearance">"Vzhled"</string>
|
||||
|
|
@ -242,6 +241,7 @@ Důvod: %1$s."</string>
|
|||
<string name="common_failed">"Selhalo"</string>
|
||||
<string name="common_favourite">"Oblíbené"</string>
|
||||
<string name="common_favourited">"Oblíbené"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Synchronizace oznámení…"</string>
|
||||
<string name="common_file">"Soubor"</string>
|
||||
<string name="common_file_deleted">"Soubor smazán"</string>
|
||||
<string name="common_file_saved">"Soubor uložen"</string>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,6 @@
|
|||
<string name="common_advanced_settings">"Avancerede indstillinger"</string>
|
||||
<string name="common_an_image">"et billede"</string>
|
||||
<string name="common_analytics">"Analyse-værktøj"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Synkroniserer notifikationer…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Du forlod rummet"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Du blev logget ud af sessionen"</string>
|
||||
<string name="common_appearance">"Udseende"</string>
|
||||
|
|
@ -244,6 +243,7 @@
|
|||
<string name="common_failed">"Mislykkedes"</string>
|
||||
<string name="common_favourite">"Favorit"</string>
|
||||
<string name="common_favourited">"Favoritmarkeret"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Synkroniserer notifikationer…"</string>
|
||||
<string name="common_file">"Fil"</string>
|
||||
<string name="common_file_deleted">"Fil slettet"</string>
|
||||
<string name="common_file_saved">"Fil gemt"</string>
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@
|
|||
<string name="common_advanced_settings">"Erweiterte Einstellungen"</string>
|
||||
<string name="common_an_image">"ein Bild"</string>
|
||||
<string name="common_analytics">"Analysedaten"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Benachrichtigungen werden synchronisiert…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Du hast den Chat verlassen"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Du wurdest aus der Sitzung abgemeldet."</string>
|
||||
<string name="common_appearance">"Erscheinungsbild"</string>
|
||||
|
|
@ -236,6 +235,7 @@ Grund: %1$s."</string>
|
|||
<string name="common_failed">"Fehlgeschlagen"</string>
|
||||
<string name="common_favourite">"Favorit"</string>
|
||||
<string name="common_favourited">"Favorisiert"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Benachrichtigungen werden synchronisiert…"</string>
|
||||
<string name="common_file">"Datei"</string>
|
||||
<string name="common_file_deleted">"Datei wurde gelöscht"</string>
|
||||
<string name="common_file_saved">"Datei gespeichert"</string>
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@
|
|||
<string name="common_advanced_settings">"Ρυθμίσεις για προχωρημένους"</string>
|
||||
<string name="common_an_image">"μια εικόνα"</string>
|
||||
<string name="common_analytics">"Στατιστικά στοιχεία"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Συγχρονισμός ειδοποιήσεων…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Αποχωρήσατε από την αίθουσα"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Αποσυνδεθήκατε από την περίοδο λειτουργίας"</string>
|
||||
<string name="common_appearance">"Εμφάνιση"</string>
|
||||
|
|
@ -236,6 +235,7 @@
|
|||
<string name="common_failed">"Απέτυχε"</string>
|
||||
<string name="common_favourite">"Αγαπημένο"</string>
|
||||
<string name="common_favourited">"Είναι αγαπημένο"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Συγχρονισμός ειδοποιήσεων…"</string>
|
||||
<string name="common_file">"Αρχείο"</string>
|
||||
<string name="common_file_deleted">"Το αρχείο διαγράφηκε"</string>
|
||||
<string name="common_file_saved">"Το αρχείο αποθηκεύτηκε"</string>
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@
|
|||
<string name="common_advanced_settings">"Täiendavad seadistused"</string>
|
||||
<string name="common_an_image">"pilt"</string>
|
||||
<string name="common_analytics">"Analüütika"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Sünkroonin teavitusi…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Sina lahkusid jututoast"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Sa olid sessioonist väljaloginud"</string>
|
||||
<string name="common_appearance">"Välimus"</string>
|
||||
|
|
@ -242,6 +241,7 @@ Põhjus: %1$s."</string>
|
|||
<string name="common_failed">"Ei õnnestunud"</string>
|
||||
<string name="common_favourite">"Lemmik"</string>
|
||||
<string name="common_favourited">"Märgitud lemmikuks"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Sünkroonin teavitusi…"</string>
|
||||
<string name="common_file">"Fail"</string>
|
||||
<string name="common_file_deleted">"Fail on kustutatud"</string>
|
||||
<string name="common_file_saved">"Fail on salvestatud"</string>
|
||||
|
|
|
|||
|
|
@ -193,7 +193,6 @@
|
|||
<string name="common_advanced_settings">"Edistyneet asetukset"</string>
|
||||
<string name="common_an_image">"kuva"</string>
|
||||
<string name="common_analytics">"Analytiikka"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Synkronoidaan ilmoituksia…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Poistuit huoneesta"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Sinut kirjattiin ulos istunnosta"</string>
|
||||
<string name="common_appearance">"Ulkoasu"</string>
|
||||
|
|
@ -237,6 +236,7 @@ Syy: %1$s."</string>
|
|||
<string name="common_failed">"Epäonnistui"</string>
|
||||
<string name="common_favourite">"Lisää suosikkeihin"</string>
|
||||
<string name="common_favourited">"Lisätty suosikkeihin"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Synkronoidaan ilmoituksia…"</string>
|
||||
<string name="common_file">"Tiedosto"</string>
|
||||
<string name="common_file_deleted">"Tiedosto poistettu"</string>
|
||||
<string name="common_file_saved">"Tiedosto tallennettu"</string>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,6 @@
|
|||
<string name="common_advanced_settings">"Paramètres avancés"</string>
|
||||
<string name="common_an_image">"une image"</string>
|
||||
<string name="common_analytics">"Statistiques d’utilisation"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Synchronisation des notifications…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Vous avez quitté le salon"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Vous avez été déconnecté de la session"</string>
|
||||
<string name="common_appearance">"Apparence"</string>
|
||||
|
|
@ -244,6 +243,7 @@ Raison : %1$s."</string>
|
|||
<string name="common_failed">"Échec"</string>
|
||||
<string name="common_favourite">"Favori"</string>
|
||||
<string name="common_favourited">"Ajouté aux favoris"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Synchronisation des notifications…"</string>
|
||||
<string name="common_file">"Fichier"</string>
|
||||
<string name="common_file_deleted">"Fichier supprimé"</string>
|
||||
<string name="common_file_saved">"Fichier enregistré"</string>
|
||||
|
|
|
|||
|
|
@ -200,7 +200,6 @@
|
|||
<string name="common_advanced_settings">"Napredne postavke"</string>
|
||||
<string name="common_an_image">"slika"</string>
|
||||
<string name="common_analytics">"Analitika"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Sinkronizacija obavijesti…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Napustili ste sobu"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Odjavljeni ste iz sesije"</string>
|
||||
<string name="common_appearance">"Izgled"</string>
|
||||
|
|
@ -246,6 +245,7 @@ Razlog: %1$s ."</string>
|
|||
<string name="common_failed">"Nije uspjelo"</string>
|
||||
<string name="common_favourite">"Favorit"</string>
|
||||
<string name="common_favourited">"Označeno kao favorit"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Sinkronizacija obavijesti…"</string>
|
||||
<string name="common_file">"Datoteka"</string>
|
||||
<string name="common_file_deleted">"Datoteka je izbrisana"</string>
|
||||
<string name="common_file_saved">"Datoteka je spremljena"</string>
|
||||
|
|
|
|||
|
|
@ -199,7 +199,6 @@
|
|||
<string name="common_advanced_settings">"Speciális beállítások"</string>
|
||||
<string name="common_an_image">"egy kép"</string>
|
||||
<string name="common_analytics">"Elemzések"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Értesítések szinkronizálása…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Elhagyta a szobát"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Ki lett jelentkeztetve a munkamenetből"</string>
|
||||
<string name="common_appearance">"Megjelenítés"</string>
|
||||
|
|
@ -245,6 +244,7 @@ Ok: %1$s."</string>
|
|||
<string name="common_failed">"Sikertelen"</string>
|
||||
<string name="common_favourite">"Kedvenc"</string>
|
||||
<string name="common_favourited">"Kedvencnek jelölve"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Értesítések szinkronizálása…"</string>
|
||||
<string name="common_file">"Fájl"</string>
|
||||
<string name="common_file_deleted">"Fájl törölve"</string>
|
||||
<string name="common_file_saved">"A fájl mentve"</string>
|
||||
|
|
|
|||
|
|
@ -199,7 +199,6 @@
|
|||
<string name="common_advanced_settings">"Impostazioni avanzate"</string>
|
||||
<string name="common_an_image">"un\'immagine"</string>
|
||||
<string name="common_analytics">"Statistiche di utilizzo"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Sincronizzazione delle notifiche…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Hai lasciato la stanza"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Sei stato disconnesso dalla sessione"</string>
|
||||
<string name="common_appearance">"Aspetto"</string>
|
||||
|
|
@ -245,6 +244,7 @@ Motivo:. %1$s"</string>
|
|||
<string name="common_failed">"Fallito"</string>
|
||||
<string name="common_favourite">"Preferiti"</string>
|
||||
<string name="common_favourited">"Preferita"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Sincronizzazione delle notifiche…"</string>
|
||||
<string name="common_file">"File"</string>
|
||||
<string name="common_file_deleted">"File eliminato"</string>
|
||||
<string name="common_file_saved">"File salvato"</string>
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@
|
|||
<string name="common_advanced_settings">"高度な設定"</string>
|
||||
<string name="common_an_image">"画像"</string>
|
||||
<string name="common_analytics">"分析"</string>
|
||||
<string name="common_android_fetching_notifications_title">"通知を同期中…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"あなたがルームを退出"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"セッションからログアウトされました"</string>
|
||||
<string name="common_appearance">"テーマ"</string>
|
||||
|
|
@ -243,6 +242,7 @@
|
|||
<string name="common_failed">"失敗"</string>
|
||||
<string name="common_favourite">"お気に入り"</string>
|
||||
<string name="common_favourited">"お気に入り"</string>
|
||||
<string name="common_fetching_notifications_title_android">"通知を同期中…"</string>
|
||||
<string name="common_file">"ファイル"</string>
|
||||
<string name="common_file_deleted">"ファイルを削除しました"</string>
|
||||
<string name="common_file_saved">"ファイルを保存しました"</string>
|
||||
|
|
|
|||
|
|
@ -190,7 +190,6 @@
|
|||
<string name="common_advanced_settings">"고급 설정"</string>
|
||||
<string name="common_an_image">"이미지"</string>
|
||||
<string name="common_analytics">"통계"</string>
|
||||
<string name="common_android_fetching_notifications_title">"알림 동기화 중…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"방을 떠남"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"세션에서 로그아웃되었습니다."</string>
|
||||
<string name="common_appearance">"외관"</string>
|
||||
|
|
@ -234,6 +233,7 @@
|
|||
<string name="common_failed">"실패"</string>
|
||||
<string name="common_favourite">"즐겨찾기"</string>
|
||||
<string name="common_favourited">"즐겨찾기 됨"</string>
|
||||
<string name="common_fetching_notifications_title_android">"알림 동기화 중…"</string>
|
||||
<string name="common_file">"파일"</string>
|
||||
<string name="common_file_deleted">"파일 삭제됨"</string>
|
||||
<string name="common_file_saved">"파일 저장됨"</string>
|
||||
|
|
|
|||
|
|
@ -201,7 +201,6 @@
|
|||
<string name="common_advanced_settings">"Ustawienia zaawansowane"</string>
|
||||
<string name="common_an_image">"obraz"</string>
|
||||
<string name="common_analytics">"Dane analityczne"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Synchronizuję powiadomienia…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Opuściłeś pokój"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Zostałeś wylogowany z sesji"</string>
|
||||
<string name="common_appearance">"Wygląd"</string>
|
||||
|
|
@ -247,6 +246,7 @@ Powód: %1$s."</string>
|
|||
<string name="common_failed">"Niepowodzenie"</string>
|
||||
<string name="common_favourite">"Ulubione"</string>
|
||||
<string name="common_favourited">"Ulubione"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Synchronizuję powiadomienia…"</string>
|
||||
<string name="common_file">"Plik"</string>
|
||||
<string name="common_file_deleted">"Plik usunięty"</string>
|
||||
<string name="common_file_saved">"Plik zapisany"</string>
|
||||
|
|
|
|||
|
|
@ -195,7 +195,6 @@
|
|||
<string name="common_advanced_settings">"Расширенные настройки"</string>
|
||||
<string name="common_an_image">"изображение"</string>
|
||||
<string name="common_analytics">"Аналитика"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Синхронизация уведомлений…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Вы покинули комнату"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Вы вышли из сессии"</string>
|
||||
<string name="common_appearance">"Внешний вид"</string>
|
||||
|
|
@ -239,6 +238,7 @@
|
|||
<string name="common_failed">"Ошибка"</string>
|
||||
<string name="common_favourite">"Избранное"</string>
|
||||
<string name="common_favourited">"Избранное"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Синхронизация уведомлений…"</string>
|
||||
<string name="common_file">"Файл"</string>
|
||||
<string name="common_file_deleted">"Файл удалён"</string>
|
||||
<string name="common_file_saved">"Файл сохранен"</string>
|
||||
|
|
|
|||
|
|
@ -201,7 +201,6 @@
|
|||
<string name="common_advanced_settings">"Додаткові налаштування"</string>
|
||||
<string name="common_an_image">"зображення"</string>
|
||||
<string name="common_analytics">"Аналітика"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Синхронізація сповіщень…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Ви вийшли з кімнати"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Ви вийшли з сеансу"</string>
|
||||
<string name="common_appearance">"Тема"</string>
|
||||
|
|
@ -247,6 +246,7 @@
|
|||
<string name="common_failed">"Помилка"</string>
|
||||
<string name="common_favourite">"Обране"</string>
|
||||
<string name="common_favourited">"Обране"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Синхронізація сповіщень…"</string>
|
||||
<string name="common_file">"Файл"</string>
|
||||
<string name="common_file_deleted">"Файл видалено"</string>
|
||||
<string name="common_file_saved">"Файл збережено"</string>
|
||||
|
|
|
|||
|
|
@ -193,7 +193,6 @@
|
|||
<string name="common_advanced_settings">"Kengaytirilgan sozlamalar"</string>
|
||||
<string name="common_an_image">"rasm"</string>
|
||||
<string name="common_analytics">"Analitika"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Bildirishnomalar sinxronlanmoqda…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Siz xonani tark etdingiz"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Siz sessiyadan chiqdingiz"</string>
|
||||
<string name="common_appearance">"Ko\'rinish"</string>
|
||||
|
|
@ -237,6 +236,7 @@ Sababi:%1$s."</string>
|
|||
<string name="common_failed">"Xatolikka uchradi"</string>
|
||||
<string name="common_favourite">"Sevimli"</string>
|
||||
<string name="common_favourited">"Sevimli"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Bildirishnomalar sinxronlanmoqda…"</string>
|
||||
<string name="common_file">"Fayl"</string>
|
||||
<string name="common_file_deleted">"Fayl o\'chirildi"</string>
|
||||
<string name="common_file_saved">"Fayl saqlandi"</string>
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@
|
|||
<string name="common_advanced_settings">"Cài đặt nâng cao"</string>
|
||||
<string name="common_an_image">"một hình ảnh"</string>
|
||||
<string name="common_analytics">"Phân tích"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Đang đồng bộ thông báo…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"Bạn rời phòng"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"Bạn đã bị đăng xuất"</string>
|
||||
<string name="common_appearance">"Giao diện"</string>
|
||||
|
|
@ -235,6 +234,7 @@ Lý do: %1$s ."</string>
|
|||
<string name="common_failed">"Thất bại"</string>
|
||||
<string name="common_favourite">"Yêu thích"</string>
|
||||
<string name="common_favourited">"Được yêu thích"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Đang đồng bộ thông báo…"</string>
|
||||
<string name="common_file">"Tập tin"</string>
|
||||
<string name="common_file_deleted">"Tệp đã bị xóa"</string>
|
||||
<string name="common_file_saved">"Tệp đã được lưu"</string>
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@
|
|||
<string name="common_advanced_settings">"進階設定"</string>
|
||||
<string name="common_an_image">"影像"</string>
|
||||
<string name="common_analytics">"分析"</string>
|
||||
<string name="common_android_fetching_notifications_title">"正在同步通知……"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"您離開聊天室"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"您已登出工作階段"</string>
|
||||
<string name="common_appearance">"外觀"</string>
|
||||
|
|
@ -235,6 +234,7 @@
|
|||
<string name="common_failed">"失敗"</string>
|
||||
<string name="common_favourite">"我的最愛"</string>
|
||||
<string name="common_favourited">"我的最愛"</string>
|
||||
<string name="common_fetching_notifications_title_android">"正在同步通知……"</string>
|
||||
<string name="common_file">"檔案"</string>
|
||||
<string name="common_file_deleted">"檔案已刪除"</string>
|
||||
<string name="common_file_saved">"檔案已儲存"</string>
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@
|
|||
<string name="common_advanced_settings">"高级设置"</string>
|
||||
<string name="common_an_image">"一张图片"</string>
|
||||
<string name="common_analytics">"分析"</string>
|
||||
<string name="common_android_fetching_notifications_title">"正在同步通知…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"你离开了房间"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"你已注销会话"</string>
|
||||
<string name="common_appearance">"外观"</string>
|
||||
|
|
@ -242,6 +241,7 @@
|
|||
<string name="common_failed">"失败"</string>
|
||||
<string name="common_favourite">"收藏"</string>
|
||||
<string name="common_favourited">"已收藏"</string>
|
||||
<string name="common_fetching_notifications_title_android">"正在同步通知…"</string>
|
||||
<string name="common_file">"文件"</string>
|
||||
<string name="common_file_deleted">"文件已删除"</string>
|
||||
<string name="common_file_saved">"文件已保存"</string>
|
||||
|
|
|
|||
|
|
@ -199,7 +199,6 @@
|
|||
<string name="common_advanced_settings">"Advanced settings"</string>
|
||||
<string name="common_an_image">"an image"</string>
|
||||
<string name="common_analytics">"Analytics"</string>
|
||||
<string name="common_android_fetching_notifications_title">"Syncing notifications…"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_left_room">"You left the room"</string>
|
||||
<string name="common_android_shortcuts_remove_reason_session_logged_out">"You were logged out of the session"</string>
|
||||
<string name="common_appearance">"Appearance"</string>
|
||||
|
|
@ -245,6 +244,7 @@ Reason: %1$s."</string>
|
|||
<string name="common_failed">"Failed"</string>
|
||||
<string name="common_favourite">"Favourite"</string>
|
||||
<string name="common_favourited">"Favourited"</string>
|
||||
<string name="common_fetching_notifications_title_android">"Syncing notifications…"</string>
|
||||
<string name="common_file">"File"</string>
|
||||
<string name="common_file_deleted">"File deleted"</string>
|
||||
<string name="common_file_saved">"File saved"</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue