From 73897f8db3ded32445b527ebb53a52b7ee81c60d Mon Sep 17 00:00:00 2001 From: p42ity Date: Tue, 23 Apr 2024 16:53:14 +0200 Subject: [PATCH 01/57] Voice Recordings: Add privacy option, deactivate workaround for AAC sensitive devices for Android 14+ and change default sampling frequency --- .../eu/siacs/conversations/ui/RecordingActivity.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java b/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java index 7c13b54fae5b55ddf0175876729295574180d429..64446e930b1bdcae45700b84612855e29797e563 100644 --- a/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java @@ -106,6 +106,9 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe private boolean startRecording() { mRecorder = new MediaRecorder(); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + mRecorder.setPrivacySensitive(true); + } final int outputFormat; if (Config.USE_OPUS_VOICE_MESSAGES && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { outputFormat = MediaRecorder.OutputFormat.OGG; @@ -115,14 +118,14 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe } else { outputFormat = MediaRecorder.OutputFormat.MPEG_4; mRecorder.setOutputFormat(outputFormat); - if (AAC_SENSITIVE_DEVICES.contains(Build.MODEL)) { - // Changing these three settings for AAC sensitive devices might lead to sporadically truncated (cut-off) voice messages. + if (AAC_SENSITIVE_DEVICES.contains(Build.MODEL) && Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) { + // Changing these three settings for AAC sensitive devices for Android<=13 might lead to sporadically truncated (cut-off) voice messages. mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC); mRecorder.setAudioSamplingRate(24_000); mRecorder.setAudioEncodingBitRate(28_000); } else { mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); - mRecorder.setAudioSamplingRate(22_050); + mRecorder.setAudioSamplingRate(44_100); mRecorder.setAudioEncodingBitRate(64_000); } } From 69ba31db65d331d1cd080a49e052538319392ed0 Mon Sep 17 00:00:00 2001 From: nautilusx Date: Sun, 21 Apr 2024 10:16:27 +0000 Subject: [PATCH 02/57] Translated using Weblate (German) Currently translated at 100.0% (1014 of 1014 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/de/ --- src/main/res/values-de/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 69e0d57ee3210376e3ebcc7f297bd54d2f15134c..16d1fd851d85ca9cca1bf371c91dd72a2dafc62a 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -404,7 +404,7 @@ Eingabe Eingabetaste sendet Nachricht Nutze die Eingabetaste zum Versenden einer Nachricht. Strg+Eingabetaste sendet die Nachricht unabhängig von dieser Einstellung. - Zeige Eingabetaste + Eingabetaste anzeigen Emoji-Taste durch Eingabetaste ersetzen Audio Video @@ -445,7 +445,7 @@ Schnell-Tasten Keine Zuletzt verwendet - Wähle Schnell-Taste + Schnell-Taste auswählen Kontakte durchsuchen Private Nachricht senden %1$s hat den Gruppenchat verlassen @@ -465,9 +465,9 @@ Abwesend bei gesperrtem Gerät Als abwesend anzeigen, wenn das Gerät gesperrt ist Beschäftigt im lautlosen Modus - Als Beschäftigt anzeigen, wenn sich das Gerät im lautlosen Modus befindet + Als beschäftigt anzeigen, wenn sich das Gerät im lautlosen Modus befindet Vibration als Lautlos behandeln - Als Beschäftigt anzeigen, wenn das Gerät auf Vibration eingestellt ist + Als beschäftigt anzeigen, wenn das Gerät auf Vibration eingestellt ist Hostname & Port Erweiterte Verbindungseinstellungen beim Einrichten eines Kontos anzeigen xmpp.domain.de @@ -600,7 +600,7 @@ Bitte warten, bis die Schlüssel abgerufen werden Als Barcode teilen Als XMPP-URI teilen - Als HTTP Link teilen + Als HTTP-Link teilen Blind vertrauen vor der Überprüfung Neuen Geräten von nicht verifizierten Kontakten vertrauen, aber bei verifizierten Kontakten eine manuelle Bestätigung der neuen Geräte verlangen. Blind vertraute OMEMO-Schlüssel bedeutet, dass es sich um eine andere Person handeln könnte oder dass jemand sie abgehört haben könnte. @@ -728,7 +728,7 @@ XMPP-Adresse kopieren HTTP-Dateifreigabe für S3 Direkte Suche - Beim Dialog \'Neuer Chat\' Tastatur öffnen und den Cursor im Suchfeld platzieren + Beim Dialog \"Neuer Chat\" Tastatur öffnen und den Cursor im Suchfeld platzieren Gruppenchat-Profilbild Host unterstützt keine Gruppenchat-Profilbilder Nur der Eigentümer kann das Gruppenchat-Profilbild ändern From 1156acf9584d0d18ded5d68180f91026bcdc68b5 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 21 Apr 2024 14:56:04 +0000 Subject: [PATCH 03/57] Translated using Weblate (Spanish) Currently translated at 100.0% (1014 of 1014 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/es/ --- src/main/res/values-es/strings.xml | 82 +++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index bb65ebf1634a2778eb9d76cb16cfa7ec60491cff..5e440a9f41290ba487608250e3f9b74d09a94d4b 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -109,11 +109,11 @@ Aceptar archivos De forma automática aceptar archivos menores que… Adjuntos - Notificaciones + Notificación Vibrar Vibra cuando llega un nuevo mensaje - Luz - La luz parpadea cuando llega un nuevo mensaje + Led de notificaciones + La luz de notificación parpadea cuando llega un nuevo mensaje Tono de llamada Sonido de notificación Sonido de notificación para nuevos mensajes @@ -561,7 +561,7 @@ Medio Largo Visto por ultima vez - Permite que tus contactos sepan cuando usas Conversations + Permitir que tus contactos vean la última vez que usaste la aplicación Privacidad Tema Selecciona el color de la paleta @@ -702,14 +702,14 @@ No se ha podido conseguir la lista de dispositivos No se han podido conseguir las claves de cifrado Consejo: En algunas ocasiones esto puede corregirse agregando a tu contacto a tu lista de contactos. Tu contacto deberá asegurarse también que estás en su lista de contactos. - ¿Estás seguro de que quieres deshabilitar el cifrado OMEMO para esta conversación? -\nEsto permitiría al administrador de tu servidor leer tus mensajes, aunque esta podría ser la única via de comunicación con personas que usen clientes desactualizados. + ¿Estás seguro de que deseas desactivar el cifrado OMEMO para este chat? +\nEsto permitirá que el administrador de su servidor lea sus mensajes, pero podría ser la única forma de comunicarse con personas que utilizan clientes obsoletos. Deshabilitar ahora Borrador: Cifrado OMEMO OMEMO siempre será usado para conversaciones uno a uno y en conversaciones en grupo privadas. - OMEMO será usado por defecto para nuevas conversaciones. - OMEMO tendrá que ser explícitamente activado para nuevas conversaciones. + OMEMO será usado por defecto para chats nuevos. + OMEMO tendrá que ser activado explícitamente para los nuevos chats. Crear acceso directo Activo por defecto Desactivado por defecto @@ -730,14 +730,14 @@ Permitir a %1$s acceder al micrófono Buscar mensajes GIF - Ver conversación + Ver el chat Plugin para Compartir Ubicación Usar el Plugin Compartir Ubicación en lugar del propio de la aplicación Copiar dirección web Copiar dirección XMPP Compartición de Archivos mediante S3 Búsqueda directa - En la pantalla de \'Nueva Conversación\' abrir el teclado y poner el cursor en el campo de búsqueda + En la pantalla \"Nuevo chat\", abra el teclado y coloque el cursor en el campo de búsqueda Avatar de la conversación en grupo El servidor no soporta avatares en conversaciones en grupo Solo el propietario de la conversación puede cambiar el avatar @@ -789,20 +789,20 @@ Verificar %s %s.]]> Hemos enviado otro mensaje SMS con un código de 6 dígitos. - Por favor, introduce el código de 6 dígitos abajo. + Por favor, introduzca a continuación el PIN de 6 dígitos. Reenviar SMS Reenviar SMS (%s) Por favor, espera (%s) - atrás - Automáticamente pegar el posible pin del portapapeles. - Por favor, introduce tu código de 6 dígitos. + Atrás + Pegado automático del posible PIN desde el portapapeles. + Por favor, introduzca su PIN de 6 dígitos. ¿Estás seguro de que quieres abortar el proceso de registro? No Verificando… Solicitando un mensaje de texto… - El código que has introducido no es correcto. - El código que te hemos enviado ha expirado. + El PIN introducido es incorrecto. + El PIN que te hemos enviado ha caducado. Error desconocido de red. Respuesta de servidor desconocida. No se ha podido conectar al servidor. @@ -951,8 +951,8 @@ Desfijar de la parte superior Recorrido GPX No se pudo corregir el mensaje - Todas las conversaciones - Esta conversación + Todos los chats + Este chat Tu imagen de perfil Imagen de perfil de %s Encriptado con OMEMO @@ -1024,7 +1024,7 @@ Sin permiso para llamar por teléfono Contacto no disponible ¡Sin integración de llamadas! - Borrar y cerrar + Borrar y cerrar el chat ¿Quieres eliminar el marcador de %s ? ¿Quieres eliminar el marcador de %s y guardar el chat? Enviar informes de errores @@ -1034,4 +1034,48 @@ Guardar este chat Chat guardado Unirse a Conversation + Burbujas de chat de colores + Colores de fondo distintos para mensajes enviados y recibidos + El código de barras no contiene huellas digitales para este chat. + Teclado + Notificaciones de participación + Solicitud + Interacción + Nombre del host y puerto, Tor + Nombre del host y puerto, Tor, descubrimiento de canales + Cifrado E2E, confianza ciega antes de la verificación, detección de MITM + Al actuar como un Distribuidor de UnifiedPush la conexión XMPP persistente, fiable y de bajo consumo de batería se utilizará para despertar a otras aplicaciones compatibles con UnifiedPush como Tusky, Ltt.rs, FluffyChat y más. + Enviar mensaje cifrado + Interfaz + Tema, Colores, Capturas de pantalla, Entrada + Seguridad + Relé de notificaciones para aplicaciones de terceros compatibles con UnifiedPush + Notificaciones + Período de gracia, Tono de llamada, Vibración, Extraños + Enviando + Recibiendo + Descarga automática + Apariencia + Modo claro/oscuro + Permitir capturas de pantalla + Cifrado de extremo a extremo + Organismos de certificación + Confiar en los certificados CA del sistema + Requerir enlace al canal + La vinculación de canales puede detectar algunos ataques al intermediario + Conexión al servidor + Sistema operativo + En el dispositivo + Fuente grande + Aumentar el tamaño del texto en las burbujas de mensajes + Chats correspondientes archivados. + Colores dinámicos + Colores del sistema (Material You) + Cambiar al chat + Notificaciones de escritura, Visto por última vez, Disponibilidad + Iniciar un chat + El descubrimiento de canales utiliza un servicio de terceros llamado <a href=https://search.jabber.network>search.jabber.network</a>.<br><br>Usar esta función transmitirá tu dirección IP y términos de búsqueda a ese servicio. Consulte su <a href=https://search.jabber.network/privacy>Política de privacidad</a> para obtener más información. + ¡No se ha seleccionado ningún certificado de cliente! + Tamaño de archivo, Compresión de imagen, Calidad de vídeo + Mostrar el contenido de la aplicación en el conmutador de aplicaciones y permitir la realización de capturas de pantalla \ No newline at end of file From 69051394281b5e1ea52d2be618fc8104392d5d45 Mon Sep 17 00:00:00 2001 From: fuzfyy Date: Sat, 20 Apr 2024 20:47:29 +0000 Subject: [PATCH 04/57] Translated using Weblate (Turkish) Currently translated at 99.4% (1008 of 1014 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/tr/ --- src/main/res/values-tr-rTR/strings.xml | 152 +++++++++++++++++++------ 1 file changed, 120 insertions(+), 32 deletions(-) diff --git a/src/main/res/values-tr-rTR/strings.xml b/src/main/res/values-tr-rTR/strings.xml index 3815ac77ac1298277a8d4b01305cff07a17a7aa8..95a736b7640e96f558b3313b89cb8d8c7e47ceca 100644 --- a/src/main/res/values-tr-rTR/strings.xml +++ b/src/main/res/values-tr-rTR/strings.xml @@ -26,8 +26,8 @@ 1 dakika önce %d dakika önc - %d okunmamış konuşma - %d okunmamış konuşmalar + %d okunmamış sohbet + %d okunmamış sohbet gönderiyor… İleti deşifre ediliyor. Lütfen bekleyin… @@ -39,7 +39,7 @@ Moderatör Katılımcı Ziyaretçi - %s adlı kişiyi listenizden çıkarmak ister misiniz? Bu kişi ile olan konuşmalar silinmeyecektir. + %s adlı kişiyi listenizden çıkarmak ister misiniz? Bu kişi ile olan sohbet silinmeyecektir. %s kişisinin size ileti göndermesini engellemek istiyor musunuz? %s kişisinin size ileti göndermesine koyduğunuz engellemeyi kaldırmak ve size ileti göndermesine izin vermek istiyor musunuz? %s üzerinden gelen tüm kişileri engellemek istiyor musunuz? @@ -77,7 +77,7 @@ Görüntüler gönderilmeye hazırlanılıyor Dosyalar Paylaşılıyor. Lütfen bekleyin… Geçmişi sil - Konuşma geçmişini sil + Sohbet geçmişini sil Bu konuşmadaki tüm mesajları silmek istiyor musunuz? \n \nUyarı: Bu eylem, diğer aygıt ve sunucularda kayıtlı mesajları etkilemeyecektir. @@ -176,7 +176,7 @@ OpenPGP genel anahtarınız Çevrim içi durum anonsunuzdan kaldırmak istediğinizden emin misiniz?\nArtık kişileriniz size şifrelenmiş OpenPGP mesajları gönderemeyecek. OpenPGP genel anahtarı yayınlandı. Hesabı etkinleştir - Hesabınızı silmekten emin misiniz? Hesabınızın silinmesi bütün konuşma geçmişinizi siler + Hesabınızı silmek istediğinizden emin misiniz? Bütün sohbetleriniz silinecektir Ses kaydet XMPP adresi XMPP adresini engelle @@ -277,7 +277,7 @@ Yok say Uyarı: Bu mesajı karşılıklı çevrim içi durum bildirimleri olmadan göndermek, beklenmeyen problemlere neden olabilir. \n\n Çevrim içi durum aboneliklerini doğrulamak için \"Kişi Bilgileri\" kısmına gidin. Güvenlik - İleti düzeltmeye izin ver + Mesaj düzeltme Kişilerinizin geçmiş iletilerini düzeltmelerine izin ver Uzman seçenekleri Lütfen dikkatli olun @@ -313,8 +313,8 @@ XMPP adresi panoya kopyalandı Hata mesajı panoya kopyalandı web adresi - 2B Barkod Tara - 2B Barkod Göster + QR Kodu tara + QR Kodu göster Engellenenler listesini göster Hesap bilgileri Doğrula @@ -357,7 +357,7 @@ OMEMO bildirimindeki diğer aygıtların hepsini silmek istediğinizden emin misiniz? Aygıtlarınız yeniden bağlandıklarında kendilerini yeniden bildirecekler ama bu süre zarfındaki iletileri alamayabilirler. Bu kişi için kullanılabilecek bir anahtar bulunmuyor.\nSunucudan yeni anahtarlar alınamıyor. Belki bağlantınızın sunucusunda bir sorun vardır? Bu kişi için kullanılabilir bir anahtar yok. -\nİkinizin de çevrim içi durum aboneliği oldudğundan emin olun. +\nİkinizin de çevrimiçi durum aboneliği olduğundan emin olun. Bir şeyler ters gitti Sunucudan geçmiş alınıyor Sunucuda başka geçmiş kalmadı @@ -470,8 +470,8 @@ Telefonunuz sessizdeyken, durum bildiriminizi müsait değil olarak gösterir. Titreşim kipini sessiz kip olarak değerlendir Telefonunuz titreşimdeyken, durum bildiriminizi müsait değil olarak gösterir. - Genişletilmiş bağlantı seçenekleri - Hesap oluştururken sunucu adıyla bağlantı noktası seçeneğini göster + Barındırıcı adı ve Port + Hesap oluştururken gelişmiş bağlantı ayarlarını göster xmpp.ornek.com Sertifika ile giriş yap Sertifika çözümlenemedi @@ -507,11 +507,10 @@ Metin %s ile paylaşıldı %1$s\'ın harici depolama erişimine izin ver %1$s\'ın kamera erişimine izin ver - Kişilerle senkronize et - %1$s XMPP listenizi telefon rehberinizle eşleştirmek için izin istiyor. -\nBöylelikle, tüm rehberinizindeki kişilerin tam adları ve avatarlarını görebileceksiniz. + Kişiler entegrasyonu + %1$s kişilerinizi yerel olarak, cihazınızda, XMPP\'de bulunan kişilerinizin isimlerini ve profil fotoğraflarını göstermek için işler. \n -\n%1$s kişilerinizi sunucunuza yüklemeyecek olup, sadece cihazınız üzerinden eşleştirme yapacaktır. +\nKişileriniz hakkında hiçbir bilgi cihazınızdan ayrılmaz! Tüm iletilerde uyar Yalnızca bahsedilğinde haber ver Uyarılar devre dışı @@ -529,13 +528,14 @@ Bu alan zorunludur ileti düzelt Düzeltilmiş iletiyi gönder - Bu kişinin güvenini doğrulamak için parmak izini zaten güvenle onayladınız. \"Tamam\"ı seçerek sadece%s kişisinin, grup konuşmasının bir parçası olduğunu doğruluyorsunuz. + Bu kişinin parmak izine zaten güvenmiştiniz. \"Tamam\"ı seçerek sadece %s\'in bu grupta olduğunu onaylamış olacaksınız. Bu hesabı devre dışı bıraktınız Güvenlik hatası: Geçersiz dosya erişimi! URL paylaşacak uygulama bulunamadı URI paylaş ile… Kabul et ve devam et - Conversations\'da hesap kurulum için bir rehber hazırlanmıştır.¹\nConversations.im\'i bir sağlayıcı olarak seçtikten sonra başka sağlayıcılar kullanan kullanıcılarla onlara tam XMPP adresinizi vererek iletişim kurabilirsiniz. + Conversations.im üzerinde hesap oluşturma rehberi bulunmaktadır. +\nConversations.im\'i sağlayıcınız olarak seçtiğinizde diğer sağlayıcıların kullanıcılarıyla tam XMPP adresinizi paylaşarak iletişim kurabileceksiniz. Tam XMPP adresiniz %s olacak Hesap Oluştur Kendi sağlayıcımı kullan @@ -559,8 +559,8 @@ Kısa Orta Uzun - Kullanımı yayınla - Kişiler Conversations\'ı kullandığınız zaman bundan haberdar olur. + Son görülme + Kişilerinizin uygulamayı en son ne zaman kullandığınızı görmesine izin verin Gizlilik Gövde Renk paletini seçin @@ -607,7 +607,7 @@ Doğrulanmamış kişilerin tüm yani aygıtlarına güven, ama doğrulanmış kişilerden aygıtlarını onaylamalarını iste. OMEMO anahtarlarına körlemisne güvenildi, yani bu kişi bir başkası olabilir veya biri konuşmayı dinleyebilir. Güvenilmeyen - Geçersiz 2D barkod + Geçersiz QR Kodu Önbellek dizinini temizle (Kamera uygulamasının kullandığı) Önbelleği temizle Özel depolama alanını temizle @@ -696,14 +696,14 @@ Aygıt listesi alınamadı Şifreleme anahtarları alınamadı İpucu: Kimi durumlarda bu sorun, birbirinizi kişi listenize eklemenizle çözülebilir. - Bu konuşma için OMEMO şifrelemesini devre dışı bırakmak istediğinizden emin misiniz? -\nBu, sunucu yöneticinizin mesajlarınızı okumasını mümkün kılsa da, tarihi geçmiş istemcileri kullanan insanlarla iletişim kurmanın tek yolu olabilir. + Bu sohbet için OMEMO şifrelemesini devre dışı bırakmak istediğinizden emin misiniz? +\nBunu yapmanız sunucu yöneticinizin mesajlarınızı okumasına izin verecektir, fakat güncel olmayan istemcileri kullanan kişilerle konuşmanın tek yolu bu olabilir. Şimdi devre dışı bırak Taslak: OMEMO Şifrelemesi Bire bir ve grup konuşmalarında her zaman OMEMO kullanılacak. - Yeni konuşmalarda OMEMO varsayılan olarak kullanılacak. - Özellikle yeni konuşmalarda OMEMO aktif hale getirilecek. + Yeni sohbetlerde OMEMO varsayılan olarak kullanılacak. + Yeni sohbetlerde OMEMO\'nun el ile aktifleştirilmesi gerekecektir. Kısayol oluştur Varsayılan olarak aktif Varsayılan olarak devre dışı @@ -724,14 +724,14 @@ %1$s\'ın mikrofon erişimine izin ver İleti ara GIF - Konuşma görüntüle + Sohbeti görüntüle Konum Eklentisini Paylaş Varolan harita yerine Konum Eklentisini Paylaş\'ı kullan Web adresini kopyala XMPP adresini kopyala S3 için HTTP Dosya Paylaşımı Doğrudan arama - \'Konuşma Başlat\" ekranında klavyeyi aç ve arama kısmına imleci getir + \"Yeni sohbet\" ekranında klavyeyi arama kutusunda aç Grup konuşması avatarı Yönetici grup konuşması avatarlarını desteklemiyor Yalnızca yönetici grup konuşması avatarını değiştirebilir @@ -783,13 +783,13 @@ %s doğrula %s telefonunuza bir SMS gönderdik.]]> Size 6 haneli kodun olduğu başka bir SMS gönderdik. - Lüfen aşağıya 6 haneli kodu girin. + Lütfen aşağıya 6 haneli kodu girin. Tekrar sms gönder Tekrar sms gönder (%s) Lütfen bekleyin (%s) - geri - Olası kod, otomatik olarak panodan yapıştırıldı. - Lütfen 6 haneli kodu girin. + Geri + Olası kod, otomatik olarak yapıştırıldı. + Lütfen 6 haneli kodunuzu girin. Kayıt sürecini iptal etmek istediğinizden emin misiniz? Evet Hayır @@ -940,8 +940,8 @@ En baştan kaldır GPX izi İleti düzeltilemedi - Bütün konuşmalar - Bu konuşma + Tüm sohbetler + Bu sohbet Avatarınız %s avatarı OMEMO ile şifrelendi @@ -978,4 +978,92 @@ Videoya geç Videoya geçme isteğini reddet XMPP Hesabı + Oturum kapatıldı + Bildirim Sunucusu + Çökme raporları gönder + Sohbete Katıl + Quicksy\'e hoşgeldiniz! + Kendiniz oluşturmadığınız yedekleri geri yüklemeye çalışmayın! + Oturumu kapat + Bildirimi gizle + Spam bildir + İstemci sertifikası seçilmedi! + Oturum aç + Arayüz + Tema, Renkler, Ekran Görüntüleri, Girdi + Açık/Koyu tema + Yazıyor bildirimi, Son görülme, Müsaitlik + Barındırıcı adı ve Portu, Tor + Barındırıcı adı ve Portu, Tor, Kanal Keşfetme + Kişiler entegrasyonu mevcut değil + Gizlilik politikası + Şununla paylaş… + Gelen arama (%s) · %s + Giden arama (%s) · %s + Giden arama · %s + Doğrulanmamış bir cihaz kullanıyorsunuz. Aktif MITM (Ortadaki Adam) saldırılarını önlemek için diğer cihazlarınızda QR kodunu okutarak doğrulama yapın. + Spam bildir ve kişiyi engelle + Sohbeti sil ve arşivle + Sohbet başlat + Kişiniz doğrulanmamış bir cihaz kullanıyor. Aktif MITM (Ortadaki Adam) saldırılarını önlemek için kişinizin QR kodunu okutarak doğrulama yapın. + Arama entegrasyonu mevcut değil! + Sohbeti arşivle + Bu sohbeti arşivle + Sohbete git + Bildirimlerin alınacağı hesap. + UnifiedPush dağıtıcısı + Hiçbiri (devre dışı) + Yeni sohbet + Görüntülü aramaya geçilsin mi? + Uygulama değiştiricide içeriği göster ve ekran görüntüsü almaya izin ver + %s için yer imini kaldırmak ve sohbeti arşivlemek ister misiniz? + Grup olarak kaydet + Sesli kitap + Şifrelenmiş ileti gönder + Gruplar + Quicksy, verilerinizi kullanmak için izninizi istiyor + Bu hesabın oturumunu kapatmışsınız + Renkli konuşma balonları + Gönderilen ve alınan mesajlar için farklı renkler kullan + Arama yapma izni yok + Uygun gelen sohbetler arşivlendi + Dinamik renklendirme + Sistem renkleri (Material You) + Kişi müsait değil + Reddet + Hesabı sunucudan sil + Hesap sunucudan silinemedi + Güvenlik + UnifiedPush destekleyen üçüncü parti uygulamalar için bildirim aktarıcısı + Bildirimler + Dosya büyüklüğü, Resim sıkıştırma, Video kalitesi + Yok sayma süresi, Zil sesi, Titreşim, Yabancılar + Gönderme + Teslim alma + Otomatik indirme + Görünüm + Ekran görüntüsü almaya izin ver + Uçtan uca şifreleme + Sertifika yetkilileri + Sistemin CA sertifikalarına güven + Kanal bağlamayı zorunlu kıl + Kanal bağlama bazı aradaki makine saldırılarını tespit edebilir + Sunucu bağlantısı + İşletim Sistemi + Klavye + Uygulama + Etkileşim + Bu Cihazda + Büyük punto + Konuşma balonlarındaki yazı büyüklüğünü arttır + %s için yer imini kaldırmak ister misiniz? + Bir gruba katılırken \"autojoin\" (otomatik katıl) işaretini ayarla ve diğer istemciler tarafından yapılan değişikliklere tepki ver. + Sohbet arşivlendi + Grup ara + Barkod, bu sohbet için parmak izi bilgisi barındırmıyor. + Grup keşfetme <a href=https://search.jabber.network>search.jabber.network</a> adlı bir hizmeti kullanır.<br><br>Bu özelliği kullanmanız IP adresinizi ve aramalarınızı bu hizmete gönderecektir. Daha fazla bilgi için hizmetin <a href=https://search.jabber.network/privacy>Gizlilik Politikasına</a> göz atın. + Artık desteklenmeyen bir yedek dosyası türünü geri yüklemeye çalışıyorsunuz + Uçtan Uca Şifreleme, Doğrulamadan Körü Körüne Güven, MITM Algılama + Etkileşim bildirimleri + UnifiedPush Dağıtıcısı olarak davranılırken devamlı, güvenli ve pil ömrü dostu olan XMPP bağlantısı diğer UnifiedPush ile uyumlu olan Tusky, Ltt.rs, FluffyChat ve benzeri uygulamaları uyandırmak için kullanılacaktır. \ No newline at end of file From 9f4cb115958ab07d97ea5ebc1496c6d0c4635c86 Mon Sep 17 00:00:00 2001 From: fuzfyy Date: Sat, 20 Apr 2024 19:47:21 +0000 Subject: [PATCH 05/57] Translated using Weblate (Turkish) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/tr/ --- src/conversations/res/values-tr-rTR/strings.xml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/conversations/res/values-tr-rTR/strings.xml b/src/conversations/res/values-tr-rTR/strings.xml index db1b0ac999b4b6ce09ee55526dd15203d390ff99..446c5485a9cc02a93a0e00de5994f52195f12b0b 100644 --- a/src/conversations/res/values-tr-rTR/strings.xml +++ b/src/conversations/res/values-tr-rTR/strings.xml @@ -3,14 +3,16 @@ XMPP sağlayıcınızı seçin conversations.im kullan Yeni hesap oluştur - Zaten bir XMPP hesabınız var mı? Bunun sebebi, zaten başka bir XMPP istemcisi kullanıyor oluşunuz veya Conversations\'ı önceden kullanmış olmanız olabilir. Eğer durum bu değilse şimdi yeni bir XMPP hesabı oluşturabilirsiniz.\nİpucu: Bağzı e-posta sağlayıcıları da XMPP hesapları kullanabilir. - XMPP; anlık yazışmalar için bağımsız bir sağlayıcıdır. Bu istemciyi istediğiniz herhangi bir XMPP sunucusu ile birlikte kullanabilirsiniz. -\nAncak kullanım rahatlığı adına sizin için conversations.im; Conversations için özellikle tasarlanmış bir sağlayıcıda hesap açmanızı kolaylaştırdık. - %1$s sağlayıcısına davet edildiniz. Sizi hesap oluşturulması konusunda yönlendireceğiz.\n%1$s bir sağlayıcı olark seçildiğinde, başka sağlayıcılar kullanan kullanıcılarla, onlara tam XMPP adresinizi vererek iletişim kurabileceksiniz. + Zaten bir XMPP hesabınız var mı? Bunun sebebi, zaten başka bir XMPP istemcisi kullanıyor oluşunuz veya Conversations\'ı önceden kullanmış olmanız olabilir. Eğer yoksa şimdi yeni bir XMPP hesabı oluşturabilirsiniz. +\nİpucu: Bazı e-posta sağlayıcıları da XMPP hesapları sağlayabilir. + XMPP, sağlayıcıdan bağımsız bir anlık mesajlaşma ağıdır. Bu uygulamayı seçtiğiniz herhangi bir sağlayıcıyla kullanabilirsiniz. +\nFakat, kullanım kolaylığı için, özellikle Conversations ile kullanılmak için tasarlanmış olan conversations.im sunucusunu da kullanabilirsiniz. + %1$s sağlayıcısına davet edildiniz. Sizi hesap oluşturulması konusunda yönlendireceğiz. +\n%1$s bir sağlayıcı olarak seçildiğinde, başka sağlayıcılar kullanan kullanıcılarla, onlara tam XMPP adresinizi vererek iletişim kurabileceksiniz. %1$s sağlayıcısına davet edildiniz. Sizin için zaten bir kullanıcı adı seçildi. Sizi hesap oluşturulması konusunda yönlendireceğiz.\nBaşka sağlayıcılar kullanan kullanıcılarla, onlara tam XMPP adresinizi vererek iletişim kurabileceksiniz. Sunucu davetiyeniz Yanlış ayarlanmış düzenleme kodu - Kişinize, %1$s grubuna davet etmek için Paylaş düğmesine basın. + Kişiyi %1$s\'e davet etmek için paylaş butonuna dokunun. Kişiniz yakınınızda ise, aşağıdaki kodu tarayak daveti kabul edebilirler. %1$s grubuna katıl ve benimle sohbet et: %2$s Daveti şununla paylaş… From cd12667d3422c80e5c45e917830feb0527ec216b Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 21 Apr 2024 12:31:56 +0000 Subject: [PATCH 06/57] Translated using Weblate (Spanish) Currently translated at 100.0% (62 of 62 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/es/ --- fastlane/metadata/android/es-ES/changelogs/4210804.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/es-ES/changelogs/4210804.txt diff --git a/fastlane/metadata/android/es-ES/changelogs/4210804.txt b/fastlane/metadata/android/es-ES/changelogs/4210804.txt new file mode 100644 index 0000000000000000000000000000000000000000..1ece57245ad12335fd19e89a76f177baa37a08fc --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/4210804.txt @@ -0,0 +1,2 @@ +* Mostrar el estado de los mensajes como iconos +* Introducir la opción "Fuente grande" para las burbujas de mensajes From f4948354c9ebc2e86268e5c441c61a88c9eda647 Mon Sep 17 00:00:00 2001 From: fuzfyy Date: Sat, 20 Apr 2024 21:40:50 +0000 Subject: [PATCH 07/57] Translated using Weblate (Turkish) Currently translated at 50.0% (1 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/tr/ --- .../fastlane/metadata/android/tr-TR/full_description.txt | 3 +++ .../fastlane/metadata/android/tr-TR/short_description.txt | 1 + 2 files changed, 4 insertions(+) create mode 100644 src/conversations/fastlane/metadata/android/tr-TR/full_description.txt create mode 100644 src/conversations/fastlane/metadata/android/tr-TR/short_description.txt diff --git a/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt b/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..8530e5fb265048c095e3ae37a81bd00cd1111ce2 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt @@ -0,0 +1,3 @@ +Kullanımı kolay, güvenilir, pil ömrü dostu. Resimler, gruplar ve uçtan uca şifreleme için yerleşik destek. + +Tasarım ilkeleri: diff --git a/src/conversations/fastlane/metadata/android/tr-TR/short_description.txt b/src/conversations/fastlane/metadata/android/tr-TR/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..1eb74ef8f8a3b66452e628c61ee1559a6a0a846a --- /dev/null +++ b/src/conversations/fastlane/metadata/android/tr-TR/short_description.txt @@ -0,0 +1 @@ +Mobil cihazınız için şifrelenmiş, kullanımı kolay bir XMPP mesajlaşma uygulaması From b366b0be4b4c5779de14717035adad2dae0bc82c Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 21 Apr 2024 15:22:38 +0000 Subject: [PATCH 08/57] Translated using Weblate (Spanish) Currently translated at 100.0% (1014 of 1014 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/es/ --- src/main/res/values-es/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 5e440a9f41290ba487608250e3f9b74d09a94d4b..d09dc3f11c5943c879ce5c7dad79343924177664 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -1066,7 +1066,7 @@ Conexión al servidor Sistema operativo En el dispositivo - Fuente grande + Texto grande Aumentar el tamaño del texto en las burbujas de mensajes Chats correspondientes archivados. Colores dinámicos From b284b36074d3c8ebfeef39efb2ab010df71b8763 Mon Sep 17 00:00:00 2001 From: random_r Date: Mon, 22 Apr 2024 07:28:46 +0000 Subject: [PATCH 09/57] Translated using Weblate (Italian) Currently translated at 100.0% (1014 of 1014 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/it/ --- src/main/res/values-it/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index fa7bc78594277e380f0b5c06fa73228f276fc6c4..eab8c2601d203c286192d28ddbeb1bc6ce4b12b6 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -276,7 +276,7 @@ Ignora Attenzione: inviarlo senza aggiornamenti della presenza reciproci può causare problemi inaspettati.\n\nVai nei dettagli del contatto per verificare le tue sottoscrizioni alla presenza. Sicurezza - Correzione del messaggio + Correzione dei messaggi Consenti ai tuoi contatti di modificare retroattivamente i loro messaggi Impostazioni per esperti Fai attenzione con queste impostazioni @@ -566,8 +566,8 @@ Tema Seleziona il colore Automatica - Chiaro - Scuro + Chiara + Scura Impossibile connettersi a OpenKeychain Questo dispositivo non è più in uso Computer @@ -1050,11 +1050,11 @@ Sistema operativo Nome host e porta, Tor, scoperta dei canali Tastiera - Notifiche di coinvolgimento + Notifiche di partecipazione Applicazione Interazione Sul dispositivo - Quando si agisce come distributore di UnifiedPush, la connessione XMPP persistente, affidabile e a basso consumo di batteria viene usata per risvegliare altre app compatibili con UnifiedPush, come Tusky, Ltt.rs, FluffyChat ed altre. + Quando si agisce come distributore di UnifiedPush, viene usata la connessione XMPP persistente, affidabile e a basso consumo di batteria per risvegliare altre app compatibili con UnifiedPush, come Tusky, Ltt.rs, FluffyChat ed altre. L\'integrazione dell\'elenco di contatti non è disponibile Informativa sulla privacy Autorizzazione mancante per effettuare una chiamata From 1cdc0c489885c3b35aa883dda4aa320dda8ee153 Mon Sep 17 00:00:00 2001 From: Waderasm Date: Mon, 22 Apr 2024 07:53:48 +0000 Subject: [PATCH 10/57] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1014 of 1014 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/zh_Hant/ --- src/main/res/values-zh-rTW/strings.xml | 104 ++++++++++++++++++++----- 1 file changed, 83 insertions(+), 21 deletions(-) diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index 48a03b6a4a82cb88981e25dc8b5f14f7a67aa9dc..9c76586e8ec194b7a9ff704ce941ae26c0600d87 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -78,12 +78,12 @@ 清除會話記錄 刪除檔案 選擇裝置 - 傳送未加密的訊息 + 傳送明文訊息 傳送訊息 傳送訊息至 %s 傳送 v\\OMEMO 加密訊息 新暱稱已被使用 - 不加密傳送 + 傳送明文 解密失敗,可能是私密金鑰不正確。 OpenKeychain 重新啟動 @@ -149,7 +149,7 @@ 不相容的用戶端 串流錯誤 串流開啟錯誤 - 未加密 + 明文 OTR OpenPGP OMEMO @@ -254,7 +254,7 @@ 立即要求 忽略 安全性 - 允許訊息修正 + 訊息修正 允許您的聯絡人追溯編輯他們的訊息 專家設定 請謹慎使用 @@ -290,8 +290,8 @@ 已複製 XMPP 位址到剪貼簿 已複製錯誤訊息到剪貼簿 網頁位址 - 掃描二維條碼 - 顯示二維條碼 + 掃描 QR 碼 + 顯示 QR 碼 顯示封鎖清單 帳戶詳細資料 確認 @@ -441,8 +441,8 @@ 靜音模式時顯示為忙碌 靜音模式開啟震動 裝置震動時顯示為忙碌 - 進階連線設定 - 註冊帳戶時顯示主機名稱和連接埠設定 + 主機名和端口 + 註冊帳戶時顯示進階連線設定 xmpp.example.com 以憑證登入 無法解析憑證 @@ -477,7 +477,7 @@ 與 %s 分享的文字 授予 %1$s 外部儲存空間存取權 授予 %1$s 相機存取權 - 同步處理聯絡人 + 整合通訊錄 通知所有訊息 僅在被提及時通知 通知已停用 @@ -564,7 +564,7 @@ 分享為 HTTP 連結 驗證前盲目信任 未受信任 - 無效的二維條碼 + 無效的 QR 碼 清理快取 清理私人儲存空間 清理儲存檔案的私人空間 (檔案可從伺服器重新下載) @@ -641,7 +641,7 @@ OMEMO 加密 OMEMO 將一律用於一對一和私人群組聊天。 OMEMO 將預設用於新會話。 - OMEMO 將明確用於新會話。 + OMEMO 將需要明確地用於新會話。 建立捷徑 預設開啟 預設關閉 @@ -669,7 +669,7 @@ 複製 XMPP 位址 用於 S3 的 HTTP 檔案分享 直接搜尋 - 在「開始對話」畫面上開啟鍵盤並將遊標放在搜尋欄位 + 在「開始會話」畫面上開啟鍵盤並將遊標放在搜尋欄位 群組聊天頭像 主機不支援群組聊天頭像 只有擁有者才能變更群組聊天頭像 @@ -800,7 +800,7 @@ 附加 探索頻道 搜尋頻道 - 可能違反隱私權! + 可能會侵犯隱私! 我已經有一個帳戶 新增現有帳戶 註冊新帳戶 @@ -905,7 +905,7 @@ 暫時驗證失敗 刪除頭像 使用 Tor 時通話已停用 - 在您使用 Conversations 時讓您的聯絡人知道 + 讓您的聯絡人知道您最後使用此應用的時間 您確定要刪除此會話中的所有訊息嗎? \n \n警告:這將不會影響儲存在其他裝置或伺服器上的訊息。 @@ -935,16 +935,15 @@ \n前往「聯絡人詳細資料」以驗證您的線上狀態訂閱。 加入或離開多使用者聊天時設定「自動加入」旗標,並回應其他用戶端所做的修改。 您確定要從 OMEMO 宣告中清除所有裝置嗎?您的裝置在下次連線時將會重新宣告,但可能不會收到您傳送的訊息。 - %1$s想要您通訊錄的存取權以將其與您的 XMPP 聯絡人清單相符。 -\n這將顯示您聯絡人的完整名稱和頭像。 + %1$s 在您的設備上本地處理您的通訊錄,以向您顯示 XMPP 上相符的聯絡人名稱和個人資料頭像。 \n -\n%1$s僅會讀取您的通訊錄並在本機進行相符處理,不會上傳任何內容至您的伺服器。 +\n任何通訊錄數據都不會離開您的設備! 您的裝置正在為 %1$s 採用強力電池效能最佳化,這可能會導致通知延遲甚至訊息遺失。 \n \n您將被要求將其停用。 您的作業系統正在限制 %1$s 在背景存取網際網路。若要接收新訊息的通知,您應該允許 %1$s 在「數據節省」開啟時無限制地存取。 \n在可能的狀況下,%1$s 仍會努力地節省數據。 - 廣播使用 + 最後在線 您確定要刪除此檔案嗎? \n \n警告:這將不會影響儲存在其他裝置或伺服器上的檔案複本。 @@ -957,7 +956,7 @@ 在您的其他裝置上偵測到活動後,通知被靜音的時間長度。 透過傳送堆疊追蹤,您可以協助開發 您用來選取此圖像的應用程式沒有足夠的權限以讀取此檔案。 - UnifiedPush 散發者 + UnifiedPush 散發程序 XMPP 帳戶 推送伺服器 無 (已停用) @@ -1000,11 +999,74 @@ 登入 隱藏通知 在其他主機上重新連接 - 您的聯絡人使用未驗證的設備。掃描他們的二維條碼進行驗證,以防止主動中間人攻擊。 + 您的聯絡人使用未驗證的設備。請掃描他們的 QR 碼進行驗證,以防止主動中間人攻擊。 登出 您正在嘗試匯入一個過時的備份檔案格式 已登出 - 您正在使用未驗證的設備。掃描您其他設備上的二維條碼進行驗證,以防止主動中間人攻擊。 + 您正在使用未驗證的設備。請掃描您其他設備上的 QR 碼進行驗證,以防止主動中間人攻擊。 有聲書 請勿嘗試還原非您自己建立的備份! + 報告垃圾訊息 + 發送崩潰報告 + 相應的會話已存檔。 + 聯絡人整合不可用 + 隱私權政策 + 報告垃圾訊息並封鎖垃圾訊息發送者 + 刪除並存檔會話 + 用戶界面 + 未選擇用戶端證書! + 安全性 + 文件大小、圖片壓縮、影片質量 + 兼容 UnifiedPush 的第三方應用的通知轉發器 + 通知 + 證書頒發機構 + 信任系統的 CA 證書 + 需要通道綁定 + 通道綁定可以檢測某些中間人攻擊 + 伺服器連接 + 作業系統 + 輸入通知、最後在線、在線狀態 + 主機名和端口、Tor + 主機名和端口、Tor、頻道探索 + 鍵盤 + 參與通知 + 應用程序 + 互動 + 端對端加密、驗證前盲目信任、中間人攻擊檢測 + 分享至… + 新會話 + 存檔會話 + 存檔此會話 + 切換到會話 + 傳送加密消息 + Quicksy 請求您同意使用您的數據 + 參與會話 + 歡迎使用 Quicksy! + 彩色聊天氣泡 + 沒有撥打電話的權限 + 二維碼並不包含此會話的指紋。 + 系統色彩 (Material You) + 聯絡人不可用 + 通話整合不可用! + 開始會話 + 主題、配色、截屏、輸入 + 靜默期、鈴聲、震動、陌生人 + 發送 + 接收 + 自動下載 + 外觀 + 淺色/深色模式 + 允許截屏 + 在切換應用時顯示應用內容並允許截屏 + 端對端加密 + 在設備上 + 在充當 UnifiedPush 散發者時,將利用持久、可靠且省電的 XMPP 連接來喚醒其他兼容 UnifiedPush 的應用,如 Tusky、Ltt.rs、FluffyChat 等。 + 會話已存檔 + 為已發送和已接收訊息使用個別的背景顏色 + 大字體 + 增加訊息氣泡中的字體大小 + 是否移除 %s 的書籤? + 是否移除 %s 的書籤並存檔會話? + 自動配色 + 頻道探索使用一個名為 <a href=https://search.jabber.network>search.jabber.network</a> 的第三方服務,<br><br>使用此功能會將您的 IP 位址和搜尋詞彙傳送至此服務。更多資訊請參見他們的 <a href=https://search.jabber.network/privacy>隱私權政策</a>。 \ No newline at end of file From a3b10cf3bc53d0da6aa1d5205c1d8b9adccbe34d Mon Sep 17 00:00:00 2001 From: Waderasm Date: Mon, 22 Apr 2024 06:27:38 +0000 Subject: [PATCH 11/57] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/zh_Hant/ --- src/conversations/res/values-zh-rTW/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/res/values-zh-rTW/strings.xml b/src/conversations/res/values-zh-rTW/strings.xml index de09fe8678196ca8bb913e6315821d577248f4d4..a356693d8db6bb284da60f225446c96e3e567f72 100644 --- a/src/conversations/res/values-zh-rTW/strings.xml +++ b/src/conversations/res/values-zh-rTW/strings.xml @@ -5,7 +5,7 @@ 建立新帳戶 您已經擁有一個 XMPP 帳戶了嗎?如果您之前使用過其他 XMPP 用戶端或 Conversations 的話,那麼您已經擁有 XMPP 帳戶了。若沒有,您現在就建立一個新的 XMPP 帳戶。 \n提示:部分電子郵件提供者也會提供 XMPP 帳戶。 - XMPP 是提供者無關的即時訊息網路。任何您選擇的 XMPP 伺服器都可在此用戶端上使用。 + XMPP 是獨立於服務提供者的即時訊息網路。任何您選擇的 XMPP 伺服器都可在此用戶端上使用。 \n不過,我們令它在 Coversations.im 中建立帳戶變得更方便;conversations.im 是特別適合 Conversations 的提供者。 你已受邀參加 %1$s 。我們將指引您完成建立帳戶的過程。 \n選擇 %1$s 作為提供者後,您可以將您完整的 XMPP 位址交給使用其他提供者的使用者,以便能與他們進行交流。 From 6df3f4491f1adfe925471bad92eae9d899f98bc9 Mon Sep 17 00:00:00 2001 From: random_r Date: Mon, 22 Apr 2024 07:25:12 +0000 Subject: [PATCH 12/57] Translated using Weblate (Italian) Currently translated at 100.0% (63 of 63 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/it/ --- fastlane/metadata/android/it-IT/changelogs/4210904.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/it-IT/changelogs/4210904.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/4210904.txt b/fastlane/metadata/android/it-IT/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e6d9c15b8cfd209ef384ef15d30698b14a3d3b1 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* Corretta registrazione a Quicksy su Android 6/7 +* Riproduci suoneria per chiamate in arrivo nel canale di notifica From ad4f2273d774db685cc6331304520eb63c2aa2e7 Mon Sep 17 00:00:00 2001 From: nautilusx Date: Mon, 22 Apr 2024 07:48:56 +0000 Subject: [PATCH 13/57] Translated using Weblate (German) Currently translated at 100.0% (63 of 63 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/de/ --- fastlane/metadata/android/de-DE/changelogs/4210904.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/de-DE/changelogs/4210904.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/4210904.txt b/fastlane/metadata/android/de-DE/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..28fcd66e1f01780696d0cf4ce7d197cc499bc374 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* Quicksy Registrierung auf Android 6/7 repariert +* Klingelton für eingehende Anrufe im Benachrichtigungskanal abspielen From adff3dfb30e1d8bc25cc9fcb0fda20274259f5cd Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Mon, 22 Apr 2024 08:35:07 +0000 Subject: [PATCH 14/57] Translated using Weblate (Polish) Currently translated at 11.1% (7 of 63 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/pl/ --- fastlane/metadata/android/pl-PL/changelogs/4210904.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/pl-PL/changelogs/4210904.txt diff --git a/fastlane/metadata/android/pl-PL/changelogs/4210904.txt b/fastlane/metadata/android/pl-PL/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..7284d0deeaff17b70392c99882e378d5c8d1f342 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* Naprawienie rejestracji w Quicksy w Androidzie 6/7 +* Odtwarzanie dzwonka połączenia przychodzącego w kanale powiadomień From 470db7b51e828cce5fcbb6bea46f5266810cdfc0 Mon Sep 17 00:00:00 2001 From: ghose Date: Mon, 22 Apr 2024 07:27:28 +0000 Subject: [PATCH 15/57] Translated using Weblate (Galician) Currently translated at 55.5% (35 of 63 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/gl/ --- fastlane/metadata/android/gl-ES/changelogs/4210904.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/gl-ES/changelogs/4210904.txt diff --git a/fastlane/metadata/android/gl-ES/changelogs/4210904.txt b/fastlane/metadata/android/gl-ES/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..14ebde079e817e5268b0c664487153fb8df52456 --- /dev/null +++ b/fastlane/metadata/android/gl-ES/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* Solución para crear conta con Quicksy en Android 6/7 +* Reproducir ton de chamada recibida na canle de notificación From 56cb9e3fd64ffa708c396718581e7761f4059a1d Mon Sep 17 00:00:00 2001 From: SomeTr Date: Sun, 21 Apr 2024 19:25:50 +0000 Subject: [PATCH 16/57] Translated using Weblate (Ukrainian) Currently translated at 100.0% (63 of 63 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/uk/ --- fastlane/metadata/android/uk/changelogs/4210904.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/uk/changelogs/4210904.txt diff --git a/fastlane/metadata/android/uk/changelogs/4210904.txt b/fastlane/metadata/android/uk/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..45c3122aa78580d5ede4c166fe6caa433ef73256 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* Виправлено реєстрацію Quicksy на Android 6/7 +* Відтворення мелодії вхідних викликів у каналі сповіщень From 71899c4a02f06c6abb941190e931d448238f763d Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 21 Apr 2024 15:19:11 +0000 Subject: [PATCH 17/57] Translated using Weblate (Spanish) Currently translated at 100.0% (63 of 63 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/es/ --- fastlane/metadata/android/es-ES/changelogs/4210904.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/es-ES/changelogs/4210904.txt diff --git a/fastlane/metadata/android/es-ES/changelogs/4210904.txt b/fastlane/metadata/android/es-ES/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..8068bcd41843b60764b8ff633a85b9c9c40539cd --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* Arreglar el registro de Quicksy en Android 6/7 +* Reproducir el tono de llamada entrante en el canal de notificación From ebcc072cd1cc53b35e0f9bda209753b8b6303f9f Mon Sep 17 00:00:00 2001 From: Outbreak2096 Date: Mon, 22 Apr 2024 03:27:19 +0000 Subject: [PATCH 18/57] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (63 of 63 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/zh_Hans/ --- fastlane/metadata/android/zh-CN/changelogs/4210904.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/zh-CN/changelogs/4210904.txt diff --git a/fastlane/metadata/android/zh-CN/changelogs/4210904.txt b/fastlane/metadata/android/zh-CN/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..f503dd304a91ca428d35a40efd659e30e7d7eb8e --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* 修复 Android 6/7 上的 Quicksy 注册问题 +* 在通知通道上播放来电铃声 From 2b66e0fe236beef4f28b27e39e45db9e728f0e27 Mon Sep 17 00:00:00 2001 From: nautilusx Date: Tue, 23 Apr 2024 15:24:27 +0000 Subject: [PATCH 19/57] Translated using Weblate (German) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/de/ --- src/main/res/values-de/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 16d1fd851d85ca9cca1bf371c91dd72a2dafc62a..912e967dbba5185a4b143fc4661e422773934043 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -1064,4 +1064,6 @@ Verschlüsselt schreiben… Schriftgröße der Nachrichten erhöhen Große Schrift + Einladungen von Unbekannten + Einladungen zu Gruppenchats von Unbekannten annehmen \ No newline at end of file From f0e2eb6fb0e903c5894d585ba539e158e54e53c0 Mon Sep 17 00:00:00 2001 From: ghose Date: Tue, 23 Apr 2024 07:22:48 +0000 Subject: [PATCH 20/57] Translated using Weblate (Galician) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/gl/ --- src/main/res/values-gl/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 06d206bdc053969d5fb07e78087c16b769db5c03..ddcdbc354e478141f4eaebe6da0d16f3acaab093 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -1066,4 +1066,6 @@ Enviar mensaxe cifrada Letra grande Aumentar o tamaño da letra das mensaxes + Convites de descoñecidas + Aceptar convites de persoas descoñecidas para grupos \ No newline at end of file From 9a473f69a358506831422f1931f21d4dbdb5ff81 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Tue, 23 Apr 2024 05:20:22 +0000 Subject: [PATCH 21/57] Translated using Weblate (Polish) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/pl/ --- src/main/res/values-pl/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index 120d7fa84f294cbbdbd59ef20eb97569df20dcf4..26a5eb13e8144cc66150936000047904f0f5abb0 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -1096,4 +1096,6 @@ Wyślij zaszyfrowaną wiadomość Dołącz do rozmowy Odkrywanie kanałów używa usługi podmiotu trzeciego nazywanej <a href=https://search.jabber.network>search.jabber.network</a>.<br><br>Używanie tej funkcjonalności spowoduje wysłanie twojego adresu IP oraz kryteriów wyszukiwania. Sprawdź ich <a href=https://search.jabber.network/privacy>politykę prywatności</a> aby uzyskać więcej informacji. + Zaproszenia od nieznajomych + Akceptuj zaproszenia do rozmów grupowych od nieznajomych \ No newline at end of file From 933701e00a64f49ac10a9a970af9c1897eb9a1e6 Mon Sep 17 00:00:00 2001 From: SomeTr Date: Mon, 22 Apr 2024 17:37:30 +0000 Subject: [PATCH 22/57] Translated using Weblate (Ukrainian) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/uk/ --- src/main/res/values-uk/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml index 1d1cd95b7cd51a8e1821b3ce5afb4120831f0f36..9d6cecfd5ec395acb682513793cf7060a5b1dd0c 100644 --- a/src/main/res/values-uk/strings.xml +++ b/src/main/res/values-uk/strings.xml @@ -646,7 +646,7 @@ Сповіщення від незнайомців Сповіщати про повідомлення і виклики від незнайомців. Отримано повідомлення від незнайомця - Заблокувати невідомий контакт + Заблокувати незнайомців Заблокувати весь домен зараз у мережі Спробувати знову розшифрувати @@ -1112,4 +1112,6 @@ Зашифроване повідомлення Великий шрифт Збільшити розмір шрифту повідомлень + Запрошення від незнайомців + Приймати запрошення до групових чатів від незнайомців \ No newline at end of file From 693159f367b827c10729ac52e6e5f11a29cd455f Mon Sep 17 00:00:00 2001 From: licaon-kter Date: Mon, 22 Apr 2024 16:29:31 +0000 Subject: [PATCH 23/57] Translated using Weblate (Romanian) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ro/ --- src/main/res/values-ro-rRO/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 333db1dc4eec2898fc18190106556952e7dd2214..a03ca93935911033b58e68bb345d44c2b5f86766 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -1083,4 +1083,6 @@ Trimite mesaj criptat Font mare Mărește fontul pentru textul din mesaje + Invitații de la persoane necunoscute + Acceptă invitații la discuții de grup de la persoane care nu sunt în lista de contacte \ No newline at end of file From 5ffe5acf8ca92b7887d319a984e25cfb8fe84743 Mon Sep 17 00:00:00 2001 From: Outbreak2096 Date: Tue, 23 Apr 2024 00:31:37 +0000 Subject: [PATCH 24/57] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/zh_Hans/ --- src/main/res/values-zh-rCN/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index 4aefb127d4c98de7920e0709b9bd774a51a914c2..e698e52d351d2f8897395310a727ffd071b24334 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -1022,7 +1022,7 @@ 频道发现使用称为 <a href=https://search.jabber.network>search.jabber.network</a> 的第三方服务。<br><br>使用此功能会将您的 IP 地址和搜索词传输到此服务。请参阅其 <a href=https://search.jabber.network/privacy>隐私政策</a> 以获取更多信息。 开始聊天 分享至… - 已发送和已接收消息的背景颜色各不相同 + 为已发送和已接收消息使用不同的背景颜色 未选择客户端证书! 彩色聊天气泡 动态色彩 @@ -1070,4 +1070,6 @@ 发送加密消息 大字体 增加消息气泡中的字体大小 + 来自陌生人的邀请 + 接受来自陌生人的群聊邀请 \ No newline at end of file From 413b4db42d4d84fa8dec7e4219a4ba0aad65d5ba Mon Sep 17 00:00:00 2001 From: nautilusx Date: Tue, 23 Apr 2024 15:27:25 +0000 Subject: [PATCH 25/57] Translated using Weblate (German) Currently translated at 100.0% (64 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/de/ --- fastlane/metadata/android/de-DE/changelogs/4211004.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/de-DE/changelogs/4211004.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/4211004.txt b/fastlane/metadata/android/de-DE/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bf3e43fa682865d719ea61954e919faed8dbc91 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* Anrufintegration auf einigen Android 14-Geräten behoben +* Neue Einstellung "Einladungen von Unbekannten" From 60f5d07fd2e8f4380c760b22c8c650c5c1b30a75 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Tue, 23 Apr 2024 05:21:36 +0000 Subject: [PATCH 26/57] Translated using Weblate (Polish) Currently translated at 12.5% (8 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/pl/ --- fastlane/metadata/android/pl-PL/changelogs/4211004.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/pl-PL/changelogs/4211004.txt diff --git a/fastlane/metadata/android/pl-PL/changelogs/4211004.txt b/fastlane/metadata/android/pl-PL/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd200026c426324710fb952a2f1b207ee6ca0942 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* Naprawienie integracji rozmów na niektórych urządzeniach z Androidem 14 +* Wprowadzenie ustawienia „Zaproszenia od nieznajomych” From 91ef19827d6116766042772540ee43f477760a89 Mon Sep 17 00:00:00 2001 From: ghose Date: Tue, 23 Apr 2024 07:24:29 +0000 Subject: [PATCH 27/57] Translated using Weblate (Galician) Currently translated at 56.2% (36 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/gl/ --- fastlane/metadata/android/gl-ES/changelogs/4211004.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/gl-ES/changelogs/4211004.txt diff --git a/fastlane/metadata/android/gl-ES/changelogs/4211004.txt b/fastlane/metadata/android/gl-ES/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..2244834aab50d50da6a2e38d397903c07ff96a34 --- /dev/null +++ b/fastlane/metadata/android/gl-ES/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* arranxo da integración de chamadas nalgúns Android 14 +* novo axuste para 'Convites de Descoñecidas' From 5de4bb9708b6845019afb8ccda47bb8d087ec771 Mon Sep 17 00:00:00 2001 From: SomeTr Date: Mon, 22 Apr 2024 17:43:35 +0000 Subject: [PATCH 28/57] Translated using Weblate (Ukrainian) Currently translated at 100.0% (64 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/uk/ --- fastlane/metadata/android/uk/changelogs/4211004.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/uk/changelogs/4211004.txt diff --git a/fastlane/metadata/android/uk/changelogs/4211004.txt b/fastlane/metadata/android/uk/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..36b7f674e0aea11a5fee1f92d135bcbbe7b5376d --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* Виправлено інтеграцію викликів на деяких пристроях Android 14 +* Додано налаштування «Запрошення від незнайомців» From 9c0501099e55a43a26e922cf48fb5ea7302f1059 Mon Sep 17 00:00:00 2001 From: Outbreak2096 Date: Tue, 23 Apr 2024 00:26:24 +0000 Subject: [PATCH 29/57] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (64 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/zh_Hans/ --- fastlane/metadata/android/zh-CN/changelogs/4211004.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/zh-CN/changelogs/4211004.txt diff --git a/fastlane/metadata/android/zh-CN/changelogs/4211004.txt b/fastlane/metadata/android/zh-CN/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..53e308fcb00e7e859112553fbef3194aea502fd8 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* 修复某些 Android 14 设备上的呼叫集成 +* 添加了“来自陌生人的邀请”设置 From 501bbac2ee0d6703c810a55b4b5c42b749a1fd39 Mon Sep 17 00:00:00 2001 From: Waderasm Date: Tue, 23 Apr 2024 17:22:15 +0000 Subject: [PATCH 30/57] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/zh_Hant/ --- src/main/res/values-zh-rTW/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index 9c76586e8ec194b7a9ff704ce941ae26c0600d87..c6d67029a376706267a8958d4f47dde75763a3f4 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -1069,4 +1069,6 @@ 是否移除 %s 的書籤並存檔會話? 自動配色 頻道探索使用一個名為 <a href=https://search.jabber.network>search.jabber.network</a> 的第三方服務,<br><br>使用此功能會將您的 IP 位址和搜尋詞彙傳送至此服務。更多資訊請參見他們的 <a href=https://search.jabber.network/privacy>隱私權政策</a>。 + 來自陌生人的邀請 + 接受來自陌生人的群聊邀請 \ No newline at end of file From 801bdfa3e32e355027287e05d325557028235bdd Mon Sep 17 00:00:00 2001 From: Waderasm Date: Tue, 23 Apr 2024 20:36:23 +0000 Subject: [PATCH 31/57] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (64 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/zh_Hant/ --- fastlane/metadata/android/zh-TW/changelogs/42015.txt | 1 + fastlane/metadata/android/zh-TW/changelogs/42018.txt | 3 +++ fastlane/metadata/android/zh-TW/changelogs/42022.txt | 2 ++ fastlane/metadata/android/zh-TW/changelogs/42023.txt | 2 ++ fastlane/metadata/android/zh-TW/changelogs/42037.txt | 11 +++++++++++ fastlane/metadata/android/zh-TW/changelogs/42038.txt | 2 ++ fastlane/metadata/android/zh-TW/changelogs/42041.txt | 5 +++++ fastlane/metadata/android/zh-TW/changelogs/42042.txt | 2 ++ fastlane/metadata/android/zh-TW/changelogs/42043.txt | 1 + fastlane/metadata/android/zh-TW/changelogs/42044.txt | 3 +++ fastlane/metadata/android/zh-TW/changelogs/42046.txt | 1 + fastlane/metadata/android/zh-TW/changelogs/42059.txt | 2 ++ fastlane/metadata/android/zh-TW/changelogs/42060.txt | 1 + fastlane/metadata/android/zh-TW/changelogs/42061.txt | 1 + fastlane/metadata/android/zh-TW/changelogs/42062.txt | 1 + fastlane/metadata/android/zh-TW/changelogs/42065.txt | 1 + fastlane/metadata/android/zh-TW/changelogs/42068.txt | 2 ++ fastlane/metadata/android/zh-TW/changelogs/42072.txt | 3 +++ .../metadata/android/zh-TW/changelogs/4207704.txt | 3 +++ .../metadata/android/zh-TW/changelogs/4208104.txt | 4 ++++ .../metadata/android/zh-TW/changelogs/4208804.txt | 3 +++ .../metadata/android/zh-TW/changelogs/4209004.txt | 2 ++ .../metadata/android/zh-TW/changelogs/4209204.txt | 2 ++ .../metadata/android/zh-TW/changelogs/4209404.txt | 1 + .../metadata/android/zh-TW/changelogs/4210104.txt | 1 + .../metadata/android/zh-TW/changelogs/4210404.txt | 3 +++ .../metadata/android/zh-TW/changelogs/4210504.txt | 2 ++ .../metadata/android/zh-TW/changelogs/4210704.txt | 3 +++ .../metadata/android/zh-TW/changelogs/4210804.txt | 2 ++ .../metadata/android/zh-TW/changelogs/4210904.txt | 2 ++ .../metadata/android/zh-TW/changelogs/4211004.txt | 2 ++ 31 files changed, 74 insertions(+) create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42015.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42018.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42022.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42023.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42037.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42038.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42041.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42042.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42043.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42044.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42046.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42059.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42060.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42061.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42062.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42065.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42068.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/42072.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4207704.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4208104.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4208804.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4209004.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4209204.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4209404.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4210104.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4210404.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4210504.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4210704.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4210804.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4210904.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/4211004.txt diff --git a/fastlane/metadata/android/zh-TW/changelogs/42015.txt b/fastlane/metadata/android/zh-TW/changelogs/42015.txt new file mode 100644 index 0000000000000000000000000000000000000000..004c1806f6294aa14245b3bbe750aaa70b369642 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42015.txt @@ -0,0 +1 @@ +* 在音頻和視頻方面略有改善 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42018.txt b/fastlane/metadata/android/zh-TW/changelogs/42018.txt new file mode 100644 index 0000000000000000000000000000000000000000..64603c144dadd7fa8f88c205c34640494f03b8b2 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42018.txt @@ -0,0 +1,3 @@ +* 當遠程視頻與屏幕寬高比不匹配時顯示黑條 +* 提高搜索性能 +* 添加防止截屏的設置 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42022.txt b/fastlane/metadata/android/zh-TW/changelogs/42022.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9269a5bd4e01209446b83316a47aacb48f63520 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42022.txt @@ -0,0 +1,2 @@ +* 修復某些視頻無法壓縮的問題 +* 修復打開通知時罕見的崩潰問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42023.txt b/fastlane/metadata/android/zh-TW/changelogs/42023.txt new file mode 100644 index 0000000000000000000000000000000000000000..b260e0cf94d8f3d07a57d3bae39c508343850cb6 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42023.txt @@ -0,0 +1,2 @@ +* 修復渲染某些引用時的崩潰問題 +* 修復歡迎屏幕崩潰問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42037.txt b/fastlane/metadata/android/zh-TW/changelogs/42037.txt new file mode 100644 index 0000000000000000000000000000000000000000..13e3ef2aa30ff657274e9b463fea66967a8195ce --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42037.txt @@ -0,0 +1,11 @@ +版本 2.10.9 +* 進行音視頻通話時請求藍牙權限(如果您不使用藍牙耳機可以拒絕) +* 修復呼叫 Movim 時的錯誤 +* 修復群組聊天的顯示錯誤頭像的問題 +* 始終要求選擇退出電池優化 +* 在“x 個已連接賬號”通知上設置僅本地標誌 +* 修復與 Google 地圖分享位置插件的交互 +* 移除有關服務器費用的腳註 +* 將文件存儲在適合 Android 11 的位置 +* 網絡切換後嘗試重新連接通話 +* 在來電屏幕中顯示來電者 JID 和帳戶 JID diff --git a/fastlane/metadata/android/zh-TW/changelogs/42038.txt b/fastlane/metadata/android/zh-TW/changelogs/42038.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca9a447c3c3b643605933878606afad4652e965b --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42038.txt @@ -0,0 +1,2 @@ +* 修正了一些小錯誤 +* 恢復通過 JMP 和其他服務呼叫的能力(Playstore 版本) diff --git a/fastlane/metadata/android/zh-TW/changelogs/42041.txt b/fastlane/metadata/android/zh-TW/changelogs/42041.txt new file mode 100644 index 0000000000000000000000000000000000000000..f88ad5b5131a4aa5c738e8f53519bfffb466f4f3 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42041.txt @@ -0,0 +1,5 @@ +* 實現可擴展 SASL Profile、Bind 2.0 和 Fast,以加快重新連接速度 +* 實現通道綁定 +* 增加從音頻通話切換到視頻通話的功能 +* 增加刪除自己頭像的功能 +* 增加未接來電通知功能 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42042.txt b/fastlane/metadata/android/zh-TW/changelogs/42042.txt new file mode 100644 index 0000000000000000000000000000000000000000..19e92ff8645c1ac5fdb14d425dd496139d9a6c89 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42042.txt @@ -0,0 +1,2 @@ +* 修復僅支持 sm:2 的服務器上的重發循環 +* 僅當對方支持視頻時才顯示“切換到視頻” diff --git a/fastlane/metadata/android/zh-TW/changelogs/42043.txt b/fastlane/metadata/android/zh-TW/changelogs/42043.txt new file mode 100644 index 0000000000000000000000000000000000000000..29ae668a1f787ea29f9f89b0e39043ee9bd2add0 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42043.txt @@ -0,0 +1 @@ +* 修復了 P2P 文件傳輸中的缺陷 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42044.txt b/fastlane/metadata/android/zh-TW/changelogs/42044.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d7ef7f8287e3fdc3185bf5049b20b7b69b24ab7 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42044.txt @@ -0,0 +1,3 @@ +* 修復使用 SASL2 時重新發送消息的問題 +* 修復部分設備之間的黑屏問題 +* 修復空密碼崩潰問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42046.txt b/fastlane/metadata/android/zh-TW/changelogs/42046.txt new file mode 100644 index 0000000000000000000000000000000000000000..a302ae7ff1f3111d47d3f779650550b89302ded9 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42046.txt @@ -0,0 +1 @@ +* 整合 UnifiedPush 分發程序,以便將消息推送到其他支持 UnifiedPush 的應用程序,例如 Tusky 和 Fedilab diff --git a/fastlane/metadata/android/zh-TW/changelogs/42059.txt b/fastlane/metadata/android/zh-TW/changelogs/42059.txt new file mode 100644 index 0000000000000000000000000000000000000000..32a329bd637056925be33ffdca4ff687ad367348 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42059.txt @@ -0,0 +1,2 @@ +* 將 Target SDK 再次提升至 33 +* 修復支持 SASL2 且不支持內聯流管理的服務器上的問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42060.txt b/fastlane/metadata/android/zh-TW/changelogs/42060.txt new file mode 100644 index 0000000000000000000000000000000000000000..16b5141f9bede90021355dfedee1dbe2131d4ab7 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42060.txt @@ -0,0 +1 @@ +* 修復“q”被錯誤識別爲西裏爾字母的問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42061.txt b/fastlane/metadata/android/zh-TW/changelogs/42061.txt new file mode 100644 index 0000000000000000000000000000000000000000..c35ffeb50a1f8a87425bb6f3c429fbf0210984ab --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42061.txt @@ -0,0 +1 @@ +* 從 Google Play 版本中移除頻道探索功能 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42062.txt b/fastlane/metadata/android/zh-TW/changelogs/42062.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c6025be5d9a10007ff975e9a218fb6d440977ed --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42062.txt @@ -0,0 +1 @@ +* 禁止從文件管理器打開備份文件(.ceb) diff --git a/fastlane/metadata/android/zh-TW/changelogs/42065.txt b/fastlane/metadata/android/zh-TW/changelogs/42065.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6346f62a5eee7d5b8db1410bd1f04406622817f --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42065.txt @@ -0,0 +1 @@ +* 引入新的備份文件格式 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42068.txt b/fastlane/metadata/android/zh-TW/changelogs/42068.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d2fecdb3f027cf39bd7b6a550f551fb971216e0 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42068.txt @@ -0,0 +1,2 @@ +* 支持對話個別通知設置 +* 在 Android 10 上使用 opus 發送語音消息 diff --git a/fastlane/metadata/android/zh-TW/changelogs/42072.txt b/fastlane/metadata/android/zh-TW/changelogs/42072.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f84a4d0a12fae23c8ac6bee9aeffa5af87de0f6 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/42072.txt @@ -0,0 +1,3 @@ +* 將 libwebrtc 依賴項提升到 M117 並提升 libvpx +* 回到 AAC 語音消息 +* 支持應用程序個別語言設置 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4207704.txt b/fastlane/metadata/android/zh-TW/changelogs/4207704.txt new file mode 100644 index 0000000000000000000000000000000000000000..b455c5e1402dfbdbb74d1ee261e28220ef8f44fe --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4207704.txt @@ -0,0 +1,3 @@ +* 支持私有 DNS(DNS over TLS) +* 支持主題啟動器圖標 +* 修復在 Android 11+ 上分享文件時罕見的權限問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4208104.txt b/fastlane/metadata/android/zh-TW/changelogs/4208104.txt new file mode 100644 index 0000000000000000000000000000000000000000..bfeabda61e0efcffd34f7277b20919f614c83255 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4208104.txt @@ -0,0 +1,4 @@ +* 更容易訪問「顯示二維碼」 +* 支持 PEP Native Bookmarks +* 添加對 SDP 請求/響應模型的支持(由 SIP 網關使用) +* 將目標 API 提升到 Android 14 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4208804.txt b/fastlane/metadata/android/zh-TW/changelogs/4208804.txt new file mode 100644 index 0000000000000000000000000000000000000000..e79d703fc55d7df000cf154068783510da53c99b --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4208804.txt @@ -0,0 +1,3 @@ +* 支持通過 WebRTC 數據通道進行 P2P 文件傳輸 +* 修復 ejabberd 上 Bind 2.0 的互操作性問題 +* 捆綁適用於 Android <= 7 的 Let’s Encrypt 根證書 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4209004.txt b/fastlane/metadata/android/zh-TW/changelogs/4209004.txt new file mode 100644 index 0000000000000000000000000000000000000000..04c07d6464db84a2ece6a748b9c43aeea20837a3 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4209004.txt @@ -0,0 +1,2 @@ +* 修正了一些小錯誤 +* Quicksy 嚮導流程略有修改 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4209204.txt b/fastlane/metadata/android/zh-TW/changelogs/4209204.txt new file mode 100644 index 0000000000000000000000000000000000000000..792ee73cb9c228021d00a0db7b48d7e426051e6c --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4209204.txt @@ -0,0 +1,2 @@ +* 在 Play 商店版本(Quicksy 和 Conversations)上提供對“隱私政策”的更輕鬆訪問 +* 移除 Play 商店版本的 Conversations 上的通訊錄整合功能 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4209404.txt b/fastlane/metadata/android/zh-TW/changelogs/4209404.txt new file mode 100644 index 0000000000000000000000000000000000000000..22c8600901d1af35a352405a6995b4ef59d8b103 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4209404.txt @@ -0,0 +1 @@ +* 修復 2.13.1 中出現的小問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4210104.txt b/fastlane/metadata/android/zh-TW/changelogs/4210104.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e6d47b6de00ff563984187653a6e13fb39cf0a5 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4210104.txt @@ -0,0 +1 @@ +* 改進音頻/視頻通話與操作系統的整合 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4210404.txt b/fastlane/metadata/android/zh-TW/changelogs/4210404.txt new file mode 100644 index 0000000000000000000000000000000000000000..541a5023027a1574aee3bc2267f1a4b9d36d2a67 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4210404.txt @@ -0,0 +1,3 @@ +* 修復安卓 8 上的音頻/視頻通話 +* 修復新通話整合中的競態條件 +* 修復視頻壓縮問題 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4210504.txt b/fastlane/metadata/android/zh-TW/changelogs/4210504.txt new file mode 100644 index 0000000000000000000000000000000000000000..238c4b60035c75afc8ff9f6053f32a7125a6dcb3 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4210504.txt @@ -0,0 +1,2 @@ +* 恢復對 Android 6 和 Android 7 頻道探索的訪問 +* 改善失敗通話整合的日誌記錄 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4210704.txt b/fastlane/metadata/android/zh-TW/changelogs/4210704.txt new file mode 100644 index 0000000000000000000000000000000000000000..30d613e89e659ac1f1388f908ed7003abdbbc0e4 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4210704.txt @@ -0,0 +1,3 @@ +* 使用 Material 3 主題 +* 重新組織設置介面 +* 跨設備同步閱讀狀態 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4210804.txt b/fastlane/metadata/android/zh-TW/changelogs/4210804.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c727b051092d3715b0231e23810947ff763f98b --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4210804.txt @@ -0,0 +1,2 @@ +* 以圖標形式顯示訊息狀態 +* 爲訊息氣泡引入「大字體」設置 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4210904.txt b/fastlane/metadata/android/zh-TW/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..38b7f0ebc8e0d6af97c0625f05cf22b11e2ab697 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* 修復 Android 6/7 上的 Quicksy 註冊問題 +* 在通知通道上播放來電鈴聲 diff --git a/fastlane/metadata/android/zh-TW/changelogs/4211004.txt b/fastlane/metadata/android/zh-TW/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..5381a3950213bc42df70672f173871ca2b3c422b --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* 修復某些 Android 14 設備上的通話整合 +* 添加了「來自陌生人的邀請」設置 From 86befddc6a0043fa29de1c3ae36e2cc40a867591 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 24 Apr 2024 12:01:29 +0000 Subject: [PATCH 32/57] Translated using Weblate (Spanish) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/es/ --- src/main/res/values-es/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index d09dc3f11c5943c879ce5c7dad79343924177664..39e794bcbdae0ed10e57547033eeb136e46118f4 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -1078,4 +1078,6 @@ ¡No se ha seleccionado ningún certificado de cliente! Tamaño de archivo, Compresión de imagen, Calidad de vídeo Mostrar el contenido de la aplicación en el conmutador de aplicaciones y permitir la realización de capturas de pantalla + Invitaciones de extraños + Aceptar invitaciones a chats grupales de extraños \ No newline at end of file From 02aa6fccf8f79595e67092241e623e8b3f0e2528 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 24 Apr 2024 08:33:16 +0000 Subject: [PATCH 33/57] Translated using Weblate (Polish) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/pl/ --- src/main/res/values-pl/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index 26a5eb13e8144cc66150936000047904f0f5abb0..a65cb8ade2483b6c09d6184ade7889108536dbe8 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -65,7 +65,7 @@ Zapisz Ok %1$s uległo awarii - Używając swojego konta XMPP do wysyłania śladów stosu pomagasz w rozwoju %1$s. + Używanie Twojego konta XMPP do wysyłania śladów stosu pomaga w ciągłym rozwoju %1$s. Wyślij teraz Nie pytaj ponownie Nie można połączyć z kontem @@ -122,7 +122,7 @@ Czas bez powiadomień Długość czasu kiedy powiadomienia są uśpione po wykryciu aktywności na jednym z twoich innych urządzeń. Zaawansowane - Wysyłając nam ślady stosu pomagasz w rozwoju + Wysyłając ślady stosu pomagasz w rozwoju Potwierdzenia wiadomości Zezwól na wysyłanie do osób z twojej listy kontaktów informacji o tym, kiedy otrzymałeś i przeczytałeś wiadomość od nich Zapobiegaj zrzutom ekranu @@ -527,9 +527,9 @@ Tylko duże obrazki Optymalizacje zużycia baterii włączone Twoje urządzenie ma włączone agresywne oszczędzanie baterii przez co %1$s może odbierać wiadomości z opóźnieniem.\nZalecamy wyłączenie tych optymalizacji. - Twoje urządzenie stosuje agresywne oszczędzanie baterii, przez co %1$s może odbierać wiadomości z opóźnieniem lub je tracić. + Twoje urządzenie stosuje agresywne oszczędzanie baterii, przez co %1$s może odbierać wiadomości z opóźnieniem lub nawet je tracić. \n -\nZostaniesz poproszony o jego wyłączenie. +\nZostaniesz poproszony o wyłączenie tej funkcjonalności. Wyłącz Zaznaczony obszar jest zbyt duży (Brak aktywynych kont) @@ -1048,7 +1048,7 @@ Archiwizuj rozmowę Nowa rozmowa Archiwizuj tę rozmowę - Kolorowe bańki rozmowy + Kolorowe dymki rozmowy Kod kreskowy nie zawiera odcisków palca dla tej rozmowy. Powiązane rozmowy zarchiwizowane. Rozpocznij rozmowę @@ -1091,7 +1091,7 @@ Aplikacja Interakcja Na urządzeniu - Zwiększ rozmiar czcionki w bańkach wiadomości + Zwiększ rozmiar czcionki w dymkach wiadomości Różne kolory tła dla wysłanych i odebranych wiadomości Wyślij zaszyfrowaną wiadomość Dołącz do rozmowy From d99a327b99af7a0b28588d93c59458a8d392a4e2 Mon Sep 17 00:00:00 2001 From: licaon-kter Date: Thu, 25 Apr 2024 09:10:09 +0000 Subject: [PATCH 34/57] Translated using Weblate (Romanian) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ro/ --- src/main/res/values-ro-rRO/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index a03ca93935911033b58e68bb345d44c2b5f86766..75a662053b851d410ee9eba9f812e7fffbbf59c6 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -1016,7 +1016,7 @@ V-ați deconectat de la acest cont Conectați-vă Ascunde notificare - Persoana de contact utilizează dispozitive neverificate. Scanați codul QR al acestora pentru a efectua verificarea și a împiedica atacurile MITM active. + Persoana de contact utilizează dispozitive neverificate. Scanați codul QR al acesteia pentru a efectua verificarea și a împiedica atacurile MITM active. Deconectare Deconectat Folosiți dispozitive neverificate. Scanați codul QR pe celelalte dispozitive pentru a efectua verificarea și a împiedica atacurile MITM active. From 1198669724274f3a4ddfb42210815e18453d9a10 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 24 Apr 2024 08:35:39 +0000 Subject: [PATCH 35/57] Translated using Weblate (Polish) Currently translated at 100.0% (9 of 9 strings) Translation: Conversations/Android App (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-quicksy/pl/ --- src/quicksy/res/values-pl/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quicksy/res/values-pl/strings.xml b/src/quicksy/res/values-pl/strings.xml index d94b0c7750eb36d77ecbb2162c694b42fe5ba038..fb4d545992b89c651f0a0806d53347cb1e87800c 100644 --- a/src/quicksy/res/values-pl/strings.xml +++ b/src/quicksy/res/values-pl/strings.xml @@ -1,7 +1,7 @@ Czas, przez który Quicksy jest cicho po zobaczeniu aktywności na innym urządzeniu - Wysyłając nam ślady stosu pomagasz w rozwoju Quicksy + Wysyłając ślady stosu pomagasz w ciągłym rozwoju Quicksy Powiadom kontakty o tym że używasz Quicksy Aby otrzymywać powiadomienia nawet kiedy ekran jest wyłączony musisz dodać Quicksy do listy chronionych aplikacji. Obrazek profilowy Quicksy From 0ad7b017c990088ef42e7e45d1f195e77b1e0ad0 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 24 Apr 2024 12:02:25 +0000 Subject: [PATCH 36/57] Translated using Weblate (Spanish) Currently translated at 100.0% (64 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/es/ --- fastlane/metadata/android/es-ES/changelogs/4211004.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/es-ES/changelogs/4211004.txt diff --git a/fastlane/metadata/android/es-ES/changelogs/4211004.txt b/fastlane/metadata/android/es-ES/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..a87e7d85c44d4beb765818aaf6f708784de74739 --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* arreglar la integración de llamadas en algunos dispositivos con Android 14 +* Introducir la configuración 'Invitaciones de extraños' From 37b3e2025e5c2d781dc874f82e8c924a99ee3559 Mon Sep 17 00:00:00 2001 From: fuzfyy2 Date: Thu, 25 Apr 2024 08:03:10 +0000 Subject: [PATCH 37/57] Translated using Weblate (Turkish) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/tr/ --- .../android/tr-TR/full_description.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt b/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt index 8530e5fb265048c095e3ae37a81bd00cd1111ce2..889d502e08270429fac00e4300d91ee3c6f61d81 100644 --- a/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt +++ b/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt @@ -1,3 +1,39 @@ Kullanımı kolay, güvenilir, pil ömrü dostu. Resimler, gruplar ve uçtan uca şifreleme için yerleşik destek. Tasarım ilkeleri: + +* Gizlilik ve güvenlikten tasarruf etmeden olabildiğince iyi görünümlü ve kolay kullanımlı olmak +* Halihazırda var olan, köklü protokollere dayanmak +* Bir Google hesabına, özellikle Google Bulut Mesajlaşması (GCM)'e, gerek duymamak +* Olabildiğince az izine gerek duymak + +Özellikler: + +* OMEMO veya OpenPGP ile uçtan uca şifreleme +* Fotoğraf gönderme ve alma +* Şifrelenmiş görüntülü ve sesli aramalar (DTLS-SRTP) +* Android tasarım standartlarına uyan öğrenmesi kolay arayüz +* Kişileriniz için profil fotoğrafları / Avatarlar +* Masaüstü uygulamasıyla senkronizasyon +* Konferanslar (yer imi desteği ile) +* Kişiler listesiyle entegrasyon +* Birden fazla hesap / Birleşik gelen kutusu +* Pil ömrüne çok düşük etki + +Conversations, kolayca ve ücretsiz olarak conversations.im sunucusunda hesap oluşturmanıza olanak tanır. Conversations başka herhangi bir XMPP sunucusuyla da çalışır. Çoğu XMPP sunucusu gönüllüler tarafından işletilir ve ücretsizdir. + +XMPP Özellikleri: + +Conversations var olan bütün XMPP sunucularıyla kullanılabilir. Ancak XMPP, eklentiler ile genişletilebilen bir protokoldür. Bu eklentiler XEP'ler olarak standardize edilmiştir. Conversations kullanıcı deneyimini iyileştirmek için bu eklentilerden birkaçını destekler. Kullandığınız XMPP sunucusu bu eklentileri desteklemiyor olabilir. Bu yüzden Conversations'tan en iyi şekilde faydalanmak için bu eklentileri destekleyen bir sunucuya geçmeli veya, daha da iyisi, siz ve arkadaşlarınız için kendi XMPP sunucunuzu kurmalısınız. + +Şimdilik bu XEP'ler: + +* XEP-0065: SOCKS5 Bytestreams (mod_proxy65). İki taraf da bir güvenlik duvarı (NAT) arkasında ise dosya aktarımı için kullanılacaktır. +* XEP-0163: Avatarlar için Kişisel Olay Protokolü (Personal Eventing Protocol) +* XEP-0191: Engelleme komutu - Spam atanları ve kişilerinizi listenizden kaldırmadan engellemenizi sağlar. +* XEP-0198: Akış Kontrolü (Stream Management) - XMPP'yi ve altındaki TCP bağlantısını küçük çaplı bağlantı kopmalarına karşı korur. +* XEP-0280: Mesaj Karbonları - Mesajlarınızı masaüstü uygulamasıyla senkronize ederek cihazlarınız arasında kesintisiz geçiş yapmanızı sağlar. +* XEP-0237: Roster Versioning (Liste Sürüm Takibi) - Zayıf mobil ağlarda bant aralığından tasarruf etmek amacıyla. +* XEP-0313: Mesaj Arşivi Yönetimi - Çevrimdışı olduğunuzda bile mesaj almaya devam edebilmeniz için mesajlarınızı sunucuyla senkronize eder. +* XEP-0352: İstemci Durum Bildirimi - Conversations'un arkaplanda çalıştığını sunucuya bildir. Sunucunun önemsiz paketleri saklayarak veriden tasarruf etmesini sağlar. +* XEP-0363: HTTP Dosya Yükleme - Konferanslarla ve çevrimdışı kişilerle dosya paylaşabilmenizi sağlar. Sunucunuzda ek bileşen gerektirir. From b185b75242faf365b38297b10c3bc1df0841b556 Mon Sep 17 00:00:00 2001 From: fuzfyy2 Date: Thu, 25 Apr 2024 08:39:18 +0000 Subject: [PATCH 38/57] Translated using Weblate (Turkish) Currently translated at 50.0% (1 of 2 strings) Translation: Conversations/App Store Metadata (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-quicksy/tr/ --- .../fastlane/metadata/android/tr-TR/short_description.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/quicksy/fastlane/metadata/android/tr-TR/short_description.txt diff --git a/src/quicksy/fastlane/metadata/android/tr-TR/short_description.txt b/src/quicksy/fastlane/metadata/android/tr-TR/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ce53527e57cca8aa38fb86b68478e1364501c1d --- /dev/null +++ b/src/quicksy/fastlane/metadata/android/tr-TR/short_description.txt @@ -0,0 +1 @@ +Kolay giriş ve keşfetmeli Jabber/XMPP From 8856c048d6e89dfd77f3590b0f3075594a00e5aa Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 26 Apr 2024 09:43:00 +0200 Subject: [PATCH 39/57] exclude all realme devices up to Android 11 --- .../services/CallIntegration.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/CallIntegration.java b/src/main/java/eu/siacs/conversations/services/CallIntegration.java index 5700a7bffe095d0646233438526a286b47080ed1..80fd42021e248ea0894d428d94533eabebe9cad2 100644 --- a/src/main/java/eu/siacs/conversations/services/CallIntegration.java +++ b/src/main/java/eu/siacs/conversations/services/CallIntegration.java @@ -38,15 +38,8 @@ public class CallIntegration extends Connection { private static final List BROKEN_DEVICE_MODELS = Arrays.asList( - "OnePlus6", // OnePlus 6 (Android 8.1-11) Device is buggy and always starts the - // operating system call screen even though we want to be self - // managed - "RMX1921", // Realme XT (Android 9-10) shows "Call not sent" dialog - "RMX1971", // Realme 5 Pro (Android 9-11), show "Call not sent" dialog - "RMX1973", // Realme 5 Pro (see above), - "RMX2071", // Realme X50 Pro 5G (Call not sent) - "RMX2075L1", // Realme X50 Pro 5G - "RMX2076" // Realme X50 Pro 5G + "OnePlus6" // OnePlus 6 (Android 8.1-11) Device is buggy and always starts the + // OS call screen even though we want to be self managed ); public static final int DEFAULT_TONE_VOLUME = 60; @@ -491,7 +484,7 @@ public class CallIntegration extends Connection { public static boolean selfManaged(final Context context) { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && hasSystemFeature(context) - && !BROKEN_DEVICE_MODELS.contains(Build.DEVICE); + && isDeviceModelSupported(); } public static boolean hasSystemFeature(final Context context) { @@ -504,6 +497,18 @@ public class CallIntegration extends Connection { } } + private static boolean isDeviceModelSupported() { + if (BROKEN_DEVICE_MODELS.contains(Build.DEVICE)) { + return false; + } + // all Realme devices at least up to and including Android 11 are broken + if ("realme".equalsIgnoreCase(Build.MANUFACTURER) + && Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { + return false; + } + return true; + } + public static boolean notSelfManaged(final Context context) { return !selfManaged(context); } From 073a445a6dedb96f5bc88f4e4cb4812701eaf07f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 29 Apr 2024 08:26:25 +0200 Subject: [PATCH 40/57] use onSurface as link color --- .../ui/adapter/MessageAdapter.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index f3cba4f3d270bf19bf97ff512b1aa9a9ead07706..c33e7765516ac8fcbaf451c8844642f29c054f6b 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -79,6 +79,8 @@ import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.mam.MamReference; import java.net.URI; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; @@ -565,10 +567,10 @@ public class MessageAdapter extends ArrayAdapter { } StylingHelper.format(body, viewHolder.messageBody.getCurrentTextColor()); + MyLinkify.addLinks(body, true); if (highlightedTerm != null) { StylingHelper.highlight(viewHolder.messageBody, body, highlightedTerm); } - MyLinkify.addLinks(body, true); viewHolder.messageBody.setAutoLinkMask(0); viewHolder.messageBody.setText(body); viewHolder.messageBody.setMovementMethod(ClickableMovementMethod.getInstance()); @@ -1169,7 +1171,15 @@ public class MessageAdapter extends ArrayAdapter { } public static void setTextColor(final TextView textView, final BubbleColor bubbleColor) { - textView.setTextColor(bubbleToOnSurfaceColor(textView, bubbleColor)); + final var color = bubbleToOnSurfaceColor(textView, bubbleColor); + textView.setTextColor(color); + if (BubbleColor.SURFACES.contains(bubbleColor)) { + textView.setLinkTextColor( + MaterialColors.getColor( + textView, com.google.android.material.R.attr.colorPrimary)); + } else { + textView.setLinkTextColor(color); + } } private static void setTextSize(final TextView textView, final boolean largeFont) { @@ -1185,7 +1195,7 @@ public class MessageAdapter extends ArrayAdapter { private static @ColorInt int bubbleToOnSurfaceVariant( final View view, final BubbleColor bubbleColor) { final @AttrRes int colorAttributeResId; - if (bubbleColor == BubbleColor.SURFACE_HIGH || bubbleColor == BubbleColor.SURFACE) { + if (BubbleColor.SURFACES.contains(bubbleColor)) { colorAttributeResId = com.google.android.material.R.attr.colorOnSurfaceVariant; } else { colorAttributeResId = bubbleToOnSurface(bubbleColor); @@ -1219,7 +1229,10 @@ public class MessageAdapter extends ArrayAdapter { PRIMARY, SECONDARY, TERTIARY, - WARNING + WARNING; + + private static final Collection SURFACES = + Arrays.asList(BubbleColor.SURFACE, BubbleColor.SURFACE_HIGH); } private static class BubbleDesign { From 0b673ef1ab7bccca3f9af5cf36bbd201e68aa83a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 2 May 2024 10:56:39 +0200 Subject: [PATCH 41/57] set message input cursor color to text color --- src/main/res/drawable/cursor_on_tertiary_container.xml | 6 ++++++ src/main/res/layout/fragment_conversation.xml | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/main/res/drawable/cursor_on_tertiary_container.xml diff --git a/src/main/res/drawable/cursor_on_tertiary_container.xml b/src/main/res/drawable/cursor_on_tertiary_container.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a86446ec6cdbc6458c93d502f6b9f6ca7d5d813 --- /dev/null +++ b/src/main/res/drawable/cursor_on_tertiary_container.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/res/layout/fragment_conversation.xml b/src/main/res/layout/fragment_conversation.xml index 34a2b969e4b72b31bdc3ab34ffef84b2a0856132..cfb280eb5b1b2784700a1e2ad58e08401fcd34ca 100644 --- a/src/main/res/layout/fragment_conversation.xml +++ b/src/main/res/layout/fragment_conversation.xml @@ -100,9 +100,10 @@ android:inputType="textShortMessage|textMultiLine|textCapSentences" android:maxLines="8" android:minHeight="32dp" + android:minLines="1" android:textColor="?colorOnTertiaryContainer" android:textColorHint="@color/hint_on_tertiary_container" - android:minLines="1"> + android:textCursorDrawable="@drawable/cursor_on_tertiary_container"> From 60e6841578a1b2752638d83aaab8c772360d7057 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 2 May 2024 10:58:06 +0200 Subject: [PATCH 42/57] ignore quickLog startService exception --- .../services/UnifiedPushDistributor.java | 38 ++++++++++++------- .../conversations/utils/Compatibility.java | 10 +---- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java index b47a61a531fdc5b4afcadd2f540acf8b803000c3..f51de2432ab3d0375fd330a7691261d168c498e4 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java @@ -35,9 +35,9 @@ public class UnifiedPushDistributor extends BroadcastReceiver { public static final String ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER"; public static final String ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER"; - // connector actions (these are actions used for distributor->connector broadcasts) - public static final String ACTION_UNREGISTERED = "org.unifiedpush.android.connector.UNREGISTERED"; + public static final String ACTION_UNREGISTERED = + "org.unifiedpush.android.connector.UNREGISTERED"; public static final String ACTION_BYTE_MESSAGE = "org.unifiedpush.android.distributor.feature.BYTES_MESSAGE"; public static final String ACTION_REGISTRATION_FAILED = @@ -69,7 +69,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver { final Parcelable appVerification = intent.getParcelableExtra("app"); if (appVerification instanceof PendingIntent pendingIntent) { application = pendingIntent.getIntentSender().getCreatorPackage(); - Log.d(Config.LOGTAG,"received application name via pending intent "+ application); + Log.d(Config.LOGTAG, "received application name via pending intent " + application); } else { application = intent.getStringExtra("application"); } @@ -79,10 +79,10 @@ public class UnifiedPushDistributor extends BroadcastReceiver { switch (Strings.nullToEmpty(action)) { case ACTION_REGISTER -> register(context, application, instance, features, messenger); case ACTION_UNREGISTER -> unregister(context, instance); - case Intent.ACTION_PACKAGE_FULLY_REMOVED -> - unregisterApplication(context, intent.getData()); - default -> - Log.d(Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action); + case Intent.ACTION_PACKAGE_FULLY_REMOVED -> unregisterApplication( + context, intent.getData()); + default -> Log.d( + Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action); } } @@ -111,7 +111,11 @@ public class UnifiedPushDistributor extends BroadcastReceiver { Log.d( Config.LOGTAG, "successfully created UnifiedPush entry. waking up XmppConnectionService"); - quickLog(context, String.format("successfully registered %s (token = %s) for UnifiedPushed", application, instance)); + quickLog( + context, + String.format( + "successfully registered %s (token = %s) for UnifiedPushed", + application, instance)); final Intent serviceIntent = new Intent(context, XmppConnectionService.class); serviceIntent.setAction(XmppConnectionService.ACTION_RENEW_UNIFIED_PUSH_ENDPOINTS); serviceIntent.putExtra("instance", instance); @@ -140,7 +144,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver { } } else { if (messenger instanceof Messenger m) { - sendRegistrationFailed(m,"Your application is not registered to receive messages"); + sendRegistrationFailed(m, "Your application is not registered to receive messages"); } Log.d( Config.LOGTAG, @@ -157,7 +161,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver { try { messenger.send(message); } catch (final RemoteException e) { - Log.d(Config.LOGTAG,"unable to tell messenger of failed registration",e); + Log.d(Config.LOGTAG, "unable to tell messenger of failed registration", e); } } @@ -177,7 +181,11 @@ public class UnifiedPushDistributor extends BroadcastReceiver { } final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(context); if (unifiedPushDatabase.deleteInstance(instance)) { - quickLog(context, String.format("successfully unregistered token %s from UnifiedPushed (application requested unregister)", instance)); + quickLog( + context, + String.format( + "successfully unregistered token %s from UnifiedPushed (application requested unregister)", + instance)); Log.d(Config.LOGTAG, "successfully removed " + instance + " from UnifiedPush"); // TODO send UNREGISTERED broadcast back to app?! } @@ -192,7 +200,11 @@ public class UnifiedPushDistributor extends BroadcastReceiver { Log.d(Config.LOGTAG, "app " + application + " has been removed from the system"); final UnifiedPushDatabase database = UnifiedPushDatabase.getInstance(context); if (database.deleteApplication(application)) { - quickLog(context, String.format("successfully removed %s from UnifiedPushed (ACTION_PACKAGE_FULLY_REMOVED)", application)); + quickLog( + context, + String.format( + "successfully removed %s from UnifiedPushed (ACTION_PACKAGE_FULLY_REMOVED)", + application)); Log.d(Config.LOGTAG, "successfully removed " + application + " from UnifiedPush"); } } @@ -210,6 +222,6 @@ public class UnifiedPushDistributor extends BroadcastReceiver { final Intent intent = new Intent(context, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_QUICK_LOG); intent.putExtra("message", message); - context.startService(intent); + Compatibility.startService(context, intent); } } diff --git a/src/main/java/eu/siacs/conversations/utils/Compatibility.java b/src/main/java/eu/siacs/conversations/utils/Compatibility.java index a6e91593ea2bf4df491f0dca173ece4d933b69b9..eaf89d1212ceb941f19ba53031158a79a6bbcc99 100644 --- a/src/main/java/eu/siacs/conversations/utils/Compatibility.java +++ b/src/main/java/eu/siacs/conversations/utils/Compatibility.java @@ -12,8 +12,6 @@ import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.os.Build; import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceCategory; import android.preference.PreferenceManager; import android.util.Log; @@ -26,10 +24,6 @@ import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - public class Compatibility { public static boolean hasStoragePermission(final Context context) { @@ -100,7 +94,7 @@ public class Compatibility { } - public static void startService(Context context, Intent intent) { + public static void startService(final Context context, final Intent intent) { try { if (Compatibility.runsAndTargetsTwentySix(context)) { intent.putExtra(EXTRA_NEEDS_FOREGROUND_SERVICE, true); @@ -108,7 +102,7 @@ public class Compatibility { } else { context.startService(intent); } - } catch (RuntimeException e) { + } catch (final RuntimeException e) { Log.d( Config.LOGTAG, context.getClass().getSimpleName() + " was unable to start service"); From cbd8fb3488c91de9f942632ba9e5438747215e7c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 2 May 2024 10:58:40 +0200 Subject: [PATCH 43/57] guard unregister phone account by system feature check --- .../siacs/conversations/services/XmppConnectionService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index f67a15d3917eea9f527e22533683598c8386f4f1..b12eaffff0b5b67db989528ef1e2c4bf54cc10b3 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2751,7 +2751,9 @@ public class XmppConnectionService extends Service { }; mDatabaseWriterExecutor.execute(runnable); this.accounts.remove(account); - CallIntegrationConnectionService.unregisterPhoneAccount(this, account); + if (CallIntegration.hasSystemFeature(this)) { + CallIntegrationConnectionService.unregisterPhoneAccount(this, account); + } this.mRosterSyncTaskManager.clear(account); updateAccountUi(); mNotificationService.updateErrorNotification(); From 45b9c4dcc9f3fd0acacf1993e8248ede213773d4 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 2 May 2024 19:12:39 +0200 Subject: [PATCH 44/57] refactor ExportBackupService to worker --- build.gradle | 1 + .../services/ImportBackupService.java | 3 +- src/main/AndroidManifest.xml | 6 +- .../ui/adapter/MediaAdapter.java | 4 +- .../settings/BackupSettingsFragment.java | 166 +++++ .../settings/MainSettingsFragment.java | 63 +- .../settings/SecuritySettingsFragment.java | 24 +- .../settings/XmppPreferenceFragment.java | 30 +- .../siacs/conversations/utils/MimeUtils.java | 4 +- .../siacs/conversations/utils/UIHelper.java | 7 +- .../ExportBackupWorker.java} | 565 +++++++++--------- .../res/drawable/ic_calendar_month_24dp.xml | 12 + src/main/res/values/arrays.xml | 7 + src/main/res/values/strings.xml | 3 + src/main/res/xml/preferences_backup.xml | 20 + src/main/res/xml/preferences_main.xml | 7 +- 16 files changed, 549 insertions(+), 373 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/ui/fragment/settings/BackupSettingsFragment.java rename src/main/java/eu/siacs/conversations/{services/ExportBackupService.java => worker/ExportBackupWorker.java} (51%) create mode 100644 src/main/res/drawable/ic_calendar_month_24dp.xml create mode 100644 src/main/res/xml/preferences_backup.xml diff --git a/build.gradle b/build.gradle index de803bbfcb7aa14ebe0b62724d78ed08e69f6093..700fd54e3ea60e97420a728fc9834f5d927469fe 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,7 @@ dependencies { implementation "androidx.preference:preference:1.2.1" implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.google.android.material:material:1.11.0' + implementation 'androidx.work:work-runtime:2.9.0' implementation "androidx.emoji2:emoji2:1.4.0" freeImplementation "androidx.emoji2:emoji2-bundled:1.4.0" diff --git a/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java b/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java index 4c7387200e56f7a78eb4d06b1ceef2e01b13ee9e..17c76d167d3b7e1fdb22096ec4403eaa5f829d2d 100644 --- a/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java +++ b/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java @@ -37,6 +37,7 @@ import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.ui.ManageAccountActivity; import eu.siacs.conversations.utils.BackupFileHeader; import eu.siacs.conversations.utils.SerialSingleThreadExecutor; +import eu.siacs.conversations.worker.ExportBackupWorker; import eu.siacs.conversations.xmpp.Jid; import org.bouncycastle.crypto.engines.AESEngine; @@ -273,7 +274,7 @@ public class ImportBackupService extends Service { return false; } - final byte[] key = ExportBackupService.getKey(password, backupFileHeader.getSalt()); + final byte[] key = ExportBackupWorker.getKey(password, backupFileHeader.getSalt()); final AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); cipher.init( diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index fa89034ae25f7d3afd3e0a1f61e0cc77f86180c3..3d0ce91b02128a98139aee28d4b730b80850928b 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -116,9 +116,9 @@ + android:name="androidx.work.impl.foreground.SystemForegroundService" + android:foregroundServiceType="dataSync" + tools:node="merge" /> requestStorageForBackupLauncher = + registerForActivityResult( + new ActivityResultContracts.RequestPermission(), + isGranted -> { + if (isGranted) { + startOneOffBackup(); + } else { + Toast.makeText( + requireActivity(), + getString( + R.string.no_storage_permission, + getString(R.string.app_name)), + Toast.LENGTH_LONG) + .show(); + } + }); + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_backup, rootKey); + final var createOneOffBackup = findPreference(CREATE_ONE_OFF_BACKUP); + final ListPreference recurringBackup = findPreference(RECURRING_BACKUP); + final var backupDirectory = findPreference("backup_directory"); + if (createOneOffBackup == null || recurringBackup == null || backupDirectory == null) { + throw new IllegalStateException( + "The preference resource file is missing some preferences"); + } + backupDirectory.setSummary( + getString( + R.string.pref_create_backup_summary, + FileBackend.getBackupDirectory(requireContext()).getAbsolutePath())); + createOneOffBackup.setOnPreferenceClickListener(this::onBackupPreferenceClicked); + final int[] choices = getResources().getIntArray(R.array.recurring_backup_values); + final CharSequence[] entries = new CharSequence[choices.length]; + final CharSequence[] entryValues = new CharSequence[choices.length]; + for (int i = 0; i < choices.length; ++i) { + entryValues[i] = String.valueOf(choices[i]); + entries[i] = timeframeValueToName(requireContext(), choices[i]); + } + recurringBackup.setEntries(entries); + recurringBackup.setEntryValues(entryValues); + recurringBackup.setSummaryProvider(new TimeframeSummaryProvider()); + } + + @Override + protected void onSharedPreferenceChanged(@NonNull String key) { + super.onSharedPreferenceChanged(key); + if (RECURRING_BACKUP.equals(key)) { + final var sharedPreferences = getPreferenceManager().getSharedPreferences(); + if (sharedPreferences == null) { + return; + } + final Long recurringBackupInterval = + Longs.tryParse( + Strings.nullToEmpty( + sharedPreferences.getString(RECURRING_BACKUP, null))); + if (recurringBackupInterval == null) { + return; + } + Log.d( + Config.LOGTAG, + "recurring backup interval changed to: " + recurringBackupInterval); + final var workManager = WorkManager.getInstance(requireContext()); + if (recurringBackupInterval <= 0) { + workManager.cancelUniqueWork(RECURRING_BACKUP); + } else { + final Constraints constraints = + new Constraints.Builder() + .setRequiresBatteryNotLow(true) + .setRequiresStorageNotLow(true) + .build(); + + final PeriodicWorkRequest periodicWorkRequest = + new PeriodicWorkRequest.Builder( + ExportBackupWorker.class, + recurringBackupInterval, + TimeUnit.SECONDS) + .setConstraints(constraints) + .setInputData( + new Data.Builder() + .putBoolean("recurring_backup", true) + .build()) + .build(); + workManager.enqueueUniquePeriodicWork( + RECURRING_BACKUP, ExistingPeriodicWorkPolicy.UPDATE, periodicWorkRequest); + } + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.backup); + } + + private boolean onBackupPreferenceClicked(final Preference preference) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission( + requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + requestStorageForBackupLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } else { + startOneOffBackup(); + } + } else { + startOneOffBackup(); + } + return true; + } + + private void startOneOffBackup() { + final OneTimeWorkRequest exportBackupWorkRequest = + new OneTimeWorkRequest.Builder(ExportBackupWorker.class) + .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) + .build(); + WorkManager.getInstance(requireContext()) + .enqueueUniqueWork( + CREATE_ONE_OFF_BACKUP, ExistingWorkPolicy.KEEP, exportBackupWorkRequest); + final MaterialAlertDialogBuilder builder = + new MaterialAlertDialogBuilder(requireActivity()); + builder.setMessage(R.string.backup_started_message); + builder.setPositiveButton(R.string.ok, null); + builder.create().show(); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/MainSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/MainSettingsFragment.java index 049523aa566dfebae1ddca8fe434d9dab628376c..4ab8ade3ceb472b2762017306aacda450ab2e82c 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/MainSettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/MainSettingsFragment.java @@ -1,63 +1,27 @@ package eu.siacs.conversations.ui.fragment.settings; -import android.Manifest; -import android.content.Intent; -import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.widget.Toast; -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.base.Strings; import eu.siacs.conversations.BuildConfig; import eu.siacs.conversations.R; -import eu.siacs.conversations.persistance.FileBackend; -import eu.siacs.conversations.services.ExportBackupService; public class MainSettingsFragment extends PreferenceFragmentCompat { - private static final String CREATE_BACKUP = "create_backup"; - - private final ActivityResultLauncher requestStorageForBackupLauncher = - registerForActivityResult( - new ActivityResultContracts.RequestPermission(), - isGranted -> { - if (isGranted) { - startBackup(); - } else { - Toast.makeText( - requireActivity(), - getString( - R.string.no_storage_permission, - getString(R.string.app_name)), - Toast.LENGTH_LONG) - .show(); - } - }); - @Override public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { setPreferencesFromResource(R.xml.preferences_main, rootKey); final var about = findPreference("about"); final var connection = findPreference("connection"); - final var backup = findPreference(CREATE_BACKUP); - if (about == null || connection == null || backup == null) { + if (about == null || connection == null) { throw new IllegalStateException( "The preference resource file is missing some preferences"); } - backup.setSummary( - getString( - R.string.pref_create_backup_summary, - FileBackend.getBackupDirectory(requireContext()).getAbsolutePath())); - backup.setOnPreferenceClickListener(this::onBackupPreferenceClicked); about.setTitle(getString(R.string.title_activity_about_x, BuildConfig.APP_NAME)); about.setSummary( String.format( @@ -73,31 +37,6 @@ public class MainSettingsFragment extends PreferenceFragmentCompat { } } - private boolean onBackupPreferenceClicked(final Preference preference) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - if (ContextCompat.checkSelfPermission( - requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - requestStorageForBackupLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE); - } else { - startBackup(); - } - } else { - startBackup(); - } - return true; - } - - private void startBackup() { - ContextCompat.startForegroundService( - requireContext(), new Intent(requireContext(), ExportBackupService.class)); - final MaterialAlertDialogBuilder builder = - new MaterialAlertDialogBuilder(requireActivity()); - builder.setMessage(R.string.backup_started_message); - builder.setPositiveButton(R.string.ok, null); - builder.create().show(); - } - @Override public void onStart() { super.onStart(); diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java index 2890db7ab57c20ee33881d58a46585f64f382fd9..0ccf2679e17d3069093148d73ba31af3dba127fc 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java @@ -1,6 +1,5 @@ package eu.siacs.conversations.ui.fragment.settings; -import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.widget.Toast; @@ -13,13 +12,11 @@ import androidx.preference.Preference; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.base.Strings; -import com.google.common.primitives.Ints; import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.OmemoSetting; import eu.siacs.conversations.services.MemorizingTrustManager; -import eu.siacs.conversations.utils.TimeFrameUtils; import java.security.KeyStoreException; import java.util.ArrayList; @@ -44,20 +41,13 @@ public class SecuritySettingsFragment extends XmppPreferenceFragment { final CharSequence[] entryValues = new CharSequence[choices.length]; for (int i = 0; i < choices.length; ++i) { entryValues[i] = String.valueOf(choices[i]); - entries[i] = messageDeletionValueToName(requireContext(), choices[i]); + entries[i] = timeframeValueToName(requireContext(), choices[i]); } automaticMessageDeletion.setEntries(entries); automaticMessageDeletion.setEntryValues(entryValues); - automaticMessageDeletion.setSummaryProvider(new MessageDeletionSummaryProvider()); + automaticMessageDeletion.setSummaryProvider(new TimeframeSummaryProvider()); } - private static String messageDeletionValueToName(final Context context, final int value) { - if (value == 0) { - return context.getString(R.string.never); - } else { - return TimeFrameUtils.resolve(context, 1000L * value); - } - } @Override protected void onSharedPreferenceChanged(@NonNull String key) { @@ -161,16 +151,6 @@ public class SecuritySettingsFragment extends XmppPreferenceFragment { .show(); } - private static class MessageDeletionSummaryProvider - implements Preference.SummaryProvider { - - @Nullable - @Override - public CharSequence provideSummary(@NonNull ListPreference preference) { - final Integer value = Ints.tryParse(Strings.nullToEmpty(preference.getValue())); - return messageDeletionValueToName(preference.getContext(), value == null ? 0 : value); - } - } private static class OmemoSummaryProvider implements Preference.SummaryProvider { diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/XmppPreferenceFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/XmppPreferenceFragment.java index f3b1dabcab1822cde306a4cfe3d8a5b5776b5b1a..76364526d187044915c099dd81dac15a04188ba4 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/XmppPreferenceFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/XmppPreferenceFragment.java @@ -1,15 +1,24 @@ package eu.siacs.conversations.ui.fragment.settings; +import android.content.Context; import android.content.SharedPreferences; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.ListPreference; +import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import com.google.common.base.Strings; +import com.google.common.primitives.Ints; + import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.XmppActivity; +import eu.siacs.conversations.utils.TimeFrameUtils; public abstract class XmppPreferenceFragment extends PreferenceFragmentCompat { @@ -25,7 +34,7 @@ public abstract class XmppPreferenceFragment extends PreferenceFragmentCompat { }; protected void onSharedPreferenceChanged(@NonNull String key) { - Log.d(Config.LOGTAG,"onSharedPreferenceChanged("+key+")"); + Log.d(Config.LOGTAG, "onSharedPreferenceChanged(" + key + ")"); } public void onBackendConnected() {} @@ -83,4 +92,23 @@ public abstract class XmppPreferenceFragment extends PreferenceFragmentCompat { protected void runOnUiThread(final Runnable runnable) { requireActivity().runOnUiThread(runnable); } + + protected static String timeframeValueToName(final Context context, final int value) { + if (value == 0) { + return context.getString(R.string.never); + } else { + return TimeFrameUtils.resolve(context, 1000L * value); + } + } + + protected static class TimeframeSummaryProvider + implements Preference.SummaryProvider { + + @Nullable + @Override + public CharSequence provideSummary(@NonNull ListPreference preference) { + final Integer value = Ints.tryParse(Strings.nullToEmpty(preference.getValue())); + return timeframeValueToName(preference.getContext(), value == null ? 0 : value); + } + } } diff --git a/src/main/java/eu/siacs/conversations/utils/MimeUtils.java b/src/main/java/eu/siacs/conversations/utils/MimeUtils.java index 6273e2b43cd45b36b3eb737afffc737855dc2f4e..ce919897ec4326df8269944a76b45e4a90e90d9a 100644 --- a/src/main/java/eu/siacs/conversations/utils/MimeUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/MimeUtils.java @@ -37,7 +37,7 @@ import java.util.Properties; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Transferable; -import eu.siacs.conversations.services.ExportBackupService; +import eu.siacs.conversations.worker.ExportBackupWorker; /** * Utilities for dealing with MIME types. @@ -91,7 +91,7 @@ public final class MimeUtils { add("application/vnd.amazon.mobi8-ebook", "kfx"); add("application/vnd.android.package-archive", "apk"); add("application/vnd.cinderella", "cdy"); - add(ExportBackupService.MIME_TYPE, "ceb"); + add(ExportBackupWorker.MIME_TYPE, "ceb"); add("application/vnd.ms-pki.stl", "stl"); add("application/vnd.oasis.opendocument.database", "odb"); add("application/vnd.oasis.opendocument.formula", "odf"); diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index e1996440cfff7c913e54e1315e00df8baebf5042..245f196a66a70b16bbfc02d567370e947a9c9010 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -16,8 +16,6 @@ import androidx.core.content.ContextCompat; import com.google.android.material.color.MaterialColors; import com.google.common.base.Strings; -import java.math.BigInteger; -import java.security.MessageDigest; import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -31,14 +29,13 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversational; -import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.RtpSessionStatus; import eu.siacs.conversations.entities.Transferable; -import eu.siacs.conversations.services.ExportBackupService; import eu.siacs.conversations.ui.util.QuoteHelper; +import eu.siacs.conversations.worker.ExportBackupWorker; import eu.siacs.conversations.xmpp.Jid; public class UIHelper { @@ -410,7 +407,7 @@ public class UIHelper { return context.getString(R.string.pdf_document); } else if (mime.equals("application/vnd.android.package-archive")) { return context.getString(R.string.apk); - } else if (mime.equals(ExportBackupService.MIME_TYPE)) { + } else if (mime.equals(ExportBackupWorker.MIME_TYPE)) { return context.getString(R.string.conversations_backup); } else if (mime.contains("vcard")) { return context.getString(R.string.vcard); diff --git a/src/main/java/eu/siacs/conversations/services/ExportBackupService.java b/src/main/java/eu/siacs/conversations/worker/ExportBackupWorker.java similarity index 51% rename from src/main/java/eu/siacs/conversations/services/ExportBackupService.java rename to src/main/java/eu/siacs/conversations/worker/ExportBackupWorker.java index 1a7ac070e9380038dfdfe8998330eebff525676f..167a1f240aa5f6511217118df3f31b75f0ff5d68 100644 --- a/src/main/java/eu/siacs/conversations/services/ExportBackupService.java +++ b/src/main/java/eu/siacs/conversations/worker/ExportBackupWorker.java @@ -1,67 +1,71 @@ -package eu.siacs.conversations.services; +package eu.siacs.conversations.worker; import static eu.siacs.conversations.utils.Compatibility.s; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.pm.ServiceInfo; import android.database.Cursor; -import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; -import android.os.IBinder; import android.util.Log; +import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; +import androidx.work.ForegroundInfo; +import androidx.work.Worker; +import androidx.work.WorkerParameters; -import com.google.common.base.CharMatcher; +import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.gson.stream.JsonWriter; +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.persistance.DatabaseBackend; +import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.utils.BackupFileHeader; +import eu.siacs.conversations.utils.Compatibility; + import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.zip.GZIPOutputStream; import javax.crypto.Cipher; import javax.crypto.CipherOutputStream; +import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; -import eu.siacs.conversations.Config; -import eu.siacs.conversations.R; -import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore; -import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Conversation; -import eu.siacs.conversations.entities.Message; -import eu.siacs.conversations.persistance.DatabaseBackend; -import eu.siacs.conversations.persistance.FileBackend; -import eu.siacs.conversations.utils.BackupFileHeader; -import eu.siacs.conversations.utils.Compatibility; - -public class ExportBackupService extends Service { +public class ExportBackupWorker extends Worker { - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US); + private static final SimpleDateFormat DATE_FORMAT = + new SimpleDateFormat("yyyy-MM-dd", Locale.US); public static final String KEYTYPE = "AES"; public static final String CIPHERMODE = "AES/GCM/NoPadding"; @@ -70,211 +74,80 @@ public class ExportBackupService extends Service { public static final String MIME_TYPE = "application/vnd.conversations.backup"; private static final int NOTIFICATION_ID = 19; - private static final AtomicBoolean RUNNING = new AtomicBoolean(false); - private DatabaseBackend mDatabaseBackend; - private List mAccounts; - private NotificationManager notificationManager; + private static final int BACKUP_CREATED_NOTIFICATION_ID = 23; - private static List getPossibleFileOpenIntents( - final Context context, final String path) { + private final boolean recurringBackup; - // http://www.openintents.org/action/android-intent-action-view/file-directory - // do not use 'vnd.android.document/directory' since this will trigger system file manager - final Intent openIntent = new Intent(Intent.ACTION_VIEW); - openIntent.addCategory(Intent.CATEGORY_DEFAULT); - if (Compatibility.runsAndTargetsTwentyFour(context)) { - openIntent.setType("resource/folder"); - } else { - openIntent.setDataAndType(Uri.parse("file://" + path), "resource/folder"); - } - openIntent.putExtra("org.openintents.extra.ABSOLUTE_PATH", path); - - final Intent amazeIntent = new Intent(Intent.ACTION_VIEW); - amazeIntent.setDataAndType(Uri.parse("com.amaze.filemanager:" + path), "resource/folder"); - - // will open a file manager at root and user can navigate themselves - final Intent systemFallBack = new Intent(Intent.ACTION_VIEW); - systemFallBack.addCategory(Intent.CATEGORY_DEFAULT); - systemFallBack.setData( - Uri.parse("content://com.android.externalstorage.documents/root/primary")); - - return Arrays.asList(openIntent, amazeIntent, systemFallBack); + public ExportBackupWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + final var inputData = workerParams.getInputData(); + this.recurringBackup = inputData.getBoolean("recurring_backup", false); } - private static void accountExport( - final SQLiteDatabase db, final String uuid, final JsonWriter writer) - throws IOException { - final Cursor accountCursor = - db.query( - Account.TABLENAME, - null, - Account.UUID + "=?", - new String[] {uuid}, - null, - null, - null); - while (accountCursor != null && accountCursor.moveToNext()) { - writer.beginObject(); - writer.name("table"); - writer.value(Account.TABLENAME); - writer.name("values"); - writer.beginObject(); - for (int i = 0; i < accountCursor.getColumnCount(); ++i) { - final String name = accountCursor.getColumnName(i); - writer.name(name); - final String value = accountCursor.getString(i); - if (value == null || Account.ROSTERVERSION.equals(accountCursor.getColumnName(i))) { - writer.nullValue(); - } else if (Account.OPTIONS.equals(accountCursor.getColumnName(i)) - && value.matches("\\d+")) { - int intValue = Integer.parseInt(value); - intValue |= 1 << Account.OPTION_DISABLED; - writer.value(intValue); - } else { - writer.value(value); - } - } - writer.endObject(); - writer.endObject(); - } - if (accountCursor != null) { - accountCursor.close(); - } - } - - private static void simpleExport( - final SQLiteDatabase db, - final String table, - final String column, - final String uuid, - final JsonWriter writer) - throws IOException { - final Cursor cursor = - db.query(table, null, column + "=?", new String[] {uuid}, null, null, null); - while (cursor != null && cursor.moveToNext()) { - writer.beginObject(); - writer.name("table"); - writer.value(table); - writer.name("values"); - writer.beginObject(); - for (int i = 0; i < cursor.getColumnCount(); ++i) { - final String name = cursor.getColumnName(i); - writer.name(name); - final String value = cursor.getString(i); - writer.value(value); - } - writer.endObject(); - writer.endObject(); - } - if (cursor != null) { - cursor.close(); - } - } - - public static byte[] getKey(final String password, final byte[] salt) - throws InvalidKeySpecException { - final SecretKeyFactory factory; + @NonNull + @Override + public Result doWork() { + final List files; try { - factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException(e); + files = export(); + } catch (final IOException + | InvalidKeySpecException + | InvalidAlgorithmParameterException + | InvalidKeyException + | NoSuchPaddingException + | NoSuchAlgorithmException + | NoSuchProviderException e) { + Log.d(Config.LOGTAG, "could not create backup", e); + return Result.failure(); } - return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)) - .getEncoded(); - } - - @Override - public void onCreate() { - mDatabaseBackend = DatabaseBackend.getInstance(getBaseContext()); - mAccounts = mDatabaseBackend.getAccounts(); - notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + Log.d(Config.LOGTAG, "done creating " + files.size() + " backup files"); + getApplicationContext().getSystemService(NotificationManager.class).cancel(NOTIFICATION_ID); + if (files.isEmpty() || recurringBackup) { + return Result.success(); + } + notifySuccess(files); + return Result.success(); } + @NonNull @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (RUNNING.compareAndSet(false, true)) { - new Thread( - () -> { - boolean success; - List files; - try { - files = export(); - success = true; - } catch (final Exception e) { - Log.d(Config.LOGTAG, "unable to create backup", e); - success = false; - files = Collections.emptyList(); - } - stopForeground(true); - RUNNING.set(false); - if (success) { - notifySuccess(files); - } - stopSelf(); - }) - .start(); - return START_STICKY; + public ForegroundInfo getForegroundInfo() { + Log.d(Config.LOGTAG, "getForegroundInfo()"); + final var context = getApplicationContext(); + final NotificationCompat.Builder notification = + new NotificationCompat.Builder(context, "backup"); + notification + .setContentTitle(context.getString(R.string.notification_create_backup_title)) + .setSmallIcon(R.drawable.ic_archive_24dp) + .setProgress(1, 0, false); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + return new ForegroundInfo( + NOTIFICATION_ID, + notification.build(), + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC); } else { - Log.d( - Config.LOGTAG, - "ExportBackupService. ignoring start command because already running"); + return new ForegroundInfo(NOTIFICATION_ID, notification.build()); } - return START_NOT_STICKY; } - private void messageExport( - final SQLiteDatabase db, - final String uuid, - final JsonWriter writer, - final Progress progress) - throws IOException { - Cursor cursor = - db.rawQuery( - "select messages.* from messages join conversations on conversations.uuid=messages.conversationUuid where conversations.accountUuid=?", - new String[] {uuid}); - int size = cursor != null ? cursor.getCount() : 0; - Log.d(Config.LOGTAG, "exporting " + size + " messages for account " + uuid); - int i = 0; - int p = 0; - while (cursor != null && cursor.moveToNext()) { - writer.beginObject(); - writer.name("table"); - writer.value(Message.TABLENAME); - writer.name("values"); - writer.beginObject(); - for (int j = 0; j < cursor.getColumnCount(); ++j) { - final String name = cursor.getColumnName(j); - writer.name(name); - final String value = cursor.getString(j); - writer.value(value); - } - writer.endObject(); - writer.endObject(); - final int percentage = i * 100 / size; - if (p < percentage) { - p = percentage; - notificationManager.notify(NOTIFICATION_ID, progress.build(p)); - } - i++; - } - if (cursor != null) { - cursor.close(); - } - } + private List export() + throws IOException, + InvalidKeySpecException, + InvalidAlgorithmParameterException, + InvalidKeyException, + NoSuchPaddingException, + NoSuchAlgorithmException, + NoSuchProviderException { + final Context context = getApplicationContext(); + final var database = DatabaseBackend.getInstance(context); + final var accounts = database.getAccounts(); - private List export() throws Exception { - NotificationCompat.Builder mBuilder = - new NotificationCompat.Builder(getBaseContext(), "backup"); - mBuilder.setContentTitle(getString(R.string.notification_create_backup_title)) - .setSmallIcon(R.drawable.ic_archive_24dp) - .setProgress(1, 0, false); - startForeground(NOTIFICATION_ID, mBuilder.build()); int count = 0; - final int max = this.mAccounts.size(); + final int max = accounts.size(); final SecureRandom secureRandom = new SecureRandom(); final List files = new ArrayList<>(); Log.d(Config.LOGTAG, "starting backup for " + max + " accounts"); - for (final Account account : this.mAccounts) { + for (final Account account : accounts) { final String password = account.getPassword(); if (Strings.nullToEmpty(password).trim().isEmpty()) { Log.d( @@ -295,20 +168,24 @@ public class ExportBackupService extends Service { secureRandom.nextBytes(salt); final BackupFileHeader backupFileHeader = new BackupFileHeader( - getString(R.string.app_name), + context.getString(R.string.app_name), account.getJid(), System.currentTimeMillis(), IV, salt); - final Progress progress = new Progress(mBuilder, max, count); + final NotificationCompat.Builder notification = + new NotificationCompat.Builder(context, "backup"); + notification + .setContentTitle(context.getString(R.string.notification_create_backup_title)) + .setSmallIcon(R.drawable.ic_archive_24dp) + .setProgress(1, 0, false); + final Progress progress = new Progress(notification, max, count); final String filename = String.format( "%s.%s.ceb", account.getJid().asBareJid().toEscapedString(), DATE_FORMAT.format(new Date())); - final File file = - new File( - FileBackend.getBackupDirectory(this), filename); + final File file = new File(FileBackend.getBackupDirectory(context), filename); files.add(file); final File directory = file.getParentFile(); if (directory != null && directory.mkdirs()) { @@ -335,7 +212,7 @@ public class ExportBackupService extends Service { new JsonWriter( new OutputStreamWriter(gzipOutputStream, StandardCharsets.UTF_8)); jsonWriter.beginArray(); - final SQLiteDatabase db = this.mDatabaseBackend.getReadableDatabase(); + final SQLiteDatabase db = database.getReadableDatabase(); final String uuid = account.getUuid(); accountExport(db, uuid, jsonWriter); simpleExport(db, Conversation.TABLENAME, Conversation.ACCOUNT, uuid, jsonWriter); @@ -361,96 +238,240 @@ public class ExportBackupService extends Service { private void mediaScannerScanFile(final File file) { final Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(file)); - sendBroadcast(intent); + getApplicationContext().sendBroadcast(intent); } - private void notifySuccess(final List files) { - final String path = FileBackend.getBackupDirectory(this).getAbsolutePath(); - - PendingIntent openFolderIntent = null; + private static void accountExport( + final SQLiteDatabase db, final String uuid, final JsonWriter writer) + throws IOException { + try (final Cursor accountCursor = + db.query( + Account.TABLENAME, + null, + Account.UUID + "=?", + new String[] {uuid}, + null, + null, + null)) { + while (accountCursor != null && accountCursor.moveToNext()) { + writer.beginObject(); + writer.name("table"); + writer.value(Account.TABLENAME); + writer.name("values"); + writer.beginObject(); + for (int i = 0; i < accountCursor.getColumnCount(); ++i) { + final String name = accountCursor.getColumnName(i); + writer.name(name); + final String value = accountCursor.getString(i); + if (value == null + || Account.ROSTERVERSION.equals(accountCursor.getColumnName(i))) { + writer.nullValue(); + } else if (Account.OPTIONS.equals(accountCursor.getColumnName(i)) + && value.matches("\\d+")) { + int intValue = Integer.parseInt(value); + intValue |= 1 << Account.OPTION_DISABLED; + writer.value(intValue); + } else { + writer.value(value); + } + } + writer.endObject(); + writer.endObject(); + } + } + } - for (final Intent intent : getPossibleFileOpenIntents(this, path)) { - if (intent.resolveActivityInfo(getPackageManager(), 0) != null) { - openFolderIntent = - PendingIntent.getActivity( - this, - 189, - intent, - s() - ? PendingIntent.FLAG_IMMUTABLE - | PendingIntent.FLAG_UPDATE_CURRENT - : PendingIntent.FLAG_UPDATE_CURRENT); - break; + private static void simpleExport( + final SQLiteDatabase db, + final String table, + final String column, + final String uuid, + final JsonWriter writer) + throws IOException { + try (final Cursor cursor = + db.query(table, null, column + "=?", new String[] {uuid}, null, null, null)) { + while (cursor != null && cursor.moveToNext()) { + writer.beginObject(); + writer.name("table"); + writer.value(table); + writer.name("values"); + writer.beginObject(); + for (int i = 0; i < cursor.getColumnCount(); ++i) { + final String name = cursor.getColumnName(i); + writer.name(name); + final String value = cursor.getString(i); + writer.value(value); + } + writer.endObject(); + writer.endObject(); } } + } - PendingIntent shareFilesIntent = null; - if (files.size() > 0) { - final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); - ArrayList uris = new ArrayList<>(); - for (File file : files) { - uris.add(FileBackend.getUriForFile(this, file)); + private void messageExport( + final SQLiteDatabase db, + final String uuid, + final JsonWriter writer, + final Progress progress) + throws IOException { + final var notificationManager = + getApplicationContext().getSystemService(NotificationManager.class); + try (final Cursor cursor = + db.rawQuery( + "select messages.* from messages join conversations on conversations.uuid=messages.conversationUuid where conversations.accountUuid=?", + new String[] {uuid})) { + final int size = cursor != null ? cursor.getCount() : 0; + Log.d(Config.LOGTAG, "exporting " + size + " messages for account " + uuid); + int i = 0; + int p = 0; + while (cursor != null && cursor.moveToNext()) { + writer.beginObject(); + writer.name("table"); + writer.value(Message.TABLENAME); + writer.name("values"); + writer.beginObject(); + for (int j = 0; j < cursor.getColumnCount(); ++j) { + final String name = cursor.getColumnName(j); + writer.name(name); + final String value = cursor.getString(j); + writer.value(value); + } + writer.endObject(); + writer.endObject(); + final int percentage = i * 100 / size; + if (p < percentage) { + p = percentage; + notificationManager.notify(NOTIFICATION_ID, progress.build(p)); + } + i++; } - intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.setType(MIME_TYPE); - final Intent chooser = - Intent.createChooser(intent, getString(R.string.share_backup_files)); - shareFilesIntent = - PendingIntent.getActivity( - this, - 190, - chooser, - s() - ? PendingIntent.FLAG_IMMUTABLE - | PendingIntent.FLAG_UPDATE_CURRENT - : PendingIntent.FLAG_UPDATE_CURRENT); } + } - NotificationCompat.Builder mBuilder = - new NotificationCompat.Builder(getBaseContext(), "backup"); - mBuilder.setContentTitle(getString(R.string.notification_backup_created_title)) - .setContentText(getString(R.string.notification_backup_created_subtitle, path)) + public static byte[] getKey(final String password, final byte[] salt) + throws InvalidKeySpecException { + final SecretKeyFactory factory; + try { + factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException(e); + } + return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)) + .getEncoded(); + } + + private void notifySuccess(final List files) { + final var context = getApplicationContext(); + final String path = FileBackend.getBackupDirectory(context).getAbsolutePath(); + + final var openFolderIntent = getOpenFolderIntent(path); + + final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + final ArrayList uris = new ArrayList<>(); + for (final File file : files) { + uris.add(FileBackend.getUriForFile(context, file)); + } + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setType(MIME_TYPE); + final Intent chooser = + Intent.createChooser(intent, context.getString(R.string.share_backup_files)); + final var shareFilesIntent = + PendingIntent.getActivity( + context, + 190, + chooser, + s() + ? PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT + : PendingIntent.FLAG_UPDATE_CURRENT); + + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, "backup"); + mBuilder.setContentTitle(context.getString(R.string.notification_backup_created_title)) + .setContentText( + context.getString(R.string.notification_backup_created_subtitle, path)) .setStyle( new NotificationCompat.BigTextStyle() .bigText( - getString( + context.getString( R.string.notification_backup_created_subtitle, - FileBackend.getBackupDirectory(this) + FileBackend.getBackupDirectory(context) .getAbsolutePath()))) .setAutoCancel(true) - .setContentIntent(openFolderIntent) .setSmallIcon(R.drawable.ic_archive_24dp); - if (shareFilesIntent != null) { - mBuilder.addAction( - R.drawable.ic_share_24dp, - getString(R.string.share_backup_files), - shareFilesIntent); + if (openFolderIntent.isPresent()) { + mBuilder.setContentIntent(openFolderIntent.get()); + } else { + Log.w(Config.LOGTAG, "no app can display folders"); } - notificationManager.notify(NOTIFICATION_ID, mBuilder.build()); + mBuilder.addAction( + R.drawable.ic_share_24dp, + context.getString(R.string.share_backup_files), + shareFilesIntent); + final var notificationManager = context.getSystemService(NotificationManager.class); + notificationManager.notify(BACKUP_CREATED_NOTIFICATION_ID, mBuilder.build()); } - @Override - public IBinder onBind(Intent intent) { - return null; + private Optional getOpenFolderIntent(final String path) { + final var context = getApplicationContext(); + for (final Intent intent : getPossibleFileOpenIntents(context, path)) { + if (intent.resolveActivityInfo(context.getPackageManager(), 0) != null) { + return Optional.of( + PendingIntent.getActivity( + context, + 189, + intent, + s() + ? PendingIntent.FLAG_IMMUTABLE + | PendingIntent.FLAG_UPDATE_CURRENT + : PendingIntent.FLAG_UPDATE_CURRENT)); + } + } + return Optional.absent(); + } + + private static List getPossibleFileOpenIntents( + final Context context, final String path) { + + // http://www.openintents.org/action/android-intent-action-view/file-directory + // do not use 'vnd.android.document/directory' since this will trigger system file manager + final Intent openIntent = new Intent(Intent.ACTION_VIEW); + openIntent.addCategory(Intent.CATEGORY_DEFAULT); + if (Compatibility.runsAndTargetsTwentyFour(context)) { + openIntent.setType("resource/folder"); + } else { + openIntent.setDataAndType(Uri.parse("file://" + path), "resource/folder"); + } + openIntent.putExtra("org.openintents.extra.ABSOLUTE_PATH", path); + + final Intent amazeIntent = new Intent(Intent.ACTION_VIEW); + amazeIntent.setDataAndType(Uri.parse("com.amaze.filemanager:" + path), "resource/folder"); + + // will open a file manager at root and user can navigate themselves + final Intent systemFallBack = new Intent(Intent.ACTION_VIEW); + systemFallBack.addCategory(Intent.CATEGORY_DEFAULT); + systemFallBack.setData( + Uri.parse("content://com.android.externalstorage.documents/root/primary")); + + return Arrays.asList(openIntent, amazeIntent, systemFallBack); } private static class Progress { - private final NotificationCompat.Builder builder; + private final NotificationCompat.Builder notification; private final int max; private final int count; - private Progress(NotificationCompat.Builder builder, int max, int count) { - this.builder = builder; + private Progress( + final NotificationCompat.Builder notification, final int max, final int count) { + this.notification = notification; this.max = max; this.count = count; } private Notification build(int percentage) { - builder.setProgress(max * 100, count * 100 + percentage, false); - return builder.build(); + notification.setProgress(max * 100, count * 100 + percentage, false); + return notification.build(); } } } diff --git a/src/main/res/drawable/ic_calendar_month_24dp.xml b/src/main/res/drawable/ic_calendar_month_24dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..007f1fa45f442d9ecc6a49cae3053f05b6c43c4c --- /dev/null +++ b/src/main/res/drawable/ic_calendar_month_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index 6dc8caca69bbeaf44a7b87b0b65df2179f2e8d5b..1c00e9e737efd498898eee6e120dd19477d260d7 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -84,6 +84,13 @@ 2592000 15811200 + + 0 + 86400 + 172800 + 604800 + 2592000 + always default_on diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index bb1e1120fd86b47441b1d8f2392eba462f6f4f29..356e828cf2a6327cd82f962d8508739ab76db914 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1059,5 +1059,8 @@ Increase font size in message bubbles Invites from strangers Accept invites to group chats from strangers + Create one-off, Schedule recurring + Create one-off backup + Recurring backup diff --git a/src/main/res/xml/preferences_backup.xml b/src/main/res/xml/preferences_backup.xml new file mode 100644 index 0000000000000000000000000000000000000000..b0362c7856b02349c266f04c63359e97e9634a51 --- /dev/null +++ b/src/main/res/xml/preferences_backup.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_main.xml b/src/main/res/xml/preferences_main.xml index 2de980c40f94446a1b1420b0dd3d11427ddefecb..013f2506cd98a685155e200d0eae5dc16a032ec5 100644 --- a/src/main/res/xml/preferences_main.xml +++ b/src/main/res/xml/preferences_main.xml @@ -34,9 +34,10 @@ app:title="@string/pref_connection_options" /> + android:key="backup" + app:fragment="eu.siacs.conversations.ui.fragment.settings.BackupSettingsFragment" + android:summary="@string/pref_backup_summary" + android:title="@string/backup" /> Date: Fri, 3 May 2024 08:51:09 +0200 Subject: [PATCH 45/57] add ability to cancel in-progress one-off backup --- src/main/AndroidManifest.xml | 8 +- .../SystemEventReceiver.java} | 5 +- .../UnifiedPushDistributor.java | 3 +- .../receiver/WorkManagerEventReceiver.java | 32 +++ .../services/ContactChooserTargetService.java | 3 +- .../services/UnifiedPushBroker.java | 1 + .../services/XmppConnectionService.java | 13 +- .../settings/BackupSettingsFragment.java | 2 +- .../fragment/settings/UpSettingsFragment.java | 2 +- .../conversations/utils/Compatibility.java | 2 +- .../worker/ExportBackupWorker.java | 248 +++++++++++------- 11 files changed, 208 insertions(+), 111 deletions(-) rename src/main/java/eu/siacs/conversations/{services/EventReceiver.java => receiver/SystemEventReceiver.java} (89%) rename src/main/java/eu/siacs/conversations/{services => receiver}/UnifiedPushDistributor.java (99%) create mode 100644 src/main/java/eu/siacs/conversations/receiver/WorkManagerEventReceiver.java diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 3d0ce91b02128a98139aee28d4b730b80850928b..749b593c607c4b4cdaa8f0e8e2cf4f9b9d2c4273 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -143,7 +143,11 @@ + + @@ -157,7 +161,7 @@ diff --git a/src/main/java/eu/siacs/conversations/services/EventReceiver.java b/src/main/java/eu/siacs/conversations/receiver/SystemEventReceiver.java similarity index 89% rename from src/main/java/eu/siacs/conversations/services/EventReceiver.java rename to src/main/java/eu/siacs/conversations/receiver/SystemEventReceiver.java index b189e9a9e0acee112fd7cc2319ba7a6e1b7265f5..3efa9b67e31a3aa26eaf893158d92639fd521dc3 100644 --- a/src/main/java/eu/siacs/conversations/services/EventReceiver.java +++ b/src/main/java/eu/siacs/conversations/receiver/SystemEventReceiver.java @@ -1,4 +1,4 @@ -package eu.siacs.conversations.services; +package eu.siacs.conversations.receiver; import android.content.BroadcastReceiver; import android.content.Context; @@ -10,9 +10,10 @@ import android.util.Log; import com.google.common.base.Strings; import eu.siacs.conversations.Config; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.Compatibility; -public class EventReceiver extends BroadcastReceiver { +public class SystemEventReceiver extends BroadcastReceiver { public static final String SETTING_ENABLED_ACCOUNTS = "enabled_accounts"; public static final String EXTRA_NEEDS_FOREGROUND_SERVICE = "needs_foreground_service"; diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java b/src/main/java/eu/siacs/conversations/receiver/UnifiedPushDistributor.java similarity index 99% rename from src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java rename to src/main/java/eu/siacs/conversations/receiver/UnifiedPushDistributor.java index f51de2432ab3d0375fd330a7691261d168c498e4..ace71ddb589ff9544d2dacb27811ad9f96b1245f 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java +++ b/src/main/java/eu/siacs/conversations/receiver/UnifiedPushDistributor.java @@ -1,4 +1,4 @@ -package eu.siacs.conversations.services; +package eu.siacs.conversations.receiver; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -25,6 +25,7 @@ import java.util.List; import eu.siacs.conversations.Config; import eu.siacs.conversations.persistance.UnifiedPushDatabase; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.Compatibility; public class UnifiedPushDistributor extends BroadcastReceiver { diff --git a/src/main/java/eu/siacs/conversations/receiver/WorkManagerEventReceiver.java b/src/main/java/eu/siacs/conversations/receiver/WorkManagerEventReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..71ec74f53bf121ab981a37d8d4ae07a14245c19d --- /dev/null +++ b/src/main/java/eu/siacs/conversations/receiver/WorkManagerEventReceiver.java @@ -0,0 +1,32 @@ +package eu.siacs.conversations.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import androidx.work.WorkManager; + +import com.google.common.base.Strings; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.ui.fragment.settings.BackupSettingsFragment; + +public class WorkManagerEventReceiver extends BroadcastReceiver { + + public static final String ACTION_STOP_BACKUP = "eu.siacs.conversations.receiver.STOP_BACKUP"; + + @Override + public void onReceive(final Context context, final Intent intent) { + final var action = Strings.nullToEmpty(intent == null ? null : intent.getAction()); + if (action.equals(ACTION_STOP_BACKUP)) { + stopBackup(context); + } + } + + private void stopBackup(final Context context) { + Log.d(Config.LOGTAG, "trying to stop one-off backup worker"); + final var workManager = WorkManager.getInstance(context); + workManager.cancelUniqueWork(BackupSettingsFragment.CREATE_ONE_OFF_BACKUP); + } +} diff --git a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java index c68b502af10af6b10e39b2cf858f391d31492e73..63a9afc3fa8558f1096d47f9a4f1689e4b1cf11e 100644 --- a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java +++ b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java @@ -21,6 +21,7 @@ import java.util.List; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.receiver.SystemEventReceiver; import eu.siacs.conversations.ui.ConversationsActivity; import eu.siacs.conversations.utils.Compatibility; @@ -44,7 +45,7 @@ public class ContactChooserTargetService extends ChooserTargetService implements @Override public List onGetChooserTargets( final ComponentName targetActivityName, final IntentFilter matchedFilter) { - if (!EventReceiver.hasEnabledAccounts(this)) { + if (!SystemEventReceiver.hasEnabledAccounts(this)) { return Collections.emptyList(); } final Intent intent = new Intent(this, XmppConnectionService.class); diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java index bfa1785f11f855e11c1c9531331c672ce20f2431..4aab05ceeb00ddefc6d366c1dfd3e94ac4e7036b 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java @@ -28,6 +28,7 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.parser.AbstractParser; import eu.siacs.conversations.persistance.UnifiedPushDatabase; +import eu.siacs.conversations.receiver.UnifiedPushDistributor; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.Jid; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index b12eaffff0b5b67db989528ef1e2c4bf54cc10b3..ce45d9083ce69ae32d17477d5d6c99194e1525ea 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -128,6 +128,7 @@ import eu.siacs.conversations.parser.PresenceParser; import eu.siacs.conversations.persistance.DatabaseBackend; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.persistance.UnifiedPushDatabase; +import eu.siacs.conversations.receiver.SystemEventReceiver; import eu.siacs.conversations.ui.ChooseAccountForProfilePictureActivity; import eu.siacs.conversations.ui.ConversationsActivity; import eu.siacs.conversations.ui.RtpSessionActivity; @@ -678,7 +679,7 @@ public class XmppConnectionService extends Service { @Override public int onStartCommand(final Intent intent, int flags, int startId) { final String action = Strings.nullToEmpty(intent == null ? null : intent.getAction()); - final boolean needsForegroundService = intent != null && intent.getBooleanExtra(EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, false); + final boolean needsForegroundService = intent != null && intent.getBooleanExtra(SystemEventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, false); if (needsForegroundService) { Log.d(Config.LOGTAG, "toggle forced foreground service after receiving event (action=" + action + ")"); toggleForegroundService(true); @@ -1286,7 +1287,7 @@ public class XmppConnectionService extends Service { this.accounts = databaseBackend.getAccounts(); final SharedPreferences.Editor editor = getPreferences().edit(); final boolean hasEnabledAccounts = hasEnabledAccounts(); - editor.putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply(); + editor.putBoolean(SystemEventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply(); editor.apply(); toggleSetProfilePictureActivity(hasEnabledAccounts); reconfigurePushDistributor(); @@ -1582,7 +1583,7 @@ public class XmppConnectionService extends Service { return; } final long triggerAtMillis = SystemClock.elapsedRealtime() + (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL * 1000); - final Intent intent = new Intent(this, EventReceiver.class); + final Intent intent = new Intent(this, SystemEventReceiver.class); intent.setAction(ACTION_POST_CONNECTIVITY_CHANGE); try { final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, s() @@ -1604,7 +1605,7 @@ public class XmppConnectionService extends Service { if (alarmManager == null) { return; } - final Intent intent = new Intent(this, EventReceiver.class); + final Intent intent = new Intent(this, SystemEventReceiver.class); intent.setAction(ACTION_PING); try { final PendingIntent pendingIntent = @@ -1623,7 +1624,7 @@ public class XmppConnectionService extends Service { if (alarmManager == null) { return; } - final Intent intent = new Intent(this, EventReceiver.class); + final Intent intent = new Intent(this, SystemEventReceiver.class); intent.setAction(ACTION_IDLE_PING); try { final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, s() @@ -2573,7 +2574,7 @@ public class XmppConnectionService extends Service { private void syncEnabledAccountSetting() { final boolean hasEnabledAccounts = hasEnabledAccounts(); - getPreferences().edit().putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply(); + getPreferences().edit().putBoolean(SystemEventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply(); toggleSetProfilePictureActivity(hasEnabledAccounts); } diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/BackupSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/BackupSettingsFragment.java index debf929aa6f3109fa519d0e850a9e1482c3ff431..f78577656d619357219dd94068dd67d968946464 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/BackupSettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/BackupSettingsFragment.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; public class BackupSettingsFragment extends XmppPreferenceFragment { - private static final String CREATE_ONE_OFF_BACKUP = "create_one_off_backup"; + public static final String CREATE_ONE_OFF_BACKUP = "create_one_off_backup"; private static final String RECURRING_BACKUP = "recurring_backup"; private final ActivityResultLauncher requestStorageForBackupLauncher = diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/UpSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/UpSettingsFragment.java index 7ab15e21e1707da180b7998e237a414a43f9c3fe..771acbbe1daa949a52d13f0e79bf27f3787562a9 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/UpSettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/UpSettingsFragment.java @@ -13,7 +13,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import eu.siacs.conversations.R; -import eu.siacs.conversations.services.UnifiedPushDistributor; +import eu.siacs.conversations.receiver.UnifiedPushDistributor; import eu.siacs.conversations.xmpp.Jid; import java.net.URI; diff --git a/src/main/java/eu/siacs/conversations/utils/Compatibility.java b/src/main/java/eu/siacs/conversations/utils/Compatibility.java index eaf89d1212ceb941f19ba53031158a79a6bbcc99..26a2331cc3143aa053859a92a77b3bd451d89bf0 100644 --- a/src/main/java/eu/siacs/conversations/utils/Compatibility.java +++ b/src/main/java/eu/siacs/conversations/utils/Compatibility.java @@ -1,6 +1,6 @@ package eu.siacs.conversations.utils; -import static eu.siacs.conversations.services.EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE; +import static eu.siacs.conversations.receiver.SystemEventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE; import android.annotation.SuppressLint; import android.app.ActivityOptions; diff --git a/src/main/java/eu/siacs/conversations/worker/ExportBackupWorker.java b/src/main/java/eu/siacs/conversations/worker/ExportBackupWorker.java index 167a1f240aa5f6511217118df3f31b75f0ff5d68..75ef9036c2fbf32bde15ca77f2cc9707813cc88e 100644 --- a/src/main/java/eu/siacs/conversations/worker/ExportBackupWorker.java +++ b/src/main/java/eu/siacs/conversations/worker/ExportBackupWorker.java @@ -11,6 +11,7 @@ import android.content.pm.ServiceInfo; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; +import android.os.SystemClock; import android.util.Log; import androidx.annotation.NonNull; @@ -21,6 +22,7 @@ import androidx.work.WorkerParameters; import com.google.common.base.Optional; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.gson.stream.JsonWriter; import eu.siacs.conversations.Config; @@ -31,6 +33,7 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.persistance.DatabaseBackend; import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.receiver.WorkManagerEventReceiver; import eu.siacs.conversations.utils.BackupFileHeader; import eu.siacs.conversations.utils.Compatibility; @@ -65,7 +68,7 @@ import javax.crypto.spec.SecretKeySpec; public class ExportBackupWorker extends Worker { private static final SimpleDateFormat DATE_FORMAT = - new SimpleDateFormat("yyyy-MM-dd", Locale.US); + new SimpleDateFormat("yyyy-MM-dd-HH-mm", Locale.US); public static final String KEYTYPE = "AES"; public static final String CIPHERMODE = "AES/GCM/NoPadding"; @@ -76,6 +79,11 @@ public class ExportBackupWorker extends Worker { private static final int NOTIFICATION_ID = 19; private static final int BACKUP_CREATED_NOTIFICATION_ID = 23; + private static final int PENDING_INTENT_FLAGS = + s() + ? PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT + : PendingIntent.FLAG_UPDATE_CURRENT; + private final boolean recurringBackup; public ExportBackupWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { @@ -99,9 +107,12 @@ public class ExportBackupWorker extends Worker { | NoSuchProviderException e) { Log.d(Config.LOGTAG, "could not create backup", e); return Result.failure(); + } finally { + getApplicationContext() + .getSystemService(NotificationManager.class) + .cancel(NOTIFICATION_ID); } Log.d(Config.LOGTAG, "done creating " + files.size() + " backup files"); - getApplicationContext().getSystemService(NotificationManager.class).cancel(NOTIFICATION_ID); if (files.isEmpty() || recurringBackup) { return Result.success(); } @@ -113,13 +124,7 @@ public class ExportBackupWorker extends Worker { @Override public ForegroundInfo getForegroundInfo() { Log.d(Config.LOGTAG, "getForegroundInfo()"); - final var context = getApplicationContext(); - final NotificationCompat.Builder notification = - new NotificationCompat.Builder(context, "backup"); - notification - .setContentTitle(context.getString(R.string.notification_create_backup_title)) - .setSmallIcon(R.drawable.ic_archive_24dp) - .setProgress(1, 0, false); + final NotificationCompat.Builder notification = getNotification(); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { return new ForegroundInfo( NOTIFICATION_ID, @@ -144,10 +149,13 @@ public class ExportBackupWorker extends Worker { int count = 0; final int max = accounts.size(); - final SecureRandom secureRandom = new SecureRandom(); - final List files = new ArrayList<>(); + final ImmutableList.Builder files = new ImmutableList.Builder<>(); Log.d(Config.LOGTAG, "starting backup for " + max + " accounts"); for (final Account account : accounts) { + if (isStopped()) { + Log.d(Config.LOGTAG, "ExportBackupWorker has stopped. Returning what we have"); + return files.build(); + } final String password = account.getPassword(); if (Strings.nullToEmpty(password).trim().isEmpty()) { Log.d( @@ -155,84 +163,140 @@ public class ExportBackupWorker extends Worker { String.format( "skipping backup for %s because password is empty. unable to encrypt", account.getJid().asBareJid())); + count++; continue; } - Log.d( - Config.LOGTAG, - String.format( - "exporting data for account %s (%s)", - account.getJid().asBareJid(), account.getUuid())); - final byte[] IV = new byte[12]; - final byte[] salt = new byte[16]; - secureRandom.nextBytes(IV); - secureRandom.nextBytes(salt); - final BackupFileHeader backupFileHeader = - new BackupFileHeader( - context.getString(R.string.app_name), - account.getJid(), - System.currentTimeMillis(), - IV, - salt); - final NotificationCompat.Builder notification = - new NotificationCompat.Builder(context, "backup"); - notification - .setContentTitle(context.getString(R.string.notification_create_backup_title)) - .setSmallIcon(R.drawable.ic_archive_24dp) - .setProgress(1, 0, false); - final Progress progress = new Progress(notification, max, count); final String filename = String.format( "%s.%s.ceb", account.getJid().asBareJid().toEscapedString(), DATE_FORMAT.format(new Date())); final File file = new File(FileBackend.getBackupDirectory(context), filename); - files.add(file); - final File directory = file.getParentFile(); - if (directory != null && directory.mkdirs()) { - Log.d(Config.LOGTAG, "created backup directory " + directory.getAbsolutePath()); - } - final FileOutputStream fileOutputStream = new FileOutputStream(file); - final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); - backupFileHeader.write(dataOutputStream); - dataOutputStream.flush(); - - final Cipher cipher = - Compatibility.twentyEight() - ? Cipher.getInstance(CIPHERMODE) - : Cipher.getInstance(CIPHERMODE, PROVIDER); - final byte[] key = getKey(password, salt); - SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE); - IvParameterSpec ivSpec = new IvParameterSpec(IV); - cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); - CipherOutputStream cipherOutputStream = - new CipherOutputStream(fileOutputStream, cipher); - - final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(cipherOutputStream); - final JsonWriter jsonWriter = - new JsonWriter( - new OutputStreamWriter(gzipOutputStream, StandardCharsets.UTF_8)); - jsonWriter.beginArray(); - final SQLiteDatabase db = database.getReadableDatabase(); - final String uuid = account.getUuid(); - accountExport(db, uuid, jsonWriter); - simpleExport(db, Conversation.TABLENAME, Conversation.ACCOUNT, uuid, jsonWriter); - messageExport(db, uuid, jsonWriter, progress); - for (final String table : - Arrays.asList( - SQLiteAxolotlStore.PREKEY_TABLENAME, - SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, - SQLiteAxolotlStore.SESSION_TABLENAME, - SQLiteAxolotlStore.IDENTITIES_TABLENAME)) { - simpleExport(db, table, SQLiteAxolotlStore.ACCOUNT, uuid, jsonWriter); + try { + export(database, account, password, file, max, count); + } catch (final WorkStoppedException e) { + if (file.delete()) { + Log.d( + Config.LOGTAG, + "deleted in progress backup file " + file.getAbsolutePath()); + } + Log.d(Config.LOGTAG, "ExportBackupWorker has stopped. Returning what we have"); + return files.build(); } - jsonWriter.endArray(); - jsonWriter.flush(); - jsonWriter.close(); - mediaScannerScanFile(file); - Log.d(Config.LOGTAG, "written backup to " + file.getAbsoluteFile()); + files.add(file); count++; } - return files; + return files.build(); + } + + private void export( + final DatabaseBackend database, + final Account account, + final String password, + final File file, + final int max, + final int count) + throws IOException, + InvalidKeySpecException, + InvalidAlgorithmParameterException, + InvalidKeyException, + NoSuchPaddingException, + NoSuchAlgorithmException, + NoSuchProviderException, + WorkStoppedException { + final var context = getApplicationContext(); + final SecureRandom secureRandom = new SecureRandom(); + Log.d( + Config.LOGTAG, + String.format( + "exporting data for account %s (%s)", + account.getJid().asBareJid(), account.getUuid())); + final byte[] IV = new byte[12]; + final byte[] salt = new byte[16]; + secureRandom.nextBytes(IV); + secureRandom.nextBytes(salt); + final BackupFileHeader backupFileHeader = + new BackupFileHeader( + context.getString(R.string.app_name), + account.getJid(), + System.currentTimeMillis(), + IV, + salt); + final var notification = getNotification(); + if (!recurringBackup) { + final var cancel = new Intent(context, WorkManagerEventReceiver.class); + cancel.setAction(WorkManagerEventReceiver.ACTION_STOP_BACKUP); + final var cancelPendingIntent = + PendingIntent.getBroadcast(context, 197, cancel, PENDING_INTENT_FLAGS); + notification.addAction( + new NotificationCompat.Action.Builder( + R.drawable.ic_cancel_24dp, + context.getString(R.string.cancel), + cancelPendingIntent) + .build()); + } + final Progress progress = new Progress(notification, max, count); + final File directory = file.getParentFile(); + if (directory != null && directory.mkdirs()) { + Log.d(Config.LOGTAG, "created backup directory " + directory.getAbsolutePath()); + } + final FileOutputStream fileOutputStream = new FileOutputStream(file); + final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); + backupFileHeader.write(dataOutputStream); + dataOutputStream.flush(); + + final Cipher cipher = + Compatibility.twentyEight() + ? Cipher.getInstance(CIPHERMODE) + : Cipher.getInstance(CIPHERMODE, PROVIDER); + final byte[] key = getKey(password, salt); + SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE); + IvParameterSpec ivSpec = new IvParameterSpec(IV); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); + CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher); + + final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(cipherOutputStream); + final JsonWriter jsonWriter = + new JsonWriter(new OutputStreamWriter(gzipOutputStream, StandardCharsets.UTF_8)); + jsonWriter.beginArray(); + final SQLiteDatabase db = database.getReadableDatabase(); + final String uuid = account.getUuid(); + accountExport(db, uuid, jsonWriter); + simpleExport(db, Conversation.TABLENAME, Conversation.ACCOUNT, uuid, jsonWriter); + messageExport(db, uuid, jsonWriter, progress); + for (final String table : + Arrays.asList( + SQLiteAxolotlStore.PREKEY_TABLENAME, + SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, + SQLiteAxolotlStore.SESSION_TABLENAME, + SQLiteAxolotlStore.IDENTITIES_TABLENAME)) { + throwIfWorkStopped(); + simpleExport(db, table, SQLiteAxolotlStore.ACCOUNT, uuid, jsonWriter); + } + jsonWriter.endArray(); + jsonWriter.flush(); + jsonWriter.close(); + mediaScannerScanFile(file); + Log.d(Config.LOGTAG, "written backup to " + file.getAbsoluteFile()); + } + + private NotificationCompat.Builder getNotification() { + final var context = getApplicationContext(); + final NotificationCompat.Builder notification = + new NotificationCompat.Builder(context, "backup"); + notification + .setContentTitle(context.getString(R.string.notification_create_backup_title)) + .setSmallIcon(R.drawable.ic_archive_24dp) + .setProgress(1, 0, false); + notification.setOngoing(true); + notification.setLocalOnly(true); + return notification; + } + + private void throwIfWorkStopped() throws WorkStoppedException { + if (isStopped()) { + throw new WorkStoppedException(); + } } private void mediaScannerScanFile(final File file) { @@ -313,7 +377,7 @@ public class ExportBackupWorker extends Worker { final String uuid, final JsonWriter writer, final Progress progress) - throws IOException { + throws IOException, WorkStoppedException { final var notificationManager = getApplicationContext().getSystemService(NotificationManager.class); try (final Cursor cursor = @@ -322,9 +386,11 @@ public class ExportBackupWorker extends Worker { new String[] {uuid})) { final int size = cursor != null ? cursor.getCount() : 0; Log.d(Config.LOGTAG, "exporting " + size + " messages for account " + uuid); + long lastUpdate = 0; int i = 0; - int p = 0; + int p = Integer.MIN_VALUE; while (cursor != null && cursor.moveToNext()) { + throwIfWorkStopped(); writer.beginObject(); writer.name("table"); writer.value(Message.TABLENAME); @@ -339,8 +405,9 @@ public class ExportBackupWorker extends Worker { writer.endObject(); writer.endObject(); final int percentage = i * 100 / size; - if (p < percentage) { + if (p < percentage && (SystemClock.elapsedRealtime() - lastUpdate) > 2_000) { p = percentage; + lastUpdate = SystemClock.elapsedRealtime(); notificationManager.notify(NOTIFICATION_ID, progress.build(p)); } i++; @@ -377,13 +444,7 @@ public class ExportBackupWorker extends Worker { final Intent chooser = Intent.createChooser(intent, context.getString(R.string.share_backup_files)); final var shareFilesIntent = - PendingIntent.getActivity( - context, - 190, - chooser, - s() - ? PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT - : PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent.getActivity(context, 190, chooser, PENDING_INTENT_FLAGS); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, "backup"); mBuilder.setContentTitle(context.getString(R.string.notification_backup_created_title)) @@ -418,14 +479,7 @@ public class ExportBackupWorker extends Worker { for (final Intent intent : getPossibleFileOpenIntents(context, path)) { if (intent.resolveActivityInfo(context.getPackageManager(), 0) != null) { return Optional.of( - PendingIntent.getActivity( - context, - 189, - intent, - s() - ? PendingIntent.FLAG_IMMUTABLE - | PendingIntent.FLAG_UPDATE_CURRENT - : PendingIntent.FLAG_UPDATE_CURRENT)); + PendingIntent.getActivity(context, 189, intent, PENDING_INTENT_FLAGS)); } } return Optional.absent(); @@ -474,4 +528,6 @@ public class ExportBackupWorker extends Worker { return notification.build(); } } + + private static class WorkStoppedException extends Exception {} } From 9bf1e51ac4dd86ffbfece1f5af132295983eba08 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 3 May 2024 09:41:29 +0200 Subject: [PATCH 46/57] fix opening ringtone chooser when channel sound was set to null --- .../conversations/ui/activity/result/PickRingtone.java | 10 +++++++--- .../settings/NotificationsSettingsFragment.java | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java b/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java index b58a7f3982eee98cf9782a2caada0344e10cfd32..975ba9431fcf1712947592d17ba027a0793f2a20 100644 --- a/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java +++ b/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.media.RingtoneManager; import android.net.Uri; + import androidx.activity.result.contract.ActivityResultContract; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -26,7 +27,7 @@ public class PickRingtone extends ActivityResultContract { intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, ringToneType); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); - if (existing != null) { + if (noneToNull(existing) != null) { intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, existing); } return intent; @@ -37,11 +38,14 @@ public class PickRingtone extends ActivityResultContract { if (resultCode != Activity.RESULT_OK || data == null) { return null; } - final Uri pickedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); - return pickedUri == null ? NONE : pickedUri; + return nullToNone(data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)); } public static Uri noneToNull(final Uri uri) { return uri == null || NONE.equals(uri) ? null : uri; } + + public static @NonNull Uri nullToNone(final Uri uri) { + return uri == null ? NONE : uri; + } } diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java index 6f9c62ecb94b0d5fefb0197f0c817d547859801f..885f94f99aa739ac49ba7d8534ae958ec2f45ea7 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java @@ -119,7 +119,7 @@ public class NotificationsSettingsFragment extends XmppPreferenceFragment { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { channelRingtone = NotificationService.getCurrentIncomingCallChannel(requireContext()) - .transform(NotificationChannel::getSound); + .transform(channel -> PickRingtone.nullToNone(channel.getSound())); } else { channelRingtone = Optional.absent(); } From 069b02004f85bd4f31f621095dcb711b6f2b0983 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 3 May 2024 11:26:41 +0200 Subject: [PATCH 47/57] deep link into FSI setting if not granted --- .../NotificationsSettingsFragment.java | 46 ++++++++++++++++++- src/main/res/drawable/ic_smartphone_24dp.xml | 12 +++++ src/main/res/values/strings.xml | 2 + .../res/xml/preferences_notifications.xml | 5 ++ 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/main/res/drawable/ic_smartphone_24dp.xml diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java index 885f94f99aa739ac49ba7d8534ae958ec2f45ea7..5d02c8d2123855f37b7eb7842caf6ef0ee2bd7ee 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java @@ -1,11 +1,15 @@ package eu.siacs.conversations.ui.fragment.settings; -import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.ActivityNotFoundException; +import android.content.Intent; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.provider.Settings; import android.util.Log; +import android.widget.Toast; import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; @@ -56,12 +60,14 @@ public class NotificationsSettingsFragment extends XmppPreferenceFragment { @Nullable final Bundle savedInstanceState, final @Nullable String rootKey) { setPreferencesFromResource(R.xml.preferences_notifications, rootKey); final var messageNotificationSettings = findPreference("message_notification_settings"); + final var fullscreenNotification = findPreference("fullscreen_notification"); final var notificationRingtone = findPreference(AppSettings.NOTIFICATION_RINGTONE); final var notificationHeadsUp = findPreference(AppSettings.NOTIFICATION_HEADS_UP); final var notificationVibrate = findPreference(AppSettings.NOTIFICATION_VIBRATE); final var notificationLed = findPreference(AppSettings.NOTIFICATION_LED); final var foregroundService = findPreference(AppSettings.KEEP_FOREGROUND_SERVICE); if (messageNotificationSettings == null + || fullscreenNotification == null || notificationRingtone == null || notificationHeadsUp == null || notificationVibrate == null @@ -78,6 +84,44 @@ public class NotificationsSettingsFragment extends XmppPreferenceFragment { } else { messageNotificationSettings.setVisible(false); } + fullscreenNotification.setOnPreferenceClickListener(this::manageAppUseFullScreen); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE + || requireContext() + .getSystemService(NotificationManager.class) + .canUseFullScreenIntent()) { + fullscreenNotification.setVisible(false); + } + } + + @Override + public void onResume() { + super.onResume(); + final var fullscreenNotification = findPreference("fullscreen_notification"); + if (fullscreenNotification == null) { + return; + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE + || requireContext() + .getSystemService(NotificationManager.class) + .canUseFullScreenIntent()) { + fullscreenNotification.setVisible(false); + } + } + + private boolean manageAppUseFullScreen(final Preference preference) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + return false; + } + final var intent = new Intent(Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT); + intent.setData(Uri.parse(String.format("package:%s", requireContext().getPackageName()))); + try { + startActivity(intent); + } catch (final ActivityNotFoundException e) { + Toast.makeText(requireContext(), R.string.no_application_found, Toast.LENGTH_SHORT) + .show(); + return false; + } + return true; } @Override diff --git a/src/main/res/drawable/ic_smartphone_24dp.xml b/src/main/res/drawable/ic_smartphone_24dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..832fa3a7662bdb24cd9a64ad060d1940f2417b63 --- /dev/null +++ b/src/main/res/drawable/ic_smartphone_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 356e828cf2a6327cd82f962d8508739ab76db914..e5c3d376f4786eabbca5d1178d853dfa418f5758 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1062,5 +1062,7 @@ Create one-off, Schedule recurring Create one-off backup Recurring backup + Full screen notifications + Allow this app to show incoming call notifications that take up the full screen when the device is locked. diff --git a/src/main/res/xml/preferences_notifications.xml b/src/main/res/xml/preferences_notifications.xml index 82e74efc907bd52ce2ae49d462f131af626bd87e..da505b65f4c87a4738fa7831f3c118ae56bcaa5b 100644 --- a/src/main/res/xml/preferences_notifications.xml +++ b/src/main/res/xml/preferences_notifications.xml @@ -46,6 +46,11 @@ android:ringtoneType="ringtone" android:summary="@string/pref_call_ringtone_summary" android:title="@string/pref_ringtone" /> + Date: Sat, 4 May 2024 15:49:05 +0200 Subject: [PATCH 48/57] support mute via call integration --- .../services/CallIntegration.java | 22 ++++++++++++- .../NotificationsSettingsFragment.java | 2 +- .../xmpp/jingle/JingleConnectionManager.java | 10 +++--- .../xmpp/jingle/JingleRtpConnection.java | 8 ++++- .../xmpp/jingle/WebRTCWrapper.java | 31 +++++++++++++------ src/main/res/values/strings.xml | 2 +- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/CallIntegration.java b/src/main/java/eu/siacs/conversations/services/CallIntegration.java index 80fd42021e248ea0894d428d94533eabebe9cad2..28cdb36e583d13a7cbf312361fa223ea5e8a8435 100644 --- a/src/main/java/eu/siacs/conversations/services/CallIntegration.java +++ b/src/main/java/eu/siacs/conversations/services/CallIntegration.java @@ -39,7 +39,7 @@ public class CallIntegration extends Connection { private static final List BROKEN_DEVICE_MODELS = Arrays.asList( "OnePlus6" // OnePlus 6 (Android 8.1-11) Device is buggy and always starts the - // OS call screen even though we want to be self managed + // OS call screen even though we want to be self managed ); public static final int DEFAULT_TONE_VOLUME = 60; @@ -56,6 +56,7 @@ public class CallIntegration extends Connection { private final AtomicBoolean isDestroyed = new AtomicBoolean(false); private List availableEndpoints = Collections.emptyList(); + private boolean isMicrophoneEnabled = true; private Callback callback = null; @@ -74,6 +75,7 @@ public class CallIntegration extends Connection { this.appRTCAudioManager.setAudioManagerEvents(this::onAudioDeviceChanged); } setRingbackRequested(true); + setConnectionCapabilities(CAPABILITY_MUTE | CAPABILITY_RESPOND_VIA_TEXT); } public void setCallback(final Callback callback) { @@ -139,10 +141,26 @@ public class CallIntegration extends Connection { Log.d(Config.LOGTAG, "ignoring onCallAudioStateChange() on Upside Down Cake"); return; } + setMicrophoneEnabled(!state.isMuted()); Log.d(Config.LOGTAG, "onCallAudioStateChange(" + state + ")"); this.onAudioDeviceChanged(getAudioDeviceOreo(state), getAudioDevicesOreo(state)); } + @Override + public void onMuteStateChanged(final boolean isMuted) { + Log.d(Config.LOGTAG, "onMuteStateChanged(" + isMuted + ")"); + setMicrophoneEnabled(!isMuted); + } + + private void setMicrophoneEnabled(final boolean enabled) { + this.isMicrophoneEnabled = enabled; + this.callback.onCallIntegrationMicrophoneEnabled(enabled); + } + + public boolean isMicrophoneEnabled() { + return this.isMicrophoneEnabled; + } + public Set getAudioDevices() { if (notSelfManaged(context)) { return getAudioDevicesFallback(); @@ -578,5 +596,7 @@ public class CallIntegration extends Connection { void onCallIntegrationAnswer(); void onCallIntegrationSilence(); + + void onCallIntegrationMicrophoneEnabled(boolean enabled); } } diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java index 5d02c8d2123855f37b7eb7842caf6ef0ee2bd7ee..b354ebaff32a1cf06fde3b3da9d5b23ba83283f8 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java @@ -117,7 +117,7 @@ public class NotificationsSettingsFragment extends XmppPreferenceFragment { try { startActivity(intent); } catch (final ActivityNotFoundException e) { - Toast.makeText(requireContext(), R.string.no_application_found, Toast.LENGTH_SHORT) + Toast.makeText(requireContext(), R.string.unsupported_operation, Toast.LENGTH_SHORT) .show(); return false; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 5f5a523e10ca2d91ccebac4c63ceb3afdff0ed0a..ba6ccf19d0ad9635afb6e0c6b6d9647e68a12cf8 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -649,7 +649,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { } public JingleRtpConnection getOngoingRtpConnection() { - for(final AbstractJingleConnection jingleConnection : this.connections.values()) { + for (final AbstractJingleConnection jingleConnection : this.connections.values()) { if (jingleConnection instanceof JingleRtpConnection jingleRtpConnection) { if (jingleRtpConnection.isTerminated()) { continue; @@ -986,10 +986,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { this.rtpSessionProposals.remove(sessionProposal); sessionProposal.getCallIntegration().error(); mXmppConnectionService.notifyJingleRtpConnectionUpdate( - account, - sessionProposal.with, - sessionProposal.sessionId, - endUserState); + account, sessionProposal.with, sessionProposal.sessionId, endUserState); return; } @@ -1226,5 +1223,8 @@ public class JingleConnectionManager extends AbstractConnectionManager { @Override public void onCallIntegrationSilence() {} + + @Override + public void onCallIntegrationMicrophoneEnabled(boolean enabled) {} } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 234c429cb5b16736194aa7b3f0149c15a2a7e412..695ce20b46f3bb703a4cc6db450b30749446c510 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -2324,6 +2324,7 @@ public class JingleRtpConnection extends AbstractJingleConnection this.jingleConnectionManager.ensureConnectionIsRegistered(this); this.webRTCWrapper.setup(this.xmppConnectionService); this.webRTCWrapper.initializePeerConnection(media, iceServers, trickle); + this.webRTCWrapper.setMicrophoneEnabledOrThrow(callIntegration.isMicrophoneEnabled()); } private void acceptCallFromProposed() { @@ -2686,7 +2687,7 @@ public class JingleRtpConnection extends AbstractJingleConnection } public boolean setMicrophoneEnabled(final boolean enabled) { - return webRTCWrapper.setMicrophoneEnabled(enabled); + return webRTCWrapper.setMicrophoneEnabledOrThrow(enabled); } public boolean isVideoEnabled() { @@ -2762,6 +2763,11 @@ public class JingleRtpConnection extends AbstractJingleConnection xmppConnectionService.getNotificationService().stopSoundAndVibration(); } + @Override + public void onCallIntegrationMicrophoneEnabled(final boolean enabled) { + this.webRTCWrapper.setMicrophoneEnabled(enabled); + } + @Override public void onAudioDeviceChanged( final CallIntegration.AudioDevice selectedAudioDevice, diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java index 8bc7c6f6f0c7c7265a7451d16f0081b77704eeeb..36433790f104b337d77d8d1060c3f8ed4c18db2f 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java @@ -506,23 +506,36 @@ public class WebRTCWrapper { } } - boolean setMicrophoneEnabled(final boolean enabled) { + boolean setMicrophoneEnabledOrThrow(final boolean enabled) { final Optional audioTrack = TrackWrapper.get(peerConnection, this.localAudioTrack); if (audioTrack.isPresent()) { - try { - audioTrack.get().setEnabled(enabled); - return true; - } catch (final IllegalStateException e) { - Log.d(Config.LOGTAG, "unable to toggle microphone", e); - // ignoring race condition in case MediaStreamTrack has been disposed - return false; - } + return setEnabled(audioTrack.get(), enabled); + } else { throw new IllegalStateException("Local audio track does not exist (yet)"); } } + private static boolean setEnabled(final AudioTrack audioTrack, final boolean enabled) { + try { + audioTrack.setEnabled(enabled); + return true; + } catch (final IllegalStateException e) { + Log.d(Config.LOGTAG, "unable to toggle audio track", e); + // ignoring race condition in case MediaStreamTrack has been disposed + return false; + } + } + + void setMicrophoneEnabled(final boolean enabled) { + final Optional audioTrack = + TrackWrapper.get(peerConnection, this.localAudioTrack); + if (audioTrack.isPresent()) { + setEnabled(audioTrack.get(), enabled); + } + } + boolean isVideoEnabled() { final Optional videoTrack = TrackWrapper.get(peerConnection, this.localVideoTrack); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e5c3d376f4786eabbca5d1178d853dfa418f5758..0310425e689dd80a831855c3ef4a4698bd304186 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1064,5 +1064,5 @@ Recurring backup Full screen notifications Allow this app to show incoming call notifications that take up the full screen when the device is locked. - + Unsupported operation From 3461862371fe8598796ad6dce609808a19596dc5 Mon Sep 17 00:00:00 2001 From: Besnik_b Date: Sat, 27 Apr 2024 10:27:46 +0000 Subject: [PATCH 49/57] Translated using Weblate (Albanian) Currently translated at 99.2% (1008 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/sq/ --- src/main/res/values-sq-rAL/strings.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-sq-rAL/strings.xml b/src/main/res/values-sq-rAL/strings.xml index fa0b62ec218393f1f5d71cd0281deea4e2cf4c2a..c37741aa94fa0e2d70d002797ba103d5951ac775 100644 --- a/src/main/res/values-sq-rAL/strings.xml +++ b/src/main/res/values-sq-rAL/strings.xml @@ -1022,7 +1022,7 @@ Doni të hiqet faqerojtësi për %s dhe arkivohet fjalosja? Fshije & Arkivoje fjalosjen Doni të hiqet faqerojtësi për %s? - Flluska të ngjyrosura fjalosjeje ndihmojnë të dalloni mesazhe të dërguar dhe të marrë + Ngjyra të dallueshme sfondi për mesazhe të dërguar dhe të marrë Ngjyra dinamike Ngjyra Sistemi (Material You) U ngjit automatikisht nga e papastra PIN i mundshëm. @@ -1074,4 +1074,8 @@ Kur veprohet si një Distributor UnifiedPush, për të zgjuar aplikacion tjetër të përputhshëm me UnifiedPush , fjala vjen, Tusky, Ltt.rs, FluffyChat, etj, do të përdoret lidhja XMPP, e vazhdueshme, e qëndrueshme dhe miqësore ndaj baterisë. Distributor UnifiedPush Dërgo mesazh të fshehtëzuar + Ftesa nga të panjohur + Prano ftesa për fjalosje në grup nga të panjohur + Shkronja të mëdha + Rrit madhësi shkronja në flluska mesazhesh \ No newline at end of file From 78a2ed6ccf38c38d3c3723483c7eed0c13ce4a57 Mon Sep 17 00:00:00 2001 From: Besnik_b Date: Sat, 27 Apr 2024 10:27:01 +0000 Subject: [PATCH 50/57] Translated using Weblate (Albanian) Currently translated at 100.0% (64 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/sq/ --- fastlane/metadata/android/sq/changelogs/4210804.txt | 2 ++ fastlane/metadata/android/sq/changelogs/4210904.txt | 2 ++ fastlane/metadata/android/sq/changelogs/4211004.txt | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 fastlane/metadata/android/sq/changelogs/4210804.txt create mode 100644 fastlane/metadata/android/sq/changelogs/4210904.txt create mode 100644 fastlane/metadata/android/sq/changelogs/4211004.txt diff --git a/fastlane/metadata/android/sq/changelogs/4210804.txt b/fastlane/metadata/android/sq/changelogs/4210804.txt new file mode 100644 index 0000000000000000000000000000000000000000..e77cdf0267c4a344f0b52b81edd069d153b89cd3 --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/4210804.txt @@ -0,0 +1,2 @@ +* Shfaqe gjendje mesazhesh si ikona +* Sjellje e rregullimit “Shkronja të mëdha” për flluska mesazhesh diff --git a/fastlane/metadata/android/sq/changelogs/4210904.txt b/fastlane/metadata/android/sq/changelogs/4210904.txt new file mode 100644 index 0000000000000000000000000000000000000000..1a7c4e53123dd02b3457a93e3d1310fb034886de --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/4210904.txt @@ -0,0 +1,2 @@ +* Ndreqje regjistrimi Quicksy në Android 6/7 +* Luajtje e ziles së thirrjes ardhëse në kanal njoftimi diff --git a/fastlane/metadata/android/sq/changelogs/4211004.txt b/fastlane/metadata/android/sq/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..21be2d1b2d3109a4e31a7225ada9d5c592843e39 --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* ndreqje integrimi thirrjesh në disa pajisje me Android 14 +* Sjellje për herë të parë e rregullimit “Ftesa nga të Panjohur” From 4c40a197cc5489abc1c0f6b0029a85ced1082d49 Mon Sep 17 00:00:00 2001 From: random_r Date: Mon, 29 Apr 2024 10:23:44 +0000 Subject: [PATCH 51/57] Translated using Weblate (Italian) Currently translated at 100.0% (1016 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/it/ --- src/main/res/values-it/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index eab8c2601d203c286192d28ddbeb1bc6ce4b12b6..a3b8c3f26c0872aaf690afa263ca4ade487c889c 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -1078,4 +1078,6 @@ Autorità di certificazione Caratteri grandi Aumenta la dimensione dei caratteri nei messaggi + Inviti da estranei + Accetta inviti a chat di gruppo da estranei \ No newline at end of file From f49879a1a758315e3ebdb2a381e2b624078ab2b4 Mon Sep 17 00:00:00 2001 From: woutput Date: Tue, 30 Apr 2024 02:32:37 +0000 Subject: [PATCH 52/57] Translated using Weblate (Dutch) Currently translated at 73.1% (743 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/nl/ --- src/main/res/values-nl/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 109e0a7d5455edf84807515b86731fcc3451e743..f08e9e4777ac3ea66fa33515c1ed2dea0313ac14 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -798,4 +798,8 @@ Onversleuteld document Accountregistraties zijn niet ondersteund Door crashrapportages te versturen help je de ontwikkeling + Inloggen met certificaat + Chat archiveren + Kan niet verbinden met OpenKeychain + Chat starten \ No newline at end of file From 0a4a518bbb94441ecacb90fea86abe66e792a7d9 Mon Sep 17 00:00:00 2001 From: random_r Date: Mon, 29 Apr 2024 10:25:04 +0000 Subject: [PATCH 53/57] Translated using Weblate (Italian) Currently translated at 100.0% (64 of 64 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/it/ --- fastlane/metadata/android/it-IT/changelogs/4211004.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/it-IT/changelogs/4211004.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/4211004.txt b/fastlane/metadata/android/it-IT/changelogs/4211004.txt new file mode 100644 index 0000000000000000000000000000000000000000..771eb3ba9944659238ae679f9134d23e39ab8626 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/4211004.txt @@ -0,0 +1,2 @@ +* corretta l'integrazione delle chiamate su alcuni dispositivi con Android 14 +* Introdotta l'impostazione 'Inviti da estranei' From 36aeb0b07bb1f0c73eb2fd0f373f9ffef2d997af Mon Sep 17 00:00:00 2001 From: nautilusx Date: Tue, 30 Apr 2024 14:28:16 +0000 Subject: [PATCH 54/57] Translated using Weblate (French) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/fr/ --- src/conversations/res/values-fr/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/res/values-fr/strings.xml b/src/conversations/res/values-fr/strings.xml index ba7122979650f86a7e3281a23475ab7d97be7625..68de25b54251a43abc609d88a7bb38fec262176c 100644 --- a/src/conversations/res/values-fr/strings.xml +++ b/src/conversations/res/values-fr/strings.xml @@ -12,6 +12,6 @@ Code de provisionnement mal formaté Appuyez sur le bouton partager pour envoyer à votre contact une invitation pour %1$s. Si vos contacts sont à proximité, ils peuvent aussi scanner le code ci-dessous pour accepter votre invitation. - Rejoignez %1$set discutez avec moi : %2$s + Rejoignez %1$s et discutez avec moi : %2$s Partager une invitation avec … \ No newline at end of file From 730f087a861b506351b10a2d37d6471380a47006 Mon Sep 17 00:00:00 2001 From: Mako Date: Sun, 5 May 2024 02:28:34 +0000 Subject: [PATCH 55/57] Translated using Weblate (Japanese) Currently translated at 98.7% (1003 of 1016 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ja/ --- src/main/res/values-ja/strings.xml | 123 +++++++++++++++++++---------- 1 file changed, 82 insertions(+), 41 deletions(-) diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index 727e81db8324ab801e3ab477f68b12f698a6bb7e..6b40fa2940a8a26fe67cecacbc6764d8333948f7 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -39,10 +39,10 @@ 参加者 訪問者 連絡先リストから%sを削除しますか? この連絡先との会話は削除されません。 - %sからあなたに送信されるメッセージをブロックしますか? + %sからあなたに送信されるメッセージをブロックしますか ? %s のブロックを解除し、あなたにメッセージを送信できるようにしますか? - %sの連絡先をすべてブロックしますか? - %sのすべての連絡先のブロックを解除しますか? + %sの連絡先をすべてブロックしますか ? + %sのすべての連絡先のブロックを解除しますか ? 連絡先をブロックしました ブロックしました サーバーに新規アカウントを登録 @@ -69,7 +69,7 @@ 複数のアカウントに接続できません タップしてアカウントを管理 ファイルを添付 - 連絡先が連絡先リストにありません。リストに追加しますか? + 連絡先が連絡先リストにありません。リストに追加しますか ? 連絡先を追加 配信に失敗しました 送信用画像の準備中 @@ -83,7 +83,7 @@ ファイルを削除 このファイルを削除してもよろしいですか?\n\n警告: これは、他のデバイスやサーバーに保存されているファイルのコピーは削除しません。 デバイスを選択 - 暗号化されていないメッセージを送信 + 暗号化されないメッセージを送信 メッセージを送信 メッセージを %s に送信 v\\OMEMO 暗号化メッセージを送信 @@ -108,7 +108,7 @@ 自動的に小さいファイルを受取… 添付ファイル 通知 - 振動 + バイブレート 新着メッセージが届いたときに振動します LED 通知 新着メッセージが届いたときに通知ライトを点滅します @@ -121,7 +121,7 @@ 詳細 スタックトレースを送信すると、 開発の助けとなります メッセージを確認 - あなたがメッセージを受信して読んだときに、連絡先に知らせる + あなたがメッセージを受信して読んだときに、連絡先に知らせます スクリーンショットを防ぐ アプリスイッチャー内でアプリの内容を隠し、スクリーンショットを防ぐ UI @@ -148,7 +148,7 @@ オンライン 接続中\u2026 オフライン - 許可されていません + 認証されていません サーバーが見つかりません 接続なし 登録に失敗しました @@ -163,7 +163,7 @@ 互換性のない端末 ストリーム エラー ストリームを開く際にエラー - 暗号化しない + 平文 OTR OpenPGP OMEMO @@ -175,7 +175,7 @@ 出席情報告知から OpenPGP 公開鍵を削除してもよろしいですか?\n連絡先はあなたに OpenPGP 暗号化メッセージを送信できなくなります。 OpenPGP 公開鍵を公開しました。 アカウントを有効化 - アカウントを削除してよろしいですか?アカウントを削除すると会話履歴がすべて消去されます + アカウントを削除してよろしいですか ? アカウントを削除すると会話履歴がすべて消去されます 音声を録音 XMPP アドレス XMPP アドレスをブロック @@ -272,7 +272,7 @@ 無視 警告: 相互の出席情報アップデートなしにこれを送信すると、予期しない問題が発生する可能性があります。\n\nあなたの出席情報サブスクリプションを検証するために、“連絡先の詳細”に移動します。 セキュリティ - メッセージの修正を許可 + メッセージの修正 連絡先が、遡及的に自分のメッセージを編集することを許可します エキスパート設定 ご利用には注意してください @@ -401,7 +401,7 @@ Enter で送信 メッセージの送信に Enter キーを使用します。このオプションが無効でも、常に Ctrl+Enter でメッセージを送信できます。 Enter キーを表示 - 絵文字キーを Enter キーに変更 + 絵文字キーを Enter キーに変更します 音声 ビデオ 画像 @@ -419,7 +419,7 @@ %s さんが入力中… %s さんが入力を止めました 入力中通知 - あなたがメッセージを書いているときに、連絡先に知らせる + あなたがメッセージを書いているときに、連絡先に知らせます 位置を送信 位置を表示 位置を表示するアプリケーションが見つかりません @@ -436,7 +436,7 @@ %d個の証明書を削除しました - “送信”ボタンをクイックアクションで置き換える + “送信”ボタンをクイックアクションで置き換えます クイックアクション なし 最近使用した @@ -458,20 +458,20 @@ 壊れています 在席状況 デバイスがロックされているときは離席 - デバイスがロックされているときは離席と表示 + デバイスがロックされているときは離席と表示します サイレントモードのときは取込中 - デバイスがサイレントモードのときは取込中と表示 + デバイスがサイレントモードのときは取込中と表示します バイブレートをサイレントモードとして扱う - デバイスがバイブレートのときは取込中と表示 - 拡張接続設定 - アカウントを設定するときに、ホスト名とポートの設定を表示 + デバイスがバイブレートのときは取込中と表示します + ホスト名とポート番号 + アカウントを設定するときに、拡張設定項目を表示します xmpp.example.com 証明書でログイン 証明書を解析できません - アーカイブ設定 - サーバー側のアーカイブ設定 - アーカイブ設定を取得しています。しばらくお待ちください… - アーカイブ設定を取得できません + 保管の設定 + サーバー側の保管の設定 + 保管の設定を取得しています。しばらくお待ちください… + 保管の設定を取得できません キャプチャが要求されました 上の画像からテキストを入力してください 信頼できない証明書チェーン @@ -551,8 +551,8 @@ - ブロードキャストを使用 - Conversations を使用するときに、連絡先に知らせましょう + 最後に見たのは + 最後にこのアプリを使用したのがいつかを、連絡先に知らせます プライバシー テーマ カラーパレットの選択 @@ -674,7 +674,7 @@ 一度だけ QR コードスキャナーはカメラにアクセスが必要です 一番下へスクロール - メッセージ送信後に下へスクロール + メッセージ送信後に下へスクロールします ステータスメッセージを編集 ステータスメッセージを編集 暗号化が無効 @@ -743,7 +743,7 @@ 配信に失敗 メッセージ通知設定 着信通話の通知設定 - 重要性、音、振動 + 重要性、音、バイブレーション ビデオの圧縮 メディアを表示 参加者 @@ -768,20 +768,20 @@ %s を検証 %sにSMSを送りました。]]> 6桁のコードを含む別のSMSを送信しました。 - 以下に6桁の pin を入力してください。 + 以下に6桁の PIN を入力してください。 SMS 再送信 SMS 再送信(%s) しばらくお待ちください(%s) 戻る - クリップボードから可能な pin を自動的に貼り付ける。 - 6桁の pin を入力してください。 - 登録手続きを中止してもよろしいのですか? + クリップボードから可能な PIN を自動的に貼り付ける。 + 6桁の PIN を入力してください。 + 登録手続きを中止してもよろしいですか ? はい いいえ 検証しています… SMSを要求しています… - 入力された pin が正しくありません。 - 送信した pin の有効期限が切れています。 + 入力された PIN が正しくありません。 + 送信した PIN の有効期限が切れています。 未知のネットワークエラー。 サーバーからの不明な応答。 サーバーに接続できません。 @@ -875,8 +875,8 @@ アカウントを有効化してください 通話をする 着信通話 - 着信映像通話 - ビデオ通話に切り替えますか? + ビデオ通話の着信 + ビデオ通話に切り替えますか ? 接続中 接続しました 再接続中 @@ -912,7 +912,7 @@ %2$d人から%1$d件の不在着信 音声通話 - 映像通話 + ビデオ通話 ヘルプ マイクが利用できません 1度に1回線の通話のみ。 @@ -945,16 +945,16 @@ アプリケーションが見つかりません Conversationsに招待 招待を解析できません - サーバーは招待の作成をサポートしていません + サーバーは招待の作成に対応していません この機能をサポートするアクティブなアカウントがありません バックアップを開始しました。 バックアップが完了すると通知が届きます。 - 映像を有効化できません。 + ビデオを有効化できません。 プレーンテキスト文書 アカウント登録はサポートされていません XMPPアドレスがみつかりません 一時的な認証失敗 アバターを削除 - Tor使用中のため通話できません + Tor 使用中のため通話できません ビデオ通話へ切替 このアカウントをログアウトしました ルート @@ -993,9 +993,50 @@ 連絡先は未検証のデバイスを使用しています。 QR コードをスキャンして検証を実行し、アクティブな MITM 攻撃を阻止してください。 未検証のデバイスを使用しています。他のデバイスで QR コードをスキャンして検証を実行し、アクティブな MITM 攻撃を阻止してください。 電話をかける権限がありません - %s のブックマークを削除して会話を閉じますか ? + %s のブックマークを削除して会話を保管しますか ? %s のブックマークを削除しますか ? 通話の統合は利用できません。 連絡先は利用できません - 削除して閉じる + 削除して会話を保管 + クラッシュ報告を送信 + 対応する会話は保管されました。 + クライアント証明書が選択されていません。 + ホスト名とポート番号、Tor + このデバイスで + 猶予期間、着信音、バイブレーション、見知らぬ人 + 端末間暗号化、検証前の無条件の信頼、MITM検出 + 会話を保管 + 新しい会話 + この会話を保管 + システムの配色 (Material You) + 暗号化メッセージを送信 + 会話は保管されました + 多彩な会話の吹き出し + 会話に切り替え + インターフェース + テーマ、配色、スクリーンショット、入力 + 外観 + 明暗モード + スクリーンショットを許可 + アプリのスイッチャーでアプリのコンテンツを表示し、スクリーンショットの撮影を許可します + セキュリティ + 端末間暗号化 + 認証局 + 通知 + ファイルサイズ、画像圧縮、ビデオ品質 + 自動ダウンロード + 受信時 + 送信時 + 会話を開始 + アプリケーション + オペレーティングシステム + キーボード + サーバー接続 + システムの CA を信頼します + ホスト名とポート番号、Tor、チャンネル探索 + 見知らぬ人からのグループチャットへの招待を受け入れます + 見知らぬ人からの招待 + 送受信メッセージの個別の背景色 + メッセージの吹き出しのフォントサイズを大きくする + 大きなフォント \ No newline at end of file From 359b2150eb8287dce6861a04fd6b8f8eeb620ec4 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 6 May 2024 13:26:16 +0200 Subject: [PATCH 56/57] move PushMessageReceiver to receiver package --- src/playstore/AndroidManifest.xml | 2 +- .../{services => receiver}/PushMessageReceiver.java | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) rename src/playstore/java/eu/siacs/conversations/{services => receiver}/PushMessageReceiver.java (74%) diff --git a/src/playstore/AndroidManifest.xml b/src/playstore/AndroidManifest.xml index 2f339c96f09dfa0a2180294b99c331d2f4b59da8..e64f7e40b344f35d25f8d68a789a3ec35f162774 100644 --- a/src/playstore/AndroidManifest.xml +++ b/src/playstore/AndroidManifest.xml @@ -24,7 +24,7 @@ diff --git a/src/playstore/java/eu/siacs/conversations/services/PushMessageReceiver.java b/src/playstore/java/eu/siacs/conversations/receiver/PushMessageReceiver.java similarity index 74% rename from src/playstore/java/eu/siacs/conversations/services/PushMessageReceiver.java rename to src/playstore/java/eu/siacs/conversations/receiver/PushMessageReceiver.java index f060747a5bd981bb057d981dd7071916466e2b7d..40812c10d910b0748c4b8ae2e471b0fbcecb96ee 100644 --- a/src/playstore/java/eu/siacs/conversations/services/PushMessageReceiver.java +++ b/src/playstore/java/eu/siacs/conversations/receiver/PushMessageReceiver.java @@ -1,21 +1,24 @@ -package eu.siacs.conversations.services; +package eu.siacs.conversations.receiver; import android.content.Intent; import android.util.Log; +import androidx.annotation.NonNull; + import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import java.util.Map; import eu.siacs.conversations.Config; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.Compatibility; public class PushMessageReceiver extends FirebaseMessagingService { @Override - public void onMessageReceived(RemoteMessage message) { - if (!EventReceiver.hasEnabledAccounts(this)) { + public void onMessageReceived(@NonNull final RemoteMessage message) { + if (!SystemEventReceiver.hasEnabledAccounts(this)) { Log.d(Config.LOGTAG,"PushMessageReceiver ignored message because no accounts are enabled"); return; } @@ -27,8 +30,8 @@ public class PushMessageReceiver extends FirebaseMessagingService { } @Override - public void onNewToken(String token) { - if (!EventReceiver.hasEnabledAccounts(this)) { + public void onNewToken(@NonNull final String token) { + if (!SystemEventReceiver.hasEnabledAccounts(this)) { Log.d(Config.LOGTAG,"PushMessageReceiver ignored new token because no accounts are enabled"); return; } From a46246c42322a9d9fcc510be5751b66e0c623daa Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 6 May 2024 13:40:10 +0200 Subject: [PATCH 57/57] synchronize renegotiate to avoid race condition when that fails --- .../conversations/xmpp/jingle/JingleRtpConnection.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 695ce20b46f3bb703a4cc6db450b30749446c510..f682f41607f1a369e02f43570e642c315fb926dc 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -2482,7 +2482,7 @@ public class JingleRtpConnection extends AbstractJingleConnection this.webRTCWrapper.execute(this::renegotiate); } - private void renegotiate() { + private synchronized void renegotiate() { final SessionDescription sessionDescription; try { sessionDescription = setLocalSessionDescription(); @@ -2531,10 +2531,11 @@ public class JingleRtpConnection extends AbstractJingleConnection + this.webRTCWrapper.getSignalingState()); } - if (diff.added.size() > 0) { - modifyLocalContentMap(rtpContentMap); - sendContentAdd(rtpContentMap, diff.added); + if (diff.added.isEmpty()) { + return; } + modifyLocalContentMap(rtpContentMap); + sendContentAdd(rtpContentMap, diff.added); } private void initiateIceRestart(final RtpContentMap rtpContentMap) {