From 7b0c0147917655c88782e21eb0321ab16671ad78 Mon Sep 17 00:00:00 2001 From: SzBenedek2006 <95222597+SzBenedek2006@users.noreply.github.com> Date: Thu, 13 Apr 2023 02:40:32 +0200 Subject: [PATCH 01/83] Fix hungarian translations (#1140) --- app/src/main/res/values-hu-rHU/strings.xml | 31 +++++++++++----------- app/src/main/res/values-hu/strings.xml | 31 +++++++++++----------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 3c8b4a54c8..517efa5604 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -92,7 +92,8 @@ Ez végelegesen törölni fogja a kiválasztott üzenetet. Ez véglegesen törölni fogja mind a(z) %1$d db kiválasztott üzenetet. - Tiltja ezt a felhasználót? + Hívás engedély szükséges + Tiltod ezt a felhasználót? Mentés tárolóra? A média mentése a tárolóra lehetővé teszi bármelyik másik alkalmazásnak a készülékeden, hogy hozzáférjen.\n\nFolytatod? @@ -206,7 +207,7 @@ Hívott téged Nem fogadott hívás Média üzenet - %s a Session-on van! + %s elérhető a Session-on! Eltűnő üzenetek letiltva Eltűnő üzenet ideje beállítva erre: %s %s készített egy képernyőképet. @@ -236,7 +237,7 @@ Te Nem támogatott médiatípus Piszkozat - A Session- nek szüksége van fájlhozzáférési engedélyekhez, hogy menteni tudjon külső tárhelyre, de ezt az engedélyt megtagadták. Kérjük, hogy a készüléke beállításaiban engedélyezze a \"fájlok és média\" opciót a Session számára. + A Session- nek szüksége van fájlhozzáférési engedélyekhez, hogy menteni tudjon külső tárhelyre. Kérlek, hogy a rendszerbeállításokban engedélyezd a \"fájlok és média\" opciót a Session számára. Nem lehet engedély nélkül menteni a külső tárolóra Törlöd az üzenetet? Ez véglegesen törölni fogja ezt az üzenetet. @@ -250,8 +251,8 @@ Összes megjelölése olvasottként Olvasottnak jelöl Válasz - Függő Session üzenetek - Függő Session üzeneteid vannak, koppints a megnyitáshoz és letöltéshez + Függőben lévő Session üzenetek + Függőben lévő Session üzeneteid vannak, koppints a megnyitáshoz és letöltéshez %1$s %2$s Névjegy @@ -275,7 +276,7 @@ Érvénytelen parancsikon - Ülés + Session Új üzenet @@ -530,17 +531,17 @@ Megosztás Érvénytelen Session azonosító Mégse - Az ön Session azonosítója - Az ön Session-ja itt kezdődik... + A session azonosítód + A Session itt kezdődik... Session azonosító létrehozása - Folytassa az ülését + Session azonosító helyreállítása Mi az a Session? Ez egy decentralizált, titkosított üzenetküldő alkalmazás Tehát nem gyűjti a személyes adataimat vagy a beszélgetés metaadatait? Hogyan működik? - Fejlett névtelen útválasztási és end-to-end titkosítási technológiák kombinációjának használata. - A barátok nem engedik, hogy a barátok kompromittált hírnököket használjanak. Szívesen. + Fejlett anonim útválasztási és végponttól-végpontig titkosítási technológiák használatával. + A barátként nem engedhetem, hogy megbízhatatlan üzenetküldő appokat használj. Szívesen. Ismerd meg a Session ID-d - Az üles azonosító az az egyedi cím, amelyet az emberek használhatnak, hogy kapcsolatba lépjenek Önnel az Ülés során. Mivel nincs kapcsolat a valódi személyazonosságával, az Ülés azonosító teljesen névtelen, és privát. + A Session azonosító az az egyedi cím, amelyet az emberek használhatnak, hogy kapcsolatba lépjenek Önnel a Sessionon. Mivel nincs kapcsolat a valódi személyazonosságával, az Session azonosító teljesen névtelen, és privát. Fiók visszaállítása Írja be azt a helyreállítási kifejezést, amelyet a fiók visszaállításához regisztrálásakor kapott. Írja be a helyreállítási kifejezést @@ -552,7 +553,7 @@ Ajánlott Kérjük, válasszon egy lehetőséget Még nincsenek névjegyei - Indítson el egy ülést + Indítson el egy beszélgetést Biztosan elhagyja ezt a csoportot? "Nem sikerült kilépni a csoportból" Biztosan törli ezt a beszélgetést? @@ -573,8 +574,8 @@ Célállomás Tudj meg többet Feloldás... - Új Ülés - Adja meg az Ülés azonosítóját + Új Session + Adja meg a Session azonosítóját QR kód beolvasása A beszélgetés elindításához olvassa be a felhasználó QR kódját. A QR kód a fiókbeállításokban található a QR kód ikonra koppintva. Írja be Session azonosítóját vagy ONS nevét diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 3c8b4a54c8..517efa5604 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -92,7 +92,8 @@ Ez végelegesen törölni fogja a kiválasztott üzenetet. Ez véglegesen törölni fogja mind a(z) %1$d db kiválasztott üzenetet. - Tiltja ezt a felhasználót? + Hívás engedély szükséges + Tiltod ezt a felhasználót? Mentés tárolóra? A média mentése a tárolóra lehetővé teszi bármelyik másik alkalmazásnak a készülékeden, hogy hozzáférjen.\n\nFolytatod? @@ -206,7 +207,7 @@ Hívott téged Nem fogadott hívás Média üzenet - %s a Session-on van! + %s elérhető a Session-on! Eltűnő üzenetek letiltva Eltűnő üzenet ideje beállítva erre: %s %s készített egy képernyőképet. @@ -236,7 +237,7 @@ Te Nem támogatott médiatípus Piszkozat - A Session- nek szüksége van fájlhozzáférési engedélyekhez, hogy menteni tudjon külső tárhelyre, de ezt az engedélyt megtagadták. Kérjük, hogy a készüléke beállításaiban engedélyezze a \"fájlok és média\" opciót a Session számára. + A Session- nek szüksége van fájlhozzáférési engedélyekhez, hogy menteni tudjon külső tárhelyre. Kérlek, hogy a rendszerbeállításokban engedélyezd a \"fájlok és média\" opciót a Session számára. Nem lehet engedély nélkül menteni a külső tárolóra Törlöd az üzenetet? Ez véglegesen törölni fogja ezt az üzenetet. @@ -250,8 +251,8 @@ Összes megjelölése olvasottként Olvasottnak jelöl Válasz - Függő Session üzenetek - Függő Session üzeneteid vannak, koppints a megnyitáshoz és letöltéshez + Függőben lévő Session üzenetek + Függőben lévő Session üzeneteid vannak, koppints a megnyitáshoz és letöltéshez %1$s %2$s Névjegy @@ -275,7 +276,7 @@ Érvénytelen parancsikon - Ülés + Session Új üzenet @@ -530,17 +531,17 @@ Megosztás Érvénytelen Session azonosító Mégse - Az ön Session azonosítója - Az ön Session-ja itt kezdődik... + A session azonosítód + A Session itt kezdődik... Session azonosító létrehozása - Folytassa az ülését + Session azonosító helyreállítása Mi az a Session? Ez egy decentralizált, titkosított üzenetküldő alkalmazás Tehát nem gyűjti a személyes adataimat vagy a beszélgetés metaadatait? Hogyan működik? - Fejlett névtelen útválasztási és end-to-end titkosítási technológiák kombinációjának használata. - A barátok nem engedik, hogy a barátok kompromittált hírnököket használjanak. Szívesen. + Fejlett anonim útválasztási és végponttól-végpontig titkosítási technológiák használatával. + A barátként nem engedhetem, hogy megbízhatatlan üzenetküldő appokat használj. Szívesen. Ismerd meg a Session ID-d - Az üles azonosító az az egyedi cím, amelyet az emberek használhatnak, hogy kapcsolatba lépjenek Önnel az Ülés során. Mivel nincs kapcsolat a valódi személyazonosságával, az Ülés azonosító teljesen névtelen, és privát. + A Session azonosító az az egyedi cím, amelyet az emberek használhatnak, hogy kapcsolatba lépjenek Önnel a Sessionon. Mivel nincs kapcsolat a valódi személyazonosságával, az Session azonosító teljesen névtelen, és privát. Fiók visszaállítása Írja be azt a helyreállítási kifejezést, amelyet a fiók visszaállításához regisztrálásakor kapott. Írja be a helyreállítási kifejezést @@ -552,7 +553,7 @@ Ajánlott Kérjük, válasszon egy lehetőséget Még nincsenek névjegyei - Indítson el egy ülést + Indítson el egy beszélgetést Biztosan elhagyja ezt a csoportot? "Nem sikerült kilépni a csoportból" Biztosan törli ezt a beszélgetést? @@ -573,8 +574,8 @@ Célállomás Tudj meg többet Feloldás... - Új Ülés - Adja meg az Ülés azonosítóját + Új Session + Adja meg a Session azonosítóját QR kód beolvasása A beszélgetés elindításához olvassa be a felhasználó QR kódját. A QR kód a fiókbeállításokban található a QR kód ikonra koppintva. Írja be Session azonosítóját vagy ONS nevét From 51856138e3ae23606c7f5ad04756a6db89ee5390 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 24 Apr 2023 15:38:06 +1000 Subject: [PATCH 02/83] refactor on SignalAudioManager --- .../securesms/service/WebRtcCallService.kt | 1 + .../securesms/webrtc/CallManager.kt | 4 + .../webrtc/audio/SignalAudioManager.kt | 99 +++++++++---------- .../libsignal/utilities/ThreadUtils.kt | 9 +- 4 files changed, 53 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt index b5e9b78a74..3ae3d30f01 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt @@ -799,6 +799,7 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener { wantsToAnswerReceiver?.let { receiver -> LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver) } + callManager.shutDownAudioManager() powerButtonReceiver = null wiredHeadsetStateReceiver = null networkChangedReceiver = null diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt index 07e73bedd2..d96de5eedb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt @@ -93,6 +93,10 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va peerConnectionObservers.remove(listener) } + fun shutDownAudioManager() { + signalAudioManager.shutdown() + } + private val _audioEvents = MutableStateFlow(AudioEnabled(false)) val audioEvents = _audioEvents.asSharedFlow() private val _videoEvents = MutableStateFlow(VideoEnabled(false)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt index 67514c58be..6eb1304430 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt @@ -9,6 +9,7 @@ import android.media.SoundPool import android.os.HandlerThread import network.loki.messenger.R import org.session.libsignal.utilities.Log +import org.session.libsignal.utilities.ThreadUtils import org.thoughtcrime.securesms.webrtc.AudioManagerCommand import org.thoughtcrime.securesms.webrtc.audio.SignalBluetoothManager.State as BState @@ -32,10 +33,10 @@ class SignalAudioManager(private val context: Context, private val eventListener: EventListener?, private val androidAudioManager: AudioManagerCompat) { - private var commandAndControlThread: HandlerThread? = HandlerThread("call-audio").apply { start() } - private var handler: SignalAudioHandler? = null + private var commandAndControlThread: HandlerThread? = HandlerThread("call-audio", ThreadUtils.PRIORITY_IMPORTANT_BACKGROUND_THREAD).apply { start() } + private var handler: SignalAudioHandler? = SignalAudioHandler(commandAndControlThread!!.looper) - private var signalBluetoothManager: SignalBluetoothManager? = null + private var signalBluetoothManager: SignalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler!!) private var state: State = State.UNINITIALIZED @@ -62,12 +63,9 @@ class SignalAudioManager(private val context: Context, private var wiredHeadsetReceiver: WiredHeadsetReceiver? = null fun handleCommand(command: AudioManagerCommand) { - if (command == AudioManagerCommand.Initialize) { - initialize() - return - } handler?.post { when (command) { + is AudioManagerCommand.Initialize -> initialize() is AudioManagerCommand.UpdateAudioDeviceState -> updateAudioDeviceState() is AudioManagerCommand.Start -> start() is AudioManagerCommand.Stop -> stop(command.playDisconnect) @@ -84,34 +82,37 @@ class SignalAudioManager(private val context: Context, Log.i(TAG, "Initializing audio manager state: $state") if (state == State.UNINITIALIZED) { - commandAndControlThread = HandlerThread("call-audio").apply { start() } - handler = SignalAudioHandler(commandAndControlThread!!.looper) + savedAudioMode = androidAudioManager.mode + savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn + savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute + hasWiredHeadset = androidAudioManager.isWiredHeadsetOn - signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler!!) + androidAudioManager.requestCallAudioFocus() - handler!!.post { + setMicrophoneMute(false) - savedAudioMode = androidAudioManager.mode - savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn - savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute - hasWiredHeadset = androidAudioManager.isWiredHeadsetOn + audioDevices.clear() - androidAudioManager.requestCallAudioFocus() + signalBluetoothManager.start() - setMicrophoneMute(false) + updateAudioDeviceState() - audioDevices.clear() + wiredHeadsetReceiver = WiredHeadsetReceiver() + context.registerReceiver(wiredHeadsetReceiver, IntentFilter(AudioManager.ACTION_HEADSET_PLUG)) - signalBluetoothManager!!.start() + state = State.PREINITIALIZED - updateAudioDeviceState() + Log.d(TAG, "Initialized") + } + } - wiredHeadsetReceiver = WiredHeadsetReceiver() - context.registerReceiver(wiredHeadsetReceiver, IntentFilter(AudioManager.ACTION_HEADSET_PLUG)) - - state = State.PREINITIALIZED - - Log.d(TAG, "Initialized") + fun shutdown() { + handler!!.post { + stop(false) + if (commandAndControlThread != null) { + Log.i(TAG, "Shutting down command and control") + commandAndControlThread?.quitSafely() + commandAndControlThread = null } } } @@ -138,23 +139,11 @@ class SignalAudioManager(private val context: Context, private fun stop(playDisconnect: Boolean) { Log.d(TAG, "Stopping. state: $state") - if (state == State.UNINITIALIZED) { - Log.i(TAG, "Trying to stop AudioManager in incorrect state: $state") - return - } - handler?.post { - incomingRinger.stop() - outgoingRinger.stop() - stop(false) - if (commandAndControlThread != null) { - Log.i(TAG, "Shutting down command and control") - commandAndControlThread?.quitSafely() - commandAndControlThread = null - } - } + incomingRinger.stop() + outgoingRinger.stop() - if (playDisconnect) { + if (playDisconnect && state != State.UNINITIALIZED) { val volume: Float = androidAudioManager.ringVolumeWithMinimum() soundPool.play(disconnectedSoundId, volume, volume, 0, 0, 1.0f) } @@ -170,7 +159,7 @@ class SignalAudioManager(private val context: Context, } wiredHeadsetReceiver = null - signalBluetoothManager?.stop() + signalBluetoothManager.stop() setSpeakerphoneOn(savedIsSpeakerPhoneOn) setMicrophoneMute(savedIsMicrophoneMute) @@ -189,19 +178,19 @@ class SignalAudioManager(private val context: Context, TAG, "updateAudioDeviceState(): " + "wired: $hasWiredHeadset " + - "bt: ${signalBluetoothManager!!.state} " + + "bt: ${signalBluetoothManager.state} " + "available: $audioDevices " + "selected: $selectedAudioDevice " + "userSelected: $userSelectedAudioDevice" ) - if (signalBluetoothManager!!.state.shouldUpdate()) { - signalBluetoothManager!!.updateDevice() + if (signalBluetoothManager.state.shouldUpdate()) { + signalBluetoothManager.updateDevice() } val newAudioDevices = mutableSetOf(AudioDevice.SPEAKER_PHONE) - if (signalBluetoothManager!!.state.hasDevice()) { + if (signalBluetoothManager.state.hasDevice()) { newAudioDevices += AudioDevice.BLUETOOTH } @@ -217,7 +206,7 @@ class SignalAudioManager(private val context: Context, var audioDeviceSetUpdated = audioDevices != newAudioDevices audioDevices = newAudioDevices - if (signalBluetoothManager!!.state == BState.UNAVAILABLE && userSelectedAudioDevice == AudioDevice.BLUETOOTH) { + if (signalBluetoothManager.state == BState.UNAVAILABLE && userSelectedAudioDevice == AudioDevice.BLUETOOTH) { userSelectedAudioDevice = AudioDevice.NONE } @@ -230,7 +219,7 @@ class SignalAudioManager(private val context: Context, userSelectedAudioDevice = AudioDevice.NONE } - val btState = signalBluetoothManager!!.state + val btState = signalBluetoothManager.state val needBluetoothAudioStart = btState == BState.AVAILABLE && (userSelectedAudioDevice == AudioDevice.NONE || userSelectedAudioDevice == AudioDevice.BLUETOOTH || autoSwitchToBluetooth) @@ -238,27 +227,27 @@ class SignalAudioManager(private val context: Context, (userSelectedAudioDevice != AudioDevice.NONE && userSelectedAudioDevice != AudioDevice.BLUETOOTH) if (btState.hasDevice()) { - Log.i(TAG, "Need bluetooth audio: state: ${signalBluetoothManager!!.state} start: $needBluetoothAudioStart stop: $needBluetoothAudioStop") + Log.i(TAG, "Need bluetooth audio: state: ${signalBluetoothManager.state} start: $needBluetoothAudioStart stop: $needBluetoothAudioStop") } if (needBluetoothAudioStop) { - signalBluetoothManager!!.stopScoAudio() - signalBluetoothManager!!.updateDevice() + signalBluetoothManager.stopScoAudio() + signalBluetoothManager.updateDevice() } - if (!autoSwitchToBluetooth && signalBluetoothManager!!.state == BState.UNAVAILABLE) { + if (!autoSwitchToBluetooth && signalBluetoothManager.state == BState.UNAVAILABLE) { autoSwitchToBluetooth = true } - if (needBluetoothAudioStart && !needBluetoothAudioStop) { - if (!signalBluetoothManager!!.startScoAudio()) { + if (!needBluetoothAudioStop && needBluetoothAudioStart) { + if (!signalBluetoothManager.startScoAudio()) { Log.e(TAG,"Failed to start sco audio") audioDevices.remove(AudioDevice.BLUETOOTH) audioDeviceSetUpdated = true } } - if (autoSwitchToBluetooth && signalBluetoothManager!!.state == BState.CONNECTED) { + if (autoSwitchToBluetooth && signalBluetoothManager.state == BState.CONNECTED) { userSelectedAudioDevice = AudioDevice.BLUETOOTH autoSwitchToBluetooth = false } diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt b/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt index 0700d01f66..ac81564bd1 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt +++ b/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt @@ -1,13 +1,12 @@ package org.session.libsignal.utilities -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import java.util.concurrent.LinkedBlockingQueue -import java.util.concurrent.ThreadPoolExecutor -import java.util.concurrent.TimeUnit +import android.os.Process +import java.util.concurrent.* object ThreadUtils { + const val PRIORITY_IMPORTANT_BACKGROUND_THREAD = Process.THREAD_PRIORITY_DEFAULT + Process.THREAD_PRIORITY_LESS_FAVORABLE + val executorPool: ExecutorService = Executors.newCachedThreadPool() @JvmStatic From c7bbdb778b93fb97bad93dad020240055c6507c8 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 24 Apr 2023 15:50:53 +1000 Subject: [PATCH 03/83] minor refactor --- .../securesms/webrtc/audio/SignalAudioHandler.kt | 2 +- .../securesms/webrtc/audio/SignalAudioManager.kt | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioHandler.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioHandler.kt index 89eba2a3aa..7ca44f46dc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioHandler.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioHandler.kt @@ -15,7 +15,7 @@ class SignalAudioHandler(looper: Looper) : Handler(looper) { } } - fun isOnHandler(): Boolean { + private fun isOnHandler(): Boolean { return Looper.myLooper() == looper } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt index 6eb1304430..229cbd13dd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.kt @@ -34,9 +34,9 @@ class SignalAudioManager(private val context: Context, private val androidAudioManager: AudioManagerCompat) { private var commandAndControlThread: HandlerThread? = HandlerThread("call-audio", ThreadUtils.PRIORITY_IMPORTANT_BACKGROUND_THREAD).apply { start() } - private var handler: SignalAudioHandler? = SignalAudioHandler(commandAndControlThread!!.looper) + private var handler: SignalAudioHandler = SignalAudioHandler(commandAndControlThread!!.looper) - private var signalBluetoothManager: SignalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler!!) + private var signalBluetoothManager: SignalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler) private var state: State = State.UNINITIALIZED @@ -63,7 +63,7 @@ class SignalAudioManager(private val context: Context, private var wiredHeadsetReceiver: WiredHeadsetReceiver? = null fun handleCommand(command: AudioManagerCommand) { - handler?.post { + handler.post { when (command) { is AudioManagerCommand.Initialize -> initialize() is AudioManagerCommand.UpdateAudioDeviceState -> updateAudioDeviceState() @@ -107,7 +107,7 @@ class SignalAudioManager(private val context: Context, } fun shutdown() { - handler!!.post { + handler.post { stop(false) if (commandAndControlThread != null) { Log.i(TAG, "Shutting down command and control") @@ -172,7 +172,7 @@ class SignalAudioManager(private val context: Context, } private fun updateAudioDeviceState() { - handler!!.assertHandlerThread() + handler.assertHandlerThread() Log.i( TAG, @@ -362,7 +362,7 @@ class SignalAudioManager(private val context: Context, val pluggedIn = intent.getIntExtra("state", 0) == 1 val hasMic = intent.getIntExtra("microphone", 0) == 1 - handler?.post { onWiredHeadsetChange(pluggedIn, hasMic) } + handler.post { onWiredHeadsetChange(pluggedIn, hasMic) } } } From 7d33177e065099d1709045b97d820c624a92707b Mon Sep 17 00:00:00 2001 From: Andrew Gallasch Date: Wed, 26 Apr 2023 14:18:34 +0930 Subject: [PATCH 04/83] Fix status and nav bar colors (#1165) --- .../org/thoughtcrime/securesms/BaseActionBarActivity.java | 7 +++++++ app/src/main/res/values-v27/colors.xml | 5 +++++ app/src/main/res/values/colors.xml | 3 +++ app/src/main/res/values/themes.xml | 8 ++++---- 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/values-v27/colors.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java index 7d82c760cc..51f66ec323 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms; +import static android.os.Build.VERSION.SDK_INT; import static org.session.libsession.utilities.TextSecurePreferences.SELECTED_ACCENT_COLOR; import android.app.ActivityManager; @@ -18,6 +19,7 @@ import androidx.appcompat.app.AppCompatActivity; import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageActivityHelper; import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper; +import org.thoughtcrime.securesms.conversation.v2.WindowUtil; import org.thoughtcrime.securesms.util.ActivityUtilitiesKt; import org.thoughtcrime.securesms.util.ThemeState; import org.thoughtcrime.securesms.util.UiModeUtilities; @@ -92,6 +94,11 @@ public abstract class BaseActionBarActivity extends AppCompatActivity { if (!currentThemeState.equals(ActivityUtilitiesKt.themeState(getPreferences()))) { recreate(); } + + // apply lightStatusBar manually as API 26 does not update properly via applyTheme + // https://issuetracker.google.com/issues/65883460?pli=1 + if (SDK_INT >= 26 && SDK_INT <= 27) WindowUtil.setLightStatusBarFromTheme(this); + if (SDK_INT == 27) WindowUtil.setLightNavigationBarFromTheme(this); } @Override diff --git a/app/src/main/res/values-v27/colors.xml b/app/src/main/res/values-v27/colors.xml new file mode 100644 index 0000000000..5c5e9494f1 --- /dev/null +++ b/app/src/main/res/values-v27/colors.xml @@ -0,0 +1,5 @@ + + + @color/classic_light_6 + @color/ocean_light_7 + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index d3b9d9b255..196e587cdc 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -60,6 +60,9 @@ #40ffffff #aaffffff + @color/compose_view_background + @color/navigation_bar + @color/navigation_bar @color/gray65 #22000000 diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 2874d42972..43d06ee7ad 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -326,7 +326,7 @@ ?android:textColorPrimary @color/gray27 ?colorPrimary - @color/compose_view_background + @color/navigation_bar @color/classic_dark_1 @style/Classic.Dark.BottomSheet ?android:textColorPrimary @@ -404,7 +404,7 @@ ?android:textColorPrimary @color/gray27 ?colorPrimary - ?colorPrimary + @color/classic_light_navigation_bar @color/classic_light_6 @color/classic_light_5 @color/classic_light_3 @@ -490,7 +490,7 @@ @color/ocean_dark_5 ?colorPrimary @color/default_background_start - @color/compose_view_background + @color/navigation_bar ?colorPrimary ?colorPrimaryDark @color/ocean_dark_3 @@ -570,7 +570,7 @@ @color/ocean_light_2 ?android:textColorPrimary @color/ocean_light_6 - @color/ocean_light_7 + @color/ocean_light_navigation_bar ?colorPrimary @color/default_background_start @color/ocean_light_7 From 716fc1f4fa840efee4e4dfb3c6596273c083aa62 Mon Sep 17 00:00:00 2001 From: Andrew Gallasch Date: Wed, 26 Apr 2023 14:24:54 +0930 Subject: [PATCH 05/83] Add SafeViewPager to fix touch exception in MediaPreviewActivity (#1166) --- .../securesms/components/SafeViewPager.kt | 30 +++++++++++++++++++ .../res/layout/media_preview_activity.xml | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/SafeViewPager.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/SafeViewPager.kt b/app/src/main/java/org/thoughtcrime/securesms/components/SafeViewPager.kt new file mode 100644 index 0000000000..6748478736 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/SafeViewPager.kt @@ -0,0 +1,30 @@ +package org.thoughtcrime.securesms.components + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import androidx.viewpager.widget.ViewPager + +/** + * An extension of ViewPager to swallow erroneous multi-touch exceptions. + * + * @see https://stackoverflow.com/questions/6919292/pointerindex-out-of-range-android-multitouch + */ +class SafeViewPager @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : ViewPager(context, attrs) { + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent?): Boolean = try { + super.onTouchEvent(event) + } catch (e: IllegalArgumentException) { + false + } + + override fun onInterceptTouchEvent(event: MotionEvent?): Boolean = try { + super.onInterceptTouchEvent(event) + } catch (e: IllegalArgumentException) { + false + } +} diff --git a/app/src/main/res/layout/media_preview_activity.xml b/app/src/main/res/layout/media_preview_activity.xml index 2f6aaff454..78327b6cc3 100644 --- a/app/src/main/res/layout/media_preview_activity.xml +++ b/app/src/main/res/layout/media_preview_activity.xml @@ -22,7 +22,7 @@ - Date: Wed, 26 Apr 2023 14:26:00 +0930 Subject: [PATCH 06/83] Remove unnecessary api version checks in WindowUtil (#1163) --- .../securesms/conversation/v2/WindowUtil.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java index 4bff4e76aa..6083bb267c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java @@ -38,14 +38,10 @@ public final class WindowUtil { } public static void setNavigationBarColor(@NonNull Window window, @ColorInt int color) { - if (Build.VERSION.SDK_INT < 21) return; - window.setNavigationBarColor(color); } public static void setLightStatusBarFromTheme(@NonNull Activity activity) { - if (Build.VERSION.SDK_INT < 23) return; - final boolean isLightStatusBar = ThemeUtil.getThemedBoolean(activity, android.R.attr.windowLightStatusBar); if (isLightStatusBar) setLightStatusBar(activity.getWindow()); @@ -53,20 +49,14 @@ public final class WindowUtil { } public static void clearLightStatusBar(@NonNull Window window) { - if (Build.VERSION.SDK_INT < 23) return; - clearSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } public static void setLightStatusBar(@NonNull Window window) { - if (Build.VERSION.SDK_INT < 23) return; - setSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } public static void setStatusBarColor(@NonNull Window window, @ColorInt int color) { - if (Build.VERSION.SDK_INT < 21) return; - window.setStatusBarColor(color); } From ffef98ecc93780e367ebe08cb8a621e51cd86cf8 Mon Sep 17 00:00:00 2001 From: Andrew Gallasch Date: Wed, 26 Apr 2023 14:29:32 +0930 Subject: [PATCH 07/83] Fix LandingActivity textColor (#1159) --- app/src/main/res/values/styles.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 5f9ee03168..1cf88c0c06 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -228,11 +228,13 @@ From 58e532f0ec0be0f34434113ce782b91958e803a9 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 26 Apr 2023 16:31:28 +0930 Subject: [PATCH 08/83] Swallow screenshot exceptions --- .../attachments/ScreenshotObserver.kt | 78 +++++++++++-------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt index 84a9b6cfc3..9c7ca21e8b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt @@ -7,6 +7,10 @@ import android.os.Build import android.os.Handler import android.provider.MediaStore import androidx.annotation.RequiresApi +import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer + +private const val TAG = "ScreenshotObserver" class ScreenshotObserver(private val context: Context, handler: Handler, private val screenshotTriggered: ()->Unit): ContentObserver(handler) { @@ -31,22 +35,26 @@ class ScreenshotObserver(private val context: Context, handler: Handler, private val projection = arrayOf( MediaStore.Images.Media.DATA ) - context.contentResolver.query( - uri, - projection, - null, - null, - null - )?.use { cursor -> - val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA) - while (cursor.moveToNext()) { - val path = cursor.getString(dataColumn) - if (path.contains("screenshot", true)) { - if (cache.add(uri.hashCode())) { - screenshotTriggered() + try { + context.contentResolver.query( + uri, + projection, + null, + null, + null + )?.use { cursor -> + val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA) + while (cursor.moveToNext()) { + val path = cursor.getString(dataColumn) + if (path.contains("screenshot", true)) { + if (cache.add(uri.hashCode())) { + screenshotTriggered() + } } } } + } catch (e: SecurityException) { + Log.e(TAG, e) } } @@ -56,28 +64,32 @@ class ScreenshotObserver(private val context: Context, handler: Handler, private MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.RELATIVE_PATH ) - context.contentResolver.query( - uri, - projection, - null, - null, - null - )?.use { cursor -> - val relativePathColumn = - cursor.getColumnIndex(MediaStore.Images.Media.RELATIVE_PATH) - val displayNameColumn = - cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME) - while (cursor.moveToNext()) { - val name = cursor.getString(displayNameColumn) - val relativePath = cursor.getString(relativePathColumn) - if (name.contains("screenshot", true) or - relativePath.contains("screenshot", true)) { - if (cache.add(uri.hashCode())) { - screenshotTriggered() + + try { + context.contentResolver.query( + uri, + projection, + null, + null, + null + )?.use { cursor -> + val relativePathColumn = + cursor.getColumnIndex(MediaStore.Images.Media.RELATIVE_PATH) + val displayNameColumn = + cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME) + while (cursor.moveToNext()) { + val name = cursor.getString(displayNameColumn) + val relativePath = cursor.getString(relativePathColumn) + if (name.contains("screenshot", true) or + relativePath.contains("screenshot", true)) { + if (cache.add(uri.hashCode())) { + screenshotTriggered() + } } } } + } catch (e: IllegalStateException) { + Log.e(TAG, e) } } - -} \ No newline at end of file +} From 2630c97a4efe34ffad3d43b5bd72a39ee2357bc9 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 1 May 2023 17:01:57 +1000 Subject: [PATCH 09/83] add where clause for marking all jobs pending to reduce the time for writing to db --- .../org/thoughtcrime/securesms/database/JobDatabase.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java index ef4746923b..21719df20b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java @@ -138,7 +138,10 @@ public class JobDatabase extends Database { ContentValues contentValues = new ContentValues(); contentValues.put(Jobs.IS_RUNNING, 0); - databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, null, null); + String query = Jobs.IS_RUNNING + " = ?"; + String[] args = new String[] { "1" }; + + databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, query, args); } public synchronized void deleteJobs(@NonNull List jobIds) { From 70aab2994b51896472e08de0d892f64f00b946a4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 1 May 2023 16:46:48 +0930 Subject: [PATCH 10/83] Refactor MmsDatabase (#1169) --- .../securesms/database/MmsDatabase.kt | 155 +++++------------- .../thoughtcrime/securesms/util/CursorUtil.kt | 6 + 2 files changed, 43 insertions(+), 118 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/CursorUtil.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index 90d3cad454..3a4b35ad17 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.database.model.Quote import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get import org.thoughtcrime.securesms.mms.MmsException import org.thoughtcrime.securesms.mms.SlideDeck +import org.thoughtcrime.securesms.util.asSequence import java.io.Closeable import java.io.IOException import java.security.SecureRandom @@ -91,54 +92,22 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa return 0 } - fun addFailures(messageId: Long, failure: List) { - try { - addToDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList::class.java) - } catch (e: IOException) { - Log.w(TAG, e) + fun isOutgoingMessage(timestamp: Long): Boolean = + databaseHelper.writableDatabase.query( + TABLE_NAME, + arrayOf(ID, THREAD_ID, MESSAGE_BOX, ADDRESS), + DATE_SENT + " = ?", + arrayOf(timestamp.toString()), + null, + null, + null, + null + ).use { cursor -> + cursor.asSequence() + .map { cursor.getColumnIndexOrThrow(MESSAGE_BOX) } + .map(cursor::getLong) + .any { MmsSmsColumns.Types.isOutgoingMessageType(it) } } - } - - fun removeFailure(messageId: Long, failure: NetworkFailure?) { - try { - removeFromDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList::class.java) - } catch (e: IOException) { - Log.w(TAG, e) - } - } - - fun isOutgoingMessage(timestamp: Long): Boolean { - val database = databaseHelper.writableDatabase - var cursor: Cursor? = null - var isOutgoing = false - try { - cursor = database.query( - TABLE_NAME, - arrayOf(ID, THREAD_ID, MESSAGE_BOX, ADDRESS), - DATE_SENT + " = ?", - arrayOf(timestamp.toString()), - null, - null, - null, - null - ) - while (cursor.moveToNext()) { - if (MmsSmsColumns.Types.isOutgoingMessageType( - cursor.getLong( - cursor.getColumnIndexOrThrow( - MESSAGE_BOX - ) - ) - ) - ) { - isOutgoing = true - } - } - } finally { - cursor?.close() - } - return isOutgoing - } fun incrementReceiptCount( messageId: SyncMessageId, @@ -254,15 +223,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa } } - private fun getThreadIdFor(notification: NotificationInd): Long { - val fromString = - if (notification.from != null && notification.from.textString != null) toIsoString( - notification.from.textString - ) else "" - val recipient = Recipient.from(context, fromExternal(context, fromString), false) - return get(context).threadDatabase().getOrCreateThreadIdFor(recipient) - } - private fun rawQuery(where: String, arguments: Array?): Cursor { val database = databaseHelper.readableDatabase return database.rawQuery( @@ -273,10 +233,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa ) } - fun getMessages(idsAsString: String): Cursor { - return rawQuery(idsAsString, null) - } - fun getMessage(messageId: Long): Cursor { val cursor = rawQuery(RAW_ID_WHERE, arrayOf(messageId.toString())) setNotifyConverationListeners(cursor, getThreadIdForMessage(messageId)) @@ -306,48 +262,30 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa } } - fun markAsPendingInsecureSmsFallback(messageId: Long) { - val threadId = getThreadIdForMessage(messageId) + private fun markAs( + messageId: Long, + baseType: Long, + threadId: Long = getThreadIdForMessage(messageId) + ) { updateMailboxBitmask( messageId, MmsSmsColumns.Types.BASE_TYPE_MASK, - MmsSmsColumns.Types.BASE_PENDING_INSECURE_SMS_FALLBACK, + baseType, Optional.of(threadId) ) notifyConversationListeners(threadId) } fun markAsSending(messageId: Long) { - val threadId = getThreadIdForMessage(messageId) - updateMailboxBitmask( - messageId, - MmsSmsColumns.Types.BASE_TYPE_MASK, - MmsSmsColumns.Types.BASE_SENDING_TYPE, - Optional.of(threadId) - ) - notifyConversationListeners(threadId) + markAs(messageId, MmsSmsColumns.Types.BASE_SENDING_TYPE) } fun markAsSentFailed(messageId: Long) { - val threadId = getThreadIdForMessage(messageId) - updateMailboxBitmask( - messageId, - MmsSmsColumns.Types.BASE_TYPE_MASK, - MmsSmsColumns.Types.BASE_SENT_FAILED_TYPE, - Optional.of(threadId) - ) - notifyConversationListeners(threadId) + markAs(messageId, MmsSmsColumns.Types.BASE_SENT_FAILED_TYPE) } override fun markAsSent(messageId: Long, secure: Boolean) { - val threadId = getThreadIdForMessage(messageId) - updateMailboxBitmask( - messageId, - MmsSmsColumns.Types.BASE_TYPE_MASK, - MmsSmsColumns.Types.BASE_SENT_TYPE or if (secure) MmsSmsColumns.Types.PUSH_MESSAGE_BIT or MmsSmsColumns.Types.SECURE_MESSAGE_BIT else 0, - Optional.of(threadId) - ) - notifyConversationListeners(threadId) + markAs(messageId, MmsSmsColumns.Types.BASE_SENT_TYPE or if (secure) MmsSmsColumns.Types.PUSH_MESSAGE_BIT or MmsSmsColumns.Types.SECURE_MESSAGE_BIT else 0) } override fun markUnidentified(messageId: Long, unidentified: Boolean) { @@ -371,13 +309,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa val mentionChange = if (hasMention) { 1 } else { 0 } get(context).threadDatabase().decrementUnread(threadId, 1, mentionChange) } - updateMailboxBitmask( - messageId, - MmsSmsColumns.Types.BASE_TYPE_MASK, - MmsSmsColumns.Types.BASE_DELETED_TYPE, - Optional.of(threadId) - ) - notifyConversationListeners(threadId) + markAs(messageId, MmsSmsColumns.Types.BASE_DELETED_TYPE, threadId) } override fun markExpireStarted(messageId: Long) { @@ -407,10 +339,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa ) } - fun setAllMessagesRead(): List { - return setMessagesRead(READ + " = 0", null) - } - private fun setMessagesRead(where: String, arguments: Array?): List { val database = databaseHelper.writableDatabase val result: MutableList = LinkedList() @@ -419,7 +347,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa try { cursor = database.query( TABLE_NAME, - arrayOf(ID, ADDRESS, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED), + arrayOf(ID, ADDRESS, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED), where, arguments, null, @@ -1400,25 +1328,16 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa val attachments = get(context).attachmentDatabase().getAttachment( cursor ) - val contacts: List = getSharedContacts( - cursor, attachments - ) - val contactAttachments = - contacts.map { obj: Contact? -> obj!!.avatarAttachment } - .filter { a: Attachment? -> a != null } - .toSet() - val previews: List = getLinkPreviews( - cursor, attachments - ) - val previewAttachments = - previews.filter { lp: LinkPreview? -> lp!!.getThumbnail().isPresent } - .map { lp: LinkPreview? -> lp!!.getThumbnail().get() } - .toSet() + val contacts: List = getSharedContacts(cursor, attachments) + val contactAttachments: Set = + contacts.mapNotNull { it?.avatarAttachment }.toSet() + val previews: List = getLinkPreviews(cursor, attachments) + val previewAttachments: Set = + previews.mapNotNull { it?.getThumbnail()?.orNull() }.toSet() val slideDeck = getSlideDeck( - Stream.of(attachments) - .filterNot { o: DatabaseAttachment? -> contactAttachments.contains(o) } - .filterNot { o: DatabaseAttachment? -> previewAttachments.contains(o) } - .toList() + attachments + .filterNot { o: DatabaseAttachment? -> o in contactAttachments } + .filterNot { o: DatabaseAttachment? -> o in previewAttachments } ) val quote = getQuote(cursor) val reactions = get(context).reactionDatabase().getReactions(cursor) @@ -1623,4 +1542,4 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa const val CREATE_REACTIONS_LAST_SEEN_COMMAND = "ALTER TABLE $TABLE_NAME ADD COLUMN $REACTIONS_LAST_SEEN INTEGER DEFAULT 0;" const val CREATE_HAS_MENTION_COMMAND = "ALTER TABLE $TABLE_NAME ADD COLUMN $HAS_MENTION INTEGER DEFAULT 0;" } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CursorUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/util/CursorUtil.kt new file mode 100644 index 0000000000..9cff8c77bc --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/CursorUtil.kt @@ -0,0 +1,6 @@ +package org.thoughtcrime.securesms.util + +import android.database.Cursor + +fun Cursor.asSequence(): Sequence = + generateSequence { if (moveToNext()) this else null } From a934c5c2e2e73ad6fb245b3dc88adbcdd15264db Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 1 May 2023 16:49:01 +0930 Subject: [PATCH 11/83] Fix missing media progress (#1151) --- .../securesms/conversation/v2/utilities/ThumbnailView.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt index e9a085dad9..4a9986d6ec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt @@ -126,10 +126,9 @@ open class ThumbnailView: FrameLayout { buildThumbnailGlideRequest(glide, slide).into(GlideDrawableListeningTarget(binding.thumbnailImage, binding.thumbnailLoadIndicator, result)) } slide.hasPlaceholder() -> { - buildPlaceholderGlideRequest(glide, slide).into(GlideBitmapListeningTarget(binding.thumbnailImage, binding.thumbnailLoadIndicator, result)) + buildPlaceholderGlideRequest(glide, slide).into(GlideBitmapListeningTarget(binding.thumbnailImage, null, result)) } else -> { - binding.thumbnailLoadIndicator.isVisible = false glide.clear(binding.thumbnailImage) result.set(false) } From 83b6002a270bca19b98826be0ec0b9d98885c890 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 1 May 2023 16:49:13 +0930 Subject: [PATCH 12/83] Fix emoji misalignment (#1155) --- .../v2/ConversationReactionOverlay.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java index b3c151690f..1d81325e03 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java @@ -203,10 +203,11 @@ public final class ConversationReactionOverlay extends FrameLayout { boolean isMessageOnLeft) { contextMenu = new ConversationContextMenu(dropdownAnchor, getMenuActionItems(messageRecord)); - float itemX = isMessageOnLeft ? scrubberHorizontalMargin : + float endX = isMessageOnLeft ? scrubberHorizontalMargin : selectedConversationModel.getBubbleX() - conversationItem.getWidth() + selectedConversationModel.getBubbleWidth(); - conversationItem.setX(itemX); - conversationItem.setY(selectedConversationModel.getBubbleY() - statusBarHeight); + float endY = selectedConversationModel.getBubbleY() - statusBarHeight; + conversationItem.setX(endX); + conversationItem.setY(endY); Bitmap conversationItemSnapshot = selectedConversationModel.getBitmap(); boolean isWideLayout = contextMenu.getMaxWidth() + scrubberWidth < getWidth(); @@ -214,8 +215,6 @@ public final class ConversationReactionOverlay extends FrameLayout { int overlayHeight = getHeight(); int bubbleWidth = selectedConversationModel.getBubbleWidth(); - float endX = itemX; - float endY = conversationItem.getY(); float endApparentTop = endY; float endScale = 1f; @@ -265,9 +264,7 @@ public final class ConversationReactionOverlay extends FrameLayout { } } else { endY = overlayHeight - contextMenu.getMaxHeight() - menuPadding - conversationItemSnapshot.getHeight(); - - float contextMenuTop = endY + conversationItemSnapshot.getHeight(); - reactionBarBackgroundY = getReactionBarOffsetForTouch(selectedConversationModel.getBubbleY(), contextMenuTop, menuPadding, reactionBarOffset, reactionBarHeight, reactionBarTopPadding, endY); + reactionBarBackgroundY = endY - reactionBarHeight - menuPadding; } endApparentTop = endY; From 99cb10f5befe288a61e56804207808b9972db200 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 1 May 2023 16:49:19 +0930 Subject: [PATCH 13/83] Add send approval message (#1157) --- .../conversation/v2/ConversationActivityV2.kt | 8 ++++++++ .../main/res/layout/activity_conversation_v2.xml | 14 +++++++++++++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index b5f1b96fd7..cabb583085 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -22,6 +22,7 @@ import androidx.activity.viewModels import androidx.annotation.DimenRes import androidx.appcompat.app.AlertDialog import androidx.core.view.drawToBitmap +import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider @@ -344,6 +345,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe updateSubtitle() setUpBlockedBanner() binding!!.searchBottomBar.setEventListener(this) + updateSendAfterApprovalText() showOrHideInputIfNeeded() setUpMessageRequestsBar() @@ -653,7 +655,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe setUpMessageRequestsBar() invalidateOptionsMenu() updateSubtitle() + updateSendAfterApprovalText() showOrHideInputIfNeeded() + binding?.toolbarContent?.profilePictureView?.root?.update(threadRecipient) binding?.toolbarContent?.conversationTitleView?.text = when { threadRecipient.isLocalNumber -> getString(R.string.note_to_self) @@ -662,6 +666,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } } + private fun updateSendAfterApprovalText() { + binding?.textSendAfterApproval?.isGone = viewModel.recipient?.hasApprovedMe() ?: true + } + private fun showOrHideInputIfNeeded() { val recipient = viewModel.recipient if (recipient != null && recipient.isClosedGroupRecipient) { diff --git a/app/src/main/res/layout/activity_conversation_v2.xml b/app/src/main/res/layout/activity_conversation_v2.xml index 4ec4666d7f..d2696a45ec 100644 --- a/app/src/main/res/layout/activity_conversation_v2.xml +++ b/app/src/main/res/layout/activity_conversation_v2.xml @@ -35,7 +35,7 @@ android:layout_width="match_parent" android:layout_height="36dp" android:visibility="gone" - android:layout_above="@+id/messageRequestBar" + android:layout_above="@+id/textSendAfterApproval" /> + + %1$d of %2$d Call Permissions Required You can enable the \'Voice and video calls\' permission in the Privacy Settings. + You will be able to send voice messages and attachments once the recipient has approved this message request Delete selected message? From d868021f0ac5f3f1770b6c0aad2f841f7df9eb3b Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 4 May 2023 15:30:09 +1000 Subject: [PATCH 14/83] move job running status from database to memory --- .../securesms/database/JobDatabase.java | 33 +++++++++---------- .../securesms/database/SessionJobDatabase.kt | 2 +- .../securesms/database/Storage.kt | 2 +- .../securesms/jobs/FastJobStorageTest.java | 10 ------ 4 files changed, 17 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java index 21719df20b..5e84d5e23a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java @@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec; import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec; import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -22,6 +23,8 @@ public class JobDatabase extends Database { Constraints.CREATE_TABLE, Dependencies.CREATE_TABLE }; + private static final ArrayList runningJobs = new ArrayList<>(); + public static final class Jobs { public static final String TABLE_NAME = "job_spec"; private static final String ID = "_id"; @@ -113,18 +116,17 @@ public class JobDatabase extends Database { } public synchronized void updateJobRunningState(@NonNull String id, boolean isRunning) { - ContentValues contentValues = new ContentValues(); - contentValues.put(Jobs.IS_RUNNING, isRunning ? 1 : 0); - - String query = Jobs.JOB_SPEC_ID + " = ?"; - String[] args = new String[]{ id }; - - databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, query, args); + if (!isRunning) { + JobDatabase.runningJobs.remove(id); + } else if (!JobDatabase.runningJobs.contains(id)) { + JobDatabase.runningJobs.add(id); + } } public synchronized void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime) { + updateJobRunningState(id, isRunning); + ContentValues contentValues = new ContentValues(); - contentValues.put(Jobs.IS_RUNNING, isRunning ? 1 : 0); contentValues.put(Jobs.RUN_ATTEMPT, runAttempt); contentValues.put(Jobs.NEXT_RUN_ATTEMPT_TIME, nextRunAttemptTime); @@ -135,13 +137,7 @@ public class JobDatabase extends Database { } public synchronized void updateAllJobsToBePending() { - ContentValues contentValues = new ContentValues(); - contentValues.put(Jobs.IS_RUNNING, 0); - - String query = Jobs.IS_RUNNING + " = ?"; - String[] args = new String[] { "1" }; - - databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, query, args); + JobDatabase.runningJobs.clear(); } public synchronized void deleteJobs(@NonNull List jobIds) { @@ -202,7 +198,7 @@ public class JobDatabase extends Database { contentValues.put(Jobs.MAX_INSTANCES, job.getMaxInstances()); contentValues.put(Jobs.LIFESPAN, job.getLifespan()); contentValues.put(Jobs.SERIALIZED_DATA, job.getSerializedData()); - contentValues.put(Jobs.IS_RUNNING, job.isRunning() ? 1 : 0); + updateJobRunningState(job.getId(), job.isRunning()); db.insertWithOnConflict(Jobs.TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE); } @@ -226,7 +222,8 @@ public class JobDatabase extends Database { } private @NonNull JobSpec jobSpecFromCursor(@NonNull Cursor cursor) { - return new JobSpec(cursor.getString(cursor.getColumnIndexOrThrow(Jobs.JOB_SPEC_ID)), + String jobId = cursor.getString(cursor.getColumnIndexOrThrow(Jobs.JOB_SPEC_ID)); + return new JobSpec(jobId, cursor.getString(cursor.getColumnIndexOrThrow(Jobs.FACTORY_KEY)), cursor.getString(cursor.getColumnIndexOrThrow(Jobs.QUEUE_KEY)), cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.CREATE_TIME)), @@ -237,7 +234,7 @@ public class JobDatabase extends Database { cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.LIFESPAN)), cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.MAX_INSTANCES)), cursor.getString(cursor.getColumnIndexOrThrow(Jobs.SERIALIZED_DATA)), - cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.IS_RUNNING)) == 1); + JobDatabase.runningJobs.contains(jobId)); } private @NonNull ConstraintSpec constraintSpecFromCursor(@NonNull Cursor cursor) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt index 66497d9da8..b081fb007e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt @@ -46,7 +46,7 @@ class SessionJobDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa databaseHelper.writableDatabase.delete(sessionJobTable, "${Companion.jobID} = ?", arrayOf( jobID )) } - fun getAllPendingJobs(type: String): Map { + fun getAllJobs(type: String): Map { val database = databaseHelper.readableDatabase return database.getAll(sessionJobTable, "$jobType = ?", arrayOf( type )) { cursor -> val jobID = cursor.getString(jobID) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 076fa57afc..0d7ea3352f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -211,7 +211,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } override fun getAllPendingJobs(type: String): Map { - return DatabaseComponent.get(context).sessionJobDatabase().getAllPendingJobs(type) + return DatabaseComponent.get(context).sessionJobDatabase().getAllJobs(type) } override fun getAttachmentUploadJob(attachmentID: Long): AttachmentUploadJob? { diff --git a/app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java b/app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java index ee1f232b54..a6624189d1 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java @@ -74,16 +74,6 @@ public class FastJobStorageTest { assertEquals(DataSet1.JOB_2, subject.getJobSpec(DataSet1.JOB_2.getId())); } - @Test - public void updateAllJobsToBePending_writesToDatabase() { - JobDatabase database = noopDatabase(); - FastJobStorage subject = new FastJobStorage(database); - - subject.updateAllJobsToBePending(); - - verify(database).updateAllJobsToBePending(); - } - @Test public void updateAllJobsToBePending_allArePending() { FullSpec fullSpec1 = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, true), From 45eb3549f6ba66838ef80b56beb83058510adf72 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 4 May 2023 14:50:51 +0930 Subject: [PATCH 15/83] Add sync status message --- .../conversation/v2/ConversationActivityV2.kt | 8 ++ .../v2/ConversationReactionOverlay.java | 5 ++ .../menus/ConversationActionModeCallback.kt | 4 + .../v2/messages/VisibleMessageView.kt | 73 ++++++++++--------- .../v2/utilities/ResendMessageUtilities.kt | 16 +++- .../securesms/database/MessagingDatabase.java | 8 +- .../securesms/database/MmsDatabase.kt | 10 +++ .../securesms/database/MmsSmsColumns.java | 17 +++++ .../securesms/database/SmsDatabase.java | 15 ++++ .../securesms/database/Storage.kt | 56 +++++++++++++- .../database/model/DisplayRecord.java | 12 +++ .../menu/menu_conversation_item_action.xml | 5 ++ app/src/main/res/values/strings.xml | 4 + .../libsession/database/StorageProtocol.kt | 5 +- .../messaging/jobs/MessageSendJob.kt | 2 + .../messaging/messages/Destination.kt | 6 +- .../messages/visible/VisibleMessage.kt | 28 +++---- .../sending_receiving/MessageSender.kt | 37 ++++++++-- 18 files changed, 248 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index cabb583085..18c62a74c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1755,6 +1755,13 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe endActionMode() } + override fun resyncMessage(messages: Set) { + messages.iterator().forEach { messageRecord -> + ResendMessageUtilities.resend(this, messageRecord, viewModel.blindedPublicKey, isResync = true) + } + endActionMode() + } + override fun resendMessage(messages: Set) { messages.iterator().forEach { messageRecord -> ResendMessageUtilities.resend(this, messageRecord, viewModel.blindedPublicKey) @@ -1915,6 +1922,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe val selectedItems = setOf(message) when (action) { ConversationReactionOverlay.Action.REPLY -> reply(selectedItems) + ConversationReactionOverlay.Action.RESYNC -> resyncMessage(selectedItems) ConversationReactionOverlay.Action.RESEND -> resendMessage(selectedItems) ConversationReactionOverlay.Action.DOWNLOAD -> saveAttachment(selectedItems) ConversationReactionOverlay.Action.COPY_MESSAGE -> copyMessages(selectedItems) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java index 1d81325e03..8f1fb6a0e5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java @@ -700,6 +700,10 @@ public final class ConversationReactionOverlay extends FrameLayout { if (message.isFailed()) { items.add(new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_resend_message), () -> handleActionItemClicked(Action.RESEND))); } + // Resync + if (message.isSyncFailed()) { + items.add(new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_resync_message), () -> handleActionItemClicked(Action.RESYNC))); + } // Save media if (message.isMms() && ((MediaMmsMessageRecord)message).containsMediaSlide()) { items.add(new ActionItem(R.attr.menu_save_icon, getContext().getResources().getString(R.string.conversation_context_image__save_attachment), () -> handleActionItemClicked(Action.DOWNLOAD), @@ -885,6 +889,7 @@ public final class ConversationReactionOverlay extends FrameLayout { public enum Action { REPLY, RESEND, + RESYNC, DOWNLOAD, COPY_MESSAGE, COPY_SESSION_ID, diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt index d475a64448..f86920f90f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt @@ -70,6 +70,8 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p menu.findItem(R.id.menu_message_details).isVisible = (selectedItems.size == 1 && firstMessage.isOutgoing) // Resend menu.findItem(R.id.menu_context_resend).isVisible = (selectedItems.size == 1 && firstMessage.isFailed) + // Resync + menu.findItem(R.id.menu_context_resync).isVisible = (selectedItems.size == 1 && firstMessage.isSyncFailed) // Save media menu.findItem(R.id.menu_context_save_attachment).isVisible = (selectedItems.size == 1 && firstMessage.isMms && (firstMessage as MediaMmsMessageRecord).containsMediaSlide()) @@ -90,6 +92,7 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p R.id.menu_context_ban_and_delete_all -> delegate?.banAndDeleteAll(selectedItems) R.id.menu_context_copy -> delegate?.copyMessages(selectedItems) R.id.menu_context_copy_public_key -> delegate?.copySessionID(selectedItems) + R.id.menu_context_resync -> delegate?.resyncMessage(selectedItems) R.id.menu_context_resend -> delegate?.resendMessage(selectedItems) R.id.menu_message_details -> delegate?.showMessageDetail(selectedItems) R.id.menu_context_save_attachment -> delegate?.saveAttachment(selectedItems) @@ -113,6 +116,7 @@ interface ConversationActionModeCallbackDelegate { fun banAndDeleteAll(messages: Set) fun copyMessages(messages: Set) fun copySessionID(messages: Set) + fun resyncMessage(messages: Set) fun resendMessage(messages: Set) fun showMessageDetail(messages: Set) fun saveAttachment(messages: Set) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 2c04bcfce3..745c91e910 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -292,39 +292,46 @@ class VisibleMessageView : LinearLayout { @StringRes val messageText: Int?, val contentDescription: String?) - private fun getMessageStatusImage(message: MessageRecord): MessageStatusInfo { - return when { - !message.isOutgoing -> MessageStatusInfo(null, - null, - null, - null) - message.isFailed -> - MessageStatusInfo( - R.drawable.ic_delivery_status_failed, - resources.getColor(R.color.destructive, context.theme), - R.string.delivery_status_failed, - null - ) - message.isPending -> - MessageStatusInfo( - R.drawable.ic_delivery_status_sending, - context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_sending, - context.getString(R.string.AccessibilityId_message_sent_status_pending) - ) - message.isRead -> - MessageStatusInfo( - R.drawable.ic_delivery_status_read, - context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_read, - null - ) - else -> - MessageStatusInfo( - R.drawable.ic_delivery_status_sent, - context.getColorFromAttr(R.attr.message_status_color), - R.string.delivery_status_sent, - context.getString(R.string.AccessibilityId_message_sent_status_tick) - ) - } + private fun getMessageStatusImage(message: MessageRecord): MessageStatusInfo = when { + message.isFailed -> + MessageStatusInfo( + R.drawable.ic_delivery_status_failed, + resources.getColor(R.color.destructive, context.theme), + R.string.delivery_status_failed, + null + ) + message.isSyncFailed -> + MessageStatusInfo( + R.drawable.ic_delivery_status_failed, + resources.getColor(R.color.destructive, context.theme), + R.string.delivery_status_sync_failed, + null + ) + message.isPending -> + MessageStatusInfo( + R.drawable.ic_delivery_status_sending, + context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_sending, + context.getString(R.string.AccessibilityId_message_sent_status_pending) + ) + message.isResyncing -> + MessageStatusInfo( + R.drawable.ic_delivery_status_sending, + context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_syncing, + context.getString(R.string.AccessibilityId_message_sent_status_syncing) + ) + message.isRead -> + MessageStatusInfo( + R.drawable.ic_delivery_status_read, + context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_read, + null + ) + else -> + MessageStatusInfo( + R.drawable.ic_delivery_status_sent, + context.getColorFromAttr(R.attr.message_status_color), + R.string.delivery_status_sent, + context.getString(R.string.AccessibilityId_message_sent_status_tick) + ) } private fun updateExpirationTimer(message: MessageRecord) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt index 80f4cc0bf8..5e6283e1ad 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2.utilities import android.content.Context import org.session.libsession.messaging.MessagingModuleConfiguration +import org.session.libsession.messaging.messages.Destination import org.session.libsession.messaging.messages.visible.LinkPreview import org.session.libsession.messaging.messages.visible.OpenGroupInvitation import org.session.libsession.messaging.messages.visible.Quote @@ -10,12 +11,16 @@ import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.utilities.UpdateMessageData import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient +import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MmsMessageRecord +private val TAG = ResendMessageUtilities.javaClass.simpleName + object ResendMessageUtilities { - fun resend(context: Context, messageRecord: MessageRecord, userBlindedKey: String?) { + fun resend(context: Context, messageRecord: MessageRecord, userBlindedKey: String?, isResync: Boolean = false) { + Log.d(TAG, "resend() called with: context = $context, messageRecord = $messageRecord, userBlindedKey = $userBlindedKey, isResync = $isResync") val recipient: Recipient = messageRecord.recipient val message = VisibleMessage() message.id = messageRecord.getId() @@ -55,8 +60,13 @@ object ResendMessageUtilities { val sentTimestamp = message.sentTimestamp val sender = MessagingModuleConfiguration.shared.storage.getUserPublicKey() if (sentTimestamp != null && sender != null) { - MessagingModuleConfiguration.shared.storage.markAsSending(sentTimestamp, sender) + if (isResync) { + MessagingModuleConfiguration.shared.storage.markAsResyncing(sentTimestamp, sender) + MessageSender.send(message, Destination.from(recipient.address), isSyncMessage = true) + } else { + MessagingModuleConfiguration.shared.storage.markAsSending(sentTimestamp, sender) + MessageSender.send(message, recipient.address) + } } - MessageSender.send(message, recipient.address) } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java index d3ba31747d..edc6bc1a6f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java @@ -37,6 +37,13 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn public abstract void markExpireStarted(long messageId, long startTime); public abstract void markAsSent(long messageId, boolean secure); + + public abstract void markAsSyncing(long id); + + public abstract void markAsResyncing(long id); + + public abstract void markAsSyncFailed(long id); + public abstract void markUnidentified(long messageId, boolean unidentified); public abstract void markAsDeleted(long messageId, boolean read, boolean hasMention); @@ -199,7 +206,6 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn contentValues.put(THREAD_ID, newThreadId); db.update(getTableName(), contentValues, where, args); } - public static class SyncMessageId { private final Address address; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index 3a4b35ad17..9e854698f5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -276,6 +276,16 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa notifyConversationListeners(threadId) } + override fun markAsSyncing(messageId: Long) { + markAs(messageId, MmsSmsColumns.Types.BASE_SYNCING_TYPE) + } + override fun markAsResyncing(messageId: Long) { + markAs(messageId, MmsSmsColumns.Types.BASE_RESYNCING_TYPE) + } + override fun markAsSyncFailed(messageId: Long) { + markAs(messageId, MmsSmsColumns.Types.BASE_SYNC_FAILED_TYPE) + } + fun markAsSending(messageId: Long) { markAs(messageId, MmsSmsColumns.Types.BASE_SENDING_TYPE) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java index f3110a5c79..1e1cc50896 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -47,8 +47,13 @@ public interface MmsSmsColumns { protected static final long BASE_PENDING_INSECURE_SMS_FALLBACK = 26; public static final long BASE_DRAFT_TYPE = 27; protected static final long BASE_DELETED_TYPE = 28; + protected static final long BASE_SYNCING_TYPE = 29; + protected static final long BASE_RESYNCING_TYPE = 30; + protected static final long BASE_SYNC_FAILED_TYPE = 31; protected static final long[] OUTGOING_MESSAGE_TYPES = {BASE_OUTBOX_TYPE, BASE_SENT_TYPE, + BASE_SYNCING_TYPE, BASE_RESYNCING_TYPE, + BASE_SYNC_FAILED_TYPE, BASE_SENDING_TYPE, BASE_SENT_FAILED_TYPE, BASE_PENDING_SECURE_SMS_FALLBACK, BASE_PENDING_INSECURE_SMS_FALLBACK, @@ -109,6 +114,18 @@ public interface MmsSmsColumns { return (type & BASE_TYPE_MASK) == BASE_DRAFT_TYPE; } + public static boolean isResyncingType(long type) { + return (type & BASE_TYPE_MASK) == BASE_RESYNCING_TYPE; + } + + public static boolean isSyncingType(long type) { + return (type & BASE_TYPE_MASK) == BASE_SYNCING_TYPE; + } + + public static boolean isSyncFailedMessageType(long type) { + return (type & BASE_TYPE_MASK) == BASE_SYNC_FAILED_TYPE; + } + public static boolean isFailedMessageType(long type) { return (type & BASE_TYPE_MASK) == BASE_SENT_FAILED_TYPE; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 0d61b26796..42a00ccbb2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -202,6 +202,21 @@ public class SmsDatabase extends MessagingDatabase { updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE); } + @Override + public void markAsSyncing(long id) { + updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SYNCING_TYPE); + } + + @Override + public void markAsResyncing(long id) { + updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_RESYNCING_TYPE); + } + + @Override + public void markAsSyncFailed(long id) { + updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SYNC_FAILED_TYPE); + } + @Override public void markUnidentified(long id, boolean unidentified) { ContentValues contentValues = new ContentValues(1); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 076fa57afc..77f616026c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -41,6 +41,7 @@ import org.session.libsignal.messages.SignalServiceAttachmentPointer import org.session.libsignal.messages.SignalServiceGroup import org.session.libsignal.utilities.IdPrefix import org.session.libsignal.utilities.KeyHelper +import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.guava.Optional import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper @@ -53,6 +54,8 @@ import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.util.SessionMetaProtocol import java.security.MessageDigest +private val TAG = Storage::class.java.simpleName + class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol { override fun getUserPublicKey(): String? { @@ -356,6 +359,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, openGroupSentTimestamp: Long, threadId: Long ) { + Log.d(TAG, "updateSentTimestamp() called with: messageID = $messageID, isMms = $isMms, openGroupSentTimestamp = $openGroupSentTimestamp, threadId = $threadId") + if (isMms) { val mmsDb = DatabaseComponent.get(context).mmsDatabase() mmsDb.updateSentTimestamp(messageID, openGroupSentTimestamp, threadId) @@ -366,6 +371,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } override fun markAsSent(timestamp: Long, author: String) { + Log.d(TAG, "markAsSent() called with: timestamp = $timestamp, author = $author") + val database = DatabaseComponent.get(context).mmsSmsDatabase() val messageRecord = database.getMessageFor(timestamp, author) ?: return if (messageRecord.isMms) { @@ -377,7 +384,29 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } } + override fun markAsSyncing(timestamp: Long, author: String) { + Log.d(TAG, "markAsSyncing() called with: timestamp = $timestamp, author = $author") + + DatabaseComponent.get(context).mmsSmsDatabase() + .getMessageFor(timestamp, author) + ?.run { getMmsDatabaseElseSms(isMms).markAsSyncing(id) } + } + + private fun getMmsDatabaseElseSms(isMms: Boolean) = + if (isMms) DatabaseComponent.get(context).mmsDatabase() + else DatabaseComponent.get(context).smsDatabase() + + override fun markAsResyncing(timestamp: Long, author: String) { + Log.d(TAG, "markAsResyncing() called with: timestamp = $timestamp, author = $author") + + DatabaseComponent.get(context).mmsSmsDatabase() + .getMessageFor(timestamp, author) + ?.run { getMmsDatabaseElseSms(isMms).markAsResyncing(id) } + } + override fun markAsSending(timestamp: Long, author: String) { + Log.d(TAG, "markAsSending() called with: timestamp = $timestamp, author = $author") + val database = DatabaseComponent.get(context).mmsSmsDatabase() val messageRecord = database.getMessageFor(timestamp, author) ?: return if (messageRecord.isMms) { @@ -402,7 +431,9 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } } - override fun setErrorMessage(timestamp: Long, author: String, error: Exception) { + override fun markAsSentFailed(timestamp: Long, author: String, error: Exception) { + Log.d(TAG, "markAsSentFailed() called with: timestamp = $timestamp, author = $author, error = $error") + val database = DatabaseComponent.get(context).mmsSmsDatabase() val messageRecord = database.getMessageFor(timestamp, author) ?: return if (messageRecord.isMms) { @@ -425,6 +456,28 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } } + override fun markAsSyncFailed(timestamp: Long, author: String, error: Exception) { + Log.d(TAG, "markAsSyncFailed() called with: timestamp = $timestamp, author = $author, error = $error") + + val database = DatabaseComponent.get(context).mmsSmsDatabase() + val messageRecord = database.getMessageFor(timestamp, author) ?: return + + database.getMessageFor(timestamp, author) + ?.run { getMmsDatabaseElseSms(isMms).markAsSyncFailed(id) } + + if (error.localizedMessage != null) { + val message: String + if (error is OnionRequestAPI.HTTPRequestFailedAtDestinationException && error.statusCode == 429) { + message = "429: Rate limited." + } else { + message = error.localizedMessage!! + } + DatabaseComponent.get(context).lokiMessageDatabase().setErrorMessage(messageRecord.getId(), message) + } else { + DatabaseComponent.get(context).lokiMessageDatabase().setErrorMessage(messageRecord.getId(), error.javaClass.simpleName) + } + } + override fun clearErrorMessage(messageID: Long) { val db = DatabaseComponent.get(context).lokiMessageDatabase() db.clearErrorMessage(messageID) @@ -983,5 +1036,4 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, val recipientDb = DatabaseComponent.get(context).recipientDatabase() return recipientDb.blockedContacts } - } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java index ef0f4b54f3..39fba182aa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -80,6 +80,18 @@ public abstract class DisplayRecord { return !isFailed() && !isPending(); } + public boolean isSyncing() { + return MmsSmsColumns.Types.isSyncingType(type); + } + + public boolean isResyncing() { + return MmsSmsColumns.Types.isResyncingType(type); + } + + public boolean isSyncFailed() { + return MmsSmsColumns.Types.isSyncFailedMessageType(type); + } + public boolean isFailed() { return MmsSmsColumns.Types.isFailedMessageType(type) || MmsSmsColumns.Types.isPendingSecureSmsFallbackType(type) diff --git a/app/src/main/res/menu/menu_conversation_item_action.xml b/app/src/main/res/menu/menu_conversation_item_action.xml index 8e20939225..ea81685617 100644 --- a/app/src/main/res/menu/menu_conversation_item_action.xml +++ b/app/src/main/res/menu/menu_conversation_item_action.xml @@ -32,6 +32,11 @@ android:icon="?menu_copy_icon" app:showAsAction="always" /> + + Message sent status: Sent Message sent status pending + Message sent status syncing Message request has been accepted Message Body Voice message @@ -627,6 +628,7 @@ Delete message Ban user Ban and delete all + Resync message Resend message Reply Reply to message @@ -1007,9 +1009,11 @@ Close Dialog Database Upgrade Failed Please contact support to report the error. + Syncing Sending Read Sent + Failed to sync Failed to send Search GIFs? Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs. diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index d75e209d11..48d15a18ac 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -106,10 +106,13 @@ interface StorageProtocol { fun getAttachmentsForMessage(messageID: Long): List fun getMessageIdInDatabase(timestamp: Long, author: String): Long? // TODO: This is a weird name fun updateSentTimestamp(messageID: Long, isMms: Boolean, openGroupSentTimestamp: Long, threadId: Long) + fun markAsResyncing(timestamp: Long, author: String) + fun markAsSyncing(timestamp: Long, author: String) fun markAsSending(timestamp: Long, author: String) fun markAsSent(timestamp: Long, author: String) fun markUnidentified(timestamp: Long, author: String) - fun setErrorMessage(timestamp: Long, author: String, error: Exception) + fun markAsSyncFailed(timestamp: Long, author: String, error: Exception) + fun markAsSentFailed(timestamp: Long, author: String, error: Exception) fun clearErrorMessage(messageID: Long) fun setMessageServerHash(messageID: Long, serverHash: String) diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt index 524338592c..4300fe4b61 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt @@ -34,6 +34,8 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job { } override fun execute(dispatcherName: String) { + Log.d(TAG, "MessageSendJob#execute() called with: dispatcherName = $dispatcherName") + val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider val message = message as? VisibleMessage val storage = MessagingModuleConfiguration.shared.storage diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt index 3abf0ed3e1..f30c1b9168 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt @@ -7,13 +7,13 @@ import org.session.libsignal.utilities.toHexString sealed class Destination { - class Contact(var publicKey: String) : Destination() { + data class Contact(var publicKey: String) : Destination() { internal constructor(): this("") } - class ClosedGroup(var groupPublicKey: String) : Destination() { + data class ClosedGroup(var groupPublicKey: String) : Destination() { internal constructor(): this("") } - class LegacyOpenGroup(var roomToken: String, var server: String) : Destination() { + data class LegacyOpenGroup(var roomToken: String, var server: String) : Destination() { internal constructor(): this("", "") } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt index e66147da18..705fc7ce45 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt @@ -11,20 +11,22 @@ import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.utilities.Log import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment -class VisibleMessage : Message() { - /** In the case of a sync message, the public key of the person the message was targeted at. - * - * **Note:** `nil` if this isn't a sync message. - */ - var syncTarget: String? = null - var text: String? = null - val attachmentIDs: MutableList = mutableListOf() - var quote: Quote? = null - var linkPreview: LinkPreview? = null - var profile: Profile? = null - var openGroupInvitation: OpenGroupInvitation? = null - var reaction: Reaction? = null +/** + * @param syncTarget In the case of a sync message, the public key of the person the message was targeted at. + * + * **Note:** `nil` if this isn't a sync message. + */ +class VisibleMessage( + var syncTarget: String? = null, + var text: String? = null, + val attachmentIDs: MutableList = mutableListOf(), + var quote: Quote? = null, + var linkPreview: LinkPreview? = null, + var profile: Profile? = null, + var openGroupInvitation: OpenGroupInvitation? = null, + var reaction: Reaction? = null, var hasMention: Boolean = false +) : Message() { override val isSelfSendValid: Boolean = true diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index eb0d15739b..9da6cd8b14 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -39,6 +39,8 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview as SignalLinkPreview import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel as SignalQuote +private val TAG = MessageSender::class.java.simpleName + object MessageSender { // Error @@ -61,16 +63,20 @@ object MessageSender { } // Convenience - fun send(message: Message, destination: Destination): Promise { + fun send(message: Message, destination: Destination, isSyncMessage: Boolean = false): Promise { + Log.d(TAG, "send() called with: message = $message, destination = $destination, isSyncMessage = $isSyncMessage") + return if (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup || destination is Destination.OpenGroupInbox) { sendToOpenGroupDestination(destination, message) } else { - sendToSnodeDestination(destination, message) + sendToSnodeDestination(destination, message, isSyncMessage) } } // One-on-One Chats & Closed Groups private fun sendToSnodeDestination(destination: Destination, message: Message, isSyncMessage: Boolean = false): Promise { + Log.d(TAG, "sendToSnodeDestination() called with: destination = $destination, message = $message, isSyncMessage = $isSyncMessage") + val deferred = deferred() val promise = deferred.promise val storage = MessagingModuleConfiguration.shared.storage @@ -86,7 +92,7 @@ object MessageSender { val isSelfSend = (message.recipient == userPublicKey) // Set the failure handler (need it here already for precondition failure handling) fun handleFailure(error: Exception) { - handleFailedMessageSend(message, error) + handleFailedMessageSend(message, error, isSyncMessage) if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) { SnodeModule.shared.broadcaster.broadcast("messageFailed", message.sentTimestamp!!) } @@ -220,6 +226,8 @@ object MessageSender { // Open Groups private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise { + Log.d(TAG, "sendToOpenGroupDestination() called with: destination = $destination, message = $message") + val deferred = deferred() val storage = MessagingModuleConfiguration.shared.storage if (message.sentTimestamp == null) { @@ -318,6 +326,8 @@ object MessageSender { // Result Handling fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false, openGroupSentTimestamp: Long = -1) { + Log.d(TAG, "handleSuccessfulMessageSend() called with: message = $message, destination = $destination, isSyncMessage = $isSyncMessage, openGroupSentTimestamp = $openGroupSentTimestamp") + val storage = MessagingModuleConfiguration.shared.storage val userPublicKey = storage.getUserPublicKey()!! // Ignore future self-sends @@ -374,21 +384,32 @@ object MessageSender { // • the destination was a contact // • we didn't sync it already if (destination is Destination.Contact && !isSyncMessage) { - if (message is VisibleMessage) { message.syncTarget = destination.publicKey } - if (message is ExpirationTimerUpdate) { message.syncTarget = destination.publicKey } + if (message is VisibleMessage) message.syncTarget = destination.publicKey + if (message is ExpirationTimerUpdate) message.syncTarget = destination.publicKey + + storage.markAsSyncing(message.sentTimestamp!!, userPublicKey) sendToSnodeDestination(Destination.Contact(userPublicKey), message, true) } } - fun handleFailedMessageSend(message: Message, error: Exception) { + fun handleFailedMessageSend(message: Message, error: Exception, isSyncMessage: Boolean = false) { + Log.d(TAG, "handleFailedMessageSend() called with: message = $message, error = $error, isSyncMessage = $isSyncMessage") + val storage = MessagingModuleConfiguration.shared.storage val userPublicKey = storage.getUserPublicKey()!! - storage.setErrorMessage(message.sentTimestamp!!, message.sender?:userPublicKey, error) + + val timestamp = message.sentTimestamp!! + val author = message.sender ?: userPublicKey + + if (isSyncMessage) storage.markAsSyncFailed(timestamp, author, error) + else storage.markAsSentFailed(timestamp, author, error) } // Convenience @JvmStatic fun send(message: VisibleMessage, address: Address, attachments: List, quote: SignalQuote?, linkPreview: SignalLinkPreview?) { + Log.d(TAG, "send() called with: message = $message, address = $address, attachments = $attachments, quote = $quote, linkPreview = $linkPreview") + val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider val attachmentIDs = messageDataProvider.getAttachmentIDsFor(message.id!!) message.attachmentIDs.addAll(attachmentIDs) @@ -407,6 +428,8 @@ object MessageSender { @JvmStatic fun send(message: Message, address: Address) { + Log.d(TAG, "send() called with: message = $message, address = $address") + val threadID = MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(address) message.threadID = threadID val destination = Destination.from(address) From d3ce899a8056c9b9d307f9993845603b0016c058 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 May 2023 12:07:19 +0930 Subject: [PATCH 16/83] Synchronize all Cipher#doFinal --- .../securesms/backup/FullBackupExporter.kt | 35 +++++++++------ .../session/libsession/utilities/AESGCM.kt | 17 ++++--- .../session/libsignal/crypto/CipherUtil.java | 5 +++ .../session/libsignal/crypto/DiffieHellman.kt | 45 ------------------- .../session/libsignal/crypto/kdf/HKDF.java | 8 +--- .../streams/AttachmentCipherOutputStream.java | 15 ++++--- .../streams/ProfileCipherInputStream.java | 30 +++++++------ .../streams/ProfileCipherOutputStream.java | 16 ++++--- 8 files changed, 75 insertions(+), 96 deletions(-) create mode 100644 libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java delete mode 100644 libsignal/src/main/java/org/session/libsignal/crypto/DiffieHellman.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt index 6b5d47a2e6..783468eee7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt @@ -14,6 +14,7 @@ import org.session.libsession.avatars.AvatarHelper import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId import org.session.libsession.utilities.Conversions import org.session.libsession.utilities.Util +import org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK import org.session.libsignal.crypto.kdf.HKDFv3 import org.session.libsignal.utilities.ByteUtil import org.session.libsignal.utilities.Log @@ -289,7 +290,7 @@ object FullBackupExporter { private var counter: Int = 0 - constructor(outputStream: OutputStream, passphrase: String) : super() { + private constructor(outputStream: OutputStream, passphrase: String) : super() { try { val salt = Util.getSecretBytes(32) val key = BackupUtil.computeBackupKey(passphrase, salt) @@ -381,18 +382,24 @@ object FullBackupExporter { private fun writeStream(inputStream: InputStream) { try { Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - mac.update(iv) - val buffer = ByteArray(8192) - var read: Int - while (inputStream.read(buffer).also { read = it } != -1) { - val ciphertext = cipher.update(buffer, 0, read) - if (ciphertext != null) { - outputStream.write(ciphertext) - mac.update(ciphertext) + val remainder = synchronized(CIPHER_LOCK) { + cipher.init( + Cipher.ENCRYPT_MODE, + SecretKeySpec(cipherKey, "AES"), + IvParameterSpec(iv) + ) + mac.update(iv) + val buffer = ByteArray(8192) + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + val ciphertext = cipher.update(buffer, 0, read) + if (ciphertext != null) { + outputStream.write(ciphertext) + mac.update(ciphertext) + } } + cipher.doFinal() } - val remainder = cipher.doFinal() outputStream.write(remainder) mac.update(remainder) val attachmentDigest = mac.doFinal() @@ -414,8 +421,10 @@ object FullBackupExporter { private fun write(out: OutputStream, frame: BackupFrame) { try { Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - val frameCiphertext = cipher.doFinal(frame.toByteArray()) + val frameCiphertext = synchronized(CIPHER_LOCK) { + cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) + cipher.doFinal(frame.toByteArray()) + } val frameMac = mac.doFinal(frameCiphertext) val length = Conversions.intToByteArray(frameCiphertext.size + 10) out.write(length) diff --git a/libsession/src/main/java/org/session/libsession/utilities/AESGCM.kt b/libsession/src/main/java/org/session/libsession/utilities/AESGCM.kt index 225900b096..4a6a588dc2 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/AESGCM.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/AESGCM.kt @@ -1,6 +1,7 @@ package org.session.libsession.utilities import androidx.annotation.WorkerThread +import org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK import org.session.libsignal.utilities.ByteUtil import org.session.libsignal.utilities.Util import org.session.libsignal.utilities.Hex @@ -27,9 +28,11 @@ internal object AESGCM { internal fun decrypt(ivAndCiphertext: ByteArray, symmetricKey: ByteArray): ByteArray { val iv = ivAndCiphertext.sliceArray(0 until ivSize) val ciphertext = ivAndCiphertext.sliceArray(ivSize until ivAndCiphertext.count()) - val cipher = Cipher.getInstance("AES/GCM/NoPadding") - cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(symmetricKey, "AES"), GCMParameterSpec(gcmTagSize, iv)) - return cipher.doFinal(ciphertext) + synchronized(CIPHER_LOCK) { + val cipher = Cipher.getInstance("AES/GCM/NoPadding") + cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(symmetricKey, "AES"), GCMParameterSpec(gcmTagSize, iv)) + return cipher.doFinal(ciphertext) + } } /** @@ -47,9 +50,11 @@ internal object AESGCM { */ internal fun encrypt(plaintext: ByteArray, symmetricKey: ByteArray): ByteArray { val iv = Util.getSecretBytes(ivSize) - val cipher = Cipher.getInstance("AES/GCM/NoPadding") - cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(symmetricKey, "AES"), GCMParameterSpec(gcmTagSize, iv)) - return ByteUtil.combine(iv, cipher.doFinal(plaintext)) + synchronized(CIPHER_LOCK) { + val cipher = Cipher.getInstance("AES/GCM/NoPadding") + cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(symmetricKey, "AES"), GCMParameterSpec(gcmTagSize, iv)) + return ByteUtil.combine(iv, cipher.doFinal(plaintext)) + } } /** diff --git a/libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java b/libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java new file mode 100644 index 0000000000..d3423a0bd4 --- /dev/null +++ b/libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java @@ -0,0 +1,5 @@ +package org.session.libsignal.crypto; + +public class CipherUtil { + public static final Object CIPHER_LOCK = new Object(); +} diff --git a/libsignal/src/main/java/org/session/libsignal/crypto/DiffieHellman.kt b/libsignal/src/main/java/org/session/libsignal/crypto/DiffieHellman.kt deleted file mode 100644 index 2b613247bf..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/crypto/DiffieHellman.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.session.libsignal.crypto - -import org.whispersystems.curve25519.Curve25519 -import org.session.libsignal.utilities.Util -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec - -object DiffieHellman { - private val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") - private val curve = Curve25519.getInstance(Curve25519.BEST) - private val ivSize = 16 - - @JvmStatic @Throws - fun encrypt(plaintext: ByteArray, symmetricKey: ByteArray): ByteArray { - val iv = Util.getSecretBytes(ivSize) - val ivSpec = IvParameterSpec(iv) - val secretKeySpec = SecretKeySpec(symmetricKey, "AES") - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec) - val ciphertext = cipher.doFinal(plaintext) - return iv + ciphertext - } - - @JvmStatic @Throws - fun encrypt(plaintext: ByteArray, publicKey: ByteArray, privateKey: ByteArray): ByteArray { - val symmetricKey = curve.calculateAgreement(publicKey, privateKey) - return encrypt(plaintext, symmetricKey) - } - - @JvmStatic @Throws - fun decrypt(ivAndCiphertext: ByteArray, symmetricKey: ByteArray): ByteArray { - val iv = ivAndCiphertext.sliceArray(0 until ivSize) - val ciphertext = ivAndCiphertext.sliceArray(ivSize until ivAndCiphertext.size) - val ivSpec = IvParameterSpec(iv) - val secretKeySpec = SecretKeySpec(symmetricKey, "AES") - cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec) - return cipher.doFinal(ciphertext) - } - - @JvmStatic @Throws - fun decrypt(ivAndCiphertext: ByteArray, publicKey: ByteArray, privateKey: ByteArray): ByteArray { - val symmetricKey = curve.calculateAgreement(publicKey, privateKey) - return decrypt(ivAndCiphertext, symmetricKey) - } -} diff --git a/libsignal/src/main/java/org/session/libsignal/crypto/kdf/HKDF.java b/libsignal/src/main/java/org/session/libsignal/crypto/kdf/HKDF.java index 3295f06e52..73c87c075d 100644 --- a/libsignal/src/main/java/org/session/libsignal/crypto/kdf/HKDF.java +++ b/libsignal/src/main/java/org/session/libsignal/crypto/kdf/HKDF.java @@ -39,9 +39,7 @@ public abstract class HKDF { Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(salt, "HmacSHA256")); return mac.doFinal(inputKeyMaterial); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new AssertionError(e); } } @@ -73,9 +71,7 @@ public abstract class HKDF { } return results.toByteArray(); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new AssertionError(e); } } diff --git a/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherOutputStream.java b/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherOutputStream.java index 91c3563700..2f58c84c78 100644 --- a/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherOutputStream.java +++ b/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherOutputStream.java @@ -6,6 +6,8 @@ package org.session.libsignal.streams; +import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK; + import org.session.libsignal.utilities.Util; import java.io.IOException; @@ -68,16 +70,17 @@ public class AttachmentCipherOutputStream extends DigestingOutputStream { @Override public void flush() throws IOException { try { - byte[] ciphertext = cipher.doFinal(); + byte[] ciphertext; + synchronized (CIPHER_LOCK) { + ciphertext = cipher.doFinal(); + } byte[] auth = mac.doFinal(ciphertext); super.write(ciphertext); super.write(auth); super.flush(); - } catch (IllegalBlockSizeException e) { - throw new AssertionError(e); - } catch (BadPaddingException e) { + } catch (IllegalBlockSizeException | BadPaddingException e) { throw new AssertionError(e); } } @@ -97,9 +100,7 @@ public class AttachmentCipherOutputStream extends DigestingOutputStream { private Cipher initializeCipher() { try { return Cipher.getInstance("AES/CBC/PKCS5Padding"); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (NoSuchPaddingException e) { + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new AssertionError(e); } } diff --git a/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherInputStream.java b/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherInputStream.java index aa15eb00c6..19996c17cb 100644 --- a/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherInputStream.java +++ b/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherInputStream.java @@ -1,5 +1,7 @@ package org.session.libsignal.streams; +import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK; + import org.session.libsignal.utilities.Util; import java.io.FilterInputStream; @@ -62,23 +64,23 @@ public class ProfileCipherInputStream extends FilterInputStream { byte[] ciphertext = new byte[outputLength / 2]; int read = in.read(ciphertext, 0, ciphertext.length); - if (read == -1) { - if (cipher.getOutputSize(0) > outputLength) { - throw new AssertionError("Need: " + cipher.getOutputSize(0) + " but only have: " + outputLength); - } + synchronized (CIPHER_LOCK) { + if (read == -1) { + if (cipher.getOutputSize(0) > outputLength) { + throw new AssertionError("Need: " + cipher.getOutputSize(0) + " but only have: " + outputLength); + } - finished = true; - return cipher.doFinal(output, outputOffset); - } else { - if (cipher.getOutputSize(read) > outputLength) { - throw new AssertionError("Need: " + cipher.getOutputSize(read) + " but only have: " + outputLength); - } + finished = true; + return cipher.doFinal(output, outputOffset); + } else { + if (cipher.getOutputSize(read) > outputLength) { + throw new AssertionError("Need: " + cipher.getOutputSize(read) + " but only have: " + outputLength); + } - return cipher.update(ciphertext, 0, read, output, outputOffset); + return cipher.update(ciphertext, 0, read, output, outputOffset); + } } - } catch (IllegalBlockSizeException e) { - throw new AssertionError(e); - } catch(ShortBufferException e) { + } catch (IllegalBlockSizeException | ShortBufferException e) { throw new AssertionError(e); } catch (BadPaddingException e) { throw new IOException(e); diff --git a/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java b/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java index 9d4e13a0c2..f47a5f72b6 100644 --- a/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java +++ b/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java @@ -1,5 +1,7 @@ package org.session.libsignal.streams; +import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK; + import java.io.IOException; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; @@ -54,20 +56,24 @@ public class ProfileCipherOutputStream extends DigestingOutputStream { byte[] input = new byte[1]; input[0] = (byte)b; - byte[] output = cipher.update(input); + byte[] output; + synchronized (CIPHER_LOCK) { + output = cipher.update(input); + } super.write(output); } @Override public void flush() throws IOException { try { - byte[] output = cipher.doFinal(); + byte[] output; + synchronized (CIPHER_LOCK) { + output = cipher.doFinal(); + } super.write(output); super.flush(); - } catch (BadPaddingException e) { - throw new AssertionError(e); - } catch (IllegalBlockSizeException e) { + } catch (BadPaddingException | IllegalBlockSizeException e) { throw new AssertionError(e); } } From 24741fcc22dabaef7757d723be355654bc70e1b9 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 May 2023 12:10:46 +0930 Subject: [PATCH 17/83] Synchronize Cipher in KeystoreHelper --- .../securesms/crypto/KeyStoreHelper.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java index 43e9865598..45ec9e207f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java @@ -45,44 +45,46 @@ public final class KeyStoreHelper { private static final String ANDROID_KEY_STORE = "AndroidKeyStore"; private static final String KEY_ALIAS = "SignalSecret"; - @RequiresApi(Build.VERSION_CODES.M) + private static final Object lock = new Object(); + public static SealedData seal(@NonNull byte[] input) { SecretKey secretKey = getOrCreateKeyStoreEntry(); try { - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); + synchronized (lock) { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); - byte[] iv = cipher.getIV(); - byte[] data = cipher.doFinal(input); + byte[] iv = cipher.getIV(); + byte[] data = cipher.doFinal(input); - return new SealedData(iv, data); + return new SealedData(iv, data); + } } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { throw new AssertionError(e); } } - @RequiresApi(Build.VERSION_CODES.M) public static byte[] unseal(@NonNull SealedData sealedData) { SecretKey secretKey = getKeyStoreEntry(); try { - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv)); + synchronized (lock) { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv)); - return cipher.doFinal(sealedData.data); + return cipher.doFinal(sealedData.data); + } } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { throw new AssertionError(e); } } - @RequiresApi(Build.VERSION_CODES.M) private static SecretKey getOrCreateKeyStoreEntry() { if (hasKeyStoreEntry()) return getKeyStoreEntry(); else return createKeyStoreEntry(); } - @RequiresApi(Build.VERSION_CODES.M) private static SecretKey createKeyStoreEntry() { try { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); @@ -99,7 +101,6 @@ public final class KeyStoreHelper { } } - @RequiresApi(Build.VERSION_CODES.M) private static SecretKey getKeyStoreEntry() { KeyStore keyStore = getKeyStore(); @@ -137,7 +138,6 @@ public final class KeyStoreHelper { } } - @RequiresApi(Build.VERSION_CODES.M) private static boolean hasKeyStoreEntry() { try { KeyStore ks = KeyStore.getInstance(ANDROID_KEY_STORE); From a152250a6007c423bda465f8c8824f1be5b73780 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 May 2023 12:18:39 +0930 Subject: [PATCH 18/83] Add comments --- .../org/thoughtcrime/securesms/crypto/KeyStoreHelper.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java index 45ec9e207f..001b4fa1a8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java @@ -51,6 +51,9 @@ public final class KeyStoreHelper { SecretKey secretKey = getOrCreateKeyStoreEntry(); try { + // Cipher operations are not thread-safe so we synchronize over them through doFinal to + // prevent crashes with quickly repeated encrypt/decrypt operations + // https://github.com/mozilla-mobile/android-components/issues/5342 synchronized (lock) { Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); @@ -69,6 +72,9 @@ public final class KeyStoreHelper { SecretKey secretKey = getKeyStoreEntry(); try { + // Cipher operations are not thread-safe so we synchronize over them through doFinal to + // prevent crashes with quickly repeated encrypt/decrypt operations + // https://github.com/mozilla-mobile/android-components/issues/5342 synchronized (lock) { Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv)); From a9078c8d08939604087b21c73446ba66bfe3248d Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 May 2023 12:32:54 +0930 Subject: [PATCH 19/83] ...and the rest --- .../securesms/backup/FullBackupImporter.kt | 39 ++++++++++++------- .../securesms/crypto/KeyStoreHelper.java | 30 +++++++------- .../securesms/logging/LogFile.java | 27 +++++++------ .../streams/AttachmentCipherInputStream.java | 35 +++++++---------- 4 files changed, 68 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt index b40c049bc2..7d2daa910e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt @@ -12,6 +12,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.utilities.Address import org.session.libsession.utilities.Conversions import org.session.libsession.utilities.Util +import org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK import org.session.libsignal.crypto.kdf.HKDFv3 import org.session.libsignal.utilities.ByteUtil import org.session.libsignal.utilities.Log @@ -243,7 +244,7 @@ object FullBackupImporter { val split = ByteUtil.split(derived, 32, 32) cipherKey = split[0] macKey = split[1] - cipher = Cipher.getInstance("AES/CTR/NoPadding") + cipher = synchronized(CIPHER_LOCK) { Cipher.getInstance("AES/CTR/NoPadding") } mac = Mac.getInstance("HmacSHA256") mac.init(SecretKeySpec(macKey, "HmacSHA256")) counter = Conversions.byteArrayToInt(iv) @@ -269,20 +270,26 @@ object FullBackupImporter { var length = length try { Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - mac.update(iv) - val buffer = ByteArray(8192) - while (length > 0) { - val read = inputStream.read(buffer, 0, Math.min(buffer.size, length)) - if (read == -1) throw IOException("File ended early!") - mac.update(buffer, 0, read) - val plaintext = cipher.update(buffer, 0, read) - if (plaintext != null) { - out.write(plaintext, 0, plaintext.size) + val plaintext = synchronized(CIPHER_LOCK) { + cipher.init( + Cipher.DECRYPT_MODE, + SecretKeySpec(cipherKey, "AES"), + IvParameterSpec(iv) + ) + mac.update(iv) + val buffer = ByteArray(8192) + while (length > 0) { + val read = inputStream.read(buffer, 0, Math.min(buffer.size, length)) + if (read == -1) throw IOException("File ended early!") + mac.update(buffer, 0, read) + val plaintext = cipher.update(buffer, 0, read) + if (plaintext != null) { + out.write(plaintext, 0, plaintext.size) + } + length -= read } - length -= read + cipher.doFinal() } - val plaintext = cipher.doFinal() if (plaintext != null) { out.write(plaintext, 0, plaintext.size) } @@ -325,8 +332,10 @@ object FullBackupImporter { throw IOException("Bad MAC") } Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - val plaintext = cipher.doFinal(frame, 0, frame.size - 10) + val plaintext = synchronized(CIPHER_LOCK) { + cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) + cipher.doFinal(frame, 0, frame.size - 10) + } BackupFrame.parseFrom(plaintext) } catch (e: Exception) { when (e) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java index 43e9865598..c0372cc7f1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java @@ -1,6 +1,8 @@ package org.thoughtcrime.securesms.crypto; +import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK; + import android.os.Build; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; @@ -45,44 +47,44 @@ public final class KeyStoreHelper { private static final String ANDROID_KEY_STORE = "AndroidKeyStore"; private static final String KEY_ALIAS = "SignalSecret"; - @RequiresApi(Build.VERSION_CODES.M) public static SealedData seal(@NonNull byte[] input) { SecretKey secretKey = getOrCreateKeyStoreEntry(); try { - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); + synchronized (CIPHER_LOCK) { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); - byte[] iv = cipher.getIV(); - byte[] data = cipher.doFinal(input); + byte[] iv = cipher.getIV(); + byte[] data = cipher.doFinal(input); - return new SealedData(iv, data); + return new SealedData(iv, data); + } } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { throw new AssertionError(e); } } - @RequiresApi(Build.VERSION_CODES.M) public static byte[] unseal(@NonNull SealedData sealedData) { SecretKey secretKey = getKeyStoreEntry(); try { - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv)); + synchronized (CIPHER_LOCK) { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv)); - return cipher.doFinal(sealedData.data); + return cipher.doFinal(sealedData.data); + } } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { throw new AssertionError(e); } } - @RequiresApi(Build.VERSION_CODES.M) private static SecretKey getOrCreateKeyStoreEntry() { if (hasKeyStoreEntry()) return getKeyStoreEntry(); else return createKeyStoreEntry(); } - @RequiresApi(Build.VERSION_CODES.M) private static SecretKey createKeyStoreEntry() { try { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); @@ -99,7 +101,6 @@ public final class KeyStoreHelper { } } - @RequiresApi(Build.VERSION_CODES.M) private static SecretKey getKeyStoreEntry() { KeyStore keyStore = getKeyStore(); @@ -137,7 +138,6 @@ public final class KeyStoreHelper { } } - @RequiresApi(Build.VERSION_CODES.M) private static boolean hasKeyStoreEntry() { try { KeyStore ks = KeyStore.getInstance(ANDROID_KEY_STORE); @@ -202,7 +202,5 @@ public final class KeyStoreHelper { return Base64.decode(p.getValueAsString(), Base64.NO_WRAP | Base64.NO_PADDING); } } - } - } diff --git a/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java b/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java index f0c083ca1d..909f19e08c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java @@ -1,5 +1,7 @@ package org.thoughtcrime.securesms.logging; +import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK; + import androidx.annotation.NonNull; import org.session.libsession.utilities.Conversions; @@ -66,15 +68,17 @@ class LogFile { byte[] plaintext = entry.getBytes(); try { - cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer)); + synchronized (CIPHER_LOCK) { + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer)); - int cipherLength = cipher.getOutputSize(plaintext.length); - byte[] ciphertext = ciphertextBuffer.get(cipherLength); - cipherLength = cipher.doFinal(plaintext, 0, plaintext.length, ciphertext); + int cipherLength = cipher.getOutputSize(plaintext.length); + byte[] ciphertext = ciphertextBuffer.get(cipherLength); + cipherLength = cipher.doFinal(plaintext, 0, plaintext.length, ciphertext); - outputStream.write(ivBuffer); - outputStream.write(Conversions.intToByteArray(cipherLength)); - outputStream.write(ciphertext, 0, cipherLength); + outputStream.write(ivBuffer); + outputStream.write(Conversions.intToByteArray(cipherLength)); + outputStream.write(ciphertext, 0, cipherLength); + } outputStream.flush(); } catch (ShortBufferException | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) { @@ -134,10 +138,11 @@ class LogFile { Util.readFully(inputStream, ciphertext, length); try { - cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer)); - byte[] plaintext = cipher.doFinal(ciphertext, 0, length); - - return new String(plaintext); + synchronized (CIPHER_LOCK) { + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer)); + byte[] plaintext = cipher.doFinal(ciphertext, 0, length); + return new String(plaintext); + } } catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { throw new AssertionError(e); } diff --git a/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherInputStream.java b/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherInputStream.java index 3158d35f73..fd3c8123df 100644 --- a/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherInputStream.java +++ b/libsignal/src/main/java/org/session/libsignal/streams/AttachmentCipherInputStream.java @@ -6,6 +6,8 @@ package org.session.libsignal.streams; +import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK; + import org.session.libsignal.exceptions.InvalidMacException; import org.session.libsignal.exceptions.InvalidMessageException; import org.session.libsignal.utilities.Util; @@ -92,19 +94,15 @@ public class AttachmentCipherInputStream extends FilterInputStream { byte[] iv = new byte[BLOCK_SIZE]; readFully(iv); - this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - this.cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv)); + synchronized (CIPHER_LOCK) { + this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + this.cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv)); + } this.done = false; this.totalRead = 0; this.totalDataSize = totalDataSize; - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (InvalidKeyException e) { - throw new AssertionError(e); - } catch (NoSuchPaddingException e) { - throw new AssertionError(e); - } catch (InvalidAlgorithmParameterException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException e) { throw new AssertionError(e); } } @@ -141,15 +139,12 @@ public class AttachmentCipherInputStream extends FilterInputStream { private int readFinal(byte[] buffer, int offset, int length) throws IOException { try { - int flourish = cipher.doFinal(buffer, offset); - - done = true; - return flourish; - } catch (IllegalBlockSizeException e) { - throw new IOException(e); - } catch (BadPaddingException e) { - throw new IOException(e); - } catch (ShortBufferException e) { + synchronized (CIPHER_LOCK) { + int flourish = cipher.doFinal(buffer, offset); + done = true; + return flourish; + } + } catch (IllegalBlockSizeException | ShortBufferException | BadPaddingException e) { throw new IOException(e); } } @@ -234,9 +229,7 @@ public class AttachmentCipherInputStream extends FilterInputStream { throw new InvalidMacException("Digest doesn't match!"); } - } catch (IOException e) { - throw new InvalidMacException(e); - } catch (ArithmeticException e) { + } catch (IOException | ArithmeticException e) { throw new InvalidMacException(e); } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); From 9e6d1e27fc4657170e8dd7c87b64f618f3bd16ff Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 May 2023 12:33:50 +0930 Subject: [PATCH 20/83] Add comment --- .../src/main/java/org/session/libsignal/crypto/CipherUtil.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java b/libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java index d3423a0bd4..a6a3808bb4 100644 --- a/libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java +++ b/libsignal/src/main/java/org/session/libsignal/crypto/CipherUtil.java @@ -1,5 +1,8 @@ package org.session.libsignal.crypto; public class CipherUtil { + // Cipher operations are not thread-safe so we synchronize over them through doFinal to + // prevent crashes with quickly repeated encrypt/decrypt operations + // https://github.com/mozilla-mobile/android-components/issues/5342 public static final Object CIPHER_LOCK = new Object(); } From 6a5d97a0f063f7385f61d18202352e98ad968cf0 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 May 2023 12:37:46 +0930 Subject: [PATCH 21/83] Fix something --- .../org/thoughtcrime/securesms/backup/FullBackupExporter.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt index 783468eee7..5eba9b9945 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt @@ -279,7 +279,7 @@ object FullBackupExporter { return false } - private class BackupFrameOutputStream : Closeable, Flushable { + private class BackupFrameOutputStream(outputStream: OutputStream, passphrase: String) : Closeable, Flushable { private val outputStream: OutputStream private var cipher: Cipher @@ -290,7 +290,7 @@ object FullBackupExporter { private var counter: Int = 0 - private constructor(outputStream: OutputStream, passphrase: String) : super() { + init { try { val salt = Util.getSecretBytes(32) val key = BackupUtil.computeBackupKey(passphrase, salt) From 375815c7190444f0a4d49b304095551866ce0cd5 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 5 May 2023 16:51:44 +1000 Subject: [PATCH 22/83] WIP: refactor on jobs using old job table --- .../securesms/jobmanager/JobManager.java | 39 --- .../securesms/jobs/JobManagerFactories.java | 4 +- .../securesms/jobs/LocalBackupJob.java | 83 ------ .../securesms/jobs/LocalBackupJob.kt | 61 ++++ .../securesms/jobs/UpdateApkJob.java | 271 ------------------ .../securesms/jobs/UpdateApkJob.kt | 200 +++++++++++++ .../service/UpdateApkRefreshListener.java | 2 + .../sskenvironment/ProfileManager.kt | 1 + 8 files changed, 266 insertions(+), 395 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java index 5906afd292..abb15d9f75 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java @@ -78,35 +78,6 @@ public class JobManager implements ConstraintObserver.Notifier { new Chain(this, Collections.singletonList(job)).enqueue(); } - /** - * Begins the creation of a job chain with a single job. - * @see Chain - */ - public Chain startChain(@NonNull Job job) { - return new Chain(this, Collections.singletonList(job)); - } - - /** - * Begins the creation of a job chain with a set of jobs that can be run in parallel. - * @see Chain - */ - public Chain startChain(@NonNull List jobs) { - return new Chain(this, jobs); - } - - /** - * Retrieves a string representing the state of the job queue. Intended for debugging. - */ - public @NonNull String getDebugInfo() { - Future result = executor.submit(jobController::getDebugInfo); - try { - return result.get(); - } catch (ExecutionException | InterruptedException e) { - Log.w(TAG, "Failed to retrieve Job info.", e); - return "Failed to retrieve Job info."; - } - } - /** * Adds a listener to that will be notified when the job queue has been drained. */ @@ -261,16 +232,6 @@ public class JobManager implements ConstraintObserver.Notifier { private Data.Serializer dataSerializer = new JsonDataSerializer(); private JobStorage jobStorage = null; - public @NonNull Builder setJobThreadCount(int jobThreadCount) { - this.jobThreadCount = jobThreadCount; - return this; - } - - public @NonNull Builder setExecutorFactory(@NonNull ExecutorFactory executorFactory) { - this.executorFactory = executorFactory; - return this; - } - public @NonNull Builder setJobFactories(@NonNull Map jobFactories) { this.jobFactories = jobFactories; return this; diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index ef73325f37..468bf58369 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -29,9 +29,9 @@ public final class JobManagerFactories { public static Map getJobFactories(@NonNull Application application) { HashMap factoryHashMap = new HashMap() {{ put(AvatarDownloadJob.KEY, new AvatarDownloadJob.Factory()); - put(LocalBackupJob.KEY, new LocalBackupJob.Factory()); + put(LocalBackupJob.Companion.getKEY(), new LocalBackupJob.Factory()); put(RetrieveProfileAvatarJob.KEY, new RetrieveProfileAvatarJob.Factory(application)); - put(UpdateApkJob.KEY, new UpdateApkJob.Factory()); + put(UpdateApkJob.Companion.getKEY(), new UpdateApkJob.Factory()); put(PrepareAttachmentAudioExtrasJob.KEY, new PrepareAttachmentAudioExtrasJob.Factory()); }}; factoryKeys.addAll(factoryHashMap.keySet()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java deleted file mode 100644 index e5715db263..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import androidx.annotation.NonNull; - -import org.session.libsession.messaging.utilities.Data; -import org.session.libsignal.utilities.NoExternalStorageException; -import org.thoughtcrime.securesms.jobmanager.Job; -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.database.BackupFileRecord; -import org.thoughtcrime.securesms.notifications.NotificationChannels; -import org.thoughtcrime.securesms.service.GenericForegroundService; -import org.thoughtcrime.securesms.util.BackupUtil; - -import java.io.IOException; -import java.util.Collections; - -import network.loki.messenger.R; - -public class LocalBackupJob extends BaseJob { - - public static final String KEY = "LocalBackupJob"; - - private static final String TAG = LocalBackupJob.class.getSimpleName(); - - public LocalBackupJob() { - this(new Job.Parameters.Builder() - .setQueue("__LOCAL_BACKUP__") - .setMaxInstances(1) - .setMaxAttempts(3) - .build()); - } - - private LocalBackupJob(@NonNull Job.Parameters parameters) { - super(parameters); - } - - @Override - public @NonNull - Data serialize() { - return Data.EMPTY; - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onRun() throws NoExternalStorageException, IOException { - Log.i(TAG, "Executing backup job..."); - - GenericForegroundService.startForegroundTask(context, - context.getString(R.string.LocalBackupJob_creating_backup), - NotificationChannels.BACKUPS, - R.drawable.ic_launcher_foreground); - - // TODO: Maybe create a new backup icon like ic_signal_backup? - - try { - BackupFileRecord record = BackupUtil.createBackupFile(context); - BackupUtil.deleteAllBackupFiles(context, Collections.singletonList(record)); - - } finally { - GenericForegroundService.stopForegroundTask(context); - } - } - - @Override - public boolean onShouldRetry(@NonNull Exception e) { - return false; - } - - @Override - public void onCanceled() { - } - - public static class Factory implements Job.Factory { - @Override - public @NonNull LocalBackupJob create(@NonNull Parameters parameters, @NonNull Data data) { - return new LocalBackupJob(parameters); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt new file mode 100644 index 0000000000..8a71760df3 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt @@ -0,0 +1,61 @@ +package org.thoughtcrime.securesms.jobs + +import android.content.Context +import org.session.libsession.messaging.jobs.Job +import org.session.libsession.messaging.jobs.JobDelegate +import org.session.libsession.messaging.utilities.Data +import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.notifications.NotificationChannels +import org.thoughtcrime.securesms.service.GenericForegroundService +import org.thoughtcrime.securesms.util.BackupUtil.createBackupFile +import org.thoughtcrime.securesms.util.BackupUtil.deleteAllBackupFiles + +import network.loki.messenger.R + + +class LocalBackupJob:Job { + override var delegate: JobDelegate? = null + override var id: String? = null + override var failureCount: Int = 0 + override val maxFailureCount: Int = 0 + + lateinit var context: Context + + companion object { + val TAG = LocalBackupJob::class.simpleName + val KEY: String = "LocalBackupJob" + } + + override fun execute(dispatcherName: String) { + Log.i(TAG, "Executing backup job...") + + GenericForegroundService.startForegroundTask( + context, + context.getString(R.string.LocalBackupJob_creating_backup), + NotificationChannels.BACKUPS, + R.drawable.ic_launcher_foreground + ) + + // TODO: Maybe create a new backup icon like ic_signal_backup? + try { + val record = createBackupFile(context) + deleteAllBackupFiles(context, listOf(record)) + } finally { + GenericForegroundService.stopForegroundTask(context) + } + } + + override fun serialize(): Data { + return Data.EMPTY + } + + override fun getFactoryKey(): String { + return KEY + } + + class Factory: Job.Factory { + override fun create(data: Data): LocalBackupJob { + return LocalBackupJob() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.java deleted file mode 100644 index 5b4ce8d13c..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.java +++ /dev/null @@ -1,271 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - - -import android.app.DownloadManager; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.net.Uri; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.session.libsession.messaging.utilities.Data; -import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.service.UpdateApkReadyListener; -import org.session.libsession.utilities.FileUtils; -import org.session.libsignal.utilities.Hex; -import org.session.libsignal.utilities.JsonUtil; -import org.session.libsession.utilities.TextSecurePreferences; - -import java.io.FileInputStream; -import java.io.IOException; -import java.security.MessageDigest; - -import network.loki.messenger.BuildConfig; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -public class UpdateApkJob extends BaseJob { - - public static final String KEY = "UpdateApkJob"; - - private static final String TAG = UpdateApkJob.class.getSimpleName(); - - public UpdateApkJob() { - this(new Job.Parameters.Builder() - .setQueue("UpdateApkJob") - .addConstraint(NetworkConstraint.KEY) - .setMaxAttempts(3) - .build()); - } - - private UpdateApkJob(@NonNull Job.Parameters parameters) { - super(parameters); - } - - @Override - public @NonNull - Data serialize() { - return Data.EMPTY; - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onRun() throws IOException, PackageManager.NameNotFoundException { - if (!BuildConfig.PLAY_STORE_DISABLED) return; - - Log.i(TAG, "Checking for APK update..."); - - OkHttpClient client = new OkHttpClient(); - Request request = new Request.Builder().url(String.format("%s/latest.json", BuildConfig.NOPLAY_UPDATE_URL)).build(); - - Response response = client.newCall(request).execute(); - - if (!response.isSuccessful()) { - throw new IOException("Bad response: " + response.message()); - } - - UpdateDescriptor updateDescriptor = JsonUtil.fromJson(response.body().string(), UpdateDescriptor.class); - byte[] digest = Hex.fromStringCondensed(updateDescriptor.getDigest()); - - Log.i(TAG, "Got descriptor: " + updateDescriptor); - - if (updateDescriptor.getVersionCode() > getVersionCode()) { - DownloadStatus downloadStatus = getDownloadStatus(updateDescriptor.getUrl(), digest); - - Log.i(TAG, "Download status: " + downloadStatus.getStatus()); - - if (downloadStatus.getStatus() == DownloadStatus.Status.COMPLETE) { - Log.i(TAG, "Download status complete, notifying..."); - handleDownloadNotify(downloadStatus.getDownloadId()); - } else if (downloadStatus.getStatus() == DownloadStatus.Status.MISSING) { - Log.i(TAG, "Download status missing, starting download..."); - handleDownloadStart(updateDescriptor.getUrl(), updateDescriptor.getVersionName(), digest); - } - } - } - - @Override - public boolean onShouldRetry(@NonNull Exception e) { - return e instanceof IOException; - } - - @Override - public void onCanceled() { - Log.w(TAG, "Update check failed"); - } - - private int getVersionCode() throws PackageManager.NameNotFoundException { - PackageManager packageManager = context.getPackageManager(); - PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); - - return packageInfo.versionCode; - } - - private DownloadStatus getDownloadStatus(String uri, byte[] theirDigest) { - DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Query query = new DownloadManager.Query(); - - query.setFilterByStatus(DownloadManager.STATUS_PAUSED | DownloadManager.STATUS_PENDING | DownloadManager.STATUS_RUNNING | DownloadManager.STATUS_SUCCESSFUL); - - long pendingDownloadId = TextSecurePreferences.getUpdateApkDownloadId(context); - byte[] pendingDigest = getPendingDigest(context); - Cursor cursor = downloadManager.query(query); - - try { - DownloadStatus status = new DownloadStatus(DownloadStatus.Status.MISSING, -1); - - while (cursor != null && cursor.moveToNext()) { - int jobStatus = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)); - String jobRemoteUri = cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_URI)); - long downloadId = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID)); - byte[] digest = getDigestForDownloadId(downloadId); - - if (jobRemoteUri != null && jobRemoteUri.equals(uri) && downloadId == pendingDownloadId) { - - if (jobStatus == DownloadManager.STATUS_SUCCESSFUL && - digest != null && pendingDigest != null && - MessageDigest.isEqual(pendingDigest, theirDigest) && - MessageDigest.isEqual(digest, theirDigest)) - { - return new DownloadStatus(DownloadStatus.Status.COMPLETE, downloadId); - } else if (jobStatus != DownloadManager.STATUS_SUCCESSFUL) { - status = new DownloadStatus(DownloadStatus.Status.PENDING, downloadId); - } - } - } - - return status; - } finally { - if (cursor != null) cursor.close(); - } - } - - private void handleDownloadStart(String uri, String versionName, byte[] digest) { - DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(uri)); - - downloadRequest.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); - downloadRequest.setTitle("Downloading Signal update"); - downloadRequest.setDescription("Downloading Signal " + versionName); - downloadRequest.setVisibleInDownloadsUi(false); - downloadRequest.setDestinationInExternalFilesDir(context, null, "signal-update.apk"); - downloadRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); - - long downloadId = downloadManager.enqueue(downloadRequest); - TextSecurePreferences.setUpdateApkDownloadId(context, downloadId); - TextSecurePreferences.setUpdateApkDigest(context, Hex.toStringCondensed(digest)); - } - - private void handleDownloadNotify(long downloadId) { - Intent intent = new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE); - intent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId); - - new UpdateApkReadyListener().onReceive(context, intent); - } - - private @Nullable byte[] getDigestForDownloadId(long downloadId) { - try { - DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - FileInputStream fin = new FileInputStream(downloadManager.openDownloadedFile(downloadId).getFileDescriptor()); - byte[] digest = FileUtils.getFileDigest(fin); - - fin.close(); - - return digest; - } catch (IOException e) { - Log.w(TAG, e); - return null; - } - } - - private @Nullable byte[] getPendingDigest(Context context) { - try { - String encodedDigest = TextSecurePreferences.getUpdateApkDigest(context); - - if (encodedDigest == null) return null; - - return Hex.fromStringCondensed(encodedDigest); - } catch (IOException e) { - Log.w(TAG, e); - return null; - } - } - - private static class UpdateDescriptor { - @JsonProperty - private int versionCode; - - @JsonProperty - private String versionName; - - @JsonProperty - private String url; - - @JsonProperty - private String sha256sum; - - - public int getVersionCode() { - return versionCode; - } - - public String getVersionName() { - return versionName; - } - - public String getUrl() { - return url; - } - - public @NonNull String toString() { - return "[" + versionCode + ", " + versionName + ", " + url + "]"; - } - - public String getDigest() { - return sha256sum; - } - } - - private static class DownloadStatus { - enum Status { - PENDING, - COMPLETE, - MISSING - } - - private final Status status; - private final long downloadId; - - DownloadStatus(Status status, long downloadId) { - this.status = status; - this.downloadId = downloadId; - } - - public Status getStatus() { - return status; - } - - public long getDownloadId() { - return downloadId; - } - } - - public static final class Factory implements Job.Factory { - @Override - public @NonNull UpdateApkJob create(@NonNull Parameters parameters, @NonNull Data data) { - return new UpdateApkJob(parameters); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt new file mode 100644 index 0000000000..411f01fcde --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt @@ -0,0 +1,200 @@ +package org.thoughtcrime.securesms.jobs + +import androidx.annotation.Nullable + +import android.app.DownloadManager +import android.content.Context +import android.content.Intent +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.net.Uri +import com.fasterxml.jackson.annotation.JsonProperty +import network.loki.messenger.BuildConfig +import okhttp3.OkHttpClient +import okhttp3.Request +import org.session.libsession.messaging.jobs.Job +import org.session.libsession.messaging.jobs.JobDelegate +import org.session.libsession.messaging.utilities.Data +import org.session.libsession.utilities.FileUtils +import org.session.libsession.utilities.TextSecurePreferences.Companion.getUpdateApkDigest +import org.session.libsession.utilities.TextSecurePreferences.Companion.getUpdateApkDownloadId +import org.session.libsession.utilities.TextSecurePreferences.Companion.setUpdateApkDigest +import org.session.libsession.utilities.TextSecurePreferences.Companion.setUpdateApkDownloadId +import org.session.libsignal.utilities.Hex +import org.session.libsignal.utilities.JsonUtil +import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.service.UpdateApkReadyListener +import java.io.FileInputStream +import java.io.IOException +import java.security.MessageDigest + +class UpdateApkJob: Job { + override var delegate: JobDelegate? = null + override var id: String? = null + override var failureCount: Int = 0 + override val maxFailureCount: Int = 0 + + lateinit var context: Context + + companion object { + val TAG = UpdateApkJob::class.simpleName + val KEY: String = "UpdateApkJob" + } + + override fun execute(dispatcherName: String) { + if (!BuildConfig.PLAY_STORE_DISABLED) return + + Log.i(TAG, "Checking for APK update...") + + val client = OkHttpClient() + val request = Request.Builder().url(String.format("%s/latest.json", BuildConfig.NOPLAY_UPDATE_URL)).build() + val response = client.newCall(request).execute() + + if (!response.isSuccessful) { + throw IOException("Bad response: " + response.message()) + } + + val updateDescriptor: UpdateDescriptor = JsonUtil.fromJson( + response.body()!!.string(), + UpdateDescriptor::class.java + ) + val digest = Hex.fromStringCondensed(updateDescriptor.digest) + + Log.i( + TAG, + "Got descriptor: $updateDescriptor" + ) + + if (updateDescriptor.versionCode > getVersionCode()) { + val downloadStatus: DownloadStatus = getDownloadStatus(updateDescriptor.url, digest) + Log.i(TAG, "Download status: " + downloadStatus.status) + if (downloadStatus.status == DownloadStatus.Status.COMPLETE) { + Log.i(TAG, "Download status complete, notifying...") + handleDownloadNotify(downloadStatus.downloadId) + } else if (downloadStatus.status == DownloadStatus.Status.MISSING) { + Log.i(TAG, "Download status missing, starting download...") + handleDownloadStart( + updateDescriptor.url, + updateDescriptor.versionName, + digest + ) + } + } + } + + @Throws(PackageManager.NameNotFoundException::class) + private fun getVersionCode(): Int { + val packageManager: PackageManager = context.getPackageManager() + val packageInfo: PackageInfo = packageManager.getPackageInfo(context.getPackageName(), 0) + return packageInfo.versionCode + } + + private fun getDownloadStatus(uri: String, theirDigest: ByteArray): DownloadStatus { + val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + val query = DownloadManager.Query() + query.setFilterByStatus(DownloadManager.STATUS_PAUSED or DownloadManager.STATUS_PENDING or DownloadManager.STATUS_RUNNING or DownloadManager.STATUS_SUCCESSFUL) + val pendingDownloadId = getUpdateApkDownloadId(context) + val pendingDigest = getPendingDigest(context) + val cursor = downloadManager.query(query) + return try { + var status = DownloadStatus(DownloadStatus.Status.MISSING, -1) + while (cursor != null && cursor.moveToNext()) { + val jobStatus = + cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) + val jobRemoteUri = + cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_URI)) + val downloadId = + cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID)) + val digest = getDigestForDownloadId(downloadId) + if (jobRemoteUri != null && jobRemoteUri == uri && downloadId == pendingDownloadId) { + if (jobStatus == DownloadManager.STATUS_SUCCESSFUL && digest != null && pendingDigest != null && + MessageDigest.isEqual(pendingDigest, theirDigest) && + MessageDigest.isEqual(digest, theirDigest) + ) { + return DownloadStatus(DownloadStatus.Status.COMPLETE, downloadId) + } else if (jobStatus != DownloadManager.STATUS_SUCCESSFUL) { + status = DownloadStatus(DownloadStatus.Status.PENDING, downloadId) + } + } + } + status + } finally { + cursor?.close() + } + } + + private fun handleDownloadStart(uri: String, versionName: String, digest: ByteArray) { + val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + val downloadRequest = DownloadManager.Request(Uri.parse(uri)) + downloadRequest.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI) + downloadRequest.setTitle("Downloading Signal update") + downloadRequest.setDescription("Downloading Signal $versionName") + downloadRequest.setVisibleInDownloadsUi(false) + downloadRequest.setDestinationInExternalFilesDir(context, null, "signal-update.apk") + downloadRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN) + val downloadId = downloadManager.enqueue(downloadRequest) + setUpdateApkDownloadId(context, downloadId) + setUpdateApkDigest(context, Hex.toStringCondensed(digest)) + } + + private fun handleDownloadNotify(downloadId: Long) { + val intent = Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE) + intent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId) + UpdateApkReadyListener().onReceive(context, intent) + } + + private fun getDigestForDownloadId(downloadId: Long): ByteArray? { + return try { + val downloadManager = + context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + val fin = FileInputStream(downloadManager.openDownloadedFile(downloadId).fileDescriptor) + val digest = FileUtils.getFileDigest(fin) + fin.close() + digest + } catch (e: IOException) { + Log.w(TAG, e) + null + } + } + + private fun getPendingDigest(context: Context): ByteArray? { + return try { + val encodedDigest = getUpdateApkDigest(context) ?: return null + Hex.fromStringCondensed(encodedDigest) + } catch (e: IOException) { + Log.w(TAG, e) + null + } + } + + override fun serialize(): Data { + return Data.EMPTY + } + + override fun getFactoryKey(): String { + return KEY + } + + private class UpdateDescriptor( + @JsonProperty("versionCode") @Nullable val versionCode: Int, + @JsonProperty("versionName") @Nullable val versionName: String, + @JsonProperty("url") @Nullable val url: String, + @JsonProperty("sha256sum") @Nullable val digest: String) + { + override fun toString(): String { + return "[$versionCode, $versionName, $url]" + } + } + + private class DownloadStatus(val status: Status, val downloadId: Long) { + enum class Status { + PENDING, COMPLETE, MISSING + } + } + + class Factory: Job.Factory { + override fun create(data: Data): UpdateApkJob { + return UpdateApkJob() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java index 187713df95..ef27916ac9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java @@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.service; import android.content.Context; import android.content.Intent; + +import org.session.libsession.messaging.jobs.JobQueue; import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.ApplicationContext; diff --git a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt index c46f75bff8..2615eff588 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.sskenvironment import android.content.Context import org.session.libsession.messaging.contacts.Contact +import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.utilities.SSKEnvironment import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.ApplicationContext From e9a15941aef5971c5058a55162d1a6fc868fa368 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 May 2023 17:47:36 +0930 Subject: [PATCH 23/83] Fix colors --- .../securesms/conversation/v2/messages/VisibleMessageView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 745c91e910..ce6019e4c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -303,7 +303,7 @@ class VisibleMessageView : LinearLayout { message.isSyncFailed -> MessageStatusInfo( R.drawable.ic_delivery_status_failed, - resources.getColor(R.color.destructive, context.theme), + context.getColor(R.color.accent_orange), R.string.delivery_status_sync_failed, null ) @@ -316,7 +316,7 @@ class VisibleMessageView : LinearLayout { message.isResyncing -> MessageStatusInfo( R.drawable.ic_delivery_status_sending, - context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_syncing, + context.getColor(R.color.accent_orange), R.string.delivery_status_syncing, context.getString(R.string.AccessibilityId_message_sent_status_syncing) ) message.isRead -> From ec2abffdccc395bc119bcb3624a55f84734f9a53 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 8 May 2023 10:33:39 +0930 Subject: [PATCH 24/83] Remove logs --- .../v2/utilities/ResendMessageUtilities.kt | 4 ---- .../thoughtcrime/securesms/database/Storage.kt | 17 ----------------- .../libsession/messaging/jobs/MessageSendJob.kt | 2 -- .../sending_receiving/MessageSender.kt | 16 ---------------- 4 files changed, 39 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt index 5e6283e1ad..e01a75b30c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt @@ -11,16 +11,12 @@ import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.utilities.UpdateMessageData import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient -import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MmsMessageRecord -private val TAG = ResendMessageUtilities.javaClass.simpleName - object ResendMessageUtilities { fun resend(context: Context, messageRecord: MessageRecord, userBlindedKey: String?, isResync: Boolean = false) { - Log.d(TAG, "resend() called with: context = $context, messageRecord = $messageRecord, userBlindedKey = $userBlindedKey, isResync = $isResync") val recipient: Recipient = messageRecord.recipient val message = VisibleMessage() message.id = messageRecord.getId() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 77f616026c..33896803b8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -41,7 +41,6 @@ import org.session.libsignal.messages.SignalServiceAttachmentPointer import org.session.libsignal.messages.SignalServiceGroup import org.session.libsignal.utilities.IdPrefix import org.session.libsignal.utilities.KeyHelper -import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.guava.Optional import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper @@ -54,8 +53,6 @@ import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.util.SessionMetaProtocol import java.security.MessageDigest -private val TAG = Storage::class.java.simpleName - class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol { override fun getUserPublicKey(): String? { @@ -359,8 +356,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, openGroupSentTimestamp: Long, threadId: Long ) { - Log.d(TAG, "updateSentTimestamp() called with: messageID = $messageID, isMms = $isMms, openGroupSentTimestamp = $openGroupSentTimestamp, threadId = $threadId") - if (isMms) { val mmsDb = DatabaseComponent.get(context).mmsDatabase() mmsDb.updateSentTimestamp(messageID, openGroupSentTimestamp, threadId) @@ -371,8 +366,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } override fun markAsSent(timestamp: Long, author: String) { - Log.d(TAG, "markAsSent() called with: timestamp = $timestamp, author = $author") - val database = DatabaseComponent.get(context).mmsSmsDatabase() val messageRecord = database.getMessageFor(timestamp, author) ?: return if (messageRecord.isMms) { @@ -385,8 +378,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } override fun markAsSyncing(timestamp: Long, author: String) { - Log.d(TAG, "markAsSyncing() called with: timestamp = $timestamp, author = $author") - DatabaseComponent.get(context).mmsSmsDatabase() .getMessageFor(timestamp, author) ?.run { getMmsDatabaseElseSms(isMms).markAsSyncing(id) } @@ -397,16 +388,12 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, else DatabaseComponent.get(context).smsDatabase() override fun markAsResyncing(timestamp: Long, author: String) { - Log.d(TAG, "markAsResyncing() called with: timestamp = $timestamp, author = $author") - DatabaseComponent.get(context).mmsSmsDatabase() .getMessageFor(timestamp, author) ?.run { getMmsDatabaseElseSms(isMms).markAsResyncing(id) } } override fun markAsSending(timestamp: Long, author: String) { - Log.d(TAG, "markAsSending() called with: timestamp = $timestamp, author = $author") - val database = DatabaseComponent.get(context).mmsSmsDatabase() val messageRecord = database.getMessageFor(timestamp, author) ?: return if (messageRecord.isMms) { @@ -432,8 +419,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } override fun markAsSentFailed(timestamp: Long, author: String, error: Exception) { - Log.d(TAG, "markAsSentFailed() called with: timestamp = $timestamp, author = $author, error = $error") - val database = DatabaseComponent.get(context).mmsSmsDatabase() val messageRecord = database.getMessageFor(timestamp, author) ?: return if (messageRecord.isMms) { @@ -457,8 +442,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } override fun markAsSyncFailed(timestamp: Long, author: String, error: Exception) { - Log.d(TAG, "markAsSyncFailed() called with: timestamp = $timestamp, author = $author, error = $error") - val database = DatabaseComponent.get(context).mmsSmsDatabase() val messageRecord = database.getMessageFor(timestamp, author) ?: return diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt index 4300fe4b61..524338592c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt @@ -34,8 +34,6 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job { } override fun execute(dispatcherName: String) { - Log.d(TAG, "MessageSendJob#execute() called with: dispatcherName = $dispatcherName") - val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider val message = message as? VisibleMessage val storage = MessagingModuleConfiguration.shared.storage diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index 9da6cd8b14..fa0a49a647 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -39,8 +39,6 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview as SignalLinkPreview import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel as SignalQuote -private val TAG = MessageSender::class.java.simpleName - object MessageSender { // Error @@ -64,8 +62,6 @@ object MessageSender { // Convenience fun send(message: Message, destination: Destination, isSyncMessage: Boolean = false): Promise { - Log.d(TAG, "send() called with: message = $message, destination = $destination, isSyncMessage = $isSyncMessage") - return if (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup || destination is Destination.OpenGroupInbox) { sendToOpenGroupDestination(destination, message) } else { @@ -75,8 +71,6 @@ object MessageSender { // One-on-One Chats & Closed Groups private fun sendToSnodeDestination(destination: Destination, message: Message, isSyncMessage: Boolean = false): Promise { - Log.d(TAG, "sendToSnodeDestination() called with: destination = $destination, message = $message, isSyncMessage = $isSyncMessage") - val deferred = deferred() val promise = deferred.promise val storage = MessagingModuleConfiguration.shared.storage @@ -226,8 +220,6 @@ object MessageSender { // Open Groups private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise { - Log.d(TAG, "sendToOpenGroupDestination() called with: destination = $destination, message = $message") - val deferred = deferred() val storage = MessagingModuleConfiguration.shared.storage if (message.sentTimestamp == null) { @@ -326,8 +318,6 @@ object MessageSender { // Result Handling fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false, openGroupSentTimestamp: Long = -1) { - Log.d(TAG, "handleSuccessfulMessageSend() called with: message = $message, destination = $destination, isSyncMessage = $isSyncMessage, openGroupSentTimestamp = $openGroupSentTimestamp") - val storage = MessagingModuleConfiguration.shared.storage val userPublicKey = storage.getUserPublicKey()!! // Ignore future self-sends @@ -393,8 +383,6 @@ object MessageSender { } fun handleFailedMessageSend(message: Message, error: Exception, isSyncMessage: Boolean = false) { - Log.d(TAG, "handleFailedMessageSend() called with: message = $message, error = $error, isSyncMessage = $isSyncMessage") - val storage = MessagingModuleConfiguration.shared.storage val userPublicKey = storage.getUserPublicKey()!! @@ -408,8 +396,6 @@ object MessageSender { // Convenience @JvmStatic fun send(message: VisibleMessage, address: Address, attachments: List, quote: SignalQuote?, linkPreview: SignalLinkPreview?) { - Log.d(TAG, "send() called with: message = $message, address = $address, attachments = $attachments, quote = $quote, linkPreview = $linkPreview") - val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider val attachmentIDs = messageDataProvider.getAttachmentIDsFor(message.id!!) message.attachmentIDs.addAll(attachmentIDs) @@ -428,8 +414,6 @@ object MessageSender { @JvmStatic fun send(message: Message, address: Address) { - Log.d(TAG, "send() called with: message = $message, address = $address") - val threadID = MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(address) message.threadID = threadID val destination = Destination.from(address) From 2b48b52df0b819f39558d792fc05aee3261f4f2a Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 8 May 2023 11:18:33 +1000 Subject: [PATCH 25/83] remove unused jobs and wrap up old job refactoring --- .../securesms/ApplicationContext.java | 2 +- .../securesms/jobs/AvatarDownloadJob.java | 133 ---------------- .../securesms/jobs/JobManagerFactories.java | 10 +- .../jobs/PrepareAttachmentAudioExtrasJob.kt | 133 ---------------- .../jobs/RetrieveProfileAvatarJob.java | 144 ------------------ .../jobs/RetrieveProfileAvatarJob.kt | 99 ++++++++++++ 6 files changed, 104 insertions(+), 417 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/PrepareAttachmentAudioExtrasJob.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index a605a84922..b398d021c5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -355,7 +355,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO private void initializeJobManager() { this.jobManager = new JobManager(this, new JobManager.Configuration.Builder() .setDataSerializer(new JsonDataSerializer()) - .setJobFactories(JobManagerFactories.getJobFactories(this)) + .setJobFactories(JobManagerFactories.getJobFactories()) .setConstraintFactories(JobManagerFactories.getConstraintFactories(this)) .setConstraintObservers(JobManagerFactories.getConstraintObservers(this)) .setJobStorage(new FastJobStorage(jobDatabase)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java deleted file mode 100644 index 0bf7ea24e4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import android.graphics.Bitmap; - -import androidx.annotation.NonNull; - -import org.session.libsession.messaging.utilities.Data; -import org.session.libsession.utilities.DownloadUtilities; -import org.session.libsession.utilities.GroupRecord; -import org.session.libsignal.exceptions.InvalidMessageException; -import org.session.libsignal.exceptions.NonSuccessfulResponseCodeException; -import org.session.libsignal.messages.SignalServiceAttachmentPointer; -import org.session.libsignal.streams.AttachmentCipherInputStream; -import org.session.libsignal.utilities.Hex; -import org.session.libsignal.utilities.Log; -import org.session.libsignal.utilities.guava.Optional; -import org.thoughtcrime.securesms.database.GroupDatabase; -import org.thoughtcrime.securesms.dependencies.DatabaseComponent; -import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; -import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel; -import org.thoughtcrime.securesms.util.BitmapDecodingException; -import org.thoughtcrime.securesms.util.BitmapUtil; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - -public class AvatarDownloadJob extends BaseJob { - - public static final String KEY = "AvatarDownloadJob"; - - private static final String TAG = AvatarDownloadJob.class.getSimpleName(); - - private static final int MAX_AVATAR_SIZE = 20 * 1024 * 1024; - - private static final String KEY_GROUP_ID = "group_id"; - - private String groupId; - - public AvatarDownloadJob(@NonNull String groupId) { - this(new Job.Parameters.Builder() - .addConstraint(NetworkConstraint.KEY) - .setMaxAttempts(10) - .build(), - groupId); - } - - private AvatarDownloadJob(@NonNull Job.Parameters parameters, @NonNull String groupId) { - super(parameters); - this.groupId = groupId; - } - - @Override - public @NonNull Data serialize() { - return new Data.Builder().putString(KEY_GROUP_ID, groupId).build(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onRun() throws IOException { - GroupDatabase database = DatabaseComponent.get(context).groupDatabase(); - Optional record = database.getGroup(groupId); - File attachment = null; - - try { - if (record.isPresent()) { - long avatarId = record.get().getAvatarId(); - String contentType = record.get().getAvatarContentType(); - byte[] key = record.get().getAvatarKey(); - String relay = record.get().getRelay(); - Optional digest = Optional.fromNullable(record.get().getAvatarDigest()); - Optional fileName = Optional.absent(); - String url = record.get().getUrl(); - - if (avatarId == -1 || key == null || url.isEmpty()) { - return; - } - - if (digest.isPresent()) { - Log.i(TAG, "Downloading group avatar with digest: " + Hex.toString(digest.get())); - } - - attachment = File.createTempFile("avatar", "tmp", context.getCacheDir()); - attachment.deleteOnExit(); - - SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), url); - - if (pointer.getUrl().isEmpty()) throw new InvalidMessageException("Missing attachment URL."); - DownloadUtilities.downloadFile(attachment, pointer.getUrl()); - - // Assume we're retrieving an attachment for an open group server if the digest is not set - InputStream inputStream; - if (!pointer.getDigest().isPresent()) { - inputStream = new FileInputStream(attachment); - } else { - inputStream = AttachmentCipherInputStream.createForAttachment(attachment, pointer.getSize().or(0), pointer.getKey(), pointer.getDigest().get()); - } - - Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500); - - database.updateProfilePicture(groupId, avatar); - inputStream.close(); - } - } catch (BitmapDecodingException | NonSuccessfulResponseCodeException | InvalidMessageException e) { - Log.w(TAG, e); - } finally { - if (attachment != null) - attachment.delete(); - } - } - - @Override - public void onCanceled() {} - - @Override - public boolean onShouldRetry(@NonNull Exception exception) { - if (exception instanceof IOException) return true; - return false; - } - - public static final class Factory implements Job.Factory { - @Override - public @NonNull AvatarDownloadJob create(@NonNull Parameters parameters, @NonNull Data data) { - return new AvatarDownloadJob(parameters, data.getString(KEY_GROUP_ID)); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index 468bf58369..910a9c09be 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -4,9 +4,9 @@ import android.app.Application; import androidx.annotation.NonNull; +import org.session.libsession.messaging.jobs.Job; import org.thoughtcrime.securesms.jobmanager.Constraint; import org.thoughtcrime.securesms.jobmanager.ConstraintObserver; -import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraint; import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraintObserver; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; @@ -28,11 +28,9 @@ public final class JobManagerFactories { public static Map getJobFactories(@NonNull Application application) { HashMap factoryHashMap = new HashMap() {{ - put(AvatarDownloadJob.KEY, new AvatarDownloadJob.Factory()); - put(LocalBackupJob.Companion.getKEY(), new LocalBackupJob.Factory()); - put(RetrieveProfileAvatarJob.KEY, new RetrieveProfileAvatarJob.Factory(application)); - put(UpdateApkJob.Companion.getKEY(), new UpdateApkJob.Factory()); - put(PrepareAttachmentAudioExtrasJob.KEY, new PrepareAttachmentAudioExtrasJob.Factory()); + put(LocalBackupJob.Companion.getKEY(), new LocalBackupJob.Factory()); + put(RetrieveProfileAvatarJob.Companion.getKEY(), new RetrieveProfileAvatarJob.Factory()); + put(UpdateApkJob.Companion.getKEY(), new UpdateApkJob.Factory()); }}; factoryKeys.addAll(factoryHashMap.keySet()); return factoryHashMap; diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PrepareAttachmentAudioExtrasJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/PrepareAttachmentAudioExtrasJob.kt deleted file mode 100644 index 69794d41bd..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PrepareAttachmentAudioExtrasJob.kt +++ /dev/null @@ -1,133 +0,0 @@ -package org.thoughtcrime.securesms.jobs - -import android.os.Build -import org.greenrobot.eventbus.EventBus -import org.session.libsession.messaging.sending_receiving.attachments.Attachment -import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId -import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachmentAudioExtras -import org.session.libsession.messaging.utilities.Data -import org.session.libsession.utilities.DecodedAudio -import org.session.libsession.utilities.InputStreamMediaDataSource -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import org.thoughtcrime.securesms.jobmanager.Job -import org.thoughtcrime.securesms.jobs.PrepareAttachmentAudioExtrasJob.AudioExtrasUpdatedEvent -import org.thoughtcrime.securesms.mms.PartAuthority -import java.util.* -import java.util.concurrent.TimeUnit - -/** - * Decodes the audio content of the related attachment entry - * and caches the result with [DatabaseAttachmentAudioExtras] data. - * - * It only process attachments with "audio" mime types. - * - * Due to [DecodedAudio] implementation limitations, it only works for API 23+. - * For any lower targets fake data will be generated. - * - * You can subscribe to [AudioExtrasUpdatedEvent] to be notified about the successful result. - */ -//TODO AC: Rewrite to WorkManager API when -// https://github.com/loki-project/session-android/pull/354 is merged. -class PrepareAttachmentAudioExtrasJob : BaseJob { - - companion object { - private const val TAG = "AttachAudioExtrasJob" - - const val KEY = "PrepareAttachmentAudioExtrasJob" - const val DATA_ATTACH_ID = "attachment_id" - - const val VISUAL_RMS_FRAMES = 32 // The amount of values to be computed for the visualization. - } - - private val attachmentId: AttachmentId - - constructor(attachmentId: AttachmentId) : this(Parameters.Builder() - .setQueue(KEY) - .setLifespan(TimeUnit.DAYS.toMillis(1)) - .build(), - attachmentId) - - private constructor(parameters: Parameters, attachmentId: AttachmentId) : super(parameters) { - this.attachmentId = attachmentId - } - - override fun serialize(): Data { - return Data.Builder().putParcelable(DATA_ATTACH_ID, attachmentId).build(); - } - - override fun getFactoryKey(): String { return KEY - } - - override fun onShouldRetry(e: Exception): Boolean { - return false - } - - override fun onCanceled() { } - - override fun onRun() { - Log.v(TAG, "Processing attachment: $attachmentId") - - val attachDb = DatabaseComponent.get(context).attachmentDatabase() - val attachment = attachDb.getAttachment(attachmentId) - - if (attachment == null) { - throw IllegalStateException("Cannot find attachment with the ID $attachmentId") - } - if (!attachment.contentType.startsWith("audio/")) { - throw IllegalStateException("Attachment $attachmentId is not of audio type.") - } - - // Check if the audio extras already exist. - if (attachDb.getAttachmentAudioExtras(attachmentId) != null) return - - fun extractAttachmentRandomSeed(attachment: Attachment): Int { - return when { - attachment.digest != null -> attachment.digest!!.sum() - attachment.fileName != null -> attachment.fileName.hashCode() - else -> attachment.hashCode() - } - } - - fun generateFakeRms(seed: Int, frames: Int = VISUAL_RMS_FRAMES): ByteArray { - return ByteArray(frames).apply { Random(seed.toLong()).nextBytes(this) } - } - - var rmsValues: ByteArray - var totalDurationMs: Long = DatabaseAttachmentAudioExtras.DURATION_UNDEFINED - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - // Due to API version incompatibility, we just display some random waveform for older API. - rmsValues = generateFakeRms(extractAttachmentRandomSeed(attachment)) - } else { - try { - @Suppress("BlockingMethodInNonBlockingContext") - val decodedAudio = PartAuthority.getAttachmentStream(context, attachment.dataUri!!).use { - DecodedAudio.create(InputStreamMediaDataSource(it)) - } - rmsValues = decodedAudio.calculateRms(VISUAL_RMS_FRAMES) - totalDurationMs = (decodedAudio.totalDuration / 1000.0).toLong() - } catch (e: Exception) { - Log.w(TAG, "Failed to decode sample values for the audio attachment \"${attachment.fileName}\".", e) - rmsValues = generateFakeRms(extractAttachmentRandomSeed(attachment)) - } - } - - attachDb.setAttachmentAudioExtras(DatabaseAttachmentAudioExtras( - attachmentId, - rmsValues, - totalDurationMs - )) - - EventBus.getDefault().post(AudioExtrasUpdatedEvent(attachmentId)) - } - - class Factory : Job.Factory { - override fun create(parameters: Parameters, data: Data): PrepareAttachmentAudioExtrasJob { - return PrepareAttachmentAudioExtrasJob(parameters, data.getParcelable(DATA_ATTACH_ID, AttachmentId.CREATOR)) - } - } - - /** Gets dispatched once the audio extras have been updated. */ - data class AudioExtrasUpdatedEvent(val attachmentId: AttachmentId) -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java deleted file mode 100644 index 39b7753035..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import android.app.Application; -import android.text.TextUtils; - -import androidx.annotation.NonNull; - -import org.session.libsession.avatars.AvatarHelper; -import org.session.libsession.messaging.utilities.Data; -import org.session.libsession.utilities.Address; -import org.session.libsession.utilities.DownloadUtilities; -import org.session.libsession.utilities.TextSecurePreferences; -import org.session.libsession.utilities.Util; -import org.session.libsession.utilities.recipients.Recipient; -import org.session.libsignal.exceptions.PushNetworkException; -import org.session.libsignal.streams.ProfileCipherInputStream; -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.database.RecipientDatabase; -import org.thoughtcrime.securesms.dependencies.DatabaseComponent; -import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.SecureRandom; -import java.util.concurrent.TimeUnit; - -public class RetrieveProfileAvatarJob extends BaseJob { - - public static final String KEY = "RetrieveProfileAvatarJob"; - - private static final String TAG = RetrieveProfileAvatarJob.class.getSimpleName(); - - private static final int MAX_PROFILE_SIZE_BYTES = 10 * 1024 * 1024; - - private static final String KEY_PROFILE_AVATAR = "profile_avatar"; - private static final String KEY_ADDRESS = "address"; - - - private String profileAvatar; - private Recipient recipient; - - public RetrieveProfileAvatarJob(Recipient recipient, String profileAvatar) { - this(new Job.Parameters.Builder() - .setQueue("RetrieveProfileAvatarJob" + recipient.getAddress().serialize()) - .addConstraint(NetworkConstraint.KEY) - .setLifespan(TimeUnit.HOURS.toMillis(1)) - .setMaxAttempts(2) - .setMaxInstances(1) - .build(), - recipient, - profileAvatar); - } - - private RetrieveProfileAvatarJob(@NonNull Job.Parameters parameters, @NonNull Recipient recipient, String profileAvatar) { - super(parameters); - this.recipient = recipient; - this.profileAvatar = profileAvatar; - } - - @Override - public @NonNull - Data serialize() { - return new Data.Builder() - .putString(KEY_PROFILE_AVATAR, profileAvatar) - .putString(KEY_ADDRESS, recipient.getAddress().serialize()) - .build(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onRun() throws IOException { - RecipientDatabase database = DatabaseComponent.get(context).recipientDatabase(); - byte[] profileKey = recipient.resolve().getProfileKey(); - - if (profileKey == null || (profileKey.length != 32 && profileKey.length != 16)) { - Log.w(TAG, "Recipient profile key is gone!"); - return; - } - - if (AvatarHelper.avatarFileExists(context, recipient.resolve().getAddress()) && Util.equals(profileAvatar, recipient.resolve().getProfileAvatar())) { - Log.w(TAG, "Already retrieved profile avatar: " + profileAvatar); - return; - } - - if (TextUtils.isEmpty(profileAvatar)) { - Log.w(TAG, "Removing profile avatar for: " + recipient.getAddress().serialize()); - AvatarHelper.delete(context, recipient.getAddress()); - database.setProfileAvatar(recipient, profileAvatar); - return; - } - - File downloadDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir()); - - try { - DownloadUtilities.downloadFile(downloadDestination, profileAvatar); - InputStream avatarStream = new ProfileCipherInputStream(new FileInputStream(downloadDestination), profileKey); - File decryptDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir()); - - Util.copy(avatarStream, new FileOutputStream(decryptDestination)); - decryptDestination.renameTo(AvatarHelper.getAvatarFile(context, recipient.getAddress())); - } finally { - if (downloadDestination != null) downloadDestination.delete(); - } - - if (recipient.isLocalNumber()) { - TextSecurePreferences.setProfileAvatarId(context, new SecureRandom().nextInt()); - } - database.setProfileAvatar(recipient, profileAvatar); - } - - @Override - public boolean onShouldRetry(@NonNull Exception e) { - if (e instanceof PushNetworkException) return true; - return false; - } - - @Override - public void onCanceled() { - } - - public static final class Factory implements Job.Factory { - - private final Application application; - - public Factory(Application application) { - this.application = application; - } - - @Override - public @NonNull RetrieveProfileAvatarJob create(@NonNull Parameters parameters, @NonNull Data data) { - return new RetrieveProfileAvatarJob(parameters, - Recipient.from(application, Address.fromSerialized(data.getString(KEY_ADDRESS)), true), - data.getString(KEY_PROFILE_AVATAR)); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.kt new file mode 100644 index 0000000000..a5b0fce2df --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.kt @@ -0,0 +1,99 @@ +package org.thoughtcrime.securesms.jobs + +import android.content.Context +import android.text.TextUtils +import org.session.libsession.avatars.AvatarHelper +import org.session.libsession.messaging.jobs.Job +import org.session.libsession.messaging.jobs.JobDelegate +import org.session.libsession.messaging.utilities.Data +import org.session.libsession.utilities.DownloadUtilities.downloadFile +import org.session.libsession.utilities.TextSecurePreferences.Companion.setProfileAvatarId +import org.session.libsession.utilities.Util.copy +import org.session.libsession.utilities.Util.equals +import org.session.libsession.utilities.Address +import org.session.libsession.utilities.recipients.Recipient +import org.session.libsignal.streams.ProfileCipherInputStream +import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.io.InputStream +import java.security.SecureRandom + +class RetrieveProfileAvatarJob(val profileAvatar: String, val recipientAddress: Address): Job { + override var delegate: JobDelegate? = null + override var id: String? = null + override var failureCount: Int = 0 + override val maxFailureCount: Int = 0 + + lateinit var context: Context + + companion object { + val TAG = RetrieveProfileAvatarJob::class.simpleName + val KEY: String = "RetrieveProfileAvatarJob" + + // Keys used for database storage + private val PROFILE_AVATAR_KEY = "profileAvatar" + private val RECEIPIENT_ADDRESS_KEY = "recipient" + } + + override fun execute(dispatcherName: String) { + val recipient = Recipient.from(context, recipientAddress, true) + val database = get(context).recipientDatabase() + val profileKey = recipient.resolve().profileKey + + if (profileKey == null || (profileKey.size != 32 && profileKey.size != 16)) { + Log.w(TAG, "Recipient profile key is gone!") + return + } + + if (AvatarHelper.avatarFileExists(context, recipient.resolve().address) && equals(profileAvatar, recipient.resolve().profileAvatar)) { + Log.w(TAG, "Already retrieved profile avatar: $profileAvatar") + return + } + + if (TextUtils.isEmpty(profileAvatar)) { + Log.w(TAG, "Removing profile avatar for: " + recipient.address.serialize()) + AvatarHelper.delete(context, recipient.address) + database.setProfileAvatar(recipient, profileAvatar) + return + } + + val downloadDestination = File.createTempFile("avatar", ".jpg", context.cacheDir) + + try { + downloadFile(downloadDestination, profileAvatar) + val avatarStream: InputStream = ProfileCipherInputStream(FileInputStream(downloadDestination), profileKey) + val decryptDestination = File.createTempFile("avatar", ".jpg", context.cacheDir) + copy(avatarStream, FileOutputStream(decryptDestination)) + decryptDestination.renameTo(AvatarHelper.getAvatarFile(context, recipient.address)) + } finally { + downloadDestination.delete() + } + + if (recipient.isLocalNumber) { + setProfileAvatarId(context, SecureRandom().nextInt()) + } + database.setProfileAvatar(recipient, profileAvatar) + } + + override fun serialize(): Data { + return Data.Builder() + .putString(PROFILE_AVATAR_KEY, profileAvatar) + .putString(RECEIPIENT_ADDRESS_KEY, recipientAddress.serialize()) + .build() + } + + override fun getFactoryKey(): String { + return KEY + } + + class Factory: Job.Factory { + override fun create(data: Data): RetrieveProfileAvatarJob { + val profileAvatar = data.getString(PROFILE_AVATAR_KEY) + val recipientAddress = Address.fromSerialized(data.getString(RECEIPIENT_ADDRESS_KEY)) + return RetrieveProfileAvatarJob(profileAvatar, recipientAddress) + } + } +} \ No newline at end of file From 2ceb9e2bf448bf37e7f855de43be87637b4d6607 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 8 May 2023 12:29:21 +1000 Subject: [PATCH 26/83] clean up old job manager --- app/src/main/AndroidManifest.xml | 8 - .../securesms/ApplicationContext.java | 6 - .../securesms/database/Storage.kt | 3 +- .../jobmanager/AlarmManagerScheduler.java | 69 ---- .../jobmanager/CompositeScheduler.java | 22 -- .../jobmanager/ConstraintInstantiator.java | 23 -- .../jobmanager/DependencyInjector.java | 24 -- .../securesms/jobmanager/InAppScheduler.java | 49 --- .../securesms/jobmanager/Job.java | 286 -------------- .../securesms/jobmanager/JobController.java | 354 ------------------ .../securesms/jobmanager/JobInstantiator.java | 5 +- .../securesms/jobmanager/JobLogger.java | 24 -- .../securesms/jobmanager/JobManager.java | 167 +-------- .../securesms/jobmanager/JobRunner.java | 110 ------ .../jobmanager/JobSchedulerScheduler.java | 90 ----- .../securesms/jobmanager/Scheduler.java | 9 - .../thoughtcrime/securesms/jobs/BaseJob.java | 41 -- .../securesms/jobs/FastJobStorage.java | 261 ------------- .../securesms/jobs/JobManagerFactories.java | 2 +- .../service/LocalBackupListener.java | 5 +- .../service/UpdateApkRefreshListener.java | 6 +- .../sskenvironment/ProfileManager.kt | 6 +- .../securesms/jobs/FastJobStorageTest.java | 350 ----------------- 23 files changed, 20 insertions(+), 1900 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/CompositeScheduler.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintInstantiator.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/DependencyInjector.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/InAppScheduler.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/Job.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobController.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobLogger.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobRunner.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobSchedulerScheduler.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/Scheduler.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/BaseJob.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/FastJobStorage.java delete mode 100644 app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6755addc03..da3be785c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -446,17 +446,9 @@ - - diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index b398d021c5..0d5e57352e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -66,9 +66,7 @@ import org.thoughtcrime.securesms.emoji.EmojiSource; import org.thoughtcrime.securesms.groups.OpenGroupManager; import org.thoughtcrime.securesms.home.HomeActivity; import org.thoughtcrime.securesms.jobmanager.JobManager; -import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; -import org.thoughtcrime.securesms.jobs.FastJobStorage; import org.thoughtcrime.securesms.jobs.JobManagerFactories; import org.thoughtcrime.securesms.logging.AndroidLogger; import org.thoughtcrime.securesms.logging.PersistentLogger; @@ -354,11 +352,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO private void initializeJobManager() { this.jobManager = new JobManager(this, new JobManager.Configuration.Builder() - .setDataSerializer(new JsonDataSerializer()) - .setJobFactories(JobManagerFactories.getJobFactories()) - .setConstraintFactories(JobManagerFactories.getConstraintFactories(this)) .setConstraintObservers(JobManagerFactories.getConstraintObservers(this)) - .setJobStorage(new FastJobStorage(jobDatabase)) .build()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 0d7ea3352f..891df6be87 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -75,8 +75,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, Recipient.from(context, it, false) } TextSecurePreferences.setProfilePictureURL(context, newValue) - RetrieveProfileAvatarJob(ourRecipient, newValue) - ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(ourRecipient, newValue)) + JobQueue.shared.add(RetrieveProfileAvatarJob(newValue, ourRecipient.address)) } override fun getOrGenerateRegistrationID(): Int { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler.java deleted file mode 100644 index dc1d2afcf1..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import android.app.AlarmManager; -import android.app.Application; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -import androidx.annotation.NonNull; - -import com.annimon.stream.Stream; - -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.ApplicationContext; - -import java.util.List; -import java.util.UUID; - -import network.loki.messenger.BuildConfig; - -/** - * Schedules tasks using the {@link AlarmManager}. - * - * Given that this scheduler is only used when {@link KeepAliveService} is also used (which keeps - * all of the {@link ConstraintObserver}s running), this only needs to schedule future runs in - * situations where all constraints are already met. Otherwise, the {@link ConstraintObserver}s will - * trigger future runs when the constraints are met. - * - * For the same reason, this class also doesn't have to schedule jobs that don't have delays. - * - * Important: Only use on API < 26. - */ -public class AlarmManagerScheduler implements Scheduler { - - private static final String TAG = AlarmManagerScheduler.class.getSimpleName(); - - private final Application application; - - AlarmManagerScheduler(@NonNull Application application) { - this.application = application; - } - - @Override - public void schedule(long delay, @NonNull List constraints) { - if (delay > 0 && Stream.of(constraints).allMatch(Constraint::isMet)) { - setUniqueAlarm(application, System.currentTimeMillis() + delay); - } - } - - private void setUniqueAlarm(@NonNull Context context, long time) { - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - Intent intent = new Intent(context, RetryReceiver.class); - - intent.setAction(BuildConfig.APPLICATION_ID + UUID.randomUUID().toString()); - alarmManager.set(AlarmManager.RTC_WAKEUP, time, PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)); - - Log.i(TAG, "Set an alarm to retry a job in " + (time - System.currentTimeMillis()) + " ms."); - } - - public static class RetryReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "Received an alarm to retry a job."); - ApplicationContext.getInstance(context).getJobManager().wakeUp(); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/CompositeScheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/CompositeScheduler.java deleted file mode 100644 index 322366f4f4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/CompositeScheduler.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import androidx.annotation.NonNull; - -import java.util.Arrays; -import java.util.List; - -class CompositeScheduler implements Scheduler { - - private final List schedulers; - - CompositeScheduler(@NonNull Scheduler... schedulers) { - this.schedulers = Arrays.asList(schedulers); - } - - @Override - public void schedule(long delay, @NonNull List constraints) { - for (Scheduler scheduler : schedulers) { - scheduler.schedule(delay, constraints); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintInstantiator.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintInstantiator.java deleted file mode 100644 index b0a67e3d19..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintInstantiator.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import androidx.annotation.NonNull; - -import java.util.HashMap; -import java.util.Map; - -public class ConstraintInstantiator { - - private final Map constraintFactories; - - ConstraintInstantiator(@NonNull Map constraintFactories) { - this.constraintFactories = new HashMap<>(constraintFactories); - } - - public @NonNull Constraint instantiate(@NonNull String constraintFactoryKey) { - if (constraintFactories.containsKey(constraintFactoryKey)) { - return constraintFactories.get(constraintFactoryKey).create(); - } else { - throw new IllegalStateException("Tried to instantiate a constraint with key '" + constraintFactoryKey + "', but no matching factory was found."); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/DependencyInjector.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/DependencyInjector.java deleted file mode 100644 index c8a266bd87..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/DependencyInjector.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.jobmanager; - -/** - * Interface responsible for injecting dependencies into Jobs. - */ -public interface DependencyInjector { - void injectDependencies(Object object); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/InAppScheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/InAppScheduler.java deleted file mode 100644 index b0f314eaa6..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/InAppScheduler.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import android.os.Handler; -import android.os.HandlerThread; -import androidx.annotation.NonNull; - -import com.annimon.stream.Stream; - -import org.session.libsignal.utilities.Log; - -import java.util.List; - -/** - * Schedules future runs on an in-app handler. Intended to be used in combination with a persistent - * {@link Scheduler} to improve responsiveness when the app is open. - * - * This should only schedule runs when all constraints are met. Because this only works when the - * app is foregrounded, jobs that don't have their constraints met will be run when the relevant - * {@link ConstraintObserver} is triggered. - * - * Similarly, this does not need to schedule retries with no delay, as this doesn't provide any - * persistence, and other mechanisms will take care of that. - */ -class InAppScheduler implements Scheduler { - - private static final String TAG = InAppScheduler.class.getSimpleName(); - - private final JobManager jobManager; - private final Handler handler; - - InAppScheduler(@NonNull JobManager jobManager) { - HandlerThread handlerThread = new HandlerThread("InAppScheduler"); - handlerThread.start(); - - this.jobManager = jobManager; - this.handler = new Handler(handlerThread.getLooper()); - } - - @Override - public void schedule(long delay, @NonNull List constraints) { - if (delay > 0 && Stream.of(constraints).allMatch(Constraint::isMet)) { - Log.i(TAG, "Scheduling a retry in " + delay + " ms."); - handler.postDelayed(() -> { - Log.i(TAG, "Triggering a job retry."); - jobManager.wakeUp(); - }, delay); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Job.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Job.java deleted file mode 100644 index 990207779d..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Job.java +++ /dev/null @@ -1,286 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.WorkerThread; - -import org.session.libsession.messaging.utilities.Data; -import org.session.libsignal.utilities.Log; - -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * A durable unit of work. - * - * Jobs have {@link Parameters} that describe the conditions upon when you'd like them to run, how - * often they should be retried, and how long they should be retried for. - * - * Never rely on a specific instance of this class being run. It can be created and destroyed as the - * job is retried. State that you want to save is persisted to a {@link Data} object in - * {@link #serialize()}. Your job is then recreated using a {@link Factory} that you register in - * {@link JobManager.Configuration.Builder#setJobFactories(Map)}, which is given the saved - * {@link Data} bundle. - * - * @deprecated - * use WorkManager - * API instead. - */ -public abstract class Job { - - private static final String TAG = Log.tag(Job.class); - - private final Parameters parameters; - - private String id; - private int runAttempt; - private long nextRunAttemptTime; - - protected Context context; - - public Job(@NonNull Parameters parameters) { - this.parameters = parameters; - } - - public final String getId() { - return id; - } - - public final @NonNull Parameters getParameters() { - return parameters; - } - - public final int getRunAttempt() { - return runAttempt; - } - - public final long getNextRunAttemptTime() { - return nextRunAttemptTime; - } - - /** - * This is already called by {@link JobController} during job submission, but if you ever run a - * job without submitting it to the {@link JobManager}, then you'll need to invoke this yourself. - */ - public final void setContext(@NonNull Context context) { - this.context = context; - } - - /** Should only be invoked by {@link JobController} */ - final void setId(@NonNull String id) { - this.id = id; - } - - /** Should only be invoked by {@link JobController} */ - final void setRunAttempt(int runAttempt) { - this.runAttempt = runAttempt; - } - - /** Should only be invoked by {@link JobController} */ - final void setNextRunAttemptTime(long nextRunAttemptTime) { - this.nextRunAttemptTime = nextRunAttemptTime; - } - - @WorkerThread - final void onSubmit() { - Log.i(TAG, JobLogger.format(this, "onSubmit()")); - onAdded(); - } - - /** - * Called when the job is first submitted to the {@link JobManager}. - */ - @WorkerThread - public void onAdded() { - } - - /** - * Called after a job has run and its determined that a retry is required. - */ - @WorkerThread - public void onRetry() { - } - - /** - * Serialize your job state so that it can be recreated in the future. - */ - public abstract @NonNull Data serialize(); - - /** - * Returns the key that can be used to find the relevant factory needed to create your job. - */ - public abstract @NonNull String getFactoryKey(); - - /** - * Called to do your actual work. - */ - @WorkerThread - public abstract @NonNull Result run(); - - /** - * Called when your job has completely failed. - */ - @WorkerThread - public abstract void onCanceled(); - - public interface Factory { - @NonNull T create(@NonNull Parameters parameters, @NonNull Data data); - } - - public enum Result { - SUCCESS, FAILURE, RETRY - } - - public static final class Parameters { - - public static final int IMMORTAL = -1; - public static final int UNLIMITED = -1; - - private final long createTime; - private final long lifespan; - private final int maxAttempts; - private final long maxBackoff; - private final int maxInstances; - private final String queue; - private final List constraintKeys; - - private Parameters(long createTime, - long lifespan, - int maxAttempts, - long maxBackoff, - int maxInstances, - @Nullable String queue, - @NonNull List constraintKeys) - { - this.createTime = createTime; - this.lifespan = lifespan; - this.maxAttempts = maxAttempts; - this.maxBackoff = maxBackoff; - this.maxInstances = maxInstances; - this.queue = queue; - this.constraintKeys = constraintKeys; - } - - public long getCreateTime() { - return createTime; - } - - public long getLifespan() { - return lifespan; - } - - public int getMaxAttempts() { - return maxAttempts; - } - - public long getMaxBackoff() { - return maxBackoff; - } - - public int getMaxInstances() { - return maxInstances; - } - - public @Nullable String getQueue() { - return queue; - } - - public List getConstraintKeys() { - return constraintKeys; - } - - - public static final class Builder { - - private long createTime = System.currentTimeMillis(); - private long maxBackoff = TimeUnit.SECONDS.toMillis(30); - private long lifespan = IMMORTAL; - private int maxAttempts = 1; - private int maxInstances = UNLIMITED; - private String queue = null; - private List constraintKeys = new LinkedList<>(); - - /** Should only be invoked by {@link JobController} */ - Builder setCreateTime(long createTime) { - this.createTime = createTime; - return this; - } - - /** - * Specify the amount of time this job is allowed to be retried. Defaults to {@link #IMMORTAL}. - */ - public @NonNull Builder setLifespan(long lifespan) { - this.lifespan = lifespan; - return this; - } - - /** - * Specify the maximum number of times you want to attempt this job. Defaults to 1. - */ - public @NonNull Builder setMaxAttempts(int maxAttempts) { - this.maxAttempts = maxAttempts; - return this; - } - - /** - * Specify the longest amount of time to wait between retries. No guarantees that this will - * be respected on API >= 26. - */ - public @NonNull Builder setMaxBackoff(long maxBackoff) { - this.maxBackoff = maxBackoff; - return this; - } - - /** - * Specify the maximum number of instances you'd want of this job at any given time. If - * enqueueing this job would put it over that limit, it will be ignored. - * - * Duplicates are determined by two jobs having the same {@link Job#getFactoryKey()}. - * - * This property is ignored if the job is submitted as part of a {@link JobManager.Chain}. - * - * Defaults to {@link #UNLIMITED}. - */ - public @NonNull Builder setMaxInstances(int maxInstances) { - this.maxInstances = maxInstances; - return this; - } - - /** - * Specify a string representing a queue. All jobs within the same queue are run in a - * serialized fashion -- one after the other, in order of insertion. Failure of a job earlier - * in the queue has no impact on the execution of jobs later in the queue. - */ - public @NonNull Builder setQueue(@Nullable String queue) { - this.queue = queue; - return this; - } - - /** - * Add a constraint via the key that was used to register its factory in - * {@link JobManager.Configuration)}; - */ - public @NonNull Builder addConstraint(@NonNull String constraintKey) { - constraintKeys.add(constraintKey); - return this; - } - - /** - * Set constraints via the key that was used to register its factory in - * {@link JobManager.Configuration)}; - */ - public @NonNull Builder setConstraints(@NonNull List constraintKeys) { - this.constraintKeys.clear(); - this.constraintKeys.addAll(constraintKeys); - return this; - } - - public @NonNull Parameters build() { - return new Parameters(createTime, lifespan, maxAttempts, maxBackoff, maxInstances, queue, constraintKeys); - } - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobController.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobController.java deleted file mode 100644 index 33345a03e1..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobController.java +++ /dev/null @@ -1,354 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import android.app.Application; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.WorkerThread; - -import com.annimon.stream.Stream; - -import org.session.libsession.messaging.utilities.Data; -import org.session.libsession.utilities.Debouncer; -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec; -import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -/** - * Manages the queue of jobs. This is the only class that should write to {@link JobStorage} to - * ensure consistency. - */ -class JobController { - - private static final String TAG = JobController.class.getSimpleName(); - - private final Application application; - private final JobStorage jobStorage; - private final JobInstantiator jobInstantiator; - private final ConstraintInstantiator constraintInstantiator; - private final Data.Serializer dataSerializer; - private final Scheduler scheduler; - private final Debouncer debouncer; - private final Callback callback; - private final Set runningJobs; - - JobController(@NonNull Application application, - @NonNull JobStorage jobStorage, - @NonNull JobInstantiator jobInstantiator, - @NonNull ConstraintInstantiator constraintInstantiator, - @NonNull Data.Serializer dataSerializer, - @NonNull Scheduler scheduler, - @NonNull Debouncer debouncer, - @NonNull Callback callback) - { - this.application = application; - this.jobStorage = jobStorage; - this.jobInstantiator = jobInstantiator; - this.constraintInstantiator = constraintInstantiator; - this.dataSerializer = dataSerializer; - this.scheduler = scheduler; - this.debouncer = debouncer; - this.callback = callback; - this.runningJobs = new HashSet<>(); - } - - @WorkerThread - synchronized void init() { - jobStorage.init(); - jobStorage.updateAllJobsToBePending(); - notifyAll(); - } - - synchronized void wakeUp() { - notifyAll(); - } - - @WorkerThread - synchronized void submitNewJobChain(@NonNull List> chain) { - chain = Stream.of(chain).filterNot(List::isEmpty).toList(); - - if (chain.isEmpty()) { - Log.w(TAG, "Tried to submit an empty job chain. Skipping."); - return; - } - - if (chainExceedsMaximumInstances(chain)) { - Job solo = chain.get(0).get(0); - Log.w(TAG, JobLogger.format(solo, "Already at the max instance count of " + solo.getParameters().getMaxInstances() + ". Skipping.")); - return; - } - - insertJobChain(chain); - scheduleJobs(chain.get(0)); - triggerOnSubmit(chain); - notifyAll(); - } - - @WorkerThread - synchronized void onRetry(@NonNull Job job) { - int nextRunAttempt = job.getRunAttempt() + 1; - long nextRunAttemptTime = calculateNextRunAttemptTime(System.currentTimeMillis(), nextRunAttempt, job.getParameters().getMaxBackoff()); - - jobStorage.updateJobAfterRetry(job.getId(), false, nextRunAttempt, nextRunAttemptTime); - - List constraints = Stream.of(jobStorage.getConstraintSpecs(job.getId())) - .map(ConstraintSpec::getFactoryKey) - .map(constraintInstantiator::instantiate) - .toList(); - - - long delay = Math.max(0, nextRunAttemptTime - System.currentTimeMillis()); - - Log.i(TAG, JobLogger.format(job, "Scheduling a retry in " + delay + " ms.")); - scheduler.schedule(delay, constraints); - - notifyAll(); - } - - synchronized void onJobFinished(@NonNull Job job) { - runningJobs.remove(job.getId()); - } - - @WorkerThread - synchronized void onSuccess(@NonNull Job job) { - jobStorage.deleteJob(job.getId()); - notifyAll(); - } - - /** - * @return The list of all dependent jobs that should also be failed. - */ - @WorkerThread - synchronized @NonNull List onFailure(@NonNull Job job) { - List dependents = Stream.of(jobStorage.getDependencySpecsThatDependOnJob(job.getId())) - .map(DependencySpec::getJobId) - .map(jobStorage::getJobSpec) - .withoutNulls() - .map(jobSpec -> { - List constraintSpecs = jobStorage.getConstraintSpecs(jobSpec.getId()); - return createJob(jobSpec, constraintSpecs); - }) - .toList(); - - List all = new ArrayList<>(dependents.size() + 1); - all.add(job); - all.addAll(dependents); - - jobStorage.deleteJobs(Stream.of(all).map(Job::getId).toList()); - - return dependents; - } - - /** - * Retrieves the next job that is eligible for execution. To be 'eligible' means that the job: - * - Has no dependencies - * - Has no unmet constraints - * - * This method will block until a job is available. - * When the job returned from this method has been run, you must call {@link #onJobFinished(Job)}. - */ - @WorkerThread - synchronized @NonNull Job pullNextEligibleJobForExecution() { - try { - Job job; - - while ((job = getNextEligibleJobForExecution()) == null) { - if (runningJobs.isEmpty()) { - debouncer.publish(callback::onEmpty); - } - - wait(); - } - - jobStorage.updateJobRunningState(job.getId(), true); - runningJobs.add(job.getId()); - - return job; - } catch (InterruptedException e) { - Log.e(TAG, "Interrupted."); - throw new AssertionError(e); - } - } - - /** - * Retrieves a string representing the state of the job queue. Intended for debugging. - */ - @WorkerThread - synchronized @NonNull String getDebugInfo() { - List jobs = jobStorage.getAllJobSpecs(); - List constraints = jobStorage.getAllConstraintSpecs(); - List dependencies = jobStorage.getAllDependencySpecs(); - - StringBuilder info = new StringBuilder(); - - info.append("-- Jobs\n"); - if (!jobs.isEmpty()) { - Stream.of(jobs).forEach(j -> info.append(j.toString()).append('\n')); - } else { - info.append("None\n"); - } - - info.append("\n-- Constraints\n"); - if (!constraints.isEmpty()) { - Stream.of(constraints).forEach(c -> info.append(c.toString()).append('\n')); - } else { - info.append("None\n"); - } - - info.append("\n-- Dependencies\n"); - if (!dependencies.isEmpty()) { - Stream.of(dependencies).forEach(d -> info.append(d.toString()).append('\n')); - } else { - info.append("None\n"); - } - - return info.toString(); - } - - @WorkerThread - private boolean chainExceedsMaximumInstances(@NonNull List> chain) { - if (chain.size() == 1 && chain.get(0).size() == 1) { - Job solo = chain.get(0).get(0); - - if (solo.getParameters().getMaxInstances() != Job.Parameters.UNLIMITED && - jobStorage.getJobInstanceCount(solo.getFactoryKey()) >= solo.getParameters().getMaxInstances()) - { - return true; - } - } - return false; - } - - @WorkerThread - private void triggerOnSubmit(@NonNull List> chain) { - Stream.of(chain) - .forEach(list -> Stream.of(list).forEach(job -> { - job.setContext(application); - job.onSubmit(); - })); - } - - @WorkerThread - private void insertJobChain(@NonNull List> chain) { - List fullSpecs = new LinkedList<>(); - List dependsOn = Collections.emptyList(); - - for (List jobList : chain) { - for (Job job : jobList) { - fullSpecs.add(buildFullSpec(job, dependsOn)); - } - dependsOn = jobList; - } - - jobStorage.insertJobs(fullSpecs); - } - - @WorkerThread - private @NonNull FullSpec buildFullSpec(@NonNull Job job, @NonNull List dependsOn) { - String id = UUID.randomUUID().toString(); - - job.setId(id); - job.setRunAttempt(0); - - JobSpec jobSpec = new JobSpec(job.getId(), - job.getFactoryKey(), - job.getParameters().getQueue(), - job.getParameters().getCreateTime(), - job.getNextRunAttemptTime(), - job.getRunAttempt(), - job.getParameters().getMaxAttempts(), - job.getParameters().getMaxBackoff(), - job.getParameters().getLifespan(), - job.getParameters().getMaxInstances(), - dataSerializer.serialize(job.serialize()), - false); - - List constraintSpecs = Stream.of(job.getParameters().getConstraintKeys()) - .map(key -> new ConstraintSpec(jobSpec.getId(), key)) - .toList(); - - List dependencySpecs = Stream.of(dependsOn) - .map(depends -> new DependencySpec(job.getId(), depends.getId())) - .toList(); - - return new FullSpec(jobSpec, constraintSpecs, dependencySpecs); - } - - @WorkerThread - private void scheduleJobs(@NonNull List jobs) { - for (Job job : jobs) { - List constraints = Stream.of(job.getParameters().getConstraintKeys()) - .map(key -> new ConstraintSpec(job.getId(), key)) - .map(ConstraintSpec::getFactoryKey) - .map(constraintInstantiator::instantiate) - .toList(); - - scheduler.schedule(0, constraints); - } - } - - @WorkerThread - private @Nullable Job getNextEligibleJobForExecution() { - List jobSpecs = jobStorage.getPendingJobsWithNoDependenciesInCreatedOrder(System.currentTimeMillis()); - - for (JobSpec jobSpec : jobSpecs) { - List constraintSpecs = jobStorage.getConstraintSpecs(jobSpec.getId()); - List constraints = Stream.of(constraintSpecs) - .map(ConstraintSpec::getFactoryKey) - .map(constraintInstantiator::instantiate) - .toList(); - - if (Stream.of(constraints).allMatch(Constraint::isMet)) { - return createJob(jobSpec, constraintSpecs); - } - } - - return null; - } - - private @NonNull Job createJob(@NonNull JobSpec jobSpec, @NonNull List constraintSpecs) { - Job.Parameters parameters = buildJobParameters(jobSpec, constraintSpecs); - Data data = dataSerializer.deserialize(jobSpec.getSerializedData()); - Job job = jobInstantiator.instantiate(jobSpec.getFactoryKey(), parameters, data); - - job.setId(jobSpec.getId()); - job.setRunAttempt(jobSpec.getRunAttempt()); - job.setNextRunAttemptTime(jobSpec.getNextRunAttemptTime()); - job.setContext(application); - - return job; - } - - private @NonNull Job.Parameters buildJobParameters(@NonNull JobSpec jobSpec, @NonNull List constraintSpecs) { - return new Job.Parameters.Builder() - .setCreateTime(jobSpec.getCreateTime()) - .setLifespan(jobSpec.getLifespan()) - .setMaxAttempts(jobSpec.getMaxAttempts()) - .setQueue(jobSpec.getQueueKey()) - .setConstraints(Stream.of(constraintSpecs).map(ConstraintSpec::getFactoryKey).toList()) - .build(); - } - - private long calculateNextRunAttemptTime(long currentTime, int nextAttempt, long maxBackoff) { - int boundedAttempt = Math.min(nextAttempt, 30); - long exponentialBackoff = (long) Math.pow(2, boundedAttempt) * 1000; - long actualBackoff = Math.min(exponentialBackoff, maxBackoff); - - return currentTime + actualBackoff; - } - - interface Callback { - void onEmpty(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java index 6d1527d131..81e378288d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobmanager; import androidx.annotation.NonNull; +import org.session.libsession.messaging.jobs.Job; import org.session.libsession.messaging.utilities.Data; import java.util.HashMap; @@ -15,9 +16,9 @@ class JobInstantiator { this.jobFactories = new HashMap<>(jobFactories); } - public @NonNull Job instantiate(@NonNull String jobFactoryKey, @NonNull Job.Parameters parameters, @NonNull Data data) { + public @NonNull Job instantiate(@NonNull String jobFactoryKey, @NonNull Data data) { if (jobFactories.containsKey(jobFactoryKey)) { - return jobFactories.get(jobFactoryKey).create(parameters, data); + return jobFactories.get(jobFactoryKey).create(data); } else { throw new IllegalStateException("Tried to instantiate a job with key '" + jobFactoryKey + "', but no matching factory was found."); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobLogger.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobLogger.java deleted file mode 100644 index c35f6dc1ac..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobLogger.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import androidx.annotation.NonNull; -import android.text.TextUtils; - -public class JobLogger { - - public static String format(@NonNull Job job, @NonNull String event) { - return format(job, "", event); - } - - public static String format(@NonNull Job job, @NonNull String extraTag, @NonNull String event) { - String id = job.getId(); - String tag = TextUtils.isEmpty(extraTag) ? "" : "[" + extraTag + "]"; - long timeSinceSubmission = System.currentTimeMillis() - job.getParameters().getCreateTime(); - int runAttempt = job.getRunAttempt() + 1; - String maxAttempts = job.getParameters().getMaxAttempts() == Job.Parameters.UNLIMITED ? "Unlimited" - : String.valueOf(job.getParameters().getMaxAttempts()); - String lifespan = job.getParameters().getLifespan() == Job.Parameters.IMMORTAL ? "Immortal" - : String.valueOf(job.getParameters().getLifespan()) + " ms"; - return String.format("[%s][%s]%s %s (Time Since Submission: %d ms, Lifespan: %s, Run Attempt: %d/%s)", - id, job.getClass().getSimpleName(), tag, event, timeSinceSubmission, lifespan, runAttempt, maxAttempts); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java index abb15d9f75..7bbd7679f7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java @@ -6,24 +6,14 @@ import android.os.Build; import androidx.annotation.NonNull; -import org.session.libsession.messaging.utilities.Data; -import org.session.libsession.utilities.Debouncer; import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.jobmanager.impl.DefaultExecutorFactory; -import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer; -import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; /** * Allows the scheduling of durable jobs that will be run as early as possible. @@ -33,32 +23,13 @@ public class JobManager implements ConstraintObserver.Notifier { private static final String TAG = JobManager.class.getSimpleName(); private final ExecutorService executor; - private final JobController jobController; - private final JobRunner[] jobRunners; private final Set emptyQueueListeners = new CopyOnWriteArraySet<>(); public JobManager(@NonNull Application application, @NonNull Configuration configuration) { this.executor = configuration.getExecutorFactory().newSingleThreadExecutor("JobManager"); - this.jobRunners = new JobRunner[configuration.getJobThreadCount()]; - this.jobController = new JobController(application, - configuration.getJobStorage(), - configuration.getJobInstantiator(), - configuration.getConstraintFactories(), - configuration.getDataSerializer(), - Build.VERSION.SDK_INT < 26 ? new AlarmManagerScheduler(application) - : new CompositeScheduler(new InAppScheduler(this), new JobSchedulerScheduler(application)), - new Debouncer(500), - this::onEmptyQueue); executor.execute(() -> { - jobController.init(); - - for (int i = 0; i < jobRunners.length; i++) { - jobRunners[i] = new JobRunner(application, i + 1, jobController); - jobRunners[i].start(); - } - for (ConstraintObserver constraintObserver : configuration.getConstraintObservers()) { constraintObserver.register(this); } @@ -71,13 +42,6 @@ public class JobManager implements ConstraintObserver.Notifier { }); } - /** - * Enqueues a single job to be run. - */ - public void add(@NonNull Job job) { - new Chain(this, Collections.singletonList(job)).enqueue(); - } - /** * Adds a listener to that will be notified when the job queue has been drained. */ @@ -105,166 +69,45 @@ public class JobManager implements ConstraintObserver.Notifier { /** * Pokes the system to take another pass at the job queue. */ - void wakeUp() { - executor.execute(jobController::wakeUp); - } - - private void enqueueChain(@NonNull Chain chain) { - executor.execute(() -> { - jobController.submitNewJobChain(chain.getJobListChain()); - wakeUp(); - }); - } - - private void onEmptyQueue() { - executor.execute(() -> { - for (EmptyQueueListener listener : emptyQueueListeners) { - listener.onQueueEmpty(); - } - }); - } + void wakeUp() {} public interface EmptyQueueListener { void onQueueEmpty(); } - /** - * Allows enqueuing work that depends on each other. Jobs that appear later in the chain will - * only run after all jobs earlier in the chain have been completed. If a job fails, all jobs - * that occur later in the chain will also be failed. - */ - public static class Chain { - - private final JobManager jobManager; - private final List> jobs; - - private Chain(@NonNull JobManager jobManager, @NonNull List jobs) { - this.jobManager = jobManager; - this.jobs = new LinkedList<>(); - - this.jobs.add(new ArrayList<>(jobs)); - } - - public Chain then(@NonNull Job job) { - return then(Collections.singletonList(job)); - } - - public Chain then(@NonNull List jobs) { - if (!jobs.isEmpty()) { - this.jobs.add(new ArrayList<>(jobs)); - } - return this; - } - - public void enqueue() { - jobManager.enqueueChain(this); - } - - private List> getJobListChain() { - return jobs; - } - } - public static class Configuration { private final ExecutorFactory executorFactory; - private final int jobThreadCount; - private final JobInstantiator jobInstantiator; - private final ConstraintInstantiator constraintInstantiator; private final List constraintObservers; - private final Data.Serializer dataSerializer; - private final JobStorage jobStorage; - private Configuration(int jobThreadCount, - @NonNull ExecutorFactory executorFactory, - @NonNull JobInstantiator jobInstantiator, - @NonNull ConstraintInstantiator constraintInstantiator, - @NonNull List constraintObservers, - @NonNull Data.Serializer dataSerializer, - @NonNull JobStorage jobStorage) + private Configuration(@NonNull ExecutorFactory executorFactory, + @NonNull List constraintObservers) { this.executorFactory = executorFactory; - this.jobThreadCount = jobThreadCount; - this.jobInstantiator = jobInstantiator; - this.constraintInstantiator = constraintInstantiator; this.constraintObservers = constraintObservers; - this.dataSerializer = dataSerializer; - this.jobStorage = jobStorage; - } - - int getJobThreadCount() { - return jobThreadCount; } @NonNull ExecutorFactory getExecutorFactory() { return executorFactory; } - @NonNull JobInstantiator getJobInstantiator() { - return jobInstantiator; - } - - @NonNull - ConstraintInstantiator getConstraintFactories() { - return constraintInstantiator; - } - @NonNull List getConstraintObservers() { return constraintObservers; } - @NonNull Data.Serializer getDataSerializer() { - return dataSerializer; - } - - @NonNull JobStorage getJobStorage() { - return jobStorage; - } - - public static class Builder { private ExecutorFactory executorFactory = new DefaultExecutorFactory(); - private int jobThreadCount = 1; - private Map jobFactories = new HashMap<>(); - private Map constraintFactories = new HashMap<>(); private List constraintObservers = new ArrayList<>(); - private Data.Serializer dataSerializer = new JsonDataSerializer(); - private JobStorage jobStorage = null; - - public @NonNull Builder setJobFactories(@NonNull Map jobFactories) { - this.jobFactories = jobFactories; - return this; - } - - public @NonNull Builder setConstraintFactories(@NonNull Map constraintFactories) { - this.constraintFactories = constraintFactories; - return this; - } public @NonNull Builder setConstraintObservers(@NonNull List constraintObservers) { this.constraintObservers = constraintObservers; return this; } - public @NonNull Builder setDataSerializer(@NonNull Data.Serializer dataSerializer) { - this.dataSerializer = dataSerializer; - return this; - } - - public @NonNull Builder setJobStorage(@NonNull JobStorage jobStorage) { - this.jobStorage = jobStorage; - return this; - } - public @NonNull Configuration build() { - return new Configuration(jobThreadCount, - executorFactory, - new JobInstantiator(jobFactories), - new ConstraintInstantiator(constraintFactories), - new ArrayList<>(constraintObservers), - dataSerializer, - jobStorage); + return new Configuration(executorFactory, + new ArrayList<>(constraintObservers)); } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobRunner.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobRunner.java deleted file mode 100644 index 6eadf0fd5d..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobRunner.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import android.app.Application; -import android.os.PowerManager; -import androidx.annotation.NonNull; - -import com.annimon.stream.Stream; - -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.util.WakeLockUtil; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -class JobRunner extends Thread { - - private static final String TAG = JobRunner.class.getSimpleName(); - - private static long WAKE_LOCK_TIMEOUT = TimeUnit.MINUTES.toMillis(10); - - private final Application application; - private final int id; - private final JobController jobController; - - JobRunner(@NonNull Application application, int id, @NonNull JobController jobController) { - super("JobRunner-" + id); - - this.application = application; - this.id = id; - this.jobController = jobController; - } - - @Override - public synchronized void run() { - while (true) { - Job job = jobController.pullNextEligibleJobForExecution(); - Job.Result result = run(job); - - jobController.onJobFinished(job); - - switch (result) { - case SUCCESS: - jobController.onSuccess(job); - break; - case RETRY: - jobController.onRetry(job); - job.onRetry(); - break; - case FAILURE: - List dependents = jobController.onFailure(job); - job.onCanceled(); - Stream.of(dependents).forEach(Job::onCanceled); - break; - } - } - } - - private Job.Result run(@NonNull Job job) { - Log.i(TAG, JobLogger.format(job, String.valueOf(id), "Running job.")); - - if (isJobExpired(job)) { - Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing after surpassing its lifespan.")); - return Job.Result.FAILURE; - } - - Job.Result result = null; - PowerManager.WakeLock wakeLock = null; - - try { - wakeLock = WakeLockUtil.acquire(application, PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TIMEOUT, job.getId()); - result = job.run(); - } catch (Exception e) { - Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing due to an unexpected exception."), e); - return Job.Result.FAILURE; - } finally { - if (wakeLock != null) { - WakeLockUtil.release(wakeLock, job.getId()); - } - } - - printResult(job, result); - - if (result == Job.Result.RETRY && job.getRunAttempt() + 1 >= job.getParameters().getMaxAttempts() && - job.getParameters().getMaxAttempts() != Job.Parameters.UNLIMITED) - { - Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Failing after surpassing its max number of attempts.")); - return Job.Result.FAILURE; - } - - return result; - } - - private boolean isJobExpired(@NonNull Job job) { - long expirationTime = job.getParameters().getCreateTime() + job.getParameters().getLifespan(); - - if (expirationTime < 0) { - expirationTime = Long.MAX_VALUE; - } - - return job.getParameters().getLifespan() != Job.Parameters.IMMORTAL && expirationTime <= System.currentTimeMillis(); - } - - private void printResult(@NonNull Job job, @NonNull Job.Result result) { - if (result == Job.Result.FAILURE) { - Log.w(TAG, JobLogger.format(job, String.valueOf(id), "Job failed.")); - } else { - Log.i(TAG, JobLogger.format(job, String.valueOf(id), "Job finished with result: " + result)); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobSchedulerScheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobSchedulerScheduler.java deleted file mode 100644 index 40acbf520b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobSchedulerScheduler.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import android.app.Application; -import android.app.job.JobInfo; -import android.app.job.JobParameters; -import android.app.job.JobScheduler; -import android.app.job.JobService; -import android.content.ComponentName; -import android.content.Context; -import android.content.SharedPreferences; -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; - -import org.thoughtcrime.securesms.ApplicationContext; -import org.session.libsignal.utilities.Log; - -import java.util.List; - -@RequiresApi(26) -public class JobSchedulerScheduler implements Scheduler { - - private static final String TAG = JobSchedulerScheduler.class.getSimpleName(); - - private static final String PREF_NAME = "JobSchedulerScheduler_prefs"; - private static final String PREF_NEXT_ID = "pref_next_id"; - - private static final int MAX_ID = 75; - - private final Application application; - - JobSchedulerScheduler(@NonNull Application application) { - this.application = application; - } - - @RequiresApi(26) - @Override - public void schedule(long delay, @NonNull List constraints) { - JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(getNextId(), new ComponentName(application, SystemService.class)) - .setMinimumLatency(delay) - .setPersisted(true); - - for (Constraint constraint : constraints) { - constraint.applyToJobInfo(jobInfoBuilder); - } - - Log.i(TAG, "Scheduling a run in " + delay + " ms."); - JobScheduler jobScheduler = application.getSystemService(JobScheduler.class); - jobScheduler.schedule(jobInfoBuilder.build()); - } - - private int getNextId() { - SharedPreferences prefs = application.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); - int returnedId = prefs.getInt(PREF_NEXT_ID, 0); - int nextId = returnedId + 1 > MAX_ID ? 0 : returnedId + 1; - - prefs.edit().putInt(PREF_NEXT_ID, nextId).apply(); - - return returnedId; - } - - @RequiresApi(api = 26) - public static class SystemService extends JobService { - - @Override - public boolean onStartJob(JobParameters params) { - Log.d(TAG, "onStartJob()"); - - JobManager jobManager = ApplicationContext.getInstance(getApplicationContext()).getJobManager(); - - jobManager.addOnEmptyQueueListener(new JobManager.EmptyQueueListener() { - @Override - public void onQueueEmpty() { - jobManager.removeOnEmptyQueueListener(this); - jobFinished(params, false); - Log.d(TAG, "jobFinished()"); - } - }); - - jobManager.wakeUp(); - - return true; - } - - @Override - public boolean onStopJob(JobParameters params) { - Log.d(TAG, "onStopJob()"); - return false; - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Scheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Scheduler.java deleted file mode 100644 index 194acd39b2..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Scheduler.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import androidx.annotation.NonNull; - -import java.util.List; - -public interface Scheduler { - void schedule(long delay, @NonNull List constraints); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BaseJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/BaseJob.java deleted file mode 100644 index 0c11cc552b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BaseJob.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.jobmanager.JobLogger; -import org.session.libsignal.utilities.Log; - -/** - * @deprecated - * use WorkManager - * API instead. - */ -public abstract class BaseJob extends Job { - - private static final String TAG = BaseJob.class.getSimpleName(); - - public BaseJob(@NonNull Parameters parameters) { - super(parameters); - } - - @Override - public @NonNull Result run() { - try { - onRun(); - return Result.SUCCESS; - } catch (Exception e) { - if (onShouldRetry(e)) { - Log.i(TAG, JobLogger.format(this, "Encountered a retryable exception."), e); - return Result.RETRY; - } else { - Log.w(TAG, JobLogger.format(this, "Encountered a failing exception."), e); - return Result.FAILURE; - } - } - } - - protected abstract void onRun() throws Exception; - - protected abstract boolean onShouldRetry(@NonNull Exception e); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/FastJobStorage.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/FastJobStorage.java deleted file mode 100644 index 3b50dc2733..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/FastJobStorage.java +++ /dev/null @@ -1,261 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.annimon.stream.Stream; - -import org.thoughtcrime.securesms.database.JobDatabase; -import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec; -import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage; - -import org.session.libsession.utilities.Util; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; - -public class FastJobStorage implements JobStorage { - - private final JobDatabase jobDatabase; - - private final List jobs; - private final Map> constraintsByJobId; - private final Map> dependenciesByJobId; - - public FastJobStorage(@NonNull JobDatabase jobDatabase) { - this.jobDatabase = jobDatabase; - this.jobs = new ArrayList<>(); - this.constraintsByJobId = new HashMap<>(); - this.dependenciesByJobId = new HashMap<>(); - } - - @Override - public synchronized void init() { - List jobSpecs = jobDatabase.getAllJobSpecs(); - List constraintSpecs = jobDatabase.getAllConstraintSpecs(); - List dependencySpecs = jobDatabase.getAllDependencySpecs(); - - jobs.addAll(jobSpecs); - - for (ConstraintSpec constraintSpec: constraintSpecs) { - List jobConstraints = Util.getOrDefault(constraintsByJobId, constraintSpec.getJobSpecId(), new LinkedList<>()); - jobConstraints.add(constraintSpec); - constraintsByJobId.put(constraintSpec.getJobSpecId(), jobConstraints); - } - - for (DependencySpec dependencySpec : dependencySpecs) { - List jobDependencies = Util.getOrDefault(dependenciesByJobId, dependencySpec.getJobId(), new LinkedList<>()); - jobDependencies.add(dependencySpec); - dependenciesByJobId.put(dependencySpec.getJobId(), jobDependencies); - } - } - - @Override - public synchronized void insertJobs(@NonNull List fullSpecs) { - jobDatabase.insertJobs(fullSpecs); - - for (FullSpec fullSpec : fullSpecs) { - jobs.add(fullSpec.getJobSpec()); - constraintsByJobId.put(fullSpec.getJobSpec().getId(), fullSpec.getConstraintSpecs()); - dependenciesByJobId.put(fullSpec.getJobSpec().getId(), fullSpec.getDependencySpecs()); - } - } - - @Override - public synchronized @Nullable JobSpec getJobSpec(@NonNull String id) { - for (JobSpec jobSpec : jobs) { - if (jobSpec.getId().equals(id)) { - return jobSpec; - } - } - return null; - } - - @Override - public synchronized @NonNull List getAllJobSpecs() { - return new ArrayList<>(jobs); - } - - @Override - public synchronized @NonNull List getPendingJobsWithNoDependenciesInCreatedOrder(long currentTime) { - return Stream.of(jobs) - .filter(j -> JobManagerFactories.hasFactoryForKey(j.getFactoryKey())) - .filterNot(JobSpec::isRunning) - .filter(this::firstInQueue) - .filter(j -> !dependenciesByJobId.containsKey(j.getId()) || dependenciesByJobId.get(j.getId()).isEmpty()) - .filter(j -> j.getNextRunAttemptTime() <= currentTime) - .sorted((j1, j2) -> Long.compare(j1.getCreateTime(), j2.getCreateTime())) - .toList(); - } - - private boolean firstInQueue(@NonNull JobSpec job) { - if (job.getQueueKey() == null) { - return true; - } - - return Stream.of(jobs) - .filter(j -> Util.equals(j.getQueueKey(), job.getQueueKey())) - .sorted((j1, j2) -> Long.compare(j1.getCreateTime(), j2.getCreateTime())) - .toList() - .get(0) - .equals(job); - } - - @Override - public synchronized int getJobInstanceCount(@NonNull String factoryKey) { - return (int) Stream.of(jobs) - .filter(j -> j.getFactoryKey().equals(factoryKey)) - .count(); - } - - @Override - public synchronized void updateJobRunningState(@NonNull String id, boolean isRunning) { - jobDatabase.updateJobRunningState(id, isRunning); - - ListIterator iter = jobs.listIterator(); - - while (iter.hasNext()) { - JobSpec existing = iter.next(); - if (existing.getId().equals(id)) { - JobSpec updated = new JobSpec(existing.getId(), - existing.getFactoryKey(), - existing.getQueueKey(), - existing.getCreateTime(), - existing.getNextRunAttemptTime(), - existing.getRunAttempt(), - existing.getMaxAttempts(), - existing.getMaxBackoff(), - existing.getLifespan(), - existing.getMaxInstances(), - existing.getSerializedData(), - isRunning); - iter.set(updated); - } - } - } - - @Override - public synchronized void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime) { - jobDatabase.updateJobAfterRetry(id, isRunning, runAttempt, nextRunAttemptTime); - - ListIterator iter = jobs.listIterator(); - - while (iter.hasNext()) { - JobSpec existing = iter.next(); - if (existing.getId().equals(id)) { - JobSpec updated = new JobSpec(existing.getId(), - existing.getFactoryKey(), - existing.getQueueKey(), - existing.getCreateTime(), - nextRunAttemptTime, - runAttempt, - existing.getMaxAttempts(), - existing.getMaxBackoff(), - existing.getLifespan(), - existing.getMaxInstances(), - existing.getSerializedData(), - isRunning); - iter.set(updated); - } - } - } - - @Override - public synchronized void updateAllJobsToBePending() { - jobDatabase.updateAllJobsToBePending(); - - ListIterator iter = jobs.listIterator(); - - while (iter.hasNext()) { - JobSpec existing = iter.next(); - JobSpec updated = new JobSpec(existing.getId(), - existing.getFactoryKey(), - existing.getQueueKey(), - existing.getCreateTime(), - existing.getNextRunAttemptTime(), - existing.getRunAttempt(), - existing.getMaxAttempts(), - existing.getMaxBackoff(), - existing.getLifespan(), - existing.getMaxInstances(), - existing.getSerializedData(), - false); - iter.set(updated); - } - } - - @Override - public synchronized void deleteJob(@NonNull String jobId) { - deleteJobs(Collections.singletonList(jobId)); - } - - @Override - public synchronized void deleteJobs(@NonNull List jobIds) { - jobDatabase.deleteJobs(jobIds); - - Set deleteIds = new HashSet<>(jobIds); - - Iterator jobIter = jobs.iterator(); - while (jobIter.hasNext()) { - if (deleteIds.contains(jobIter.next().getId())) { - jobIter.remove(); - } - } - - for (String jobId : jobIds) { - constraintsByJobId.remove(jobId); - dependenciesByJobId.remove(jobId); - - for (Map.Entry> entry : dependenciesByJobId.entrySet()) { - Iterator depedencyIter = entry.getValue().iterator(); - - while (depedencyIter.hasNext()) { - if (depedencyIter.next().getDependsOnJobId().equals(jobId)) { - depedencyIter.remove(); - } - } - } - } - } - - @Override - public synchronized @NonNull List getConstraintSpecs(@NonNull String jobId) { - return Util.getOrDefault(constraintsByJobId, jobId, new LinkedList<>()); - } - - @Override - public synchronized @NonNull List getAllConstraintSpecs() { - return Stream.of(constraintsByJobId) - .map(Map.Entry::getValue) - .flatMap(Stream::of) - .toList(); - } - - @Override - public synchronized @NonNull List getDependencySpecsThatDependOnJob(@NonNull String jobSpecId) { - return Stream.of(dependenciesByJobId.entrySet()) - .map(Map.Entry::getValue) - .flatMap(Stream::of) - .filter(j -> j.getDependsOnJobId().equals(jobSpecId)) - .toList(); - } - - @Override - public @NonNull List getAllDependencySpecs() { - return Stream.of(dependenciesByJobId) - .map(Map.Entry::getValue) - .flatMap(Stream::of) - .toList(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index 910a9c09be..d892c0f439 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -26,7 +26,7 @@ public final class JobManagerFactories { private static Collection factoryKeys = new ArrayList<>(); - public static Map getJobFactories(@NonNull Application application) { + public static Map getJobFactories() { HashMap factoryHashMap = new HashMap() {{ put(LocalBackupJob.Companion.getKEY(), new LocalBackupJob.Factory()); put(RetrieveProfileAvatarJob.Companion.getKEY(), new RetrieveProfileAvatarJob.Factory()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java index 0b1b3f8423..9cf88f4094 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.service; import android.content.Context; import android.content.Intent; +import org.session.libsession.messaging.jobs.JobQueue; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.jobs.LocalBackupJob; import org.session.libsession.utilities.TextSecurePreferences; @@ -21,7 +22,9 @@ public class LocalBackupListener extends PersistentAlarmManagerListener { @Override protected long onAlarm(Context context, long scheduledTime) { if (TextSecurePreferences.isBackupEnabled(context)) { - ApplicationContext.getInstance(context).getJobManager().add(new LocalBackupJob()); + LocalBackupJob job = new LocalBackupJob(); + job.context = context; + JobQueue.getShared().add(job); } long nextTime = System.currentTimeMillis() + INTERVAL; diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java index ef27916ac9..01ade94214 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java @@ -31,9 +31,9 @@ public class UpdateApkRefreshListener extends PersistentAlarmManagerListener { if (scheduledTime != 0 && BuildConfig.PLAY_STORE_DISABLED) { Log.i(TAG, "Queueing APK update job..."); - ApplicationContext.getInstance(context) - .getJobManager() - .add(new UpdateApkJob()); + UpdateApkJob job = new UpdateApkJob(); + job.context = context; + JobQueue.getShared().add(job); } long newTime = System.currentTimeMillis() + INTERVAL; diff --git a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt index 2615eff588..3b6db9a76f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt @@ -41,9 +41,9 @@ class ProfileManager : SSKEnvironment.ProfileManagerProtocol { } override fun setProfilePictureURL(context: Context, recipient: Recipient, profilePictureURL: String) { - val job = RetrieveProfileAvatarJob(recipient, profilePictureURL) - val jobManager = ApplicationContext.getInstance(context).jobManager - jobManager.add(job) + val job = RetrieveProfileAvatarJob(profilePictureURL, recipient.address) + job.context = context + JobQueue.shared.add(job) val sessionID = recipient.address.serialize() val contactDatabase = DatabaseComponent.get(context).sessionContactDatabase() var contact = contactDatabase.getContactWithSessionID(sessionID) diff --git a/app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java b/app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java deleted file mode 100644 index a6624189d1..0000000000 --- a/app/src/test/java/org/thoughtcrime/securesms/jobs/FastJobStorageTest.java +++ /dev/null @@ -1,350 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.Application; - -import androidx.annotation.NonNull; - -import com.annimon.stream.Stream; - -import org.junit.Test; -import org.session.libsession.messaging.utilities.Data; -import org.thoughtcrime.securesms.database.JobDatabase; -import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer; -import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec; -import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class FastJobStorageTest { - - private static final JsonDataSerializer serializer = new JsonDataSerializer(); - private static final String EMPTY_DATA = serializer.serialize(Data.EMPTY); - - @Test - public void init_allStoredDataAvailable() { - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS)); - - subject.init(); - - DataSet1.assertJobsMatch(subject.getAllJobSpecs()); - DataSet1.assertConstraintsMatch(subject.getAllConstraintSpecs()); - DataSet1.assertDependenciesMatch(subject.getAllDependencySpecs()); - } - - @Test - public void insertJobs_writesToDatabase() { - JobDatabase database = noopDatabase(); - FastJobStorage subject = new FastJobStorage(database); - - subject.insertJobs(DataSet1.FULL_SPECS); - - verify(database).insertJobs(DataSet1.FULL_SPECS); - } - - @Test - public void insertJobs_dataCanBeFound() { - FastJobStorage subject = new FastJobStorage(noopDatabase()); - - subject.insertJobs(DataSet1.FULL_SPECS); - - DataSet1.assertJobsMatch(subject.getAllJobSpecs()); - DataSet1.assertConstraintsMatch(subject.getAllConstraintSpecs()); - DataSet1.assertDependenciesMatch(subject.getAllDependencySpecs()); - } - - @Test - public void insertJobs_individualJobCanBeFound() { - FastJobStorage subject = new FastJobStorage(noopDatabase()); - - subject.insertJobs(DataSet1.FULL_SPECS); - - assertEquals(DataSet1.JOB_1, subject.getJobSpec(DataSet1.JOB_1.getId())); - assertEquals(DataSet1.JOB_2, subject.getJobSpec(DataSet1.JOB_2.getId())); - } - - @Test - public void updateAllJobsToBePending_allArePending() { - FullSpec fullSpec1 = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, true), - Collections.emptyList(), - Collections.emptyList()); - FullSpec fullSpec2 = new FullSpec(new JobSpec("2", AvatarDownloadJob.KEY, null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, true), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2))); - - subject.init(); - subject.updateAllJobsToBePending(); - - assertFalse(subject.getJobSpec("1").isRunning()); - assertFalse(subject.getJobSpec("2").isRunning()); - } - - @Test - public void updateJobRunningState_writesToDatabase() { - JobDatabase database = noopDatabase(); - FastJobStorage subject = new FastJobStorage(database); - - subject.updateJobRunningState("1", true); - - verify(database).updateJobRunningState("1", true); - } - - @Test - public void updateJobRunningState_stateUpdated() { - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS)); - subject.init(); - - subject.updateJobRunningState(DataSet1.JOB_1.getId(), true); - assertTrue(subject.getJobSpec(DataSet1.JOB_1.getId()).isRunning()); - - subject.updateJobRunningState(DataSet1.JOB_1.getId(), false); - assertFalse(subject.getJobSpec(DataSet1.JOB_1.getId()).isRunning()); - } - - @Test - public void updateJobAfterRetry_writesToDatabase() { - JobDatabase database = noopDatabase(); - FastJobStorage subject = new FastJobStorage(database); - - subject.updateJobAfterRetry("1", true, 1, 10); - - verify(database).updateJobAfterRetry("1", true, 1, 10); - } - - @Test - public void updateJobAfterRetry_stateUpdated() { - FullSpec fullSpec = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, null, 0, 0, 0, 3, 30000, -1, -1, EMPTY_DATA, true), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec))); - - subject.init(); - subject.updateJobAfterRetry("1", false, 1, 10); - - JobSpec job = subject.getJobSpec("1"); - - assertNotNull(job); - assertFalse(job.isRunning()); - assertEquals(1, job.getRunAttempt()); - assertEquals(10, job.getNextRunAttemptTime()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenEarlierItemInQueueInRunning() { - FullSpec fullSpec1 = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true), - Collections.emptyList(), - Collections.emptyList()); - FullSpec fullSpec2 = new FullSpec(new JobSpec("2", AvatarDownloadJob.KEY, "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2))); - subject.init(); - - assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(1).size()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenAllJobsAreRunning() { - FullSpec fullSpec = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec))); - subject.init(); - - assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(10).size()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenNextRunTimeIsAfterCurrentTime() { - FullSpec fullSpec = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, "q", 0, 10, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec))); - subject.init(); - - assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(0).size()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenDependentOnAnotherJob() { - FullSpec fullSpec1 = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true), - Collections.emptyList(), - Collections.emptyList()); - FullSpec fullSpec2 = new FullSpec(new JobSpec("2", AvatarDownloadJob.KEY, null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.singletonList(new DependencySpec("2", "1"))); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2))); - subject.init(); - - assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(0).size()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_singleEligibleJob() { - FullSpec fullSpec = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec))); - subject.init(); - - assertEquals(1, subject.getPendingJobsWithNoDependenciesInCreatedOrder(10).size()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_multipleEligibleJobs() { - FullSpec fullSpec1 = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - FullSpec fullSpec2 = new FullSpec(new JobSpec("2", AvatarDownloadJob.KEY, null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2))); - subject.init(); - - assertEquals(2, subject.getPendingJobsWithNoDependenciesInCreatedOrder(10).size()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_singleEligibleJobInMixedList() { - FullSpec fullSpec1 = new FullSpec(new JobSpec("1", AvatarDownloadJob.KEY, null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true), - Collections.emptyList(), - Collections.emptyList()); - FullSpec fullSpec2 = new FullSpec(new JobSpec("2", AvatarDownloadJob.KEY, null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2))); - subject.init(); - - List jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10); - - assertEquals(1, jobs.size()); - assertEquals("2", jobs.get(0).getId()); - } - - @Test - public void getPendingJobsWithNoDependenciesInCreatedOrder_firstItemInQueue() { - FullSpec fullSpec1 = new FullSpec(new JobSpec("1", RetrieveProfileAvatarJob.KEY, "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - FullSpec fullSpec2 = new FullSpec(new JobSpec("2", RetrieveProfileAvatarJob.KEY, "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false), - Collections.emptyList(), - Collections.emptyList()); - - JobManagerFactories.getJobFactories(mock(Application.class)); - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2))); - subject.init(); - - List jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10); - - assertEquals(1, jobs.size()); - assertEquals("1", jobs.get(0).getId()); - } - - @Test - public void deleteJobs_writesToDatabase() { - JobDatabase database = noopDatabase(); - FastJobStorage subject = new FastJobStorage(database); - List ids = Arrays.asList("1", "2"); - - subject.deleteJobs(ids); - - verify(database).deleteJobs(ids); - } - - @Test - public void deleteJobs_deletesAllRelevantPieces() { - FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS)); - - subject.init(); - subject.deleteJobs(Collections.singletonList("id1")); - - List jobs = subject.getAllJobSpecs(); - List constraints = subject.getAllConstraintSpecs(); - List dependencies = subject.getAllDependencySpecs(); - - assertEquals(1, jobs.size()); - assertEquals(DataSet1.JOB_2, jobs.get(0)); - assertEquals(1, constraints.size()); - assertEquals(DataSet1.CONSTRAINT_2, constraints.get(0)); - assertEquals(0, dependencies.size()); - } - - - private JobDatabase noopDatabase() { - JobDatabase database = mock(JobDatabase.class); - - when(database.getAllJobSpecs()).thenReturn(Collections.emptyList()); - when(database.getAllConstraintSpecs()).thenReturn(Collections.emptyList()); - when(database.getAllDependencySpecs()).thenReturn(Collections.emptyList()); - - return database; - } - - private JobDatabase fixedDataDatabase(List fullSpecs) { - JobDatabase database = mock(JobDatabase.class); - - when(database.getAllJobSpecs()).thenReturn(Stream.of(fullSpecs).map(FullSpec::getJobSpec).toList()); - when(database.getAllConstraintSpecs()).thenReturn(Stream.of(fullSpecs).map(FullSpec::getConstraintSpecs).flatMap(Stream::of).toList()); - when(database.getAllDependencySpecs()).thenReturn(Stream.of(fullSpecs).map(FullSpec::getDependencySpecs).flatMap(Stream::of).toList()); - - return database; - } - - private static final class DataSet1 { - static final JobSpec JOB_1 = new JobSpec("id1", "f1", "q1", 1, 2, 3, 4, 5, 6, 7, EMPTY_DATA, false); - static final JobSpec JOB_2 = new JobSpec("id2", "f2", "q2", 1, 2, 3, 4, 5, 6, 7, EMPTY_DATA, false); - static final ConstraintSpec CONSTRAINT_1 = new ConstraintSpec("id1", "f1"); - static final ConstraintSpec CONSTRAINT_2 = new ConstraintSpec("id2", "f2"); - static final DependencySpec DEPENDENCY_2 = new DependencySpec("id2", "id1"); - static final FullSpec FULL_SPEC_1 = new FullSpec(JOB_1, Collections.singletonList(CONSTRAINT_1), Collections.emptyList()); - static final FullSpec FULL_SPEC_2 = new FullSpec(JOB_2, Collections.singletonList(CONSTRAINT_2), Collections.singletonList(DEPENDENCY_2)); - static final List FULL_SPECS = Arrays.asList(FULL_SPEC_1, FULL_SPEC_2); - - static void assertJobsMatch(@NonNull List jobs) { - assertEquals(jobs.size(), 2); - assertTrue(jobs.contains(DataSet1.JOB_1)); - assertTrue(jobs.contains(DataSet1.JOB_1)); - } - - static void assertConstraintsMatch(@NonNull List constraints) { - assertEquals(constraints.size(), 2); - assertTrue(constraints.contains(DataSet1.CONSTRAINT_1)); - assertTrue(constraints.contains(DataSet1.CONSTRAINT_2)); - } - - static void assertDependenciesMatch(@NonNull List dependencies) { - assertEquals(dependencies.size(), 1); - assertTrue(dependencies.contains(DataSet1.DEPENDENCY_2)); - } - } -} From f0715f16e0e49df0161302c79a33fc46d5b546ca Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 8 May 2023 14:07:36 +0930 Subject: [PATCH 27/83] Fix scroll to bottom button always visible if last item is taller than RecyclerView --- .../securesms/conversation/v2/ConversationActivityV2.kt | 5 +---- .../java/org/session/libsession/utilities/ViewUtils.kt | 9 ++++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index cabb583085..107627b2c1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -212,10 +212,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe var searchViewItem: MenuItem? = null private val isScrolledToBottom: Boolean - get() { - val position = layoutManager?.findFirstCompletelyVisibleItemPosition() ?: 0 - return position == 0 - } + get() = binding?.conversationRecyclerView?.isScrolledToBottom ?: true private val layoutManager: LinearLayoutManager? get() { return binding?.conversationRecyclerView?.layoutManager as LinearLayoutManager? } diff --git a/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt b/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt index 5781ea3e2c..f67abe8ec4 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt @@ -4,6 +4,7 @@ import android.content.Context import android.util.TypedValue import androidx.annotation.AttrRes import androidx.annotation.ColorInt +import androidx.recyclerview.widget.RecyclerView @ColorInt fun Context.getColorFromAttr( @@ -13,4 +14,10 @@ fun Context.getColorFromAttr( ): Int { theme.resolveAttribute(attrColor, typedValue, resolveRefs) return typedValue.data -} \ No newline at end of file +} + +val RecyclerView.isScrolledToBottom: Boolean + get() { + val contentHeight = height - (paddingTop + paddingBottom) + return computeVerticalScrollRange() == computeVerticalScrollOffset() + contentHeight + } From b6667b83ce116e3f494a34af991e485c4182c126 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 8 May 2023 14:43:08 +0930 Subject: [PATCH 28/83] Fix scroll to bottom button position when input not visible --- app/src/main/res/layout/activity_conversation_v2.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/activity_conversation_v2.xml b/app/src/main/res/layout/activity_conversation_v2.xml index d2696a45ec..099f9b9909 100644 --- a/app/src/main/res/layout/activity_conversation_v2.xml +++ b/app/src/main/res/layout/activity_conversation_v2.xml @@ -137,6 +137,7 @@ android:layout_height="50dp" android:layout_alignParentEnd="true" android:layout_above="@+id/messageRequestBar" + android:layout_alignWithParentIfMissing="true" android:layout_marginEnd="12dp" android:layout_marginBottom="32dp"> From b494088c3db0e09a3dc3b8df35e8d969f2b31f83 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 8 May 2023 17:12:20 +1000 Subject: [PATCH 29/83] WIP: further refactor on old jobs --- .../securesms/ApplicationContext.java | 14 --- .../securesms/database/Storage.kt | 3 +- .../jobmanager/ConstraintObserver.java | 12 -- .../securesms/jobmanager/JobInstantiator.java | 26 ---- .../securesms/jobmanager/JobManager.java | 114 ------------------ .../impl/CellServiceConstraint.java | 48 -------- .../impl/CellServiceConstraintObserver.java | 38 ------ .../impl/NetworkConstraintObserver.java | 36 ------ .../impl/NetworkOrCellServiceConstraint.java | 48 -------- .../impl/SqlCipherMigrationConstraint.java | 48 -------- .../SqlCipherMigrationConstraintObserver.java | 32 ----- .../securesms/jobs/JobManagerFactories.java | 57 --------- .../sskenvironment/ProfileManager.kt | 3 +- .../libsession/database/StorageProtocol.kt | 1 + .../jobs/RetrieveProfileAvatarJob.kt | 14 +-- 15 files changed, 9 insertions(+), 485 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintObserver.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraint.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkConstraintObserver.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkOrCellServiceConstraint.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraint.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraintObserver.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java rename {app/src/main/java/org/thoughtcrime/securesms => libsession/src/main/java/org/session/libsession/messaging}/jobs/RetrieveProfileAvatarJob.kt (90%) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 0d5e57352e..df1bed7b3b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -65,9 +65,7 @@ import org.thoughtcrime.securesms.dependencies.DatabaseModule; import org.thoughtcrime.securesms.emoji.EmojiSource; import org.thoughtcrime.securesms.groups.OpenGroupManager; import org.thoughtcrime.securesms.home.HomeActivity; -import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; -import org.thoughtcrime.securesms.jobs.JobManagerFactories; import org.thoughtcrime.securesms.logging.AndroidLogger; import org.thoughtcrime.securesms.logging.PersistentLogger; import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger; @@ -130,7 +128,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO private ExpiringMessageManager expiringMessageManager; private TypingStatusRepository typingStatusRepository; private TypingStatusSender typingStatusSender; - private JobManager jobManager; private ReadReceiptManager readReceiptManager; private ProfileManager profileManager; public MessageNotifier messageNotifier = null; @@ -227,7 +224,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO initializeProfileManager(); initializePeriodicTasks(); SSKEnvironment.Companion.configure(getTypingStatusRepository(), getReadReceiptManager(), getProfileManager(), messageNotifier, getExpiringMessageManager()); - initializeJobManager(); initializeWebRtc(); initializeBlobProvider(); resubmitProfilePictureIfNeeded(); @@ -284,10 +280,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO LocaleParser.Companion.configure(new LocaleParseHelper()); } - public JobManager getJobManager() { - return jobManager; - } - public ExpiringMessageManager getExpiringMessageManager() { return expiringMessageManager; } @@ -350,12 +342,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionLogger(originalHandler)); } - private void initializeJobManager() { - this.jobManager = new JobManager(this, new JobManager.Configuration.Builder() - .setConstraintObservers(JobManagerFactories.getConstraintObservers(this)) - .build()); - } - private void initializeExpiringMessageManager() { this.expiringMessageManager = new ExpiringMessageManager(this); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 891df6be87..3e21f63c09 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -42,13 +42,12 @@ import org.session.libsignal.messages.SignalServiceGroup import org.session.libsignal.utilities.IdPrefix import org.session.libsignal.utilities.KeyHelper import org.session.libsignal.utilities.guava.Optional -import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.database.model.MessageId import org.thoughtcrime.securesms.database.model.ReactionRecord import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.groups.OpenGroupManager -import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob +import org.session.libsession.messaging.jobs.RetrieveProfileAvatarJob import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.util.SessionMetaProtocol import java.security.MessageDigest diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintObserver.java deleted file mode 100644 index fd7f4fd43c..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintObserver.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import androidx.annotation.NonNull; - -public interface ConstraintObserver { - - void register(@NonNull Notifier notifier); - - interface Notifier { - void onConstraintMet(@NonNull String reason); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java deleted file mode 100644 index 81e378288d..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import androidx.annotation.NonNull; - -import org.session.libsession.messaging.jobs.Job; -import org.session.libsession.messaging.utilities.Data; - -import java.util.HashMap; -import java.util.Map; - -class JobInstantiator { - - private final Map jobFactories; - - JobInstantiator(@NonNull Map jobFactories) { - this.jobFactories = new HashMap<>(jobFactories); - } - - public @NonNull Job instantiate(@NonNull String jobFactoryKey, @NonNull Data data) { - if (jobFactories.containsKey(jobFactoryKey)) { - return jobFactories.get(jobFactoryKey).create(data); - } else { - throw new IllegalStateException("Tried to instantiate a job with key '" + jobFactoryKey + "', but no matching factory was found."); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java deleted file mode 100644 index 7bbd7679f7..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobManager.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import android.app.Application; -import android.content.Intent; -import android.os.Build; - -import androidx.annotation.NonNull; - -import org.session.libsignal.utilities.Log; -import org.thoughtcrime.securesms.jobmanager.impl.DefaultExecutorFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.ExecutorService; - -/** - * Allows the scheduling of durable jobs that will be run as early as possible. - */ -public class JobManager implements ConstraintObserver.Notifier { - - private static final String TAG = JobManager.class.getSimpleName(); - - private final ExecutorService executor; - - private final Set emptyQueueListeners = new CopyOnWriteArraySet<>(); - - public JobManager(@NonNull Application application, @NonNull Configuration configuration) { - this.executor = configuration.getExecutorFactory().newSingleThreadExecutor("JobManager"); - - executor.execute(() -> { - for (ConstraintObserver constraintObserver : configuration.getConstraintObservers()) { - constraintObserver.register(this); - } - - if (Build.VERSION.SDK_INT < 26) { - application.startService(new Intent(application, KeepAliveService.class)); - } - - wakeUp(); - }); - } - - /** - * Adds a listener to that will be notified when the job queue has been drained. - */ - void addOnEmptyQueueListener(@NonNull EmptyQueueListener listener) { - executor.execute(() -> { - emptyQueueListeners.add(listener); - }); - } - - /** - * Removes a listener that was added via {@link #addOnEmptyQueueListener(EmptyQueueListener)}. - */ - void removeOnEmptyQueueListener(@NonNull EmptyQueueListener listener) { - executor.execute(() -> { - emptyQueueListeners.remove(listener); - }); - } - - @Override - public void onConstraintMet(@NonNull String reason) { - Log.i(TAG, "onConstraintMet(" + reason + ")"); - wakeUp(); - } - - /** - * Pokes the system to take another pass at the job queue. - */ - void wakeUp() {} - - public interface EmptyQueueListener { - void onQueueEmpty(); - } - - public static class Configuration { - - private final ExecutorFactory executorFactory; - private final List constraintObservers; - - private Configuration(@NonNull ExecutorFactory executorFactory, - @NonNull List constraintObservers) - { - this.executorFactory = executorFactory; - this.constraintObservers = constraintObservers; - } - - @NonNull ExecutorFactory getExecutorFactory() { - return executorFactory; - } - - @NonNull List getConstraintObservers() { - return constraintObservers; - } - - public static class Builder { - - private ExecutorFactory executorFactory = new DefaultExecutorFactory(); - private List constraintObservers = new ArrayList<>(); - - public @NonNull Builder setConstraintObservers(@NonNull List constraintObservers) { - this.constraintObservers = constraintObservers; - return this; - } - - public @NonNull Configuration build() { - return new Configuration(executorFactory, - new ArrayList<>(constraintObservers)); - } - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraint.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraint.java deleted file mode 100644 index 6d6fc0499f..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraint.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.impl; - -import android.app.Application; -import android.app.job.JobInfo; -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.jobmanager.Constraint; -import org.thoughtcrime.securesms.sms.TelephonyServiceState; - -public class CellServiceConstraint implements Constraint { - - public static final String KEY = "CellServiceConstraint"; - - private final Application application; - - public CellServiceConstraint(@NonNull Application application) { - this.application = application; - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public boolean isMet() { - TelephonyServiceState telephonyServiceState = new TelephonyServiceState(); - return telephonyServiceState.isConnected(application); - } - - @Override - public void applyToJobInfo(@NonNull JobInfo.Builder jobInfoBuilder) { - } - - public static final class Factory implements Constraint.Factory { - - private final Application application; - - public Factory(@NonNull Application application) { - this.application = application; - } - - @Override - public CellServiceConstraint create() { - return new CellServiceConstraint(application); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java deleted file mode 100644 index fd0971dc57..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.impl; - -import android.app.Application; -import android.content.Context; -import androidx.annotation.NonNull; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; - -import org.thoughtcrime.securesms.jobmanager.ConstraintObserver; - -public class CellServiceConstraintObserver implements ConstraintObserver { - - private static final String REASON = CellServiceConstraintObserver.class.getSimpleName(); - - private Notifier notifier; - - public CellServiceConstraintObserver(@NonNull Application application) { - TelephonyManager telephonyManager = (TelephonyManager) application.getSystemService(Context.TELEPHONY_SERVICE); - ServiceStateListener serviceStateListener = new ServiceStateListener(); - - telephonyManager.listen(serviceStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); - } - - @Override - public void register(@NonNull Notifier notifier) { - this.notifier = notifier; - } - - private class ServiceStateListener extends PhoneStateListener { - @Override - public void onServiceStateChanged(ServiceState serviceState) { - if (serviceState.getState() == ServiceState.STATE_IN_SERVICE && notifier != null) { - notifier.onConstraintMet(REASON); - } - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkConstraintObserver.java deleted file mode 100644 index ef4a61c7c5..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkConstraintObserver.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.impl; - -import android.app.Application; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.jobmanager.ConstraintObserver; - -public class NetworkConstraintObserver implements ConstraintObserver { - - private static final String REASON = NetworkConstraintObserver.class.getSimpleName(); - - private final Application application; - - public NetworkConstraintObserver(Application application) { - this.application = application; - } - - @Override - public void register(@NonNull Notifier notifier) { - application.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - NetworkConstraint constraint = new NetworkConstraint.Factory(application).create(); - - if (constraint.isMet()) { - notifier.onConstraintMet(REASON); - } - } - }, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkOrCellServiceConstraint.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkOrCellServiceConstraint.java deleted file mode 100644 index c17931f977..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/NetworkOrCellServiceConstraint.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.impl; - -import android.app.Application; -import android.app.job.JobInfo; -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.jobmanager.Constraint; - -public class NetworkOrCellServiceConstraint implements Constraint { - - public static final String KEY = "NetworkOrCellServiceConstraint"; - - private final NetworkConstraint networkConstraint; - private final CellServiceConstraint serviceConstraint; - - public NetworkOrCellServiceConstraint(@NonNull Application application) { - networkConstraint = new NetworkConstraint.Factory(application).create(); - serviceConstraint = new CellServiceConstraint.Factory(application).create(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public boolean isMet() { - return networkConstraint.isMet() || serviceConstraint.isMet(); - } - - @Override - public void applyToJobInfo(@NonNull JobInfo.Builder jobInfoBuilder) { - } - - public static class Factory implements Constraint.Factory { - - private final Application application; - - public Factory(@NonNull Application application) { - this.application = application; - } - - @Override - public NetworkOrCellServiceConstraint create() { - return new NetworkOrCellServiceConstraint(application); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraint.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraint.java deleted file mode 100644 index 32fa84b6f5..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraint.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.impl; - -import android.app.Application; -import android.app.job.JobInfo; -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.jobmanager.Constraint; -import org.session.libsession.utilities.TextSecurePreferences; - -public class SqlCipherMigrationConstraint implements Constraint { - - public static final String KEY = "SqlCipherMigrationConstraint"; - - private final Application application; - - private SqlCipherMigrationConstraint(@NonNull Application application) { - this.application = application; - } - - @Override - public boolean isMet() { - return !TextSecurePreferences.getNeedsSqlCipherMigration(application); - } - - @NonNull - @Override - public String getFactoryKey() { - return KEY; - } - - @Override - public void applyToJobInfo(@NonNull JobInfo.Builder jobInfoBuilder) { - } - - public static final class Factory implements Constraint.Factory { - - private final Application application; - - public Factory(@NonNull Application application) { - this.application = application; - } - - @Override - public SqlCipherMigrationConstraint create() { - return new SqlCipherMigrationConstraint(application); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraintObserver.java deleted file mode 100644 index 0c9225434d..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/SqlCipherMigrationConstraintObserver.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.impl; - -import androidx.annotation.NonNull; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; -import org.thoughtcrime.securesms.jobmanager.ConstraintObserver; - -public class SqlCipherMigrationConstraintObserver implements ConstraintObserver { - - private static final String REASON = SqlCipherMigrationConstraintObserver.class.getSimpleName(); - - private Notifier notifier; - - public SqlCipherMigrationConstraintObserver() { - EventBus.getDefault().register(this); - } - - @Override - public void register(@NonNull Notifier notifier) { - this.notifier = notifier; - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEvent(SqlCipherNeedsMigrationEvent event) { - if (notifier != null) notifier.onConstraintMet(REASON); - } - - public static class SqlCipherNeedsMigrationEvent { - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java deleted file mode 100644 index d892c0f439..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import android.app.Application; - -import androidx.annotation.NonNull; - -import org.session.libsession.messaging.jobs.Job; -import org.thoughtcrime.securesms.jobmanager.Constraint; -import org.thoughtcrime.securesms.jobmanager.ConstraintObserver; -import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraint; -import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraintObserver; -import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; -import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver; -import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint; -import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint; -import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public final class JobManagerFactories { - - private static Collection factoryKeys = new ArrayList<>(); - - public static Map getJobFactories() { - HashMap factoryHashMap = new HashMap() {{ - put(LocalBackupJob.Companion.getKEY(), new LocalBackupJob.Factory()); - put(RetrieveProfileAvatarJob.Companion.getKEY(), new RetrieveProfileAvatarJob.Factory()); - put(UpdateApkJob.Companion.getKEY(), new UpdateApkJob.Factory()); - }}; - factoryKeys.addAll(factoryHashMap.keySet()); - return factoryHashMap; - } - - public static Map getConstraintFactories(@NonNull Application application) { - return new HashMap() {{ - put(CellServiceConstraint.KEY, new CellServiceConstraint.Factory(application)); - put(NetworkConstraint.KEY, new NetworkConstraint.Factory(application)); - put(NetworkOrCellServiceConstraint.KEY, new NetworkOrCellServiceConstraint.Factory(application)); - put(SqlCipherMigrationConstraint.KEY, new SqlCipherMigrationConstraint.Factory(application)); - }}; - } - - public static List getConstraintObservers(@NonNull Application application) { - return Arrays.asList(new CellServiceConstraintObserver(application), - new NetworkConstraintObserver(application), - new SqlCipherMigrationConstraintObserver()); - } - - public static boolean hasFactoryForKey(String factoryKey) { - return factoryKeys.contains(factoryKey); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt index 3b6db9a76f..08ca6090bf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt @@ -5,9 +5,8 @@ import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.utilities.SSKEnvironment import org.session.libsession.utilities.recipients.Recipient -import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob +import org.session.libsession.messaging.jobs.RetrieveProfileAvatarJob class ProfileManager : SSKEnvironment.ProfileManagerProtocol { diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index d75e209d11..8ae9442748 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -38,6 +38,7 @@ interface StorageProtocol { fun getUserX25519KeyPair(): ECKeyPair fun getUserProfile(): Profile fun setUserProfilePictureURL(newProfilePicture: String) + fun // Signal fun getOrGenerateRegistrationID(): Int diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt similarity index 90% rename from app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.kt rename to libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt index a5b0fce2df..f00ba49a5f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt @@ -1,10 +1,9 @@ -package org.thoughtcrime.securesms.jobs +package org.session.libsession.messaging.jobs import android.content.Context import android.text.TextUtils import org.session.libsession.avatars.AvatarHelper -import org.session.libsession.messaging.jobs.Job -import org.session.libsession.messaging.jobs.JobDelegate +import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.utilities.Data import org.session.libsession.utilities.DownloadUtilities.downloadFile import org.session.libsession.utilities.TextSecurePreferences.Companion.setProfileAvatarId @@ -27,8 +26,6 @@ class RetrieveProfileAvatarJob(val profileAvatar: String, val recipientAddress: override var failureCount: Int = 0 override val maxFailureCount: Int = 0 - lateinit var context: Context - companion object { val TAG = RetrieveProfileAvatarJob::class.simpleName val KEY: String = "RetrieveProfileAvatarJob" @@ -39,8 +36,9 @@ class RetrieveProfileAvatarJob(val profileAvatar: String, val recipientAddress: } override fun execute(dispatcherName: String) { + val context = MessagingModuleConfiguration.shared.context + val storage = MessagingModuleConfiguration.shared.storage val recipient = Recipient.from(context, recipientAddress, true) - val database = get(context).recipientDatabase() val profileKey = recipient.resolve().profileKey if (profileKey == null || (profileKey.size != 32 && profileKey.size != 16)) { @@ -56,7 +54,7 @@ class RetrieveProfileAvatarJob(val profileAvatar: String, val recipientAddress: if (TextUtils.isEmpty(profileAvatar)) { Log.w(TAG, "Removing profile avatar for: " + recipient.address.serialize()) AvatarHelper.delete(context, recipient.address) - database.setProfileAvatar(recipient, profileAvatar) + storage.setProfileAvatar(recipient, profileAvatar) return } @@ -75,7 +73,7 @@ class RetrieveProfileAvatarJob(val profileAvatar: String, val recipientAddress: if (recipient.isLocalNumber) { setProfileAvatarId(context, SecureRandom().nextInt()) } - database.setProfileAvatar(recipient, profileAvatar) + storage.setProfileAvatar(recipient, profileAvatar) } override fun serialize(): Data { From 8d38d1c0fbbd7f3685ec7d8a53b138a5634ab482 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 9 May 2023 13:25:32 +0930 Subject: [PATCH 30/83] Fix links not working when message is partially offscreen --- .../securesms/conversation/v2/utilities/TextUtilities.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt index 800ace54c3..7a47b92756 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt @@ -38,13 +38,12 @@ object TextUtilities { fun TextView.getIntersectedModalSpans(hitRect: Rect): List { val textLayout = layout ?: return emptyList() val lineRect = Rect() - val bodyTextRect = Rect() - getGlobalVisibleRect(bodyTextRect) + val offset = intArrayOf(0, 0).also { getLocationOnScreen(it) } val textSpannable = text.toSpannable() return (0 until textLayout.lineCount).flatMap { line -> textLayout.getLineBounds(line, lineRect) - lineRect.offset(bodyTextRect.left + totalPaddingLeft, bodyTextRect.top + totalPaddingTop) - if ((Rect(lineRect)).contains(hitRect)) { + lineRect.offset(offset[0] + totalPaddingLeft, offset[1] + totalPaddingTop) + if (lineRect.contains(hitRect)) { // calculate the url span intersected with (if any) val off = textLayout.getOffsetForHorizontal(line, hitRect.left.toFloat()) // left and right will be the same textSpannable.getSpans(off, off).toList() From fa71ea1850e0d3444eac4176df2ac82002b53f96 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 9 May 2023 14:14:49 +1000 Subject: [PATCH 31/83] make RetrieveProfileAvatarJob work --- .../main/java/org/thoughtcrime/securesms/database/Storage.kt | 5 +++++ .../thoughtcrime/securesms/sskenvironment/ProfileManager.kt | 1 - .../java/org/session/libsession/database/StorageProtocol.kt | 2 +- .../java/org/session/libsession/messaging/jobs/JobQueue.kt | 2 ++ .../libsession/messaging/jobs/RetrieveProfileAvatarJob.kt | 2 -- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 3e21f63c09..54d36af896 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -77,6 +77,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, JobQueue.shared.add(RetrieveProfileAvatarJob(newValue, ourRecipient.address)) } + override fun setProfileAvatar(recipient: Recipient, profileAvatar: String) { + val database = DatabaseComponent.get(context).recipientDatabase() + database.setProfileAvatar(recipient, profileAvatar) + } + override fun getOrGenerateRegistrationID(): Int { var registrationID = TextSecurePreferences.getLocalRegistrationId(context) if (registrationID == 0) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt index 08ca6090bf..f9f5524efa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt @@ -41,7 +41,6 @@ class ProfileManager : SSKEnvironment.ProfileManagerProtocol { override fun setProfilePictureURL(context: Context, recipient: Recipient, profilePictureURL: String) { val job = RetrieveProfileAvatarJob(profilePictureURL, recipient.address) - job.context = context JobQueue.shared.add(job) val sessionID = recipient.address.serialize() val contactDatabase = DatabaseComponent.get(context).sessionContactDatabase() diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index 8ae9442748..0727d1ab56 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -38,7 +38,7 @@ interface StorageProtocol { fun getUserX25519KeyPair(): ECKeyPair fun getUserProfile(): Profile fun setUserProfilePictureURL(newProfilePicture: String) - fun + fun setProfileAvatar(recipient: Recipient, profileAvatar: String) // Signal fun getOrGenerateRegistrationID(): Int diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt index b78590c729..03b9546c4c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt @@ -125,6 +125,7 @@ class JobQueue : JobDelegate { is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob -> { txQueue.send(job) } + is RetrieveProfileAvatarJob, is AttachmentDownloadJob -> { mediaQueue.send(job) } @@ -224,6 +225,7 @@ class JobQueue : JobDelegate { GroupAvatarDownloadJob.KEY, BackgroundGroupAddJob.KEY, OpenGroupDeleteJob.KEY, + RetrieveProfileAvatarJob.KEY, ) allJobTypes.forEach { type -> resumePendingJobs(type) diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt index f00ba49a5f..8ce397a3a9 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt @@ -1,6 +1,5 @@ package org.session.libsession.messaging.jobs -import android.content.Context import android.text.TextUtils import org.session.libsession.avatars.AvatarHelper import org.session.libsession.messaging.MessagingModuleConfiguration @@ -13,7 +12,6 @@ import org.session.libsession.utilities.Address import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.streams.ProfileCipherInputStream import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get import java.io.File import java.io.FileInputStream import java.io.FileOutputStream From c8fa2d8d6e2806c5c1de493552281c9887498311 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 9 May 2023 14:51:28 +0930 Subject: [PATCH 32/83] Remove reply from context menu when you can't write --- .../securesms/conversation/v2/ConversationReactionOverlay.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java index 1d81325e03..b311327a4b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java @@ -660,7 +660,8 @@ public final class ConversationReactionOverlay extends FrameLayout { items.add(new ActionItem(R.attr.menu_select_icon, getContext().getResources().getString(R.string.conversation_context__menu_select), () -> handleActionItemClicked(Action.SELECT), getContext().getResources().getString(R.string.AccessibilityId_select))); // Reply - if (!message.isPending() && !message.isFailed()) { + boolean canWrite = openGroup == null || openGroup.getCanWrite(); + if (canWrite && !message.isPending() && !message.isFailed()) { items.add( new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_reply), () -> handleActionItemClicked(Action.REPLY), getContext().getResources().getString(R.string.AccessibilityId_reply_message)) From 4469d9754a11978e8d5f1b2d8f03f1ef9e9c982a Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 9 May 2023 15:10:03 +0930 Subject: [PATCH 33/83] Fix bubble entrance coordinates --- .../securesms/conversation/v2/ConversationActivityV2.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index cabb583085..97cf699db4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1109,12 +1109,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } }) - val contentBounds = Rect() - visibleMessageView.messageContentView.getGlobalVisibleRect(contentBounds) + val topLeft = intArrayOf(0, 0).also { visibleMessageView.messageContentView.getLocationInWindow(it) } val selectedConversationModel = SelectedConversationModel( messageContentBitmap, - contentBounds.left.toFloat(), - contentBounds.top.toFloat(), + topLeft[0].toFloat(), + topLeft[1].toFloat(), visibleMessageView.messageContentView.width, message.isOutgoing, visibleMessageView.messageContentView From d20c27d6d3ef11bfe07511393ee3afe5023217fd Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 9 May 2023 22:26:36 +0930 Subject: [PATCH 34/83] Remove laid out check before drawToBitmap --- .../securesms/conversation/v2/ConversationActivityV2.kt | 1 - .../java/org/thoughtcrime/securesms/util/ViewUtilities.kt | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index cabb583085..b2ec6d1233 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -21,7 +21,6 @@ import android.widget.Toast import androidx.activity.viewModels import androidx.annotation.DimenRes import androidx.appcompat.app.AlertDialog -import androidx.core.view.drawToBitmap import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.Observer diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt index 7b7f3a04f3..ffe5e9094f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt @@ -5,6 +5,7 @@ import android.animation.AnimatorListenerAdapter import android.animation.FloatEvaluator import android.animation.ValueAnimator import android.content.Context +import android.graphics.Bitmap import android.graphics.PointF import android.graphics.Rect import android.view.View @@ -13,6 +14,7 @@ import androidx.annotation.DimenRes import network.loki.messenger.R import org.session.libsession.utilities.getColorFromAttr import android.view.inputmethod.InputMethodManager +import androidx.core.graphics.applyCanvas fun View.contains(point: PointF): Boolean { return hitRect.contains(point.x.toInt(), point.y.toInt()) @@ -65,3 +67,9 @@ fun View.hideKeyboard() { val imm = this.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(this.windowToken, 0) } + +fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap = + Bitmap.createBitmap(width, height, config).applyCanvas { + translate(-scrollX.toFloat(), -scrollY.toFloat()) + draw(this) + } From 89545f0406176069402f5014e33a4a87de0b76a0 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 10 May 2023 15:36:10 +1000 Subject: [PATCH 35/83] further clean up --- app/src/main/AndroidManifest.xml | 6 - .../securesms/ApplicationContext.java | 7 - .../securesms/backup/BackupEvent.kt | 14 - .../securesms/backup/BackupPassphrase.java | 47 - .../securesms/backup/BackupPreferences.kt | 101 - .../securesms/backup/BackupProtos.java | 6778 ----------------- .../securesms/backup/FullBackupExporter.kt | 447 -- .../securesms/backup/FullBackupImporter.kt | 352 - .../securesms/database/JobDatabase.java | 178 - .../dependencies/DatabaseComponent.kt | 1 - .../securesms/dependencies/DatabaseModule.kt | 4 - .../securesms/jobmanager/ExecutorFactory.java | 9 - .../impl/DefaultExecutorFactory.java | 15 - .../persistence/ConstraintSpec.java | 43 - .../persistence/DependencySpec.java | 43 - .../jobmanager/persistence/FullSpec.java | 50 - .../jobmanager/persistence/JobSpec.java | 129 - .../jobmanager/persistence/JobStorage.java | 55 - .../securesms/jobs/LocalBackupJob.kt | 61 - .../securesms/jobs/UpdateApkJob.kt | 200 - .../service/LocalBackupListener.java | 41 - .../service/UpdateApkRefreshListener.java | 49 - .../thoughtcrime/securesms/util/BackupUtil.kt | 313 - 23 files changed, 8943 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/BackupEvent.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/BackupPassphrase.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/BackupPreferences.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/BackupProtos.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/ExecutorFactory.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DefaultExecutorFactory.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/ConstraintSpec.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/DependencySpec.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/FullSpec.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobSpec.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobStorage.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/BackupUtil.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index da3be785c3..2d2b2123dd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -407,12 +407,6 @@ - - - - - diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index df1bed7b3b..5a9999a7bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -55,7 +55,6 @@ import org.signal.aesgcmprovider.AesGcmProvider; import org.thoughtcrime.securesms.components.TypingStatusSender; import org.thoughtcrime.securesms.crypto.KeyPairUtilities; import org.thoughtcrime.securesms.database.EmojiSearchDatabase; -import org.thoughtcrime.securesms.database.JobDatabase; import org.thoughtcrime.securesms.database.LokiAPIDatabase; import org.thoughtcrime.securesms.database.Storage; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; @@ -78,7 +77,6 @@ import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier; import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.service.KeyCachingService; -import org.thoughtcrime.securesms.service.UpdateApkRefreshListener; import org.thoughtcrime.securesms.sskenvironment.ProfileManager; import org.thoughtcrime.securesms.sskenvironment.ReadReceiptManager; import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository; @@ -142,7 +140,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO @Inject LokiAPIDatabase lokiAPIDatabase; @Inject Storage storage; @Inject MessageDataProvider messageDataProvider; - @Inject JobDatabase jobDatabase; @Inject TextSecurePreferences textSecurePreferences; CallMessageProcessor callMessageProcessor; MessagingModuleConfiguration messagingModuleConfiguration; @@ -364,10 +361,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO private void initializePeriodicTasks() { BackgroundPollWorker.schedulePeriodic(this); - - if (BuildConfig.PLAY_STORE_DISABLED) { - UpdateApkRefreshListener.schedule(this); - } } private void initializeWebRtc() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupEvent.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupEvent.kt deleted file mode 100644 index 614dc30bba..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupEvent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.thoughtcrime.securesms.backup - -data class BackupEvent constructor(val type: Type, val count: Int, val exception: Exception?) { - - enum class Type { - PROGRESS, FINISHED - } - - companion object { - @JvmStatic fun createProgress(count: Int) = BackupEvent(Type.PROGRESS, count, null) - @JvmStatic fun createFinished() = BackupEvent(Type.FINISHED, 0, null) - @JvmStatic fun createFinished(e: Exception?) = BackupEvent(Type.FINISHED, 0, e) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPassphrase.java b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPassphrase.java deleted file mode 100644 index eec2a2e588..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPassphrase.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.thoughtcrime.securesms.backup; - -import android.content.Context; -import android.os.Build; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.thoughtcrime.securesms.crypto.KeyStoreHelper; -import org.session.libsignal.utilities.Log; -import org.session.libsession.utilities.TextSecurePreferences; - -/** - * Allows the getting and setting of the backup passphrase, which is stored encrypted on API >= 23. - */ -public class BackupPassphrase { - - private static final String TAG = BackupPassphrase.class.getSimpleName(); - - public static @Nullable String get(@NonNull Context context) { - String passphrase = TextSecurePreferences.getBackupPassphrase(context); - String encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context); - - if (Build.VERSION.SDK_INT < 23 || (passphrase == null && encryptedPassphrase == null)) { - return passphrase; - } - - if (encryptedPassphrase == null) { - Log.i(TAG, "Migrating to encrypted passphrase."); - set(context, passphrase); - encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context); - } - - KeyStoreHelper.SealedData data = KeyStoreHelper.SealedData.fromString(encryptedPassphrase); - return new String(KeyStoreHelper.unseal(data)); - } - - public static void set(@NonNull Context context, @Nullable String passphrase) { - if (passphrase == null || Build.VERSION.SDK_INT < 23) { - TextSecurePreferences.setBackupPassphrase(context, passphrase); - TextSecurePreferences.setEncryptedBackupPassphrase(context, null); - } else { - KeyStoreHelper.SealedData encryptedPassphrase = KeyStoreHelper.seal(passphrase.getBytes()); - TextSecurePreferences.setEncryptedBackupPassphrase(context, encryptedPassphrase.serialize()); - TextSecurePreferences.setBackupPassphrase(context, null); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPreferences.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPreferences.kt deleted file mode 100644 index 8ddfc23a8b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPreferences.kt +++ /dev/null @@ -1,101 +0,0 @@ -package org.thoughtcrime.securesms.backup - -import android.content.Context -import android.content.SharedPreferences -import android.os.Build -import android.preference.PreferenceManager -import android.preference.PreferenceManager.getDefaultSharedPreferencesName -import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.backup.FullBackupImporter.PREF_PREFIX_TYPE_BOOLEAN -import org.thoughtcrime.securesms.backup.FullBackupImporter.PREF_PREFIX_TYPE_INT -import java.util.* - -object BackupPreferences { - // region Backup related - fun getBackupRecords(context: Context): List { - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - val prefsFileName: String - prefsFileName = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - getDefaultSharedPreferencesName(context) - } else { - context.packageName + "_preferences" - } - val prefList: LinkedList = LinkedList() - addBackupEntryInt(prefList, preferences, prefsFileName, TextSecurePreferences.LOCAL_REGISTRATION_ID_PREF) - addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.LOCAL_NUMBER_PREF) - addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_NAME_PREF) - addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_AVATAR_URL_PREF) - addBackupEntryInt(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_AVATAR_ID_PREF) - addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_KEY_PREF) - addBackupEntryBoolean(prefList, preferences, prefsFileName, TextSecurePreferences.IS_USING_FCM) - return prefList - } - - private fun addBackupEntryString( - outPrefList: MutableList, - prefs: SharedPreferences, - prefFileName: String, - prefKey: String, - ) { - val value = prefs.getString(prefKey, null) - if (value == null) { - logBackupEntry(prefKey, false) - return - } - outPrefList.add(BackupProtos.SharedPreference.newBuilder() - .setFile(prefFileName) - .setKey(prefKey) - .setValue(value) - .build()) - logBackupEntry(prefKey, true) - } - - private fun addBackupEntryInt( - outPrefList: MutableList, - prefs: SharedPreferences, - prefFileName: String, - prefKey: String, - ) { - val value = prefs.getInt(prefKey, -1) - if (value == -1) { - logBackupEntry(prefKey, false) - return - } - outPrefList.add(BackupProtos.SharedPreference.newBuilder() - .setFile(prefFileName) - .setKey(PREF_PREFIX_TYPE_INT + prefKey) // The prefix denotes the type of the preference. - .setValue(value.toString()) - .build()) - logBackupEntry(prefKey, true) - } - - private fun addBackupEntryBoolean( - outPrefList: MutableList, - prefs: SharedPreferences, - prefFileName: String, - prefKey: String, - ) { - if (!prefs.contains(prefKey)) { - logBackupEntry(prefKey, false) - return - } - outPrefList.add(BackupProtos.SharedPreference.newBuilder() - .setFile(prefFileName) - .setKey(PREF_PREFIX_TYPE_BOOLEAN + prefKey) // The prefix denotes the type of the preference. - .setValue(prefs.getBoolean(prefKey, false).toString()) - .build()) - logBackupEntry(prefKey, true) - } - - private fun logBackupEntry(prefName: String, wasIncluded: Boolean) { - val sb = StringBuilder() - sb.append("Backup preference ") - sb.append(if (wasIncluded) "+ " else "- ") - sb.append('\"').append(prefName).append("\" ") - if (!wasIncluded) { - sb.append("(is empty and not included)") - } - Log.d("Loki", sb.toString()) - } // endregion -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupProtos.java b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupProtos.java deleted file mode 100644 index f3b78606f4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupProtos.java +++ /dev/null @@ -1,6778 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: Backups.proto - -package org.thoughtcrime.securesms.backup; - -public final class BackupProtos { - private BackupProtos() {} - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistry registry) { - } - public interface SqlStatementOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional string statement = 1; - /** - * optional string statement = 1; - */ - boolean hasStatement(); - /** - * optional string statement = 1; - */ - java.lang.String getStatement(); - /** - * optional string statement = 1; - */ - com.google.protobuf.ByteString - getStatementBytes(); - - // repeated .signal.SqlStatement.SqlParameter parameters = 2; - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - java.util.List - getParametersList(); - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getParameters(int index); - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - int getParametersCount(); - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - java.util.List - getParametersOrBuilderList(); - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder getParametersOrBuilder( - int index); - } - /** - * Protobuf type {@code signal.SqlStatement} - */ - public static final class SqlStatement extends - com.google.protobuf.GeneratedMessage - implements SqlStatementOrBuilder { - // Use SqlStatement.newBuilder() to construct. - private SqlStatement(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private SqlStatement(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final SqlStatement defaultInstance; - public static SqlStatement getDefaultInstance() { - return defaultInstance; - } - - public SqlStatement getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private SqlStatement( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - bitField0_ |= 0x00000001; - statement_ = input.readBytes(); - break; - } - case 18: { - if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { - parameters_ = new java.util.ArrayList(); - mutable_bitField0_ |= 0x00000002; - } - parameters_.add(input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.PARSER, extensionRegistry)); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { - parameters_ = java.util.Collections.unmodifiableList(parameters_); - } - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public SqlStatement parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new SqlStatement(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public interface SqlParameterOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional string stringParamter = 1; - /** - * optional string stringParamter = 1; - */ - boolean hasStringParamter(); - /** - * optional string stringParamter = 1; - */ - java.lang.String getStringParamter(); - /** - * optional string stringParamter = 1; - */ - com.google.protobuf.ByteString - getStringParamterBytes(); - - // optional uint64 integerParameter = 2; - /** - * optional uint64 integerParameter = 2; - */ - boolean hasIntegerParameter(); - /** - * optional uint64 integerParameter = 2; - */ - long getIntegerParameter(); - - // optional double doubleParameter = 3; - /** - * optional double doubleParameter = 3; - */ - boolean hasDoubleParameter(); - /** - * optional double doubleParameter = 3; - */ - double getDoubleParameter(); - - // optional bytes blobParameter = 4; - /** - * optional bytes blobParameter = 4; - */ - boolean hasBlobParameter(); - /** - * optional bytes blobParameter = 4; - */ - com.google.protobuf.ByteString getBlobParameter(); - - // optional bool nullparameter = 5; - /** - * optional bool nullparameter = 5; - */ - boolean hasNullparameter(); - /** - * optional bool nullparameter = 5; - */ - boolean getNullparameter(); - } - /** - * Protobuf type {@code signal.SqlStatement.SqlParameter} - */ - public static final class SqlParameter extends - com.google.protobuf.GeneratedMessage - implements SqlParameterOrBuilder { - // Use SqlParameter.newBuilder() to construct. - private SqlParameter(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private SqlParameter(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final SqlParameter defaultInstance; - public static SqlParameter getDefaultInstance() { - return defaultInstance; - } - - public SqlParameter getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private SqlParameter( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - bitField0_ |= 0x00000001; - stringParamter_ = input.readBytes(); - break; - } - case 16: { - bitField0_ |= 0x00000002; - integerParameter_ = input.readUInt64(); - break; - } - case 25: { - bitField0_ |= 0x00000004; - doubleParameter_ = input.readDouble(); - break; - } - case 34: { - bitField0_ |= 0x00000008; - blobParameter_ = input.readBytes(); - break; - } - case 40: { - bitField0_ |= 0x00000010; - nullparameter_ = input.readBool(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public SqlParameter parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new SqlParameter(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional string stringParamter = 1; - public static final int STRINGPARAMTER_FIELD_NUMBER = 1; - private java.lang.Object stringParamter_; - /** - * optional string stringParamter = 1; - */ - public boolean hasStringParamter() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string stringParamter = 1; - */ - public java.lang.String getStringParamter() { - java.lang.Object ref = stringParamter_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - stringParamter_ = s; - } - return s; - } - } - /** - * optional string stringParamter = 1; - */ - public com.google.protobuf.ByteString - getStringParamterBytes() { - java.lang.Object ref = stringParamter_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - stringParamter_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - // optional uint64 integerParameter = 2; - public static final int INTEGERPARAMETER_FIELD_NUMBER = 2; - private long integerParameter_; - /** - * optional uint64 integerParameter = 2; - */ - public boolean hasIntegerParameter() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint64 integerParameter = 2; - */ - public long getIntegerParameter() { - return integerParameter_; - } - - // optional double doubleParameter = 3; - public static final int DOUBLEPARAMETER_FIELD_NUMBER = 3; - private double doubleParameter_; - /** - * optional double doubleParameter = 3; - */ - public boolean hasDoubleParameter() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional double doubleParameter = 3; - */ - public double getDoubleParameter() { - return doubleParameter_; - } - - // optional bytes blobParameter = 4; - public static final int BLOBPARAMETER_FIELD_NUMBER = 4; - private com.google.protobuf.ByteString blobParameter_; - /** - * optional bytes blobParameter = 4; - */ - public boolean hasBlobParameter() { - return ((bitField0_ & 0x00000008) == 0x00000008); - } - /** - * optional bytes blobParameter = 4; - */ - public com.google.protobuf.ByteString getBlobParameter() { - return blobParameter_; - } - - // optional bool nullparameter = 5; - public static final int NULLPARAMETER_FIELD_NUMBER = 5; - private boolean nullparameter_; - /** - * optional bool nullparameter = 5; - */ - public boolean hasNullparameter() { - return ((bitField0_ & 0x00000010) == 0x00000010); - } - /** - * optional bool nullparameter = 5; - */ - public boolean getNullparameter() { - return nullparameter_; - } - - private void initFields() { - stringParamter_ = ""; - integerParameter_ = 0L; - doubleParameter_ = 0D; - blobParameter_ = com.google.protobuf.ByteString.EMPTY; - nullparameter_ = false; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeBytes(1, getStringParamterBytes()); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeUInt64(2, integerParameter_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - output.writeDouble(3, doubleParameter_); - } - if (((bitField0_ & 0x00000008) == 0x00000008)) { - output.writeBytes(4, blobParameter_); - } - if (((bitField0_ & 0x00000010) == 0x00000010)) { - output.writeBool(5, nullparameter_); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(1, getStringParamterBytes()); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt64Size(2, integerParameter_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - size += com.google.protobuf.CodedOutputStream - .computeDoubleSize(3, doubleParameter_); - } - if (((bitField0_ & 0x00000008) == 0x00000008)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(4, blobParameter_); - } - if (((bitField0_ & 0x00000010) == 0x00000010)) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(5, nullparameter_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.SqlStatement.SqlParameter} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - stringParamter_ = ""; - bitField0_ = (bitField0_ & ~0x00000001); - integerParameter_ = 0L; - bitField0_ = (bitField0_ & ~0x00000002); - doubleParameter_ = 0D; - bitField0_ = (bitField0_ & ~0x00000004); - blobParameter_ = com.google.protobuf.ByteString.EMPTY; - bitField0_ = (bitField0_ & ~0x00000008); - nullparameter_ = false; - bitField0_ = (bitField0_ & ~0x00000010); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter build() { - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter result = new org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.stringParamter_ = stringParamter_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.integerParameter_ = integerParameter_; - if (((from_bitField0_ & 0x00000004) == 0x00000004)) { - to_bitField0_ |= 0x00000004; - } - result.doubleParameter_ = doubleParameter_; - if (((from_bitField0_ & 0x00000008) == 0x00000008)) { - to_bitField0_ |= 0x00000008; - } - result.blobParameter_ = blobParameter_; - if (((from_bitField0_ & 0x00000010) == 0x00000010)) { - to_bitField0_ |= 0x00000010; - } - result.nullparameter_ = nullparameter_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance()) return this; - if (other.hasStringParamter()) { - bitField0_ |= 0x00000001; - stringParamter_ = other.stringParamter_; - onChanged(); - } - if (other.hasIntegerParameter()) { - setIntegerParameter(other.getIntegerParameter()); - } - if (other.hasDoubleParameter()) { - setDoubleParameter(other.getDoubleParameter()); - } - if (other.hasBlobParameter()) { - setBlobParameter(other.getBlobParameter()); - } - if (other.hasNullparameter()) { - setNullparameter(other.getNullparameter()); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional string stringParamter = 1; - private java.lang.Object stringParamter_ = ""; - /** - * optional string stringParamter = 1; - */ - public boolean hasStringParamter() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string stringParamter = 1; - */ - public java.lang.String getStringParamter() { - java.lang.Object ref = stringParamter_; - if (!(ref instanceof java.lang.String)) { - java.lang.String s = ((com.google.protobuf.ByteString) ref) - .toStringUtf8(); - stringParamter_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * optional string stringParamter = 1; - */ - public com.google.protobuf.ByteString - getStringParamterBytes() { - java.lang.Object ref = stringParamter_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - stringParamter_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * optional string stringParamter = 1; - */ - public Builder setStringParamter( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - stringParamter_ = value; - onChanged(); - return this; - } - /** - * optional string stringParamter = 1; - */ - public Builder clearStringParamter() { - bitField0_ = (bitField0_ & ~0x00000001); - stringParamter_ = getDefaultInstance().getStringParamter(); - onChanged(); - return this; - } - /** - * optional string stringParamter = 1; - */ - public Builder setStringParamterBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - stringParamter_ = value; - onChanged(); - return this; - } - - // optional uint64 integerParameter = 2; - private long integerParameter_ ; - /** - * optional uint64 integerParameter = 2; - */ - public boolean hasIntegerParameter() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint64 integerParameter = 2; - */ - public long getIntegerParameter() { - return integerParameter_; - } - /** - * optional uint64 integerParameter = 2; - */ - public Builder setIntegerParameter(long value) { - bitField0_ |= 0x00000002; - integerParameter_ = value; - onChanged(); - return this; - } - /** - * optional uint64 integerParameter = 2; - */ - public Builder clearIntegerParameter() { - bitField0_ = (bitField0_ & ~0x00000002); - integerParameter_ = 0L; - onChanged(); - return this; - } - - // optional double doubleParameter = 3; - private double doubleParameter_ ; - /** - * optional double doubleParameter = 3; - */ - public boolean hasDoubleParameter() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional double doubleParameter = 3; - */ - public double getDoubleParameter() { - return doubleParameter_; - } - /** - * optional double doubleParameter = 3; - */ - public Builder setDoubleParameter(double value) { - bitField0_ |= 0x00000004; - doubleParameter_ = value; - onChanged(); - return this; - } - /** - * optional double doubleParameter = 3; - */ - public Builder clearDoubleParameter() { - bitField0_ = (bitField0_ & ~0x00000004); - doubleParameter_ = 0D; - onChanged(); - return this; - } - - // optional bytes blobParameter = 4; - private com.google.protobuf.ByteString blobParameter_ = com.google.protobuf.ByteString.EMPTY; - /** - * optional bytes blobParameter = 4; - */ - public boolean hasBlobParameter() { - return ((bitField0_ & 0x00000008) == 0x00000008); - } - /** - * optional bytes blobParameter = 4; - */ - public com.google.protobuf.ByteString getBlobParameter() { - return blobParameter_; - } - /** - * optional bytes blobParameter = 4; - */ - public Builder setBlobParameter(com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000008; - blobParameter_ = value; - onChanged(); - return this; - } - /** - * optional bytes blobParameter = 4; - */ - public Builder clearBlobParameter() { - bitField0_ = (bitField0_ & ~0x00000008); - blobParameter_ = getDefaultInstance().getBlobParameter(); - onChanged(); - return this; - } - - // optional bool nullparameter = 5; - private boolean nullparameter_ ; - /** - * optional bool nullparameter = 5; - */ - public boolean hasNullparameter() { - return ((bitField0_ & 0x00000010) == 0x00000010); - } - /** - * optional bool nullparameter = 5; - */ - public boolean getNullparameter() { - return nullparameter_; - } - /** - * optional bool nullparameter = 5; - */ - public Builder setNullparameter(boolean value) { - bitField0_ |= 0x00000010; - nullparameter_ = value; - onChanged(); - return this; - } - /** - * optional bool nullparameter = 5; - */ - public Builder clearNullparameter() { - bitField0_ = (bitField0_ & ~0x00000010); - nullparameter_ = false; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:signal.SqlStatement.SqlParameter) - } - - static { - defaultInstance = new SqlParameter(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.SqlStatement.SqlParameter) - } - - private int bitField0_; - // optional string statement = 1; - public static final int STATEMENT_FIELD_NUMBER = 1; - private java.lang.Object statement_; - /** - * optional string statement = 1; - */ - public boolean hasStatement() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string statement = 1; - */ - public java.lang.String getStatement() { - java.lang.Object ref = statement_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - statement_ = s; - } - return s; - } - } - /** - * optional string statement = 1; - */ - public com.google.protobuf.ByteString - getStatementBytes() { - java.lang.Object ref = statement_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - statement_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - // repeated .signal.SqlStatement.SqlParameter parameters = 2; - public static final int PARAMETERS_FIELD_NUMBER = 2; - private java.util.List parameters_; - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public java.util.List getParametersList() { - return parameters_; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public java.util.List - getParametersOrBuilderList() { - return parameters_; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public int getParametersCount() { - return parameters_.size(); - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getParameters(int index) { - return parameters_.get(index); - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder getParametersOrBuilder( - int index) { - return parameters_.get(index); - } - - private void initFields() { - statement_ = ""; - parameters_ = java.util.Collections.emptyList(); - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeBytes(1, getStatementBytes()); - } - for (int i = 0; i < parameters_.size(); i++) { - output.writeMessage(2, parameters_.get(i)); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(1, getStatementBytes()); - } - for (int i = 0; i < parameters_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, parameters_.get(i)); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.SqlStatement} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - getParametersFieldBuilder(); - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - statement_ = ""; - bitField0_ = (bitField0_ & ~0x00000001); - if (parametersBuilder_ == null) { - parameters_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000002); - } else { - parametersBuilder_.clear(); - } - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement build() { - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement result = new org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.statement_ = statement_; - if (parametersBuilder_ == null) { - if (((bitField0_ & 0x00000002) == 0x00000002)) { - parameters_ = java.util.Collections.unmodifiableList(parameters_); - bitField0_ = (bitField0_ & ~0x00000002); - } - result.parameters_ = parameters_; - } else { - result.parameters_ = parametersBuilder_.build(); - } - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance()) return this; - if (other.hasStatement()) { - bitField0_ |= 0x00000001; - statement_ = other.statement_; - onChanged(); - } - if (parametersBuilder_ == null) { - if (!other.parameters_.isEmpty()) { - if (parameters_.isEmpty()) { - parameters_ = other.parameters_; - bitField0_ = (bitField0_ & ~0x00000002); - } else { - ensureParametersIsMutable(); - parameters_.addAll(other.parameters_); - } - onChanged(); - } - } else { - if (!other.parameters_.isEmpty()) { - if (parametersBuilder_.isEmpty()) { - parametersBuilder_.dispose(); - parametersBuilder_ = null; - parameters_ = other.parameters_; - bitField0_ = (bitField0_ & ~0x00000002); - parametersBuilder_ = - com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? - getParametersFieldBuilder() : null; - } else { - parametersBuilder_.addAllMessages(other.parameters_); - } - } - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional string statement = 1; - private java.lang.Object statement_ = ""; - /** - * optional string statement = 1; - */ - public boolean hasStatement() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string statement = 1; - */ - public java.lang.String getStatement() { - java.lang.Object ref = statement_; - if (!(ref instanceof java.lang.String)) { - java.lang.String s = ((com.google.protobuf.ByteString) ref) - .toStringUtf8(); - statement_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * optional string statement = 1; - */ - public com.google.protobuf.ByteString - getStatementBytes() { - java.lang.Object ref = statement_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - statement_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * optional string statement = 1; - */ - public Builder setStatement( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - statement_ = value; - onChanged(); - return this; - } - /** - * optional string statement = 1; - */ - public Builder clearStatement() { - bitField0_ = (bitField0_ & ~0x00000001); - statement_ = getDefaultInstance().getStatement(); - onChanged(); - return this; - } - /** - * optional string statement = 1; - */ - public Builder setStatementBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - statement_ = value; - onChanged(); - return this; - } - - // repeated .signal.SqlStatement.SqlParameter parameters = 2; - private java.util.List parameters_ = - java.util.Collections.emptyList(); - private void ensureParametersIsMutable() { - if (!((bitField0_ & 0x00000002) == 0x00000002)) { - parameters_ = new java.util.ArrayList(parameters_); - bitField0_ |= 0x00000002; - } - } - - private com.google.protobuf.RepeatedFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder> parametersBuilder_; - - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public java.util.List getParametersList() { - if (parametersBuilder_ == null) { - return java.util.Collections.unmodifiableList(parameters_); - } else { - return parametersBuilder_.getMessageList(); - } - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public int getParametersCount() { - if (parametersBuilder_ == null) { - return parameters_.size(); - } else { - return parametersBuilder_.getCount(); - } - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getParameters(int index) { - if (parametersBuilder_ == null) { - return parameters_.get(index); - } else { - return parametersBuilder_.getMessage(index); - } - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder setParameters( - int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter value) { - if (parametersBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureParametersIsMutable(); - parameters_.set(index, value); - onChanged(); - } else { - parametersBuilder_.setMessage(index, value); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder setParameters( - int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder builderForValue) { - if (parametersBuilder_ == null) { - ensureParametersIsMutable(); - parameters_.set(index, builderForValue.build()); - onChanged(); - } else { - parametersBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder addParameters(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter value) { - if (parametersBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureParametersIsMutable(); - parameters_.add(value); - onChanged(); - } else { - parametersBuilder_.addMessage(value); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder addParameters( - int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter value) { - if (parametersBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureParametersIsMutable(); - parameters_.add(index, value); - onChanged(); - } else { - parametersBuilder_.addMessage(index, value); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder addParameters( - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder builderForValue) { - if (parametersBuilder_ == null) { - ensureParametersIsMutable(); - parameters_.add(builderForValue.build()); - onChanged(); - } else { - parametersBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder addParameters( - int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder builderForValue) { - if (parametersBuilder_ == null) { - ensureParametersIsMutable(); - parameters_.add(index, builderForValue.build()); - onChanged(); - } else { - parametersBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder addAllParameters( - java.lang.Iterable values) { - if (parametersBuilder_ == null) { - ensureParametersIsMutable(); - super.addAll(values, parameters_); - onChanged(); - } else { - parametersBuilder_.addAllMessages(values); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder clearParameters() { - if (parametersBuilder_ == null) { - parameters_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - } else { - parametersBuilder_.clear(); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public Builder removeParameters(int index) { - if (parametersBuilder_ == null) { - ensureParametersIsMutable(); - parameters_.remove(index); - onChanged(); - } else { - parametersBuilder_.remove(index); - } - return this; - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder getParametersBuilder( - int index) { - return getParametersFieldBuilder().getBuilder(index); - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder getParametersOrBuilder( - int index) { - if (parametersBuilder_ == null) { - return parameters_.get(index); } else { - return parametersBuilder_.getMessageOrBuilder(index); - } - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public java.util.List - getParametersOrBuilderList() { - if (parametersBuilder_ != null) { - return parametersBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(parameters_); - } - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder addParametersBuilder() { - return getParametersFieldBuilder().addBuilder( - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance()); - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder addParametersBuilder( - int index) { - return getParametersFieldBuilder().addBuilder( - index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance()); - } - /** - * repeated .signal.SqlStatement.SqlParameter parameters = 2; - */ - public java.util.List - getParametersBuilderList() { - return getParametersFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder> - getParametersFieldBuilder() { - if (parametersBuilder_ == null) { - parametersBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder>( - parameters_, - ((bitField0_ & 0x00000002) == 0x00000002), - getParentForChildren(), - isClean()); - parameters_ = null; - } - return parametersBuilder_; - } - - // @@protoc_insertion_point(builder_scope:signal.SqlStatement) - } - - static { - defaultInstance = new SqlStatement(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.SqlStatement) - } - - public interface SharedPreferenceOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional string file = 1; - /** - * optional string file = 1; - */ - boolean hasFile(); - /** - * optional string file = 1; - */ - java.lang.String getFile(); - /** - * optional string file = 1; - */ - com.google.protobuf.ByteString - getFileBytes(); - - // optional string key = 2; - /** - * optional string key = 2; - */ - boolean hasKey(); - /** - * optional string key = 2; - */ - java.lang.String getKey(); - /** - * optional string key = 2; - */ - com.google.protobuf.ByteString - getKeyBytes(); - - // optional string value = 3; - /** - * optional string value = 3; - */ - boolean hasValue(); - /** - * optional string value = 3; - */ - java.lang.String getValue(); - /** - * optional string value = 3; - */ - com.google.protobuf.ByteString - getValueBytes(); - } - /** - * Protobuf type {@code signal.SharedPreference} - */ - public static final class SharedPreference extends - com.google.protobuf.GeneratedMessage - implements SharedPreferenceOrBuilder { - // Use SharedPreference.newBuilder() to construct. - private SharedPreference(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private SharedPreference(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final SharedPreference defaultInstance; - public static SharedPreference getDefaultInstance() { - return defaultInstance; - } - - public SharedPreference getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private SharedPreference( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - bitField0_ |= 0x00000001; - file_ = input.readBytes(); - break; - } - case 18: { - bitField0_ |= 0x00000002; - key_ = input.readBytes(); - break; - } - case 26: { - bitField0_ |= 0x00000004; - value_ = input.readBytes(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.class, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public SharedPreference parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new SharedPreference(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional string file = 1; - public static final int FILE_FIELD_NUMBER = 1; - private java.lang.Object file_; - /** - * optional string file = 1; - */ - public boolean hasFile() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string file = 1; - */ - public java.lang.String getFile() { - java.lang.Object ref = file_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - file_ = s; - } - return s; - } - } - /** - * optional string file = 1; - */ - public com.google.protobuf.ByteString - getFileBytes() { - java.lang.Object ref = file_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - file_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - // optional string key = 2; - public static final int KEY_FIELD_NUMBER = 2; - private java.lang.Object key_; - /** - * optional string key = 2; - */ - public boolean hasKey() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional string key = 2; - */ - public java.lang.String getKey() { - java.lang.Object ref = key_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - key_ = s; - } - return s; - } - } - /** - * optional string key = 2; - */ - public com.google.protobuf.ByteString - getKeyBytes() { - java.lang.Object ref = key_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - key_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - // optional string value = 3; - public static final int VALUE_FIELD_NUMBER = 3; - private java.lang.Object value_; - /** - * optional string value = 3; - */ - public boolean hasValue() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional string value = 3; - */ - public java.lang.String getValue() { - java.lang.Object ref = value_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - value_ = s; - } - return s; - } - } - /** - * optional string value = 3; - */ - public com.google.protobuf.ByteString - getValueBytes() { - java.lang.Object ref = value_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - value_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private void initFields() { - file_ = ""; - key_ = ""; - value_ = ""; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeBytes(1, getFileBytes()); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeBytes(2, getKeyBytes()); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - output.writeBytes(3, getValueBytes()); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(1, getFileBytes()); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(2, getKeyBytes()); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(3, getValueBytes()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.SharedPreference} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.class, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - file_ = ""; - bitField0_ = (bitField0_ & ~0x00000001); - key_ = ""; - bitField0_ = (bitField0_ & ~0x00000002); - value_ = ""; - bitField0_ = (bitField0_ & ~0x00000004); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference build() { - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference result = new org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.file_ = file_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.key_ = key_; - if (((from_bitField0_ & 0x00000004) == 0x00000004)) { - to_bitField0_ |= 0x00000004; - } - result.value_ = value_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance()) return this; - if (other.hasFile()) { - bitField0_ |= 0x00000001; - file_ = other.file_; - onChanged(); - } - if (other.hasKey()) { - bitField0_ |= 0x00000002; - key_ = other.key_; - onChanged(); - } - if (other.hasValue()) { - bitField0_ |= 0x00000004; - value_ = other.value_; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional string file = 1; - private java.lang.Object file_ = ""; - /** - * optional string file = 1; - */ - public boolean hasFile() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string file = 1; - */ - public java.lang.String getFile() { - java.lang.Object ref = file_; - if (!(ref instanceof java.lang.String)) { - java.lang.String s = ((com.google.protobuf.ByteString) ref) - .toStringUtf8(); - file_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * optional string file = 1; - */ - public com.google.protobuf.ByteString - getFileBytes() { - java.lang.Object ref = file_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - file_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * optional string file = 1; - */ - public Builder setFile( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - file_ = value; - onChanged(); - return this; - } - /** - * optional string file = 1; - */ - public Builder clearFile() { - bitField0_ = (bitField0_ & ~0x00000001); - file_ = getDefaultInstance().getFile(); - onChanged(); - return this; - } - /** - * optional string file = 1; - */ - public Builder setFileBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - file_ = value; - onChanged(); - return this; - } - - // optional string key = 2; - private java.lang.Object key_ = ""; - /** - * optional string key = 2; - */ - public boolean hasKey() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional string key = 2; - */ - public java.lang.String getKey() { - java.lang.Object ref = key_; - if (!(ref instanceof java.lang.String)) { - java.lang.String s = ((com.google.protobuf.ByteString) ref) - .toStringUtf8(); - key_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * optional string key = 2; - */ - public com.google.protobuf.ByteString - getKeyBytes() { - java.lang.Object ref = key_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - key_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * optional string key = 2; - */ - public Builder setKey( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000002; - key_ = value; - onChanged(); - return this; - } - /** - * optional string key = 2; - */ - public Builder clearKey() { - bitField0_ = (bitField0_ & ~0x00000002); - key_ = getDefaultInstance().getKey(); - onChanged(); - return this; - } - /** - * optional string key = 2; - */ - public Builder setKeyBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000002; - key_ = value; - onChanged(); - return this; - } - - // optional string value = 3; - private java.lang.Object value_ = ""; - /** - * optional string value = 3; - */ - public boolean hasValue() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional string value = 3; - */ - public java.lang.String getValue() { - java.lang.Object ref = value_; - if (!(ref instanceof java.lang.String)) { - java.lang.String s = ((com.google.protobuf.ByteString) ref) - .toStringUtf8(); - value_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * optional string value = 3; - */ - public com.google.protobuf.ByteString - getValueBytes() { - java.lang.Object ref = value_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - value_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * optional string value = 3; - */ - public Builder setValue( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000004; - value_ = value; - onChanged(); - return this; - } - /** - * optional string value = 3; - */ - public Builder clearValue() { - bitField0_ = (bitField0_ & ~0x00000004); - value_ = getDefaultInstance().getValue(); - onChanged(); - return this; - } - /** - * optional string value = 3; - */ - public Builder setValueBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000004; - value_ = value; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:signal.SharedPreference) - } - - static { - defaultInstance = new SharedPreference(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.SharedPreference) - } - - public interface AttachmentOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional uint64 rowId = 1; - /** - * optional uint64 rowId = 1; - */ - boolean hasRowId(); - /** - * optional uint64 rowId = 1; - */ - long getRowId(); - - // optional uint64 attachmentId = 2; - /** - * optional uint64 attachmentId = 2; - */ - boolean hasAttachmentId(); - /** - * optional uint64 attachmentId = 2; - */ - long getAttachmentId(); - - // optional uint32 length = 3; - /** - * optional uint32 length = 3; - */ - boolean hasLength(); - /** - * optional uint32 length = 3; - */ - int getLength(); - } - /** - * Protobuf type {@code signal.Attachment} - */ - public static final class Attachment extends - com.google.protobuf.GeneratedMessage - implements AttachmentOrBuilder { - // Use Attachment.newBuilder() to construct. - private Attachment(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private Attachment(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final Attachment defaultInstance; - public static Attachment getDefaultInstance() { - return defaultInstance; - } - - public Attachment getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Attachment( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 8: { - bitField0_ |= 0x00000001; - rowId_ = input.readUInt64(); - break; - } - case 16: { - bitField0_ |= 0x00000002; - attachmentId_ = input.readUInt64(); - break; - } - case 24: { - bitField0_ |= 0x00000004; - length_ = input.readUInt32(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Attachment.class, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public Attachment parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Attachment(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional uint64 rowId = 1; - public static final int ROWID_FIELD_NUMBER = 1; - private long rowId_; - /** - * optional uint64 rowId = 1; - */ - public boolean hasRowId() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional uint64 rowId = 1; - */ - public long getRowId() { - return rowId_; - } - - // optional uint64 attachmentId = 2; - public static final int ATTACHMENTID_FIELD_NUMBER = 2; - private long attachmentId_; - /** - * optional uint64 attachmentId = 2; - */ - public boolean hasAttachmentId() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint64 attachmentId = 2; - */ - public long getAttachmentId() { - return attachmentId_; - } - - // optional uint32 length = 3; - public static final int LENGTH_FIELD_NUMBER = 3; - private int length_; - /** - * optional uint32 length = 3; - */ - public boolean hasLength() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional uint32 length = 3; - */ - public int getLength() { - return length_; - } - - private void initFields() { - rowId_ = 0L; - attachmentId_ = 0L; - length_ = 0; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeUInt64(1, rowId_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeUInt64(2, attachmentId_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - output.writeUInt32(3, length_); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt64Size(1, rowId_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt64Size(2, attachmentId_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(3, length_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Attachment prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.Attachment} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Attachment.class, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Attachment.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - rowId_ = 0L; - bitField0_ = (bitField0_ & ~0x00000001); - attachmentId_ = 0L; - bitField0_ = (bitField0_ & ~0x00000002); - length_ = 0; - bitField0_ = (bitField0_ & ~0x00000004); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Attachment getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Attachment build() { - org.thoughtcrime.securesms.backup.BackupProtos.Attachment result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Attachment buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.Attachment result = new org.thoughtcrime.securesms.backup.BackupProtos.Attachment(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.rowId_ = rowId_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.attachmentId_ = attachmentId_; - if (((from_bitField0_ & 0x00000004) == 0x00000004)) { - to_bitField0_ |= 0x00000004; - } - result.length_ = length_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Attachment) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Attachment)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Attachment other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance()) return this; - if (other.hasRowId()) { - setRowId(other.getRowId()); - } - if (other.hasAttachmentId()) { - setAttachmentId(other.getAttachmentId()); - } - if (other.hasLength()) { - setLength(other.getLength()); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.Attachment parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Attachment) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional uint64 rowId = 1; - private long rowId_ ; - /** - * optional uint64 rowId = 1; - */ - public boolean hasRowId() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional uint64 rowId = 1; - */ - public long getRowId() { - return rowId_; - } - /** - * optional uint64 rowId = 1; - */ - public Builder setRowId(long value) { - bitField0_ |= 0x00000001; - rowId_ = value; - onChanged(); - return this; - } - /** - * optional uint64 rowId = 1; - */ - public Builder clearRowId() { - bitField0_ = (bitField0_ & ~0x00000001); - rowId_ = 0L; - onChanged(); - return this; - } - - // optional uint64 attachmentId = 2; - private long attachmentId_ ; - /** - * optional uint64 attachmentId = 2; - */ - public boolean hasAttachmentId() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint64 attachmentId = 2; - */ - public long getAttachmentId() { - return attachmentId_; - } - /** - * optional uint64 attachmentId = 2; - */ - public Builder setAttachmentId(long value) { - bitField0_ |= 0x00000002; - attachmentId_ = value; - onChanged(); - return this; - } - /** - * optional uint64 attachmentId = 2; - */ - public Builder clearAttachmentId() { - bitField0_ = (bitField0_ & ~0x00000002); - attachmentId_ = 0L; - onChanged(); - return this; - } - - // optional uint32 length = 3; - private int length_ ; - /** - * optional uint32 length = 3; - */ - public boolean hasLength() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional uint32 length = 3; - */ - public int getLength() { - return length_; - } - /** - * optional uint32 length = 3; - */ - public Builder setLength(int value) { - bitField0_ |= 0x00000004; - length_ = value; - onChanged(); - return this; - } - /** - * optional uint32 length = 3; - */ - public Builder clearLength() { - bitField0_ = (bitField0_ & ~0x00000004); - length_ = 0; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:signal.Attachment) - } - - static { - defaultInstance = new Attachment(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.Attachment) - } - - public interface StickerOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional uint64 rowId = 1; - /** - * optional uint64 rowId = 1; - */ - boolean hasRowId(); - /** - * optional uint64 rowId = 1; - */ - long getRowId(); - - // optional uint32 length = 2; - /** - * optional uint32 length = 2; - */ - boolean hasLength(); - /** - * optional uint32 length = 2; - */ - int getLength(); - } - /** - * Protobuf type {@code signal.Sticker} - */ - public static final class Sticker extends - com.google.protobuf.GeneratedMessage - implements StickerOrBuilder { - // Use Sticker.newBuilder() to construct. - private Sticker(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private Sticker(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final Sticker defaultInstance; - public static Sticker getDefaultInstance() { - return defaultInstance; - } - - public Sticker getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Sticker( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 8: { - bitField0_ |= 0x00000001; - rowId_ = input.readUInt64(); - break; - } - case 16: { - bitField0_ |= 0x00000002; - length_ = input.readUInt32(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Sticker.class, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public Sticker parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Sticker(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional uint64 rowId = 1; - public static final int ROWID_FIELD_NUMBER = 1; - private long rowId_; - /** - * optional uint64 rowId = 1; - */ - public boolean hasRowId() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional uint64 rowId = 1; - */ - public long getRowId() { - return rowId_; - } - - // optional uint32 length = 2; - public static final int LENGTH_FIELD_NUMBER = 2; - private int length_; - /** - * optional uint32 length = 2; - */ - public boolean hasLength() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint32 length = 2; - */ - public int getLength() { - return length_; - } - - private void initFields() { - rowId_ = 0L; - length_ = 0; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeUInt64(1, rowId_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeUInt32(2, length_); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt64Size(1, rowId_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(2, length_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Sticker prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.Sticker} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Sticker.class, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Sticker.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - rowId_ = 0L; - bitField0_ = (bitField0_ & ~0x00000001); - length_ = 0; - bitField0_ = (bitField0_ & ~0x00000002); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Sticker getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Sticker build() { - org.thoughtcrime.securesms.backup.BackupProtos.Sticker result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Sticker buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.Sticker result = new org.thoughtcrime.securesms.backup.BackupProtos.Sticker(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.rowId_ = rowId_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.length_ = length_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Sticker) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Sticker)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Sticker other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance()) return this; - if (other.hasRowId()) { - setRowId(other.getRowId()); - } - if (other.hasLength()) { - setLength(other.getLength()); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.Sticker parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Sticker) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional uint64 rowId = 1; - private long rowId_ ; - /** - * optional uint64 rowId = 1; - */ - public boolean hasRowId() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional uint64 rowId = 1; - */ - public long getRowId() { - return rowId_; - } - /** - * optional uint64 rowId = 1; - */ - public Builder setRowId(long value) { - bitField0_ |= 0x00000001; - rowId_ = value; - onChanged(); - return this; - } - /** - * optional uint64 rowId = 1; - */ - public Builder clearRowId() { - bitField0_ = (bitField0_ & ~0x00000001); - rowId_ = 0L; - onChanged(); - return this; - } - - // optional uint32 length = 2; - private int length_ ; - /** - * optional uint32 length = 2; - */ - public boolean hasLength() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint32 length = 2; - */ - public int getLength() { - return length_; - } - /** - * optional uint32 length = 2; - */ - public Builder setLength(int value) { - bitField0_ |= 0x00000002; - length_ = value; - onChanged(); - return this; - } - /** - * optional uint32 length = 2; - */ - public Builder clearLength() { - bitField0_ = (bitField0_ & ~0x00000002); - length_ = 0; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:signal.Sticker) - } - - static { - defaultInstance = new Sticker(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.Sticker) - } - - public interface AvatarOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional string name = 1; - /** - * optional string name = 1; - */ - boolean hasName(); - /** - * optional string name = 1; - */ - java.lang.String getName(); - /** - * optional string name = 1; - */ - com.google.protobuf.ByteString - getNameBytes(); - - // optional uint32 length = 2; - /** - * optional uint32 length = 2; - */ - boolean hasLength(); - /** - * optional uint32 length = 2; - */ - int getLength(); - } - /** - * Protobuf type {@code signal.Avatar} - */ - public static final class Avatar extends - com.google.protobuf.GeneratedMessage - implements AvatarOrBuilder { - // Use Avatar.newBuilder() to construct. - private Avatar(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private Avatar(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final Avatar defaultInstance; - public static Avatar getDefaultInstance() { - return defaultInstance; - } - - public Avatar getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Avatar( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - bitField0_ |= 0x00000001; - name_ = input.readBytes(); - break; - } - case 16: { - bitField0_ |= 0x00000002; - length_ = input.readUInt32(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Avatar.class, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public Avatar parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Avatar(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional string name = 1; - public static final int NAME_FIELD_NUMBER = 1; - private java.lang.Object name_; - /** - * optional string name = 1; - */ - public boolean hasName() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string name = 1; - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - name_ = s; - } - return s; - } - } - /** - * optional string name = 1; - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - // optional uint32 length = 2; - public static final int LENGTH_FIELD_NUMBER = 2; - private int length_; - /** - * optional uint32 length = 2; - */ - public boolean hasLength() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint32 length = 2; - */ - public int getLength() { - return length_; - } - - private void initFields() { - name_ = ""; - length_ = 0; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeBytes(1, getNameBytes()); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeUInt32(2, length_); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(1, getNameBytes()); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(2, length_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Avatar prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.Avatar} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Avatar.class, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Avatar.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - name_ = ""; - bitField0_ = (bitField0_ & ~0x00000001); - length_ = 0; - bitField0_ = (bitField0_ & ~0x00000002); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Avatar getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Avatar build() { - org.thoughtcrime.securesms.backup.BackupProtos.Avatar result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Avatar buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.Avatar result = new org.thoughtcrime.securesms.backup.BackupProtos.Avatar(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.name_ = name_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.length_ = length_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Avatar) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Avatar)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Avatar other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance()) return this; - if (other.hasName()) { - bitField0_ |= 0x00000001; - name_ = other.name_; - onChanged(); - } - if (other.hasLength()) { - setLength(other.getLength()); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.Avatar parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Avatar) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional string name = 1; - private java.lang.Object name_ = ""; - /** - * optional string name = 1; - */ - public boolean hasName() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional string name = 1; - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - java.lang.String s = ((com.google.protobuf.ByteString) ref) - .toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * optional string name = 1; - */ - public com.google.protobuf.ByteString - getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * optional string name = 1; - */ - public Builder setName( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - name_ = value; - onChanged(); - return this; - } - /** - * optional string name = 1; - */ - public Builder clearName() { - bitField0_ = (bitField0_ & ~0x00000001); - name_ = getDefaultInstance().getName(); - onChanged(); - return this; - } - /** - * optional string name = 1; - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - name_ = value; - onChanged(); - return this; - } - - // optional uint32 length = 2; - private int length_ ; - /** - * optional uint32 length = 2; - */ - public boolean hasLength() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional uint32 length = 2; - */ - public int getLength() { - return length_; - } - /** - * optional uint32 length = 2; - */ - public Builder setLength(int value) { - bitField0_ |= 0x00000002; - length_ = value; - onChanged(); - return this; - } - /** - * optional uint32 length = 2; - */ - public Builder clearLength() { - bitField0_ = (bitField0_ & ~0x00000002); - length_ = 0; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:signal.Avatar) - } - - static { - defaultInstance = new Avatar(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.Avatar) - } - - public interface DatabaseVersionOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional uint32 version = 1; - /** - * optional uint32 version = 1; - */ - boolean hasVersion(); - /** - * optional uint32 version = 1; - */ - int getVersion(); - } - /** - * Protobuf type {@code signal.DatabaseVersion} - */ - public static final class DatabaseVersion extends - com.google.protobuf.GeneratedMessage - implements DatabaseVersionOrBuilder { - // Use DatabaseVersion.newBuilder() to construct. - private DatabaseVersion(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private DatabaseVersion(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final DatabaseVersion defaultInstance; - public static DatabaseVersion getDefaultInstance() { - return defaultInstance; - } - - public DatabaseVersion getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private DatabaseVersion( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 8: { - bitField0_ |= 0x00000001; - version_ = input.readUInt32(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.class, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public DatabaseVersion parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new DatabaseVersion(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional uint32 version = 1; - public static final int VERSION_FIELD_NUMBER = 1; - private int version_; - /** - * optional uint32 version = 1; - */ - public boolean hasVersion() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional uint32 version = 1; - */ - public int getVersion() { - return version_; - } - - private void initFields() { - version_ = 0; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeUInt32(1, version_); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(1, version_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.DatabaseVersion} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.class, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - version_ = 0; - bitField0_ = (bitField0_ & ~0x00000001); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion build() { - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion result = new org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.version_ = version_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance()) return this; - if (other.hasVersion()) { - setVersion(other.getVersion()); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional uint32 version = 1; - private int version_ ; - /** - * optional uint32 version = 1; - */ - public boolean hasVersion() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional uint32 version = 1; - */ - public int getVersion() { - return version_; - } - /** - * optional uint32 version = 1; - */ - public Builder setVersion(int value) { - bitField0_ |= 0x00000001; - version_ = value; - onChanged(); - return this; - } - /** - * optional uint32 version = 1; - */ - public Builder clearVersion() { - bitField0_ = (bitField0_ & ~0x00000001); - version_ = 0; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:signal.DatabaseVersion) - } - - static { - defaultInstance = new DatabaseVersion(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.DatabaseVersion) - } - - public interface HeaderOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional bytes iv = 1; - /** - * optional bytes iv = 1; - */ - boolean hasIv(); - /** - * optional bytes iv = 1; - */ - com.google.protobuf.ByteString getIv(); - - // optional bytes salt = 2; - /** - * optional bytes salt = 2; - */ - boolean hasSalt(); - /** - * optional bytes salt = 2; - */ - com.google.protobuf.ByteString getSalt(); - } - /** - * Protobuf type {@code signal.Header} - */ - public static final class Header extends - com.google.protobuf.GeneratedMessage - implements HeaderOrBuilder { - // Use Header.newBuilder() to construct. - private Header(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private Header(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final Header defaultInstance; - public static Header getDefaultInstance() { - return defaultInstance; - } - - public Header getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Header( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - bitField0_ |= 0x00000001; - iv_ = input.readBytes(); - break; - } - case 18: { - bitField0_ |= 0x00000002; - salt_ = input.readBytes(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Header.class, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder.class); - } - - public static com.google.protobuf.Parser
PARSER = - new com.google.protobuf.AbstractParser
() { - public Header parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Header(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser
getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional bytes iv = 1; - public static final int IV_FIELD_NUMBER = 1; - private com.google.protobuf.ByteString iv_; - /** - * optional bytes iv = 1; - */ - public boolean hasIv() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional bytes iv = 1; - */ - public com.google.protobuf.ByteString getIv() { - return iv_; - } - - // optional bytes salt = 2; - public static final int SALT_FIELD_NUMBER = 2; - private com.google.protobuf.ByteString salt_; - /** - * optional bytes salt = 2; - */ - public boolean hasSalt() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional bytes salt = 2; - */ - public com.google.protobuf.ByteString getSalt() { - return salt_; - } - - private void initFields() { - iv_ = com.google.protobuf.ByteString.EMPTY; - salt_ = com.google.protobuf.ByteString.EMPTY; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeBytes(1, iv_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeBytes(2, salt_); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(1, iv_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(2, salt_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Header prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.Header} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.Header.class, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Header.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - iv_ = com.google.protobuf.ByteString.EMPTY; - bitField0_ = (bitField0_ & ~0x00000001); - salt_ = com.google.protobuf.ByteString.EMPTY; - bitField0_ = (bitField0_ & ~0x00000002); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Header getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Header build() { - org.thoughtcrime.securesms.backup.BackupProtos.Header result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.Header buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.Header result = new org.thoughtcrime.securesms.backup.BackupProtos.Header(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.iv_ = iv_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.salt_ = salt_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Header) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Header)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Header other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance()) return this; - if (other.hasIv()) { - setIv(other.getIv()); - } - if (other.hasSalt()) { - setSalt(other.getSalt()); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.Header parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Header) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional bytes iv = 1; - private com.google.protobuf.ByteString iv_ = com.google.protobuf.ByteString.EMPTY; - /** - * optional bytes iv = 1; - */ - public boolean hasIv() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional bytes iv = 1; - */ - public com.google.protobuf.ByteString getIv() { - return iv_; - } - /** - * optional bytes iv = 1; - */ - public Builder setIv(com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - iv_ = value; - onChanged(); - return this; - } - /** - * optional bytes iv = 1; - */ - public Builder clearIv() { - bitField0_ = (bitField0_ & ~0x00000001); - iv_ = getDefaultInstance().getIv(); - onChanged(); - return this; - } - - // optional bytes salt = 2; - private com.google.protobuf.ByteString salt_ = com.google.protobuf.ByteString.EMPTY; - /** - * optional bytes salt = 2; - */ - public boolean hasSalt() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional bytes salt = 2; - */ - public com.google.protobuf.ByteString getSalt() { - return salt_; - } - /** - * optional bytes salt = 2; - */ - public Builder setSalt(com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000002; - salt_ = value; - onChanged(); - return this; - } - /** - * optional bytes salt = 2; - */ - public Builder clearSalt() { - bitField0_ = (bitField0_ & ~0x00000002); - salt_ = getDefaultInstance().getSalt(); - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:signal.Header) - } - - static { - defaultInstance = new Header(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.Header) - } - - public interface BackupFrameOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // optional .signal.Header header = 1; - /** - * optional .signal.Header header = 1; - */ - boolean hasHeader(); - /** - * optional .signal.Header header = 1; - */ - org.thoughtcrime.securesms.backup.BackupProtos.Header getHeader(); - /** - * optional .signal.Header header = 1; - */ - org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder getHeaderOrBuilder(); - - // optional .signal.SqlStatement statement = 2; - /** - * optional .signal.SqlStatement statement = 2; - */ - boolean hasStatement(); - /** - * optional .signal.SqlStatement statement = 2; - */ - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getStatement(); - /** - * optional .signal.SqlStatement statement = 2; - */ - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder getStatementOrBuilder(); - - // optional .signal.SharedPreference preference = 3; - /** - * optional .signal.SharedPreference preference = 3; - */ - boolean hasPreference(); - /** - * optional .signal.SharedPreference preference = 3; - */ - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getPreference(); - /** - * optional .signal.SharedPreference preference = 3; - */ - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder getPreferenceOrBuilder(); - - // optional .signal.Attachment attachment = 4; - /** - * optional .signal.Attachment attachment = 4; - */ - boolean hasAttachment(); - /** - * optional .signal.Attachment attachment = 4; - */ - org.thoughtcrime.securesms.backup.BackupProtos.Attachment getAttachment(); - /** - * optional .signal.Attachment attachment = 4; - */ - org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder getAttachmentOrBuilder(); - - // optional .signal.DatabaseVersion version = 5; - /** - * optional .signal.DatabaseVersion version = 5; - */ - boolean hasVersion(); - /** - * optional .signal.DatabaseVersion version = 5; - */ - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getVersion(); - /** - * optional .signal.DatabaseVersion version = 5; - */ - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder getVersionOrBuilder(); - - // optional bool end = 6; - /** - * optional bool end = 6; - */ - boolean hasEnd(); - /** - * optional bool end = 6; - */ - boolean getEnd(); - - // optional .signal.Avatar avatar = 7; - /** - * optional .signal.Avatar avatar = 7; - */ - boolean hasAvatar(); - /** - * optional .signal.Avatar avatar = 7; - */ - org.thoughtcrime.securesms.backup.BackupProtos.Avatar getAvatar(); - /** - * optional .signal.Avatar avatar = 7; - */ - org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder getAvatarOrBuilder(); - - // optional .signal.Sticker sticker = 8; - /** - * optional .signal.Sticker sticker = 8; - */ - boolean hasSticker(); - /** - * optional .signal.Sticker sticker = 8; - */ - org.thoughtcrime.securesms.backup.BackupProtos.Sticker getSticker(); - /** - * optional .signal.Sticker sticker = 8; - */ - org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder getStickerOrBuilder(); - } - /** - * Protobuf type {@code signal.BackupFrame} - */ - public static final class BackupFrame extends - com.google.protobuf.GeneratedMessage - implements BackupFrameOrBuilder { - // Use BackupFrame.newBuilder() to construct. - private BackupFrame(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private BackupFrame(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final BackupFrame defaultInstance; - public static BackupFrame getDefaultInstance() { - return defaultInstance; - } - - public BackupFrame getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private BackupFrame( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder subBuilder = null; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - subBuilder = header_.toBuilder(); - } - header_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Header.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(header_); - header_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000001; - break; - } - case 18: { - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder subBuilder = null; - if (((bitField0_ & 0x00000002) == 0x00000002)) { - subBuilder = statement_.toBuilder(); - } - statement_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(statement_); - statement_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000002; - break; - } - case 26: { - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder subBuilder = null; - if (((bitField0_ & 0x00000004) == 0x00000004)) { - subBuilder = preference_.toBuilder(); - } - preference_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(preference_); - preference_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000004; - break; - } - case 34: { - org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder subBuilder = null; - if (((bitField0_ & 0x00000008) == 0x00000008)) { - subBuilder = attachment_.toBuilder(); - } - attachment_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Attachment.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(attachment_); - attachment_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000008; - break; - } - case 42: { - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder subBuilder = null; - if (((bitField0_ & 0x00000010) == 0x00000010)) { - subBuilder = version_.toBuilder(); - } - version_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(version_); - version_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000010; - break; - } - case 48: { - bitField0_ |= 0x00000020; - end_ = input.readBool(); - break; - } - case 58: { - org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder subBuilder = null; - if (((bitField0_ & 0x00000040) == 0x00000040)) { - subBuilder = avatar_.toBuilder(); - } - avatar_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Avatar.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(avatar_); - avatar_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000040; - break; - } - case 66: { - org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder subBuilder = null; - if (((bitField0_ & 0x00000080) == 0x00000080)) { - subBuilder = sticker_.toBuilder(); - } - sticker_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Sticker.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(sticker_); - sticker_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000080; - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.class, org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public BackupFrame parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new BackupFrame(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // optional .signal.Header header = 1; - public static final int HEADER_FIELD_NUMBER = 1; - private org.thoughtcrime.securesms.backup.BackupProtos.Header header_; - /** - * optional .signal.Header header = 1; - */ - public boolean hasHeader() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional .signal.Header header = 1; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Header getHeader() { - return header_; - } - /** - * optional .signal.Header header = 1; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder getHeaderOrBuilder() { - return header_; - } - - // optional .signal.SqlStatement statement = 2; - public static final int STATEMENT_FIELD_NUMBER = 2; - private org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement statement_; - /** - * optional .signal.SqlStatement statement = 2; - */ - public boolean hasStatement() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getStatement() { - return statement_; - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder getStatementOrBuilder() { - return statement_; - } - - // optional .signal.SharedPreference preference = 3; - public static final int PREFERENCE_FIELD_NUMBER = 3; - private org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference preference_; - /** - * optional .signal.SharedPreference preference = 3; - */ - public boolean hasPreference() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getPreference() { - return preference_; - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder getPreferenceOrBuilder() { - return preference_; - } - - // optional .signal.Attachment attachment = 4; - public static final int ATTACHMENT_FIELD_NUMBER = 4; - private org.thoughtcrime.securesms.backup.BackupProtos.Attachment attachment_; - /** - * optional .signal.Attachment attachment = 4; - */ - public boolean hasAttachment() { - return ((bitField0_ & 0x00000008) == 0x00000008); - } - /** - * optional .signal.Attachment attachment = 4; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Attachment getAttachment() { - return attachment_; - } - /** - * optional .signal.Attachment attachment = 4; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder getAttachmentOrBuilder() { - return attachment_; - } - - // optional .signal.DatabaseVersion version = 5; - public static final int VERSION_FIELD_NUMBER = 5; - private org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion version_; - /** - * optional .signal.DatabaseVersion version = 5; - */ - public boolean hasVersion() { - return ((bitField0_ & 0x00000010) == 0x00000010); - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getVersion() { - return version_; - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder getVersionOrBuilder() { - return version_; - } - - // optional bool end = 6; - public static final int END_FIELD_NUMBER = 6; - private boolean end_; - /** - * optional bool end = 6; - */ - public boolean hasEnd() { - return ((bitField0_ & 0x00000020) == 0x00000020); - } - /** - * optional bool end = 6; - */ - public boolean getEnd() { - return end_; - } - - // optional .signal.Avatar avatar = 7; - public static final int AVATAR_FIELD_NUMBER = 7; - private org.thoughtcrime.securesms.backup.BackupProtos.Avatar avatar_; - /** - * optional .signal.Avatar avatar = 7; - */ - public boolean hasAvatar() { - return ((bitField0_ & 0x00000040) == 0x00000040); - } - /** - * optional .signal.Avatar avatar = 7; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Avatar getAvatar() { - return avatar_; - } - /** - * optional .signal.Avatar avatar = 7; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder getAvatarOrBuilder() { - return avatar_; - } - - // optional .signal.Sticker sticker = 8; - public static final int STICKER_FIELD_NUMBER = 8; - private org.thoughtcrime.securesms.backup.BackupProtos.Sticker sticker_; - /** - * optional .signal.Sticker sticker = 8; - */ - public boolean hasSticker() { - return ((bitField0_ & 0x00000080) == 0x00000080); - } - /** - * optional .signal.Sticker sticker = 8; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Sticker getSticker() { - return sticker_; - } - /** - * optional .signal.Sticker sticker = 8; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder getStickerOrBuilder() { - return sticker_; - } - - private void initFields() { - header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance(); - statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance(); - preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance(); - attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance(); - version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance(); - end_ = false; - avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance(); - sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance(); - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeMessage(1, header_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeMessage(2, statement_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - output.writeMessage(3, preference_); - } - if (((bitField0_ & 0x00000008) == 0x00000008)) { - output.writeMessage(4, attachment_); - } - if (((bitField0_ & 0x00000010) == 0x00000010)) { - output.writeMessage(5, version_); - } - if (((bitField0_ & 0x00000020) == 0x00000020)) { - output.writeBool(6, end_); - } - if (((bitField0_ & 0x00000040) == 0x00000040)) { - output.writeMessage(7, avatar_); - } - if (((bitField0_ & 0x00000080) == 0x00000080)) { - output.writeMessage(8, sticker_); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, header_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, statement_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, preference_); - } - if (((bitField0_ & 0x00000008) == 0x00000008)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, attachment_); - } - if (((bitField0_ & 0x00000010) == 0x00000010)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, version_); - } - if (((bitField0_ & 0x00000020) == 0x00000020)) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(6, end_); - } - if (((bitField0_ & 0x00000040) == 0x00000040)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(7, avatar_); - } - if (((bitField0_ & 0x00000080) == 0x00000080)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(8, sticker_); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code signal.BackupFrame} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.thoughtcrime.securesms.backup.BackupProtos.BackupFrameOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.class, org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.Builder.class); - } - - // Construct using org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - getHeaderFieldBuilder(); - getStatementFieldBuilder(); - getPreferenceFieldBuilder(); - getAttachmentFieldBuilder(); - getVersionFieldBuilder(); - getAvatarFieldBuilder(); - getStickerFieldBuilder(); - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - if (headerBuilder_ == null) { - header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance(); - } else { - headerBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000001); - if (statementBuilder_ == null) { - statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance(); - } else { - statementBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000002); - if (preferenceBuilder_ == null) { - preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance(); - } else { - preferenceBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000004); - if (attachmentBuilder_ == null) { - attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance(); - } else { - attachmentBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000008); - if (versionBuilder_ == null) { - version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance(); - } else { - versionBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000010); - end_ = false; - bitField0_ = (bitField0_ & ~0x00000020); - if (avatarBuilder_ == null) { - avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance(); - } else { - avatarBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000040); - if (stickerBuilder_ == null) { - sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance(); - } else { - stickerBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000080); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_descriptor; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame getDefaultInstanceForType() { - return org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.getDefaultInstance(); - } - - public org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame build() { - org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame buildPartial() { - org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame result = new org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - if (headerBuilder_ == null) { - result.header_ = header_; - } else { - result.header_ = headerBuilder_.build(); - } - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - if (statementBuilder_ == null) { - result.statement_ = statement_; - } else { - result.statement_ = statementBuilder_.build(); - } - if (((from_bitField0_ & 0x00000004) == 0x00000004)) { - to_bitField0_ |= 0x00000004; - } - if (preferenceBuilder_ == null) { - result.preference_ = preference_; - } else { - result.preference_ = preferenceBuilder_.build(); - } - if (((from_bitField0_ & 0x00000008) == 0x00000008)) { - to_bitField0_ |= 0x00000008; - } - if (attachmentBuilder_ == null) { - result.attachment_ = attachment_; - } else { - result.attachment_ = attachmentBuilder_.build(); - } - if (((from_bitField0_ & 0x00000010) == 0x00000010)) { - to_bitField0_ |= 0x00000010; - } - if (versionBuilder_ == null) { - result.version_ = version_; - } else { - result.version_ = versionBuilder_.build(); - } - if (((from_bitField0_ & 0x00000020) == 0x00000020)) { - to_bitField0_ |= 0x00000020; - } - result.end_ = end_; - if (((from_bitField0_ & 0x00000040) == 0x00000040)) { - to_bitField0_ |= 0x00000040; - } - if (avatarBuilder_ == null) { - result.avatar_ = avatar_; - } else { - result.avatar_ = avatarBuilder_.build(); - } - if (((from_bitField0_ & 0x00000080) == 0x00000080)) { - to_bitField0_ |= 0x00000080; - } - if (stickerBuilder_ == null) { - result.sticker_ = sticker_; - } else { - result.sticker_ = stickerBuilder_.build(); - } - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame) { - return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame other) { - if (other == org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.getDefaultInstance()) return this; - if (other.hasHeader()) { - mergeHeader(other.getHeader()); - } - if (other.hasStatement()) { - mergeStatement(other.getStatement()); - } - if (other.hasPreference()) { - mergePreference(other.getPreference()); - } - if (other.hasAttachment()) { - mergeAttachment(other.getAttachment()); - } - if (other.hasVersion()) { - mergeVersion(other.getVersion()); - } - if (other.hasEnd()) { - setEnd(other.getEnd()); - } - if (other.hasAvatar()) { - mergeAvatar(other.getAvatar()); - } - if (other.hasSticker()) { - mergeSticker(other.getSticker()); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // optional .signal.Header header = 1; - private org.thoughtcrime.securesms.backup.BackupProtos.Header header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Header, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder, org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder> headerBuilder_; - /** - * optional .signal.Header header = 1; - */ - public boolean hasHeader() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * optional .signal.Header header = 1; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Header getHeader() { - if (headerBuilder_ == null) { - return header_; - } else { - return headerBuilder_.getMessage(); - } - } - /** - * optional .signal.Header header = 1; - */ - public Builder setHeader(org.thoughtcrime.securesms.backup.BackupProtos.Header value) { - if (headerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - header_ = value; - onChanged(); - } else { - headerBuilder_.setMessage(value); - } - bitField0_ |= 0x00000001; - return this; - } - /** - * optional .signal.Header header = 1; - */ - public Builder setHeader( - org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder builderForValue) { - if (headerBuilder_ == null) { - header_ = builderForValue.build(); - onChanged(); - } else { - headerBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000001; - return this; - } - /** - * optional .signal.Header header = 1; - */ - public Builder mergeHeader(org.thoughtcrime.securesms.backup.BackupProtos.Header value) { - if (headerBuilder_ == null) { - if (((bitField0_ & 0x00000001) == 0x00000001) && - header_ != org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance()) { - header_ = - org.thoughtcrime.securesms.backup.BackupProtos.Header.newBuilder(header_).mergeFrom(value).buildPartial(); - } else { - header_ = value; - } - onChanged(); - } else { - headerBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000001; - return this; - } - /** - * optional .signal.Header header = 1; - */ - public Builder clearHeader() { - if (headerBuilder_ == null) { - header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance(); - onChanged(); - } else { - headerBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000001); - return this; - } - /** - * optional .signal.Header header = 1; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder getHeaderBuilder() { - bitField0_ |= 0x00000001; - onChanged(); - return getHeaderFieldBuilder().getBuilder(); - } - /** - * optional .signal.Header header = 1; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder getHeaderOrBuilder() { - if (headerBuilder_ != null) { - return headerBuilder_.getMessageOrBuilder(); - } else { - return header_; - } - } - /** - * optional .signal.Header header = 1; - */ - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Header, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder, org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder> - getHeaderFieldBuilder() { - if (headerBuilder_ == null) { - headerBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Header, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder, org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder>( - header_, - getParentForChildren(), - isClean()); - header_ = null; - } - return headerBuilder_; - } - - // optional .signal.SqlStatement statement = 2; - private org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder> statementBuilder_; - /** - * optional .signal.SqlStatement statement = 2; - */ - public boolean hasStatement() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getStatement() { - if (statementBuilder_ == null) { - return statement_; - } else { - return statementBuilder_.getMessage(); - } - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public Builder setStatement(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement value) { - if (statementBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - statement_ = value; - onChanged(); - } else { - statementBuilder_.setMessage(value); - } - bitField0_ |= 0x00000002; - return this; - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public Builder setStatement( - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder builderForValue) { - if (statementBuilder_ == null) { - statement_ = builderForValue.build(); - onChanged(); - } else { - statementBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000002; - return this; - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public Builder mergeStatement(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement value) { - if (statementBuilder_ == null) { - if (((bitField0_ & 0x00000002) == 0x00000002) && - statement_ != org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance()) { - statement_ = - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.newBuilder(statement_).mergeFrom(value).buildPartial(); - } else { - statement_ = value; - } - onChanged(); - } else { - statementBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000002; - return this; - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public Builder clearStatement() { - if (statementBuilder_ == null) { - statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance(); - onChanged(); - } else { - statementBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000002); - return this; - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder getStatementBuilder() { - bitField0_ |= 0x00000002; - onChanged(); - return getStatementFieldBuilder().getBuilder(); - } - /** - * optional .signal.SqlStatement statement = 2; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder getStatementOrBuilder() { - if (statementBuilder_ != null) { - return statementBuilder_.getMessageOrBuilder(); - } else { - return statement_; - } - } - /** - * optional .signal.SqlStatement statement = 2; - */ - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder> - getStatementFieldBuilder() { - if (statementBuilder_ == null) { - statementBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder>( - statement_, - getParentForChildren(), - isClean()); - statement_ = null; - } - return statementBuilder_; - } - - // optional .signal.SharedPreference preference = 3; - private org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder> preferenceBuilder_; - /** - * optional .signal.SharedPreference preference = 3; - */ - public boolean hasPreference() { - return ((bitField0_ & 0x00000004) == 0x00000004); - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getPreference() { - if (preferenceBuilder_ == null) { - return preference_; - } else { - return preferenceBuilder_.getMessage(); - } - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public Builder setPreference(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference value) { - if (preferenceBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - preference_ = value; - onChanged(); - } else { - preferenceBuilder_.setMessage(value); - } - bitField0_ |= 0x00000004; - return this; - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public Builder setPreference( - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder builderForValue) { - if (preferenceBuilder_ == null) { - preference_ = builderForValue.build(); - onChanged(); - } else { - preferenceBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000004; - return this; - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public Builder mergePreference(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference value) { - if (preferenceBuilder_ == null) { - if (((bitField0_ & 0x00000004) == 0x00000004) && - preference_ != org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance()) { - preference_ = - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.newBuilder(preference_).mergeFrom(value).buildPartial(); - } else { - preference_ = value; - } - onChanged(); - } else { - preferenceBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000004; - return this; - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public Builder clearPreference() { - if (preferenceBuilder_ == null) { - preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance(); - onChanged(); - } else { - preferenceBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000004); - return this; - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder getPreferenceBuilder() { - bitField0_ |= 0x00000004; - onChanged(); - return getPreferenceFieldBuilder().getBuilder(); - } - /** - * optional .signal.SharedPreference preference = 3; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder getPreferenceOrBuilder() { - if (preferenceBuilder_ != null) { - return preferenceBuilder_.getMessageOrBuilder(); - } else { - return preference_; - } - } - /** - * optional .signal.SharedPreference preference = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder> - getPreferenceFieldBuilder() { - if (preferenceBuilder_ == null) { - preferenceBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder>( - preference_, - getParentForChildren(), - isClean()); - preference_ = null; - } - return preferenceBuilder_; - } - - // optional .signal.Attachment attachment = 4; - private org.thoughtcrime.securesms.backup.BackupProtos.Attachment attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Attachment, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder> attachmentBuilder_; - /** - * optional .signal.Attachment attachment = 4; - */ - public boolean hasAttachment() { - return ((bitField0_ & 0x00000008) == 0x00000008); - } - /** - * optional .signal.Attachment attachment = 4; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Attachment getAttachment() { - if (attachmentBuilder_ == null) { - return attachment_; - } else { - return attachmentBuilder_.getMessage(); - } - } - /** - * optional .signal.Attachment attachment = 4; - */ - public Builder setAttachment(org.thoughtcrime.securesms.backup.BackupProtos.Attachment value) { - if (attachmentBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - attachment_ = value; - onChanged(); - } else { - attachmentBuilder_.setMessage(value); - } - bitField0_ |= 0x00000008; - return this; - } - /** - * optional .signal.Attachment attachment = 4; - */ - public Builder setAttachment( - org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder builderForValue) { - if (attachmentBuilder_ == null) { - attachment_ = builderForValue.build(); - onChanged(); - } else { - attachmentBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000008; - return this; - } - /** - * optional .signal.Attachment attachment = 4; - */ - public Builder mergeAttachment(org.thoughtcrime.securesms.backup.BackupProtos.Attachment value) { - if (attachmentBuilder_ == null) { - if (((bitField0_ & 0x00000008) == 0x00000008) && - attachment_ != org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance()) { - attachment_ = - org.thoughtcrime.securesms.backup.BackupProtos.Attachment.newBuilder(attachment_).mergeFrom(value).buildPartial(); - } else { - attachment_ = value; - } - onChanged(); - } else { - attachmentBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000008; - return this; - } - /** - * optional .signal.Attachment attachment = 4; - */ - public Builder clearAttachment() { - if (attachmentBuilder_ == null) { - attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance(); - onChanged(); - } else { - attachmentBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000008); - return this; - } - /** - * optional .signal.Attachment attachment = 4; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder getAttachmentBuilder() { - bitField0_ |= 0x00000008; - onChanged(); - return getAttachmentFieldBuilder().getBuilder(); - } - /** - * optional .signal.Attachment attachment = 4; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder getAttachmentOrBuilder() { - if (attachmentBuilder_ != null) { - return attachmentBuilder_.getMessageOrBuilder(); - } else { - return attachment_; - } - } - /** - * optional .signal.Attachment attachment = 4; - */ - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Attachment, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder> - getAttachmentFieldBuilder() { - if (attachmentBuilder_ == null) { - attachmentBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Attachment, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder>( - attachment_, - getParentForChildren(), - isClean()); - attachment_ = null; - } - return attachmentBuilder_; - } - - // optional .signal.DatabaseVersion version = 5; - private org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder> versionBuilder_; - /** - * optional .signal.DatabaseVersion version = 5; - */ - public boolean hasVersion() { - return ((bitField0_ & 0x00000010) == 0x00000010); - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getVersion() { - if (versionBuilder_ == null) { - return version_; - } else { - return versionBuilder_.getMessage(); - } - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public Builder setVersion(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion value) { - if (versionBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - version_ = value; - onChanged(); - } else { - versionBuilder_.setMessage(value); - } - bitField0_ |= 0x00000010; - return this; - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public Builder setVersion( - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder builderForValue) { - if (versionBuilder_ == null) { - version_ = builderForValue.build(); - onChanged(); - } else { - versionBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000010; - return this; - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public Builder mergeVersion(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion value) { - if (versionBuilder_ == null) { - if (((bitField0_ & 0x00000010) == 0x00000010) && - version_ != org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance()) { - version_ = - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.newBuilder(version_).mergeFrom(value).buildPartial(); - } else { - version_ = value; - } - onChanged(); - } else { - versionBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000010; - return this; - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public Builder clearVersion() { - if (versionBuilder_ == null) { - version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance(); - onChanged(); - } else { - versionBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000010); - return this; - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder getVersionBuilder() { - bitField0_ |= 0x00000010; - onChanged(); - return getVersionFieldBuilder().getBuilder(); - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder getVersionOrBuilder() { - if (versionBuilder_ != null) { - return versionBuilder_.getMessageOrBuilder(); - } else { - return version_; - } - } - /** - * optional .signal.DatabaseVersion version = 5; - */ - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder> - getVersionFieldBuilder() { - if (versionBuilder_ == null) { - versionBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder>( - version_, - getParentForChildren(), - isClean()); - version_ = null; - } - return versionBuilder_; - } - - // optional bool end = 6; - private boolean end_ ; - /** - * optional bool end = 6; - */ - public boolean hasEnd() { - return ((bitField0_ & 0x00000020) == 0x00000020); - } - /** - * optional bool end = 6; - */ - public boolean getEnd() { - return end_; - } - /** - * optional bool end = 6; - */ - public Builder setEnd(boolean value) { - bitField0_ |= 0x00000020; - end_ = value; - onChanged(); - return this; - } - /** - * optional bool end = 6; - */ - public Builder clearEnd() { - bitField0_ = (bitField0_ & ~0x00000020); - end_ = false; - onChanged(); - return this; - } - - // optional .signal.Avatar avatar = 7; - private org.thoughtcrime.securesms.backup.BackupProtos.Avatar avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Avatar, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder> avatarBuilder_; - /** - * optional .signal.Avatar avatar = 7; - */ - public boolean hasAvatar() { - return ((bitField0_ & 0x00000040) == 0x00000040); - } - /** - * optional .signal.Avatar avatar = 7; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Avatar getAvatar() { - if (avatarBuilder_ == null) { - return avatar_; - } else { - return avatarBuilder_.getMessage(); - } - } - /** - * optional .signal.Avatar avatar = 7; - */ - public Builder setAvatar(org.thoughtcrime.securesms.backup.BackupProtos.Avatar value) { - if (avatarBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - avatar_ = value; - onChanged(); - } else { - avatarBuilder_.setMessage(value); - } - bitField0_ |= 0x00000040; - return this; - } - /** - * optional .signal.Avatar avatar = 7; - */ - public Builder setAvatar( - org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder builderForValue) { - if (avatarBuilder_ == null) { - avatar_ = builderForValue.build(); - onChanged(); - } else { - avatarBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000040; - return this; - } - /** - * optional .signal.Avatar avatar = 7; - */ - public Builder mergeAvatar(org.thoughtcrime.securesms.backup.BackupProtos.Avatar value) { - if (avatarBuilder_ == null) { - if (((bitField0_ & 0x00000040) == 0x00000040) && - avatar_ != org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance()) { - avatar_ = - org.thoughtcrime.securesms.backup.BackupProtos.Avatar.newBuilder(avatar_).mergeFrom(value).buildPartial(); - } else { - avatar_ = value; - } - onChanged(); - } else { - avatarBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000040; - return this; - } - /** - * optional .signal.Avatar avatar = 7; - */ - public Builder clearAvatar() { - if (avatarBuilder_ == null) { - avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance(); - onChanged(); - } else { - avatarBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000040); - return this; - } - /** - * optional .signal.Avatar avatar = 7; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder getAvatarBuilder() { - bitField0_ |= 0x00000040; - onChanged(); - return getAvatarFieldBuilder().getBuilder(); - } - /** - * optional .signal.Avatar avatar = 7; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder getAvatarOrBuilder() { - if (avatarBuilder_ != null) { - return avatarBuilder_.getMessageOrBuilder(); - } else { - return avatar_; - } - } - /** - * optional .signal.Avatar avatar = 7; - */ - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Avatar, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder> - getAvatarFieldBuilder() { - if (avatarBuilder_ == null) { - avatarBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Avatar, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder>( - avatar_, - getParentForChildren(), - isClean()); - avatar_ = null; - } - return avatarBuilder_; - } - - // optional .signal.Sticker sticker = 8; - private org.thoughtcrime.securesms.backup.BackupProtos.Sticker sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Sticker, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder, org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder> stickerBuilder_; - /** - * optional .signal.Sticker sticker = 8; - */ - public boolean hasSticker() { - return ((bitField0_ & 0x00000080) == 0x00000080); - } - /** - * optional .signal.Sticker sticker = 8; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Sticker getSticker() { - if (stickerBuilder_ == null) { - return sticker_; - } else { - return stickerBuilder_.getMessage(); - } - } - /** - * optional .signal.Sticker sticker = 8; - */ - public Builder setSticker(org.thoughtcrime.securesms.backup.BackupProtos.Sticker value) { - if (stickerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - sticker_ = value; - onChanged(); - } else { - stickerBuilder_.setMessage(value); - } - bitField0_ |= 0x00000080; - return this; - } - /** - * optional .signal.Sticker sticker = 8; - */ - public Builder setSticker( - org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder builderForValue) { - if (stickerBuilder_ == null) { - sticker_ = builderForValue.build(); - onChanged(); - } else { - stickerBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000080; - return this; - } - /** - * optional .signal.Sticker sticker = 8; - */ - public Builder mergeSticker(org.thoughtcrime.securesms.backup.BackupProtos.Sticker value) { - if (stickerBuilder_ == null) { - if (((bitField0_ & 0x00000080) == 0x00000080) && - sticker_ != org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance()) { - sticker_ = - org.thoughtcrime.securesms.backup.BackupProtos.Sticker.newBuilder(sticker_).mergeFrom(value).buildPartial(); - } else { - sticker_ = value; - } - onChanged(); - } else { - stickerBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000080; - return this; - } - /** - * optional .signal.Sticker sticker = 8; - */ - public Builder clearSticker() { - if (stickerBuilder_ == null) { - sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance(); - onChanged(); - } else { - stickerBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000080); - return this; - } - /** - * optional .signal.Sticker sticker = 8; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder getStickerBuilder() { - bitField0_ |= 0x00000080; - onChanged(); - return getStickerFieldBuilder().getBuilder(); - } - /** - * optional .signal.Sticker sticker = 8; - */ - public org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder getStickerOrBuilder() { - if (stickerBuilder_ != null) { - return stickerBuilder_.getMessageOrBuilder(); - } else { - return sticker_; - } - } - /** - * optional .signal.Sticker sticker = 8; - */ - private com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Sticker, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder, org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder> - getStickerFieldBuilder() { - if (stickerBuilder_ == null) { - stickerBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.thoughtcrime.securesms.backup.BackupProtos.Sticker, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder, org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder>( - sticker_, - getParentForChildren(), - isClean()); - sticker_ = null; - } - return stickerBuilder_; - } - - // @@protoc_insertion_point(builder_scope:signal.BackupFrame) - } - - static { - defaultInstance = new BackupFrame(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:signal.BackupFrame) - } - - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_SqlStatement_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_SqlStatement_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_SqlStatement_SqlParameter_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_SharedPreference_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_SharedPreference_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_Attachment_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_Attachment_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_Sticker_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_Sticker_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_Avatar_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_Avatar_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_DatabaseVersion_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_DatabaseVersion_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_Header_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_Header_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_signal_BackupFrame_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_signal_BackupFrame_fieldAccessorTable; - - public static com.google.protobuf.Descriptors.FileDescriptor - getDescriptor() { - return descriptor; - } - private static com.google.protobuf.Descriptors.FileDescriptor - descriptor; - static { - java.lang.String[] descriptorData = { - "\n\rBackups.proto\022\006signal\"\342\001\n\014SqlStatement" + - "\022\021\n\tstatement\030\001 \001(\t\0225\n\nparameters\030\002 \003(\0132" + - "!.signal.SqlStatement.SqlParameter\032\207\001\n\014S" + - "qlParameter\022\026\n\016stringParamter\030\001 \001(\t\022\030\n\020i" + - "ntegerParameter\030\002 \001(\004\022\027\n\017doubleParameter" + - "\030\003 \001(\001\022\025\n\rblobParameter\030\004 \001(\014\022\025\n\rnullpar" + - "ameter\030\005 \001(\010\"<\n\020SharedPreference\022\014\n\004file" + - "\030\001 \001(\t\022\013\n\003key\030\002 \001(\t\022\r\n\005value\030\003 \001(\t\"A\n\nAt" + - "tachment\022\r\n\005rowId\030\001 \001(\004\022\024\n\014attachmentId\030" + - "\002 \001(\004\022\016\n\006length\030\003 \001(\r\"(\n\007Sticker\022\r\n\005rowI", - "d\030\001 \001(\004\022\016\n\006length\030\002 \001(\r\"&\n\006Avatar\022\014\n\004nam" + - "e\030\001 \001(\t\022\016\n\006length\030\002 \001(\r\"\"\n\017DatabaseVersi" + - "on\022\017\n\007version\030\001 \001(\r\"\"\n\006Header\022\n\n\002iv\030\001 \001(" + - "\014\022\014\n\004salt\030\002 \001(\014\"\245\002\n\013BackupFrame\022\036\n\006heade" + - "r\030\001 \001(\0132\016.signal.Header\022\'\n\tstatement\030\002 \001" + - "(\0132\024.signal.SqlStatement\022,\n\npreference\030\003" + - " \001(\0132\030.signal.SharedPreference\022&\n\nattach" + - "ment\030\004 \001(\0132\022.signal.Attachment\022(\n\007versio" + - "n\030\005 \001(\0132\027.signal.DatabaseVersion\022\013\n\003end\030" + - "\006 \001(\010\022\036\n\006avatar\030\007 \001(\0132\016.signal.Avatar\022 \n", - "\007sticker\030\010 \001(\0132\017.signal.StickerB1\n!org.t" + - "houghtcrime.securesms.backupB\014BackupProt" + - "os" - }; - com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = - new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { - public com.google.protobuf.ExtensionRegistry assignDescriptors( - com.google.protobuf.Descriptors.FileDescriptor root) { - descriptor = root; - internal_static_signal_SqlStatement_descriptor = - getDescriptor().getMessageTypes().get(0); - internal_static_signal_SqlStatement_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_SqlStatement_descriptor, - new java.lang.String[] { "Statement", "Parameters", }); - internal_static_signal_SqlStatement_SqlParameter_descriptor = - internal_static_signal_SqlStatement_descriptor.getNestedTypes().get(0); - internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_SqlStatement_SqlParameter_descriptor, - new java.lang.String[] { "StringParamter", "IntegerParameter", "DoubleParameter", "BlobParameter", "Nullparameter", }); - internal_static_signal_SharedPreference_descriptor = - getDescriptor().getMessageTypes().get(1); - internal_static_signal_SharedPreference_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_SharedPreference_descriptor, - new java.lang.String[] { "File", "Key", "Value", }); - internal_static_signal_Attachment_descriptor = - getDescriptor().getMessageTypes().get(2); - internal_static_signal_Attachment_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_Attachment_descriptor, - new java.lang.String[] { "RowId", "AttachmentId", "Length", }); - internal_static_signal_Sticker_descriptor = - getDescriptor().getMessageTypes().get(3); - internal_static_signal_Sticker_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_Sticker_descriptor, - new java.lang.String[] { "RowId", "Length", }); - internal_static_signal_Avatar_descriptor = - getDescriptor().getMessageTypes().get(4); - internal_static_signal_Avatar_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_Avatar_descriptor, - new java.lang.String[] { "Name", "Length", }); - internal_static_signal_DatabaseVersion_descriptor = - getDescriptor().getMessageTypes().get(5); - internal_static_signal_DatabaseVersion_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_DatabaseVersion_descriptor, - new java.lang.String[] { "Version", }); - internal_static_signal_Header_descriptor = - getDescriptor().getMessageTypes().get(6); - internal_static_signal_Header_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_Header_descriptor, - new java.lang.String[] { "Iv", "Salt", }); - internal_static_signal_BackupFrame_descriptor = - getDescriptor().getMessageTypes().get(7); - internal_static_signal_BackupFrame_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_signal_BackupFrame_descriptor, - new java.lang.String[] { "Header", "Statement", "Preference", "Attachment", "Version", "End", "Avatar", "Sticker", }); - return null; - } - }; - com.google.protobuf.Descriptors.FileDescriptor - .internalBuildGeneratedFileFrom(descriptorData, - new com.google.protobuf.Descriptors.FileDescriptor[] { - }, assigner); - } - - // @@protoc_insertion_point(outer_class_scope) -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt deleted file mode 100644 index 6b5d47a2e6..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt +++ /dev/null @@ -1,447 +0,0 @@ -package org.thoughtcrime.securesms.backup - -import android.content.Context -import android.database.Cursor -import android.net.Uri -import android.text.TextUtils -import androidx.annotation.WorkerThread -import com.annimon.stream.function.Consumer -import com.annimon.stream.function.Predicate -import com.google.protobuf.ByteString -import net.zetetic.database.sqlcipher.SQLiteDatabase -import org.greenrobot.eventbus.EventBus -import org.session.libsession.avatars.AvatarHelper -import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId -import org.session.libsession.utilities.Conversions -import org.session.libsession.utilities.Util -import org.session.libsignal.crypto.kdf.HKDFv3 -import org.session.libsignal.utilities.ByteUtil -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.backup.BackupProtos.Attachment -import org.thoughtcrime.securesms.backup.BackupProtos.Avatar -import org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame -import org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion -import org.thoughtcrime.securesms.backup.BackupProtos.Header -import org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference -import org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement -import org.thoughtcrime.securesms.backup.BackupProtos.Sticker -import org.thoughtcrime.securesms.crypto.AttachmentSecret -import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream -import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream -import org.thoughtcrime.securesms.database.AttachmentDatabase -import org.thoughtcrime.securesms.database.GroupReceiptDatabase -import org.thoughtcrime.securesms.database.JobDatabase -import org.thoughtcrime.securesms.database.LokiAPIDatabase -import org.thoughtcrime.securesms.database.LokiBackupFilesDatabase -import org.thoughtcrime.securesms.database.MmsDatabase -import org.thoughtcrime.securesms.database.MmsSmsColumns -import org.thoughtcrime.securesms.database.PushDatabase -import org.thoughtcrime.securesms.database.SearchDatabase -import org.thoughtcrime.securesms.database.SmsDatabase -import org.thoughtcrime.securesms.util.BackupUtil -import java.io.Closeable -import java.io.File -import java.io.FileInputStream -import java.io.Flushable -import java.io.IOException -import java.io.InputStream -import java.io.OutputStream -import java.security.InvalidAlgorithmParameterException -import java.security.InvalidKeyException -import java.security.NoSuchAlgorithmException -import java.util.LinkedList -import javax.crypto.BadPaddingException -import javax.crypto.Cipher -import javax.crypto.IllegalBlockSizeException -import javax.crypto.Mac -import javax.crypto.NoSuchPaddingException -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec - -object FullBackupExporter { - private val TAG = FullBackupExporter::class.java.simpleName - - @JvmStatic - @WorkerThread - @Throws(IOException::class) - fun export(context: Context, - attachmentSecret: AttachmentSecret, - input: SQLiteDatabase, - fileUri: Uri, - passphrase: String) { - - val baseOutputStream = context.contentResolver.openOutputStream(fileUri) - ?: throw IOException("Cannot open an output stream for the file URI: $fileUri") - - var count = 0 - try { - BackupFrameOutputStream(baseOutputStream, passphrase).use { outputStream -> - outputStream.writeDatabaseVersion(input.version) - val tables = exportSchema(input, outputStream) - for (table in tables) if (shouldExportTable(table)) { - count = when (table) { - SmsDatabase.TABLE_NAME, MmsDatabase.TABLE_NAME -> { - exportTable(table, input, outputStream, - { cursor: Cursor -> - cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0 - }, - null, - count) - } - GroupReceiptDatabase.TABLE_NAME -> { - exportTable(table, input, outputStream, - { cursor: Cursor -> - isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))) - }, - null, - count) - } - AttachmentDatabase.TABLE_NAME -> { - exportTable(table, input, outputStream, - { cursor: Cursor -> - isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))) - }, - { cursor: Cursor -> - exportAttachment(attachmentSecret, cursor, outputStream) - }, - count) - } - else -> { - exportTable(table, input, outputStream, null, null, count) - } - } - } - for (preference in BackupUtil.getBackupRecords(context)) { - EventBus.getDefault().post(BackupEvent.createProgress(++count)) - outputStream.writePreferenceEntry(preference) - } - for (preference in BackupPreferences.getBackupRecords(context)) { - EventBus.getDefault().post(BackupEvent.createProgress(++count)) - outputStream.writePreferenceEntry(preference) - } - for (avatar in AvatarHelper.getAvatarFiles(context)) { - EventBus.getDefault().post(BackupEvent.createProgress(++count)) - outputStream.writeAvatar(avatar.name, FileInputStream(avatar), avatar.length()) - } - outputStream.writeEnd() - } - EventBus.getDefault().post(BackupEvent.createFinished()) - } catch (e: Exception) { - Log.e(TAG, "Failed to make full backup.", e) - EventBus.getDefault().post(BackupEvent.createFinished(e)) - throw e - } - } - - private inline fun shouldExportTable(table: String): Boolean { - return table != PushDatabase.TABLE_NAME && - - table != LokiBackupFilesDatabase.TABLE_NAME && - table != LokiAPIDatabase.openGroupProfilePictureTable && - - table != JobDatabase.Jobs.TABLE_NAME && - table != JobDatabase.Constraints.TABLE_NAME && - table != JobDatabase.Dependencies.TABLE_NAME && - - !table.startsWith(SearchDatabase.SMS_FTS_TABLE_NAME) && - !table.startsWith(SearchDatabase.MMS_FTS_TABLE_NAME) && - !table.startsWith("sqlite_") - } - - @Throws(IOException::class) - private fun exportSchema(input: SQLiteDatabase, outputStream: BackupFrameOutputStream): List { - val tables: MutableList = LinkedList() - input.rawQuery("SELECT sql, name, type FROM sqlite_master", null).use { cursor -> - while (cursor != null && cursor.moveToNext()) { - val sql = cursor.getString(0) - val name = cursor.getString(1) - val type = cursor.getString(2) - if (sql != null) { - val isSmsFtsSecretTable = name != null && name != SearchDatabase.SMS_FTS_TABLE_NAME && name.startsWith(SearchDatabase.SMS_FTS_TABLE_NAME) - val isMmsFtsSecretTable = name != null && name != SearchDatabase.MMS_FTS_TABLE_NAME && name.startsWith(SearchDatabase.MMS_FTS_TABLE_NAME) - if (!isSmsFtsSecretTable && !isMmsFtsSecretTable) { - if ("table" == type) { - tables.add(name) - } - outputStream.writeSql(SqlStatement.newBuilder().setStatement(cursor.getString(0)).build()) - } - } - } - } - return tables - } - - @Throws(IOException::class) - private fun exportTable(table: String, - input: SQLiteDatabase, - outputStream: BackupFrameOutputStream, - predicate: Predicate?, - postProcess: Consumer?, - count: Int): Int { - var count = count - val template = "INSERT INTO $table VALUES " - input.rawQuery("SELECT * FROM $table", null).use { cursor -> - while (cursor != null && cursor.moveToNext()) { - EventBus.getDefault().post(BackupEvent.createProgress(++count)) - if (predicate != null && !predicate.test(cursor)) continue - - val statement = StringBuilder(template) - val statementBuilder = SqlStatement.newBuilder() - statement.append('(') - for (i in 0 until cursor.columnCount) { - statement.append('?') - when (cursor.getType(i)) { - Cursor.FIELD_TYPE_STRING -> { - statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder() - .setStringParamter(cursor.getString(i))) - } - Cursor.FIELD_TYPE_FLOAT -> { - statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder() - .setDoubleParameter(cursor.getDouble(i))) - } - Cursor.FIELD_TYPE_INTEGER -> { - statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder() - .setIntegerParameter(cursor.getLong(i))) - } - Cursor.FIELD_TYPE_BLOB -> { - statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder() - .setBlobParameter(ByteString.copyFrom(cursor.getBlob(i)))) - } - Cursor.FIELD_TYPE_NULL -> { - statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder() - .setNullparameter(true)) - } - else -> { - throw AssertionError("unknown type?" + cursor.getType(i)) - } - } - if (i < cursor.columnCount - 1) { - statement.append(',') - } - } - statement.append(')') - outputStream.writeSql(statementBuilder.setStatement(statement.toString()).build()) - postProcess?.accept(cursor) - } - } - return count - } - - private fun exportAttachment(attachmentSecret: AttachmentSecret, cursor: Cursor, outputStream: BackupFrameOutputStream) { - try { - val rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID)) - val uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID)) - var size = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.SIZE)) - val data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA)) - val random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA_RANDOM)) - if (!TextUtils.isEmpty(data) && size <= 0) { - size = calculateVeryOldStreamLength(attachmentSecret, random, data) - } - if (!TextUtils.isEmpty(data) && size > 0) { - val inputStream: InputStream = if (random != null && random.size == 32) { - ModernDecryptingPartInputStream.createFor(attachmentSecret, random, File(data), 0) - } else { - ClassicDecryptingPartInputStream.createFor(attachmentSecret, File(data)) - } - outputStream.writeAttachment(AttachmentId(rowId, uniqueId), inputStream, size) - } - } catch (e: IOException) { - Log.w(TAG, e) - } - } - - @Throws(IOException::class) - private fun calculateVeryOldStreamLength(attachmentSecret: AttachmentSecret, random: ByteArray?, data: String): Long { - var result: Long = 0 - val inputStream: InputStream = if (random != null && random.size == 32) { - ModernDecryptingPartInputStream.createFor(attachmentSecret, random, File(data), 0) - } else { - ClassicDecryptingPartInputStream.createFor(attachmentSecret, File(data)) - } - var read: Int - val buffer = ByteArray(8192) - while (inputStream.read(buffer, 0, buffer.size).also { read = it } != -1) { - result += read.toLong() - } - return result - } - - private fun isForNonExpiringMessage(db: SQLiteDatabase, mmsId: Long): Boolean { - val columns = arrayOf(MmsSmsColumns.EXPIRES_IN) - val where = MmsSmsColumns.ID + " = ?" - val args = arrayOf(mmsId.toString()) - db.query(MmsDatabase.TABLE_NAME, columns, where, args, null, null, null).use { mmsCursor -> - if (mmsCursor != null && mmsCursor.moveToFirst()) { - return mmsCursor.getLong(0) == 0L - } - } - return false - } - - private class BackupFrameOutputStream : Closeable, Flushable { - - private val outputStream: OutputStream - private var cipher: Cipher - private var mac: Mac - private val cipherKey: ByteArray - private val macKey: ByteArray - private val iv: ByteArray - - private var counter: Int = 0 - - constructor(outputStream: OutputStream, passphrase: String) : super() { - try { - val salt = Util.getSecretBytes(32) - val key = BackupUtil.computeBackupKey(passphrase, salt) - val derived = HKDFv3().deriveSecrets(key, "Backup Export".toByteArray(), 64) - val split = ByteUtil.split(derived, 32, 32) - cipherKey = split[0] - macKey = split[1] - cipher = Cipher.getInstance("AES/CTR/NoPadding") - mac = Mac.getInstance("HmacSHA256") - this.outputStream = outputStream - iv = Util.getSecretBytes(16) - counter = Conversions.byteArrayToInt(iv) - mac.init(SecretKeySpec(macKey, "HmacSHA256")) - val header = BackupFrame.newBuilder().setHeader(Header.newBuilder() - .setIv(ByteString.copyFrom(iv)) - .setSalt(ByteString.copyFrom(salt))) - .build().toByteArray() - outputStream.write(Conversions.intToByteArray(header.size)) - outputStream.write(header) - } catch (e: Exception) { - when (e) { - is NoSuchAlgorithmException, - is NoSuchPaddingException, - is InvalidKeyException -> { - throw AssertionError(e) - } - else -> throw e - } - } - } - - @Throws(IOException::class) - fun writeSql(statement: SqlStatement) { - write(outputStream, BackupFrame.newBuilder().setStatement(statement).build()) - } - - @Throws(IOException::class) - fun writePreferenceEntry(preference: SharedPreference?) { - write(outputStream, BackupFrame.newBuilder().setPreference(preference).build()) - } - - @Throws(IOException::class) - fun writeAvatar(avatarName: String, inputStream: InputStream, size: Long) { - write(outputStream, BackupFrame.newBuilder() - .setAvatar(Avatar.newBuilder() - .setName(avatarName) - .setLength(Util.toIntExact(size)) - .build()) - .build()) - writeStream(inputStream) - } - - @Throws(IOException::class) - fun writeAttachment(attachmentId: AttachmentId, inputStream: InputStream, size: Long) { - write(outputStream, BackupFrame.newBuilder() - .setAttachment(Attachment.newBuilder() - .setRowId(attachmentId.rowId) - .setAttachmentId(attachmentId.uniqueId) - .setLength(Util.toIntExact(size)) - .build()) - .build()) - writeStream(inputStream) - } - - @Throws(IOException::class) - fun writeSticker(rowId: Long, inputStream: InputStream, size: Long) { - write(outputStream, BackupFrame.newBuilder() - .setSticker(Sticker.newBuilder() - .setRowId(rowId) - .setLength(Util.toIntExact(size)) - .build()) - .build()) - writeStream(inputStream) - } - - @Throws(IOException::class) - fun writeDatabaseVersion(version: Int) { - write(outputStream, BackupFrame.newBuilder() - .setVersion(DatabaseVersion.newBuilder().setVersion(version)) - .build()) - } - - @Throws(IOException::class) - fun writeEnd() { - write(outputStream, BackupFrame.newBuilder().setEnd(true).build()) - } - - @Throws(IOException::class) - private fun writeStream(inputStream: InputStream) { - try { - Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - mac.update(iv) - val buffer = ByteArray(8192) - var read: Int - while (inputStream.read(buffer).also { read = it } != -1) { - val ciphertext = cipher.update(buffer, 0, read) - if (ciphertext != null) { - outputStream.write(ciphertext) - mac.update(ciphertext) - } - } - val remainder = cipher.doFinal() - outputStream.write(remainder) - mac.update(remainder) - val attachmentDigest = mac.doFinal() - outputStream.write(attachmentDigest, 0, 10) - } catch (e: Exception) { - when (e) { - is InvalidKeyException, - is InvalidAlgorithmParameterException, - is IllegalBlockSizeException, - is BadPaddingException -> { - throw AssertionError(e) - } - else -> throw e - } - } - } - - @Throws(IOException::class) - private fun write(out: OutputStream, frame: BackupFrame) { - try { - Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - val frameCiphertext = cipher.doFinal(frame.toByteArray()) - val frameMac = mac.doFinal(frameCiphertext) - val length = Conversions.intToByteArray(frameCiphertext.size + 10) - out.write(length) - out.write(frameCiphertext) - out.write(frameMac, 0, 10) - } catch (e: Exception) { - when (e) { - is InvalidKeyException, - is InvalidAlgorithmParameterException, - is IllegalBlockSizeException, - is BadPaddingException -> { - throw AssertionError(e) - } - else -> throw e - } - } - } - - @Throws(IOException::class) - override fun flush() { - outputStream.flush() - } - - @Throws(IOException::class) - override fun close() { - outputStream.close() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt deleted file mode 100644 index b40c049bc2..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt +++ /dev/null @@ -1,352 +0,0 @@ -package org.thoughtcrime.securesms.backup - -import android.annotation.SuppressLint -import android.content.ContentValues -import android.content.Context -import android.net.Uri -import androidx.annotation.WorkerThread -import net.zetetic.database.sqlcipher.SQLiteDatabase -import org.greenrobot.eventbus.EventBus -import org.session.libsession.avatars.AvatarHelper -import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId -import org.session.libsession.utilities.Address -import org.session.libsession.utilities.Conversions -import org.session.libsession.utilities.Util -import org.session.libsignal.crypto.kdf.HKDFv3 -import org.session.libsignal.utilities.ByteUtil -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.backup.BackupProtos.Attachment -import org.thoughtcrime.securesms.backup.BackupProtos.Avatar -import org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame -import org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion -import org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference -import org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement -import org.thoughtcrime.securesms.crypto.AttachmentSecret -import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream -import org.thoughtcrime.securesms.database.AttachmentDatabase -import org.thoughtcrime.securesms.database.GroupReceiptDatabase -import org.thoughtcrime.securesms.database.MmsDatabase -import org.thoughtcrime.securesms.database.MmsSmsColumns -import org.thoughtcrime.securesms.database.SearchDatabase -import org.thoughtcrime.securesms.database.ThreadDatabase -import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import org.thoughtcrime.securesms.util.BackupUtil -import java.io.Closeable -import java.io.File -import java.io.FileOutputStream -import java.io.IOException -import java.io.InputStream -import java.io.OutputStream -import java.security.InvalidAlgorithmParameterException -import java.security.InvalidKeyException -import java.security.MessageDigest -import java.security.NoSuchAlgorithmException -import java.util.LinkedList -import java.util.Locale -import javax.crypto.BadPaddingException -import javax.crypto.Cipher -import javax.crypto.IllegalBlockSizeException -import javax.crypto.Mac -import javax.crypto.NoSuchPaddingException -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec - -object FullBackupImporter { - /** - * Because BackupProtos.SharedPreference was made only to serialize string values, - * we use these 3-char prefixes to explicitly cast the values before inserting to a preference file. - */ - const val PREF_PREFIX_TYPE_INT = "i__" - const val PREF_PREFIX_TYPE_BOOLEAN = "b__" - - private val TAG = FullBackupImporter::class.java.simpleName - - @JvmStatic - @WorkerThread - @Throws(IOException::class) - fun importFromUri(context: Context, - attachmentSecret: AttachmentSecret, - db: SQLiteDatabase, - fileUri: Uri, - passphrase: String) { - - val baseInputStream = context.contentResolver.openInputStream(fileUri) - ?: throw IOException("Cannot open an input stream for the file URI: $fileUri") - - var count = 0 - try { - BackupRecordInputStream(baseInputStream, passphrase).use { inputStream -> - db.beginTransaction() - dropAllTables(db) - var frame: BackupFrame - while (!inputStream.readFrame().also { frame = it }.end) { - if (count++ % 100 == 0) EventBus.getDefault().post(BackupEvent.createProgress(count)) - when { - frame.hasVersion() -> processVersion(db, frame.version) - frame.hasStatement() -> processStatement(db, frame.statement) - frame.hasPreference() -> processPreference(context, frame.preference) - frame.hasAttachment() -> processAttachment(context, attachmentSecret, db, frame.attachment, inputStream) - frame.hasAvatar() -> processAvatar(context, frame.avatar, inputStream) - } - } - trimEntriesForExpiredMessages(context, db) - db.setTransactionSuccessful() - } - } finally { - if (db.inTransaction()) { - db.endTransaction() - } - } - EventBus.getDefault().post(BackupEvent.createFinished()) - } - - @Throws(IOException::class) - private fun processVersion(db: SQLiteDatabase, version: DatabaseVersion) { - if (version.version > db.version) { - throw DatabaseDowngradeException(db.version, version.version) - } - db.version = version.version - } - - private fun processStatement(db: SQLiteDatabase, statement: SqlStatement) { - val isForSmsFtsSecretTable = statement.statement.contains(SearchDatabase.SMS_FTS_TABLE_NAME + "_") - val isForMmsFtsSecretTable = statement.statement.contains(SearchDatabase.MMS_FTS_TABLE_NAME + "_") - val isForSqliteSecretTable = statement.statement.toLowerCase(Locale.ENGLISH).startsWith("create table sqlite_") - if (isForSmsFtsSecretTable || isForMmsFtsSecretTable || isForSqliteSecretTable) { - Log.i(TAG, "Ignoring import for statement: " + statement.statement) - return - } - val parameters: MutableList = LinkedList() - for (parameter in statement.parametersList) { - when { - parameter.hasStringParamter() -> parameters.add(parameter.stringParamter) - parameter.hasDoubleParameter() -> parameters.add(parameter.doubleParameter) - parameter.hasIntegerParameter() -> parameters.add(parameter.integerParameter) - parameter.hasBlobParameter() -> parameters.add(parameter.blobParameter.toByteArray()) - parameter.hasNullparameter() -> parameters.add(null) - } - } - if (parameters.size > 0) { - db.execSQL(statement.statement, parameters.toTypedArray()) - } else { - db.execSQL(statement.statement) - } - } - - @Throws(IOException::class) - private fun processAttachment(context: Context, attachmentSecret: AttachmentSecret, - db: SQLiteDatabase, attachment: Attachment, - inputStream: BackupRecordInputStream) { - val partsDirectory = context.getDir(AttachmentDatabase.DIRECTORY, Context.MODE_PRIVATE) - val dataFile = File.createTempFile("part", ".mms", partsDirectory) - val output = ModernEncryptingPartOutputStream.createFor(attachmentSecret, dataFile, false) - inputStream.readAttachmentTo(output.second, attachment.length) - val contentValues = ContentValues() - contentValues.put(AttachmentDatabase.DATA, dataFile.absolutePath) - contentValues.put(AttachmentDatabase.THUMBNAIL, null as String?) - contentValues.put(AttachmentDatabase.DATA_RANDOM, output.first) - db.update(AttachmentDatabase.TABLE_NAME, contentValues, - "${AttachmentDatabase.ROW_ID} = ? AND ${AttachmentDatabase.UNIQUE_ID} = ?", - arrayOf(attachment.rowId.toString(), attachment.attachmentId.toString())) - } - - @Throws(IOException::class) - private fun processAvatar(context: Context, avatar: Avatar, inputStream: BackupRecordInputStream) { - inputStream.readAttachmentTo(FileOutputStream( - AvatarHelper.getAvatarFile(context, Address.fromExternal(context, avatar.name))), avatar.length) - } - - @SuppressLint("ApplySharedPref") - private fun processPreference(context: Context, preference: SharedPreference) { - val preferences = context.getSharedPreferences(preference.file, 0) - val key = preference.key - val value = preference.value - - // See the comment next to PREF_PREFIX_TYPE_* constants. - when { - key.startsWith(PREF_PREFIX_TYPE_INT) -> - preferences.edit().putInt( - key.substring(PREF_PREFIX_TYPE_INT.length), - value.toInt() - ).commit() - key.startsWith(PREF_PREFIX_TYPE_BOOLEAN) -> - preferences.edit().putBoolean( - key.substring(PREF_PREFIX_TYPE_BOOLEAN.length), - value.toBoolean() - ).commit() - else -> - preferences.edit().putString(key, value).commit() - } - } - - private fun dropAllTables(db: SQLiteDatabase) { - db.rawQuery("SELECT name, type FROM sqlite_master", null).use { cursor -> - while (cursor != null && cursor.moveToNext()) { - val name = cursor.getString(0) - val type = cursor.getString(1) - if ("table" == type && !name.startsWith("sqlite_")) { - db.execSQL("DROP TABLE IF EXISTS $name") - } - } - } - } - - private fun trimEntriesForExpiredMessages(context: Context, db: SQLiteDatabase) { - val trimmedCondition = " NOT IN (SELECT ${MmsSmsColumns.ID} FROM ${MmsDatabase.TABLE_NAME})" - db.delete(GroupReceiptDatabase.TABLE_NAME, GroupReceiptDatabase.MMS_ID + trimmedCondition, null) - val columns = arrayOf(AttachmentDatabase.ROW_ID, AttachmentDatabase.UNIQUE_ID) - val where = AttachmentDatabase.MMS_ID + trimmedCondition - db.query(AttachmentDatabase.TABLE_NAME, columns, where, null, null, null, null).use { cursor -> - while (cursor != null && cursor.moveToNext()) { - DatabaseComponent.get(context).attachmentDatabase() - .deleteAttachment(AttachmentId(cursor.getLong(0), cursor.getLong(1))) - } - } - db.query(ThreadDatabase.TABLE_NAME, arrayOf(ThreadDatabase.ID), - ThreadDatabase.EXPIRES_IN + " > 0", null, null, null, null).use { cursor -> - while (cursor != null && cursor.moveToNext()) { - DatabaseComponent.get(context).threadDatabase().update(cursor.getLong(0), false) - } - } - } - - private class BackupRecordInputStream : Closeable { - private val inputStream: InputStream - private val cipher: Cipher - private val mac: Mac - private val cipherKey: ByteArray - private val macKey: ByteArray - private val iv: ByteArray - - private var counter = 0 - - @Throws(IOException::class) - constructor(inputStream: InputStream, passphrase: String) : super() { - try { - this.inputStream = inputStream - val headerLengthBytes = ByteArray(4) - Util.readFully(this.inputStream, headerLengthBytes) - val headerLength = Conversions.byteArrayToInt(headerLengthBytes) - val headerFrame = ByteArray(headerLength) - Util.readFully(this.inputStream, headerFrame) - val frame = BackupFrame.parseFrom(headerFrame) - if (!frame.hasHeader()) { - throw IOException("Backup stream does not start with header!") - } - val header = frame.header - iv = header.iv.toByteArray() - if (iv.size != 16) { - throw IOException("Invalid IV length!") - } - val key = BackupUtil.computeBackupKey(passphrase, if (header.hasSalt()) header.salt.toByteArray() else null) - val derived = HKDFv3().deriveSecrets(key, "Backup Export".toByteArray(), 64) - val split = ByteUtil.split(derived, 32, 32) - cipherKey = split[0] - macKey = split[1] - cipher = Cipher.getInstance("AES/CTR/NoPadding") - mac = Mac.getInstance("HmacSHA256") - mac.init(SecretKeySpec(macKey, "HmacSHA256")) - counter = Conversions.byteArrayToInt(iv) - } catch (e: Exception) { - when (e) { - is NoSuchAlgorithmException, - is NoSuchPaddingException, - is InvalidKeyException -> { - throw AssertionError(e) - } - else -> throw e - } - } - } - - @Throws(IOException::class) - fun readFrame(): BackupFrame { - return readFrame(inputStream) - } - - @Throws(IOException::class) - fun readAttachmentTo(out: OutputStream, length: Int) { - var length = length - try { - Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - mac.update(iv) - val buffer = ByteArray(8192) - while (length > 0) { - val read = inputStream.read(buffer, 0, Math.min(buffer.size, length)) - if (read == -1) throw IOException("File ended early!") - mac.update(buffer, 0, read) - val plaintext = cipher.update(buffer, 0, read) - if (plaintext != null) { - out.write(plaintext, 0, plaintext.size) - } - length -= read - } - val plaintext = cipher.doFinal() - if (plaintext != null) { - out.write(plaintext, 0, plaintext.size) - } - out.close() - val ourMac = ByteUtil.trim(mac.doFinal(), 10) - val theirMac = ByteArray(10) - try { - Util.readFully(inputStream, theirMac) - } catch (e: IOException) { - throw IOException(e) - } - if (!MessageDigest.isEqual(ourMac, theirMac)) { - throw IOException("Bad MAC") - } - } catch (e: Exception) { - when (e) { - is InvalidKeyException, - is InvalidAlgorithmParameterException, - is IllegalBlockSizeException, - is BadPaddingException -> { - throw AssertionError(e) - } - else -> throw e - } - } - } - - @Throws(IOException::class) - private fun readFrame(`in`: InputStream?): BackupFrame { - return try { - val length = ByteArray(4) - Util.readFully(`in`, length) - val frame = ByteArray(Conversions.byteArrayToInt(length)) - Util.readFully(`in`, frame) - val theirMac = ByteArray(10) - System.arraycopy(frame, frame.size - 10, theirMac, 0, theirMac.size) - mac.update(frame, 0, frame.size - 10) - val ourMac = ByteUtil.trim(mac.doFinal(), 10) - if (!MessageDigest.isEqual(ourMac, theirMac)) { - throw IOException("Bad MAC") - } - Conversions.intToByteArray(iv, 0, counter++) - cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv)) - val plaintext = cipher.doFinal(frame, 0, frame.size - 10) - BackupFrame.parseFrom(plaintext) - } catch (e: Exception) { - when (e) { - is InvalidKeyException, - is InvalidAlgorithmParameterException, - is IllegalBlockSizeException, - is BadPaddingException -> { - throw AssertionError(e) - } - else -> throw e - } - } - } - - @Throws(IOException::class) - override fun close() { - inputStream.close() - } - } - - class DatabaseDowngradeException internal constructor(currentVersion: Int, backupVersion: Int) : - IOException("Tried to import a backup with version $backupVersion into a database with version $currentVersion") -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java index 5e84d5e23a..ddef0200e1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java @@ -1,21 +1,7 @@ package org.thoughtcrime.securesms.database; -import android.content.ContentValues; import android.content.Context; -import android.database.Cursor; -import androidx.annotation.NonNull; - -import net.zetetic.database.sqlcipher.SQLiteDatabase; - import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; -import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec; -import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec; -import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; public class JobDatabase extends Database { @@ -23,8 +9,6 @@ public class JobDatabase extends Database { Constraints.CREATE_TABLE, Dependencies.CREATE_TABLE }; - private static final ArrayList runningJobs = new ArrayList<>(); - public static final class Jobs { public static final String TABLE_NAME = "job_spec"; private static final String ID = "_id"; @@ -84,166 +68,4 @@ public class JobDatabase extends Database { public JobDatabase(Context context, SQLCipherOpenHelper databaseHelper) { super(context, databaseHelper); } - - public synchronized void insertJobs(@NonNull List fullSpecs) { - SQLiteDatabase db = databaseHelper.getWritableDatabase(); - - db.beginTransaction(); - - try { - for (FullSpec fullSpec : fullSpecs) { - insertJobSpec(db, fullSpec.getJobSpec()); - insertConstraintSpecs(db, fullSpec.getConstraintSpecs()); - insertDependencySpecs(db, fullSpec.getDependencySpecs()); - } - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } - - public synchronized @NonNull List getAllJobSpecs() { - List jobs = new LinkedList<>(); - - try (Cursor cursor = databaseHelper.getReadableDatabase().query(Jobs.TABLE_NAME, null, null, null, null, null, Jobs.CREATE_TIME + ", " + Jobs.ID + " ASC")) { - while (cursor != null && cursor.moveToNext()) { - jobs.add(jobSpecFromCursor(cursor)); - } - } - - return jobs; - } - - public synchronized void updateJobRunningState(@NonNull String id, boolean isRunning) { - if (!isRunning) { - JobDatabase.runningJobs.remove(id); - } else if (!JobDatabase.runningJobs.contains(id)) { - JobDatabase.runningJobs.add(id); - } - } - - public synchronized void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime) { - updateJobRunningState(id, isRunning); - - ContentValues contentValues = new ContentValues(); - contentValues.put(Jobs.RUN_ATTEMPT, runAttempt); - contentValues.put(Jobs.NEXT_RUN_ATTEMPT_TIME, nextRunAttemptTime); - - String query = Jobs.JOB_SPEC_ID + " = ?"; - String[] args = new String[]{ id }; - - databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, query, args); - } - - public synchronized void updateAllJobsToBePending() { - JobDatabase.runningJobs.clear(); - } - - public synchronized void deleteJobs(@NonNull List jobIds) { - SQLiteDatabase db = databaseHelper.getWritableDatabase(); - - db.beginTransaction(); - - try { - for (String jobId : jobIds) { - String[] arg = new String[]{jobId}; - - db.delete(Jobs.TABLE_NAME, Jobs.JOB_SPEC_ID + " = ?", arg); - db.delete(Constraints.TABLE_NAME, Constraints.JOB_SPEC_ID + " = ?", arg); - db.delete(Dependencies.TABLE_NAME, Dependencies.JOB_SPEC_ID + " = ?", arg); - db.delete(Dependencies.TABLE_NAME, Dependencies.DEPENDS_ON_JOB_SPEC_ID + " = ?", arg); - } - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } - - public synchronized @NonNull List getAllConstraintSpecs() { - List constraints = new LinkedList<>(); - - try (Cursor cursor = databaseHelper.getReadableDatabase().query(Constraints.TABLE_NAME, null, null, null, null, null, null)) { - while (cursor != null && cursor.moveToNext()) { - constraints.add(constraintSpecFromCursor(cursor)); - } - } - - return constraints; - } - - public synchronized @NonNull List getAllDependencySpecs() { - List dependencies = new LinkedList<>(); - - try (Cursor cursor = databaseHelper.getReadableDatabase().query(Dependencies.TABLE_NAME, null, null, null, null, null, null)) { - while (cursor != null && cursor.moveToNext()) { - dependencies.add(dependencySpecFromCursor(cursor)); - } - } - - return dependencies; - } - - private void insertJobSpec(@NonNull SQLiteDatabase db, @NonNull JobSpec job) { - ContentValues contentValues = new ContentValues(); - contentValues.put(Jobs.JOB_SPEC_ID, job.getId()); - contentValues.put(Jobs.FACTORY_KEY, job.getFactoryKey()); - contentValues.put(Jobs.QUEUE_KEY, job.getQueueKey()); - contentValues.put(Jobs.CREATE_TIME, job.getCreateTime()); - contentValues.put(Jobs.NEXT_RUN_ATTEMPT_TIME, job.getNextRunAttemptTime()); - contentValues.put(Jobs.RUN_ATTEMPT, job.getRunAttempt()); - contentValues.put(Jobs.MAX_ATTEMPTS, job.getMaxAttempts()); - contentValues.put(Jobs.MAX_BACKOFF, job.getMaxBackoff()); - contentValues.put(Jobs.MAX_INSTANCES, job.getMaxInstances()); - contentValues.put(Jobs.LIFESPAN, job.getLifespan()); - contentValues.put(Jobs.SERIALIZED_DATA, job.getSerializedData()); - updateJobRunningState(job.getId(), job.isRunning()); - - db.insertWithOnConflict(Jobs.TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE); - } - - private void insertConstraintSpecs(@NonNull SQLiteDatabase db, @NonNull List constraints) { - for (ConstraintSpec constraintSpec : constraints) { - ContentValues contentValues = new ContentValues(); - contentValues.put(Constraints.JOB_SPEC_ID, constraintSpec.getJobSpecId()); - contentValues.put(Constraints.FACTORY_KEY, constraintSpec.getFactoryKey()); - db.insertWithOnConflict(Constraints.TABLE_NAME, null ,contentValues, SQLiteDatabase.CONFLICT_IGNORE); - } - } - - private void insertDependencySpecs(@NonNull SQLiteDatabase db, @NonNull List dependencies) { - for (DependencySpec dependencySpec : dependencies) { - ContentValues contentValues = new ContentValues(); - contentValues.put(Dependencies.JOB_SPEC_ID, dependencySpec.getJobId()); - contentValues.put(Dependencies.DEPENDS_ON_JOB_SPEC_ID, dependencySpec.getDependsOnJobId()); - db.insertWithOnConflict(Dependencies.TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE); - } - } - - private @NonNull JobSpec jobSpecFromCursor(@NonNull Cursor cursor) { - String jobId = cursor.getString(cursor.getColumnIndexOrThrow(Jobs.JOB_SPEC_ID)); - return new JobSpec(jobId, - cursor.getString(cursor.getColumnIndexOrThrow(Jobs.FACTORY_KEY)), - cursor.getString(cursor.getColumnIndexOrThrow(Jobs.QUEUE_KEY)), - cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.CREATE_TIME)), - cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.NEXT_RUN_ATTEMPT_TIME)), - cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.RUN_ATTEMPT)), - cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.MAX_ATTEMPTS)), - cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.MAX_BACKOFF)), - cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.LIFESPAN)), - cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.MAX_INSTANCES)), - cursor.getString(cursor.getColumnIndexOrThrow(Jobs.SERIALIZED_DATA)), - JobDatabase.runningJobs.contains(jobId)); - } - - private @NonNull ConstraintSpec constraintSpecFromCursor(@NonNull Cursor cursor) { - return new ConstraintSpec(cursor.getString(cursor.getColumnIndexOrThrow(Constraints.JOB_SPEC_ID)), - cursor.getString(cursor.getColumnIndexOrThrow(Constraints.FACTORY_KEY))); - } - - private @NonNull DependencySpec dependencySpecFromCursor(@NonNull Cursor cursor) { - return new DependencySpec(cursor.getString(cursor.getColumnIndexOrThrow(Dependencies.JOB_SPEC_ID)), - cursor.getString(cursor.getColumnIndexOrThrow(Dependencies.DEPENDS_ON_JOB_SPEC_ID))); - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt index 648b9c43ec..60d31a19d4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt @@ -32,7 +32,6 @@ interface DatabaseComponent { fun recipientDatabase(): RecipientDatabase fun groupReceiptDatabase(): GroupReceiptDatabase fun searchDatabase(): SearchDatabase - fun jobDatabase(): JobDatabase fun lokiAPIDatabase(): LokiAPIDatabase fun lokiMessageDatabase(): LokiMessageDatabase fun lokiThreadDatabase(): LokiThreadDatabase diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt index fba7a7e503..3372e10330 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt @@ -86,10 +86,6 @@ object DatabaseModule { @Singleton fun searchDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = SearchDatabase(context,openHelper) - @Provides - @Singleton - fun provideJobDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = JobDatabase(context, openHelper) - @Provides @Singleton fun provideLokiApiDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = LokiAPIDatabase(context,openHelper) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ExecutorFactory.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ExecutorFactory.java deleted file mode 100644 index b0c2b974de..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ExecutorFactory.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager; - -import androidx.annotation.NonNull; - -import java.util.concurrent.ExecutorService; - -public interface ExecutorFactory { - @NonNull ExecutorService newSingleThreadExecutor(@NonNull String name); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DefaultExecutorFactory.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DefaultExecutorFactory.java deleted file mode 100644 index a9d4591009..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/DefaultExecutorFactory.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.impl; - -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.jobmanager.ExecutorFactory; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class DefaultExecutorFactory implements ExecutorFactory { - @Override - public @NonNull ExecutorService newSingleThreadExecutor(@NonNull String name) { - return Executors.newSingleThreadExecutor(r -> new Thread(r, name)); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/ConstraintSpec.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/ConstraintSpec.java deleted file mode 100644 index 1dab10ae56..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/ConstraintSpec.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.persistence; - -import androidx.annotation.NonNull; - -import java.util.Objects; - -public final class ConstraintSpec { - - private final String jobSpecId; - private final String factoryKey; - - public ConstraintSpec(@NonNull String jobSpecId, @NonNull String factoryKey) { - this.jobSpecId = jobSpecId; - this.factoryKey = factoryKey; - } - - public String getJobSpecId() { - return jobSpecId; - } - - public String getFactoryKey() { - return factoryKey; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ConstraintSpec that = (ConstraintSpec) o; - return Objects.equals(jobSpecId, that.jobSpecId) && - Objects.equals(factoryKey, that.factoryKey); - } - - @Override - public int hashCode() { - return Objects.hash(jobSpecId, factoryKey); - } - - @Override - public @NonNull String toString() { - return String.format("jobSpecId: %s | factoryKey: %s", jobSpecId, factoryKey); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/DependencySpec.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/DependencySpec.java deleted file mode 100644 index 2faea0485b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/DependencySpec.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.persistence; - -import androidx.annotation.NonNull; - -import java.util.Objects; - -public final class DependencySpec { - - private final String jobId; - private final String dependsOnJobId; - - public DependencySpec(@NonNull String jobId, @NonNull String dependsOnJobId) { - this.jobId = jobId; - this.dependsOnJobId = dependsOnJobId; - } - - public @NonNull String getJobId() { - return jobId; - } - - public @NonNull String getDependsOnJobId() { - return dependsOnJobId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - DependencySpec that = (DependencySpec) o; - return Objects.equals(jobId, that.jobId) && - Objects.equals(dependsOnJobId, that.dependsOnJobId); - } - - @Override - public int hashCode() { - return Objects.hash(jobId, dependsOnJobId); - } - - @Override - public @NonNull String toString() { - return String.format("jobSpecId: %s | dependsOnJobSpecId: %s", jobId, dependsOnJobId); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/FullSpec.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/FullSpec.java deleted file mode 100644 index f93c0e64bd..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/FullSpec.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.persistence; - -import androidx.annotation.NonNull; - -import java.util.List; -import java.util.Objects; - -public final class FullSpec { - - private final JobSpec jobSpec; - private final List constraintSpecs; - private final List dependencySpecs; - - public FullSpec(@NonNull JobSpec jobSpec, - @NonNull List constraintSpecs, - @NonNull List dependencySpecs) - { - this.jobSpec = jobSpec; - this.constraintSpecs = constraintSpecs; - this.dependencySpecs = dependencySpecs; - } - - public @NonNull JobSpec getJobSpec() { - return jobSpec; - } - - public @NonNull List getConstraintSpecs() { - return constraintSpecs; - } - - public @NonNull List getDependencySpecs() { - return dependencySpecs; - } - - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - FullSpec fullSpec = (FullSpec) o; - return Objects.equals(jobSpec, fullSpec.jobSpec) && - Objects.equals(constraintSpecs, fullSpec.constraintSpecs) && - Objects.equals(dependencySpecs, fullSpec.dependencySpecs); - } - - @Override - public int hashCode() { - return Objects.hash(jobSpec, constraintSpecs, dependencySpecs); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobSpec.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobSpec.java deleted file mode 100644 index d5f5cd5b3e..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobSpec.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.persistence; - -import android.annotation.SuppressLint; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Objects; - -public final class JobSpec { - - private final String id; - private final String factoryKey; - private final String queueKey; - private final long createTime; - private final long nextRunAttemptTime; - private final int runAttempt; - private final int maxAttempts; - private final long maxBackoff; - private final long lifespan; - private final int maxInstances; - private final String serializedData; - private final boolean isRunning; - - public JobSpec(@NonNull String id, - @NonNull String factoryKey, - @Nullable String queueKey, - long createTime, - long nextRunAttemptTime, - int runAttempt, - int maxAttempts, - long maxBackoff, - long lifespan, - int maxInstances, - @NonNull String serializedData, - boolean isRunning) - { - this.id = id; - this.factoryKey = factoryKey; - this.queueKey = queueKey; - this.createTime = createTime; - this.nextRunAttemptTime = nextRunAttemptTime; - this.maxBackoff = maxBackoff; - this.runAttempt = runAttempt; - this.maxAttempts = maxAttempts; - this.lifespan = lifespan; - this.maxInstances = maxInstances; - this.serializedData = serializedData; - this.isRunning = isRunning; - } - - public @NonNull String getId() { - return id; - } - - public @NonNull String getFactoryKey() { - return factoryKey; - } - - public @Nullable String getQueueKey() { - return queueKey; - } - - public long getCreateTime() { - return createTime; - } - - public long getNextRunAttemptTime() { - return nextRunAttemptTime; - } - - public int getRunAttempt() { - return runAttempt; - } - - public int getMaxAttempts() { - return maxAttempts; - } - - public long getMaxBackoff() { - return maxBackoff; - } - - public int getMaxInstances() { - return maxInstances; - } - - public long getLifespan() { - return lifespan; - } - - public @NonNull String getSerializedData() { - return serializedData; - } - - public boolean isRunning() { - return isRunning; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - JobSpec jobSpec = (JobSpec) o; - return createTime == jobSpec.createTime && - nextRunAttemptTime == jobSpec.nextRunAttemptTime && - runAttempt == jobSpec.runAttempt && - maxAttempts == jobSpec.maxAttempts && - maxBackoff == jobSpec.maxBackoff && - lifespan == jobSpec.lifespan && - maxInstances == jobSpec.maxInstances && - isRunning == jobSpec.isRunning && - Objects.equals(id, jobSpec.id) && - Objects.equals(factoryKey, jobSpec.factoryKey) && - Objects.equals(queueKey, jobSpec.queueKey) && - Objects.equals(serializedData, jobSpec.serializedData); - } - - @Override - public int hashCode() { - return Objects.hash(id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, lifespan, maxInstances, serializedData, isRunning); - } - - @SuppressLint("DefaultLocale") - @Override - public @NonNull String toString() { - return String.format("id: %s | factoryKey: %s | queueKey: %s | createTime: %d | nextRunAttemptTime: %d | runAttempt: %d | maxAttempts: %d | maxBackoff: %d | maxInstances: %d | lifespan: %d | isRunning: %b | data: %s", - id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, maxInstances, lifespan, isRunning, serializedData); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobStorage.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobStorage.java deleted file mode 100644 index b7c035ac60..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/persistence/JobStorage.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.thoughtcrime.securesms.jobmanager.persistence; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.WorkerThread; - -import java.util.List; - -public interface JobStorage { - - @WorkerThread - void init(); - - @WorkerThread - void insertJobs(@NonNull List fullSpecs); - - @WorkerThread - @Nullable JobSpec getJobSpec(@NonNull String id); - - @WorkerThread - @NonNull List getAllJobSpecs(); - - @WorkerThread - @NonNull List getPendingJobsWithNoDependenciesInCreatedOrder(long currentTime); - - @WorkerThread - int getJobInstanceCount(@NonNull String factoryKey); - - @WorkerThread - void updateJobRunningState(@NonNull String id, boolean isRunning); - - @WorkerThread - void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime); - - @WorkerThread - void updateAllJobsToBePending(); - - @WorkerThread - void deleteJob(@NonNull String id); - - @WorkerThread - void deleteJobs(@NonNull List ids); - - @WorkerThread - @NonNull List getConstraintSpecs(@NonNull String jobId); - - @WorkerThread - @NonNull List getAllConstraintSpecs(); - - @WorkerThread - @NonNull List getDependencySpecsThatDependOnJob(@NonNull String jobSpecId); - - @WorkerThread - @NonNull List getAllDependencySpecs(); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt deleted file mode 100644 index 8a71760df3..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/LocalBackupJob.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.thoughtcrime.securesms.jobs - -import android.content.Context -import org.session.libsession.messaging.jobs.Job -import org.session.libsession.messaging.jobs.JobDelegate -import org.session.libsession.messaging.utilities.Data -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.notifications.NotificationChannels -import org.thoughtcrime.securesms.service.GenericForegroundService -import org.thoughtcrime.securesms.util.BackupUtil.createBackupFile -import org.thoughtcrime.securesms.util.BackupUtil.deleteAllBackupFiles - -import network.loki.messenger.R - - -class LocalBackupJob:Job { - override var delegate: JobDelegate? = null - override var id: String? = null - override var failureCount: Int = 0 - override val maxFailureCount: Int = 0 - - lateinit var context: Context - - companion object { - val TAG = LocalBackupJob::class.simpleName - val KEY: String = "LocalBackupJob" - } - - override fun execute(dispatcherName: String) { - Log.i(TAG, "Executing backup job...") - - GenericForegroundService.startForegroundTask( - context, - context.getString(R.string.LocalBackupJob_creating_backup), - NotificationChannels.BACKUPS, - R.drawable.ic_launcher_foreground - ) - - // TODO: Maybe create a new backup icon like ic_signal_backup? - try { - val record = createBackupFile(context) - deleteAllBackupFiles(context, listOf(record)) - } finally { - GenericForegroundService.stopForegroundTask(context) - } - } - - override fun serialize(): Data { - return Data.EMPTY - } - - override fun getFactoryKey(): String { - return KEY - } - - class Factory: Job.Factory { - override fun create(data: Data): LocalBackupJob { - return LocalBackupJob() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt deleted file mode 100644 index 411f01fcde..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/UpdateApkJob.kt +++ /dev/null @@ -1,200 +0,0 @@ -package org.thoughtcrime.securesms.jobs - -import androidx.annotation.Nullable - -import android.app.DownloadManager -import android.content.Context -import android.content.Intent -import android.content.pm.PackageInfo -import android.content.pm.PackageManager -import android.net.Uri -import com.fasterxml.jackson.annotation.JsonProperty -import network.loki.messenger.BuildConfig -import okhttp3.OkHttpClient -import okhttp3.Request -import org.session.libsession.messaging.jobs.Job -import org.session.libsession.messaging.jobs.JobDelegate -import org.session.libsession.messaging.utilities.Data -import org.session.libsession.utilities.FileUtils -import org.session.libsession.utilities.TextSecurePreferences.Companion.getUpdateApkDigest -import org.session.libsession.utilities.TextSecurePreferences.Companion.getUpdateApkDownloadId -import org.session.libsession.utilities.TextSecurePreferences.Companion.setUpdateApkDigest -import org.session.libsession.utilities.TextSecurePreferences.Companion.setUpdateApkDownloadId -import org.session.libsignal.utilities.Hex -import org.session.libsignal.utilities.JsonUtil -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.service.UpdateApkReadyListener -import java.io.FileInputStream -import java.io.IOException -import java.security.MessageDigest - -class UpdateApkJob: Job { - override var delegate: JobDelegate? = null - override var id: String? = null - override var failureCount: Int = 0 - override val maxFailureCount: Int = 0 - - lateinit var context: Context - - companion object { - val TAG = UpdateApkJob::class.simpleName - val KEY: String = "UpdateApkJob" - } - - override fun execute(dispatcherName: String) { - if (!BuildConfig.PLAY_STORE_DISABLED) return - - Log.i(TAG, "Checking for APK update...") - - val client = OkHttpClient() - val request = Request.Builder().url(String.format("%s/latest.json", BuildConfig.NOPLAY_UPDATE_URL)).build() - val response = client.newCall(request).execute() - - if (!response.isSuccessful) { - throw IOException("Bad response: " + response.message()) - } - - val updateDescriptor: UpdateDescriptor = JsonUtil.fromJson( - response.body()!!.string(), - UpdateDescriptor::class.java - ) - val digest = Hex.fromStringCondensed(updateDescriptor.digest) - - Log.i( - TAG, - "Got descriptor: $updateDescriptor" - ) - - if (updateDescriptor.versionCode > getVersionCode()) { - val downloadStatus: DownloadStatus = getDownloadStatus(updateDescriptor.url, digest) - Log.i(TAG, "Download status: " + downloadStatus.status) - if (downloadStatus.status == DownloadStatus.Status.COMPLETE) { - Log.i(TAG, "Download status complete, notifying...") - handleDownloadNotify(downloadStatus.downloadId) - } else if (downloadStatus.status == DownloadStatus.Status.MISSING) { - Log.i(TAG, "Download status missing, starting download...") - handleDownloadStart( - updateDescriptor.url, - updateDescriptor.versionName, - digest - ) - } - } - } - - @Throws(PackageManager.NameNotFoundException::class) - private fun getVersionCode(): Int { - val packageManager: PackageManager = context.getPackageManager() - val packageInfo: PackageInfo = packageManager.getPackageInfo(context.getPackageName(), 0) - return packageInfo.versionCode - } - - private fun getDownloadStatus(uri: String, theirDigest: ByteArray): DownloadStatus { - val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager - val query = DownloadManager.Query() - query.setFilterByStatus(DownloadManager.STATUS_PAUSED or DownloadManager.STATUS_PENDING or DownloadManager.STATUS_RUNNING or DownloadManager.STATUS_SUCCESSFUL) - val pendingDownloadId = getUpdateApkDownloadId(context) - val pendingDigest = getPendingDigest(context) - val cursor = downloadManager.query(query) - return try { - var status = DownloadStatus(DownloadStatus.Status.MISSING, -1) - while (cursor != null && cursor.moveToNext()) { - val jobStatus = - cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) - val jobRemoteUri = - cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_URI)) - val downloadId = - cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID)) - val digest = getDigestForDownloadId(downloadId) - if (jobRemoteUri != null && jobRemoteUri == uri && downloadId == pendingDownloadId) { - if (jobStatus == DownloadManager.STATUS_SUCCESSFUL && digest != null && pendingDigest != null && - MessageDigest.isEqual(pendingDigest, theirDigest) && - MessageDigest.isEqual(digest, theirDigest) - ) { - return DownloadStatus(DownloadStatus.Status.COMPLETE, downloadId) - } else if (jobStatus != DownloadManager.STATUS_SUCCESSFUL) { - status = DownloadStatus(DownloadStatus.Status.PENDING, downloadId) - } - } - } - status - } finally { - cursor?.close() - } - } - - private fun handleDownloadStart(uri: String, versionName: String, digest: ByteArray) { - val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager - val downloadRequest = DownloadManager.Request(Uri.parse(uri)) - downloadRequest.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI) - downloadRequest.setTitle("Downloading Signal update") - downloadRequest.setDescription("Downloading Signal $versionName") - downloadRequest.setVisibleInDownloadsUi(false) - downloadRequest.setDestinationInExternalFilesDir(context, null, "signal-update.apk") - downloadRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN) - val downloadId = downloadManager.enqueue(downloadRequest) - setUpdateApkDownloadId(context, downloadId) - setUpdateApkDigest(context, Hex.toStringCondensed(digest)) - } - - private fun handleDownloadNotify(downloadId: Long) { - val intent = Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE) - intent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId) - UpdateApkReadyListener().onReceive(context, intent) - } - - private fun getDigestForDownloadId(downloadId: Long): ByteArray? { - return try { - val downloadManager = - context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager - val fin = FileInputStream(downloadManager.openDownloadedFile(downloadId).fileDescriptor) - val digest = FileUtils.getFileDigest(fin) - fin.close() - digest - } catch (e: IOException) { - Log.w(TAG, e) - null - } - } - - private fun getPendingDigest(context: Context): ByteArray? { - return try { - val encodedDigest = getUpdateApkDigest(context) ?: return null - Hex.fromStringCondensed(encodedDigest) - } catch (e: IOException) { - Log.w(TAG, e) - null - } - } - - override fun serialize(): Data { - return Data.EMPTY - } - - override fun getFactoryKey(): String { - return KEY - } - - private class UpdateDescriptor( - @JsonProperty("versionCode") @Nullable val versionCode: Int, - @JsonProperty("versionName") @Nullable val versionName: String, - @JsonProperty("url") @Nullable val url: String, - @JsonProperty("sha256sum") @Nullable val digest: String) - { - override fun toString(): String { - return "[$versionCode, $versionName, $url]" - } - } - - private class DownloadStatus(val status: Status, val downloadId: Long) { - enum class Status { - PENDING, COMPLETE, MISSING - } - } - - class Factory: Job.Factory { - override fun create(data: Data): UpdateApkJob { - return UpdateApkJob() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java deleted file mode 100644 index 9cf88f4094..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.thoughtcrime.securesms.service; - -import android.content.Context; -import android.content.Intent; - -import org.session.libsession.messaging.jobs.JobQueue; -import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.jobs.LocalBackupJob; -import org.session.libsession.utilities.TextSecurePreferences; - -import java.util.concurrent.TimeUnit; - -public class LocalBackupListener extends PersistentAlarmManagerListener { - - private static final long INTERVAL = TimeUnit.DAYS.toMillis(1); - - @Override - protected long getNextScheduledExecutionTime(Context context) { - return TextSecurePreferences.getNextBackupTime(context); - } - - @Override - protected long onAlarm(Context context, long scheduledTime) { - if (TextSecurePreferences.isBackupEnabled(context)) { - LocalBackupJob job = new LocalBackupJob(); - job.context = context; - JobQueue.getShared().add(job); - } - - long nextTime = System.currentTimeMillis() + INTERVAL; - TextSecurePreferences.setNextBackupTime(context, nextTime); - - return nextTime; - } - - public static void schedule(Context context) { - if (TextSecurePreferences.isBackupEnabled(context)) { - new LocalBackupListener().onReceive(context, new Intent()); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java deleted file mode 100644 index 01ade94214..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/service/UpdateApkRefreshListener.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.thoughtcrime.securesms.service; - - -import android.content.Context; -import android.content.Intent; - -import org.session.libsession.messaging.jobs.JobQueue; -import org.session.libsignal.utilities.Log; - -import org.thoughtcrime.securesms.ApplicationContext; -import network.loki.messenger.BuildConfig; -import org.thoughtcrime.securesms.jobs.UpdateApkJob; -import org.session.libsession.utilities.TextSecurePreferences; - -import java.util.concurrent.TimeUnit; - -public class UpdateApkRefreshListener extends PersistentAlarmManagerListener { - - private static final String TAG = UpdateApkRefreshListener.class.getSimpleName(); - - private static final long INTERVAL = TimeUnit.HOURS.toMillis(6); - - @Override - protected long getNextScheduledExecutionTime(Context context) { - return TextSecurePreferences.getUpdateApkRefreshTime(context); - } - - @Override - protected long onAlarm(Context context, long scheduledTime) { - Log.i(TAG, "onAlarm..."); - - if (scheduledTime != 0 && BuildConfig.PLAY_STORE_DISABLED) { - Log.i(TAG, "Queueing APK update job..."); - UpdateApkJob job = new UpdateApkJob(); - job.context = context; - JobQueue.getShared().add(job); - } - - long newTime = System.currentTimeMillis() + INTERVAL; - TextSecurePreferences.setUpdateApkRefreshTime(context, newTime); - - return newTime; - } - - public static void schedule(Context context) { - new UpdateApkRefreshListener().onReceive(context, new Intent()); - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/BackupUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/util/BackupUtil.kt deleted file mode 100644 index 074278cb92..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/util/BackupUtil.kt +++ /dev/null @@ -1,313 +0,0 @@ -package org.thoughtcrime.securesms.util - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.Build -import android.os.Environment -import android.provider.DocumentsContract -import android.widget.Toast -import androidx.annotation.WorkerThread -import androidx.documentfile.provider.DocumentFile -import androidx.fragment.app.Fragment -import network.loki.messenger.R -import org.greenrobot.eventbus.EventBus -import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsignal.utilities.ByteUtil -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.backup.BackupEvent -import org.thoughtcrime.securesms.backup.BackupPassphrase -import org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference -import org.thoughtcrime.securesms.backup.FullBackupExporter -import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider -import org.thoughtcrime.securesms.crypto.IdentityKeyUtil -import org.thoughtcrime.securesms.database.BackupFileRecord -import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import java.io.IOException -import java.security.MessageDigest -import java.security.NoSuchAlgorithmException -import java.security.SecureRandom -import java.text.SimpleDateFormat -import java.util.* - -object BackupUtil { - private const val MASTER_SECRET_UTIL_PREFERENCES_NAME = "SecureSMS-Preferences" - private const val TAG = "BackupUtil" - const val BACKUP_FILE_MIME_TYPE = "application/session-backup" - const val BACKUP_PASSPHRASE_LENGTH = 30 - - fun getBackupRecords(context: Context): List { - val prefName = MASTER_SECRET_UTIL_PREFERENCES_NAME - val preferences = context.getSharedPreferences(prefName, 0) - val prefList = LinkedList() - prefList.add(SharedPreference.newBuilder() - .setFile(prefName) - .setKey(IdentityKeyUtil.IDENTITY_PUBLIC_KEY_PREF) - .setValue(preferences.getString(IdentityKeyUtil.IDENTITY_PUBLIC_KEY_PREF, null)) - .build()) - prefList.add(SharedPreference.newBuilder() - .setFile(prefName) - .setKey(IdentityKeyUtil.IDENTITY_PRIVATE_KEY_PREF) - .setValue(preferences.getString(IdentityKeyUtil.IDENTITY_PRIVATE_KEY_PREF, null)) - .build()) - if (preferences.contains(IdentityKeyUtil.ED25519_PUBLIC_KEY)) { - prefList.add(SharedPreference.newBuilder() - .setFile(prefName) - .setKey(IdentityKeyUtil.ED25519_PUBLIC_KEY) - .setValue(preferences.getString(IdentityKeyUtil.ED25519_PUBLIC_KEY, null)) - .build()) - } - if (preferences.contains(IdentityKeyUtil.ED25519_SECRET_KEY)) { - prefList.add(SharedPreference.newBuilder() - .setFile(prefName) - .setKey(IdentityKeyUtil.ED25519_SECRET_KEY) - .setValue(preferences.getString(IdentityKeyUtil.ED25519_SECRET_KEY, null)) - .build()) - } - prefList.add(SharedPreference.newBuilder() - .setFile(prefName) - .setKey(IdentityKeyUtil.LOKI_SEED) - .setValue(preferences.getString(IdentityKeyUtil.LOKI_SEED, null)) - .build()) - return prefList - } - - @JvmStatic - fun getLastBackupTimeString(context: Context, locale: Locale): String { - val timestamp = DatabaseComponent.get(context).lokiBackupFilesDatabase().getLastBackupFileTime() - if (timestamp == null) { - return context.getString(R.string.BackupUtil_never) - } - return DateUtils.getDisplayFormattedTimeSpanString(context, locale, timestamp.time) - } - - @JvmStatic - fun getLastBackup(context: Context): BackupFileRecord? { - return DatabaseComponent.get(context).lokiBackupFilesDatabase().getLastBackupFile() - } - - @JvmStatic - fun generateBackupPassphrase(): Array { - val random = ByteArray(BACKUP_PASSPHRASE_LENGTH).also { SecureRandom().nextBytes(it) } - return Array(6) { i -> - String.format("%05d", ByteUtil.byteArray5ToLong(random, i * 5) % 100000) - } - } - - @JvmStatic - fun validateDirAccess(context: Context, dirUri: Uri): Boolean { - val hasWritePermission = context.contentResolver.persistedUriPermissions.any { - it.isWritePermission && it.uri == dirUri - } - if (!hasWritePermission) return false - - val document = DocumentFile.fromTreeUri(context, dirUri) - if (document == null || !document.exists()) { - return false - } - - return true - } - - @JvmStatic - fun getBackupDirUri(context: Context): Uri? { - val dirUriString = TextSecurePreferences.getBackupSaveDir(context) ?: return null - return Uri.parse(dirUriString) - } - - @JvmStatic - fun setBackupDirUri(context: Context, uriString: String?) { - TextSecurePreferences.setBackupSaveDir(context, uriString) - } - - /** - * @return The selected backup directory if it's valid (exists, is writable). - */ - @JvmStatic - fun getSelectedBackupDirIfValid(context: Context): Uri? { - val dirUri = getBackupDirUri(context) - - if (dirUri == null) { - Log.v(TAG, "The backup dir wasn't selected yet.") - return null - } - if (!validateDirAccess(context, dirUri)) { - Log.v(TAG, "Cannot validate the access to the dir $dirUri.") - return null - } - - return dirUri; - } - - @JvmStatic - @WorkerThread - @Throws(IOException::class) - fun createBackupFile(context: Context): BackupFileRecord { - val backupPassword = BackupPassphrase.get(context) - ?: throw IOException("Backup password is null") - - val dirUri = getSelectedBackupDirIfValid(context) - ?: throw IOException("Backup save directory is not selected or invalid") - - val date = Date() - val timestamp = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US).format(date) - val fileName = String.format("session-%s.backup", timestamp) - - val fileUri = DocumentsContract.createDocument( - context.contentResolver, - DocumentFile.fromTreeUri(context, dirUri)!!.uri, - BACKUP_FILE_MIME_TYPE, - fileName) - - if (fileUri == null) { - Toast.makeText(context, "Cannot create writable file in the dir $dirUri", Toast.LENGTH_LONG).show() - throw IOException("Cannot create writable file in the dir $dirUri") - } - - try { - FullBackupExporter.export(context, - AttachmentSecretProvider.getInstance(context).orCreateAttachmentSecret, - DatabaseComponent.get(context).openHelper().readableDatabase, - fileUri, - backupPassword) - } catch (e: Exception) { - // Delete the backup file on any error. - DocumentsContract.deleteDocument(context.contentResolver, fileUri) - throw e - } - - //TODO Use real file size. - val record = DatabaseComponent.get(context).lokiBackupFilesDatabase() - .insertBackupFile(BackupFileRecord(fileUri, -1, date)) - - Log.v(TAG, "A backup file was created: $fileUri") - - return record - } - - @JvmStatic - @JvmOverloads - fun deleteAllBackupFiles(context: Context, except: Collection? = null) { - val db = DatabaseComponent.get(context).lokiBackupFilesDatabase() - db.getBackupFiles().iterator().forEach { record -> - if (except != null && except.contains(record)) return@forEach - - // Try to delete the related file. The operation may fail in many cases - // (the user moved/deleted the file, revoked the write permission, etc), so that's OK. - try { - val result = DocumentsContract.deleteDocument(context.contentResolver, record.uri) - if (!result) { - Log.w(TAG, "Failed to delete backup file: ${record.uri}") - } - } catch (e: Exception) { - Log.w(TAG, "Failed to delete backup file: ${record.uri}", e) - } - - db.deleteBackupFile(record) - - Log.v(TAG, "Backup file was deleted: ${record.uri}") - } - } - - @JvmStatic - fun computeBackupKey(passphrase: String, salt: ByteArray?): ByteArray { - return try { - EventBus.getDefault().post(BackupEvent.createProgress(0)) - val digest = MessageDigest.getInstance("SHA-512") - val input = passphrase.replace(" ", "").toByteArray() - var hash: ByteArray = input - if (salt != null) digest.update(salt) - for (i in 0..249999) { - if (i % 1000 == 0) EventBus.getDefault().post(BackupEvent.createProgress(0)) - digest.update(hash) - hash = digest.digest(input) - } - ByteUtil.trim(hash, 32) - } catch (e: NoSuchAlgorithmException) { - throw AssertionError(e) - } - } -} - -/** - * An utility class to help perform backup directory selection requests. - * - * An instance of this class should be created per an [Activity] or [Fragment] - * and [onActivityResult] should be called appropriately. - */ -class BackupDirSelector(private val contextProvider: ContextProvider) { - - companion object { - private const val REQUEST_CODE_SAVE_DIR = 7844 - } - - private val context: Context get() = contextProvider.getContext() - - private var listener: Listener? = null - - constructor(activity: Activity) : - this(ActivityContextProvider(activity)) - - constructor(fragment: Fragment) : - this(FragmentContextProvider(fragment)) - - /** - * Performs ACTION_OPEN_DOCUMENT_TREE intent to select backup directory URI. - * If the directory is already selected and valid, the request will be skipped. - * @param force if true, the previous selection is ignored and the user is requested to select another directory. - * @param onSelectedListener an optional action to perform once the directory is selected. - */ - fun selectBackupDir(force: Boolean, onSelectedListener: Listener? = null) { - if (!force) { - val dirUri = BackupUtil.getSelectedBackupDirIfValid(context) - if (dirUri != null && onSelectedListener != null) { - onSelectedListener.onBackupDirSelected(dirUri) - } - return - } - - // Let user pick the dir. - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - - // Request read/write permission grant for the dir. - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION or - Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) - - // Set the default dir. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val dirUri = BackupUtil.getBackupDirUri(context) - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, dirUri - ?: Uri.fromFile(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS))) - } - - if (onSelectedListener != null) { - this.listener = onSelectedListener - } - - contextProvider.startActivityForResult(intent, REQUEST_CODE_SAVE_DIR) - } - - fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode != REQUEST_CODE_SAVE_DIR) return - - if (resultCode == Activity.RESULT_OK && data != null && data.data != null) { - // Acquire persistent access permissions for the file selected. - val persistentFlags: Int = data.flags and - (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - context.contentResolver.takePersistableUriPermission(data.data!!, persistentFlags) - - BackupUtil.setBackupDirUri(context, data.dataString) - - listener?.onBackupDirSelected(data.data!!) - } - - listener = null - } - - @FunctionalInterface - interface Listener { - fun onBackupDirSelected(uri: Uri) - } -} \ No newline at end of file From ba3566f7e883d90287749ae88583a483b7eb5f5a Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 11 May 2023 09:30:39 +0930 Subject: [PATCH 36/83] Fix approval text position when input bar is gone (#1181) --- app/src/main/res/layout/activity_conversation_v2.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/activity_conversation_v2.xml b/app/src/main/res/layout/activity_conversation_v2.xml index d2696a45ec..8992a660d7 100644 --- a/app/src/main/res/layout/activity_conversation_v2.xml +++ b/app/src/main/res/layout/activity_conversation_v2.xml @@ -128,6 +128,7 @@ android:textSize="12sp" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_alignWithParentIfMissing="true" android:layout_above="@id/messageRequestBar"/> Date: Thu, 11 May 2023 09:31:05 +0930 Subject: [PATCH 37/83] Fix message request button overlap (#1188) --- .../main/res/layout/view_message_request_banner.xml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/view_message_request_banner.xml b/app/src/main/res/layout/view_message_request_banner.xml index d37fde8a3f..c03e9c1cdf 100644 --- a/app/src/main/res/layout/view_message_request_banner.xml +++ b/app/src/main/res/layout/view_message_request_banner.xml @@ -3,9 +3,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:contentDescription="@string/AccessibilityId_message_request_banner" android:layout_height="wrap_content" android:background="@drawable/conversation_view_background" + android:contentDescription="@string/AccessibilityId_message_request_banner" android:gravity="center_vertical" android:orientation="horizontal" android:paddingStart="@dimen/accent_line_thickness" @@ -72,11 +72,15 @@ android:alpha="0.4" android:ellipsize="end" android:maxLines="1" + android:textAlignment="textEnd" android:textColor="?android:textColorPrimary" android:textSize="@dimen/small_font_size" + app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="1" + app:layout_constraintStart_toEndOf="@id/unreadCountIndicator" app:layout_constraintTop_toTopOf="parent" - tools:text="9:41 AM" /> + tools:text="11 Apr, 9:41 AM" /> - \ No newline at end of file + From 8dbabec4e7c90a975df1307bba2c810bbff67b42 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 11 May 2023 09:32:38 +0930 Subject: [PATCH 38/83] Fix send after approval message (#1178) * Fix send after approval message * Fix logic * Utilise isLocalNumber --- .../securesms/conversation/v2/ConversationActivityV2.kt | 2 +- .../securesms/conversation/v2/ConversationViewModel.kt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index cabb583085..c30a491a8f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -667,7 +667,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } private fun updateSendAfterApprovalText() { - binding?.textSendAfterApproval?.isGone = viewModel.recipient?.hasApprovedMe() ?: true + binding?.textSendAfterApproval?.isVisible = viewModel.showSendAfterApprovalText } private fun showOrHideInputIfNeeded() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt index 7f6768ee93..fc557f7260 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt @@ -31,6 +31,9 @@ class ConversationViewModel( private val storage: Storage ) : ViewModel() { + val showSendAfterApprovalText: Boolean + get() = recipient?.run { isContactRecipient && !isLocalNumber && !hasApprovedMe() } ?: false + private val _uiState = MutableStateFlow(ConversationUiState()) val uiState: StateFlow = _uiState From 88e788a4060ded3fefb052e68889febeac1d12c0 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 11 May 2023 12:16:37 +1000 Subject: [PATCH 39/83] clean --- .../java/org/thoughtcrime/securesms/ApplicationContext.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 5a9999a7bc..53141534af 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -106,7 +106,6 @@ import dagger.hilt.EntryPoints; import dagger.hilt.android.HiltAndroidApp; import kotlin.Unit; import kotlinx.coroutines.Job; -import network.loki.messenger.BuildConfig; /** * Will be called once when the TextSecure process is created. @@ -158,10 +157,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO return (ApplicationContext) context.getApplicationContext(); } - public TextSecurePreferences getPrefs() { - return textSecurePreferences; - } - public DatabaseComponent getDatabaseComponent() { return EntryPoints.get(getApplicationContext(), DatabaseComponent.class); } From a334b8912af8dc5aad3705af831711b82981cd64 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 17 May 2023 14:39:47 +0930 Subject: [PATCH 40/83] Fix device notification settings preference color --- app/src/main/res/layout/go_to_device_settings.xml | 14 -------------- app/src/main/res/xml/preferences_notifications.xml | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 app/src/main/res/layout/go_to_device_settings.xml diff --git a/app/src/main/res/layout/go_to_device_settings.xml b/app/src/main/res/layout/go_to_device_settings.xml deleted file mode 100644 index 97d452e53c..0000000000 --- a/app/src/main/res/layout/go_to_device_settings.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/xml/preferences_notifications.xml b/app/src/main/res/xml/preferences_notifications.xml index 52a429cc36..03945d6957 100644 --- a/app/src/main/res/xml/preferences_notifications.xml +++ b/app/src/main/res/xml/preferences_notifications.xml @@ -10,7 +10,7 @@ android:summary="@string/preferences_notifications_strategy_category_fast_mode_summary" android:defaultValue="false" /> - From 8c5ff1f9449f5f1495367fe90b50450e327900c0 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 17 May 2023 14:50:20 +0930 Subject: [PATCH 41/83] Fix dialog button color --- app/src/main/res/values/styles.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1cf88c0c06..9fa6059885 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -29,8 +29,6 @@ ?colorPrimary true 0.6 - @style/Widget.Session.AlertDialog.NegativeButtonStyle - @style/Widget.Session.AlertDialog.PositiveButtonStyle @null @null ?android:textColorPrimary @@ -46,14 +44,6 @@ @drawable/default_bottom_sheet_background - - - - From 235b94a905296b9f489744bd6ce99b5ea2309fb7 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 18 May 2023 19:20:44 +0930 Subject: [PATCH 42/83] Fix ripple color --- .../drawable/conversation_pinned_background.xml | 2 +- .../drawable/conversation_unread_background.xml | 2 +- .../drawable/conversation_view_background.xml | 2 +- .../mention_candidate_view_background.xml | 2 +- .../res/drawable/setting_button_background.xml | 2 +- .../main/res/layout/blocked_contact_layout.xml | 1 - app/src/main/res/values/attrs.xml | 2 -- app/src/main/res/values/themes.xml | 16 ++++------------ 8 files changed, 9 insertions(+), 20 deletions(-) diff --git a/app/src/main/res/drawable/conversation_pinned_background.xml b/app/src/main/res/drawable/conversation_pinned_background.xml index 104b9c272e..eb64dc7f5f 100644 --- a/app/src/main/res/drawable/conversation_pinned_background.xml +++ b/app/src/main/res/drawable/conversation_pinned_background.xml @@ -1,7 +1,7 @@ + android:color="?android:colorControlHighlight"> diff --git a/app/src/main/res/drawable/conversation_unread_background.xml b/app/src/main/res/drawable/conversation_unread_background.xml index de0f5fb688..9e9bb94361 100644 --- a/app/src/main/res/drawable/conversation_unread_background.xml +++ b/app/src/main/res/drawable/conversation_unread_background.xml @@ -1,7 +1,7 @@ + android:color="?android:colorControlHighlight"> diff --git a/app/src/main/res/drawable/conversation_view_background.xml b/app/src/main/res/drawable/conversation_view_background.xml index aaceb7ed54..2f177318e0 100644 --- a/app/src/main/res/drawable/conversation_view_background.xml +++ b/app/src/main/res/drawable/conversation_view_background.xml @@ -1,7 +1,7 @@ + android:color="?android:colorControlHighlight"> diff --git a/app/src/main/res/drawable/mention_candidate_view_background.xml b/app/src/main/res/drawable/mention_candidate_view_background.xml index 7b179020aa..4e9785a41e 100644 --- a/app/src/main/res/drawable/mention_candidate_view_background.xml +++ b/app/src/main/res/drawable/mention_candidate_view_background.xml @@ -1,7 +1,7 @@ + android:color="?android:colorControlHighlight"> diff --git a/app/src/main/res/drawable/setting_button_background.xml b/app/src/main/res/drawable/setting_button_background.xml index aaceb7ed54..2f177318e0 100644 --- a/app/src/main/res/drawable/setting_button_background.xml +++ b/app/src/main/res/drawable/setting_button_background.xml @@ -1,7 +1,7 @@ + android:color="?android:colorControlHighlight"> diff --git a/app/src/main/res/layout/blocked_contact_layout.xml b/app/src/main/res/layout/blocked_contact_layout.xml index 40d7f40dd3..673779cfd0 100644 --- a/app/src/main/res/layout/blocked_contact_layout.xml +++ b/app/src/main/res/layout/blocked_contact_layout.xml @@ -7,7 +7,6 @@ android:paddingHorizontal="@dimen/medium_spacing" android:paddingVertical="@dimen/small_spacing" android:gravity="center_vertical" - android:background="?selectableItemBackground" android:id="@+id/backgroundContainer"> - @@ -176,7 +175,6 @@ - diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 43d06ee7ad..204089862b 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -319,7 +319,6 @@ @color/classic_dark_0 ?android:textColorPrimary ?colorAccent - ?colorAccent @color/classic_dark_6 ?android:textColorPrimary @color/classic_dark_5 @@ -334,7 +333,7 @@ @color/classic_dark_1 @color/classic_dark_1 @color/classic_dark_3 - @color/classic_dark_3 + @color/classic_dark_3 @style/Dark.Popup @null @style/ThemeOverlay.AppCompat.Dark.ActionBar @@ -382,7 +381,6 @@ @color/classic_dark_2 @color/classic_dark_3 @color/classic_dark_2 - @color/classic_dark_3 @color/classic_dark_1 @color/classic_dark_3 @color/classic_dark_4 @@ -397,7 +395,6 @@ @color/classic_light_6 ?android:textColorPrimary ?colorAccent - ?colorAccent @color/classic_light_0 @color/classic_light_1 @color/classic_light_1 @@ -408,7 +405,7 @@ @color/classic_light_6 @color/classic_light_5 @color/classic_light_3 - @color/classic_light_3 + @color/classic_light_3 @style/Classic.Light.BottomSheet ?android:textColorPrimary ?actionBarPopupTheme @@ -467,7 +464,6 @@ @color/classic_light_4 @color/classic_light_2 ?colorCellBackground - ?colorCellRipple @color/classic_light_4 @color/classic_light_2 @color/classic_dark_4 @@ -482,7 +478,6 @@ @color/ocean_dark_2 @color/ocean_dark_7 ?colorAccent - ?colorAccent @color/ocean_dark_7 @color/ocean_dark_5 @color/ocean_dark_5 @@ -496,7 +491,7 @@ @color/ocean_dark_3 @color/ocean_dark_1 @color/ocean_dark_4 - @color/ocean_dark_4 + @color/ocean_dark_4 @style/Ocean.Dark.BottomSheet ?actionBarPopupTheme ?android:textColorPrimary @@ -549,7 +544,6 @@ ?colorPrimary ?colorPrimary @color/ocean_dark_2 - @color/ocean_dark_3 @color/ocean_dark_4 ?colorPrimary @color/ocean_dark_4 @@ -564,7 +558,6 @@ @color/ocean_light_6 @color/ocean_light_1 ?colorAccent - ?colorAccent @color/ocean_light_1 @color/ocean_light_2 @color/ocean_light_2 @@ -578,7 +571,7 @@ @color/ocean_light_5 @color/ocean_light_6 @color/ocean_light_3 - @color/ocean_light_4 + @color/ocean_light_4 @style/Ocean.Light.BottomSheet @style/Light.Popup ?actionBarPopupTheme @@ -633,7 +626,6 @@ @color/ocean_light_5 @color/ocean_light_1 ?colorCellBackground - ?colorCellRipple ?input_bar_button_background_opaque ?input_bar_button_background_opaque_border ?colorAccent From 30d748e1476a7dc9f7cf5f4ee00d65db22544deb Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 19 May 2023 23:44:07 +0930 Subject: [PATCH 43/83] Disable unblock button --- .../securesms/database/RecipientDatabase.java | 2 +- .../securesms/database/Storage.kt | 2 +- .../preferences/BlockedContactsActivity.kt | 78 ++++++------------- .../preferences/BlockedContactsAdapter.kt | 16 ++-- .../preferences/BlockedContactsViewModel.kt | 68 +++++++++++++--- app/src/main/res/color/button_destructive.xml | 5 ++ ...ctive_outline_button_medium_background.xml | 2 +- app/src/main/res/values/styles.xml | 2 +- .../libsession/database/StorageProtocol.kt | 2 +- 9 files changed, 98 insertions(+), 79 deletions(-) create mode 100644 app/src/main/res/color/button_destructive.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java index af2faaaca9..e3570fd283 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -276,7 +276,7 @@ public class RecipientDatabase extends Database { notifyRecipientListeners(); } - public void setBlocked(@NonNull List recipients, boolean blocked) { + public void setBlocked(@NonNull Iterable recipients, boolean blocked) { SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 33896803b8..ed6510f741 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -1010,7 +1010,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, DatabaseComponent.get(context).reactionDatabase().deleteMessageReactions(MessageId(messageId, mms)) } - override fun unblock(toUnblock: List) { + override fun unblock(toUnblock: Iterable) { val recipientDb = DatabaseComponent.get(context).recipientDatabase() recipientDb.setBlocked(toUnblock, false) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsActivity.kt index 504194d3a4..9b8d800dd5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsActivity.kt @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.preferences import android.app.AlertDialog import android.os.Bundle -import android.view.View import androidx.activity.viewModels import androidx.core.view.isVisible import dagger.hilt.android.AndroidEntryPoint @@ -11,58 +10,31 @@ import network.loki.messenger.databinding.ActivityBlockedContactsBinding import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity @AndroidEntryPoint -class BlockedContactsActivity: PassphraseRequiredActionBarActivity(), View.OnClickListener { +class BlockedContactsActivity: PassphraseRequiredActionBarActivity() { lateinit var binding: ActivityBlockedContactsBinding val viewModel: BlockedContactsViewModel by viewModels() - val adapter = BlockedContactsAdapter() + val adapter: BlockedContactsAdapter by lazy { BlockedContactsAdapter(viewModel) } - override fun onClick(v: View?) { - if (v === binding.unblockButton && adapter.getSelectedItems().isNotEmpty()) { - val contactsToUnblock = adapter.getSelectedItems() - // show dialog - val title = if (contactsToUnblock.size == 1) { - getString(R.string.Unblock_dialog__title_single, contactsToUnblock.first().name) - } else { - getString(R.string.Unblock_dialog__title_multiple) + fun unblock() { + // show dialog + val title = viewModel.getTitle(this) + + val message = viewModel.getMessage(this) + + AlertDialog.Builder(this) + .setTitle(title) + .setMessage(message) + .setPositiveButton(R.string.continue_2) { d, _ -> + viewModel.unblock() + d.dismiss() } - - val message = if (contactsToUnblock.size == 1) { - getString(R.string.Unblock_dialog__message, contactsToUnblock.first().name) - } else { - val stringBuilder = StringBuilder() - val iterator = contactsToUnblock.iterator() - var numberAdded = 0 - while (iterator.hasNext() && numberAdded < 3) { - val nextRecipient = iterator.next() - if (numberAdded > 0) stringBuilder.append(", ") - - stringBuilder.append(nextRecipient.name) - numberAdded++ - } - val overflow = contactsToUnblock.size - numberAdded - if (overflow > 0) { - stringBuilder.append(" ") - val string = resources.getQuantityString(R.plurals.Unblock_dialog__message_multiple_overflow, overflow) - stringBuilder.append(string.format(overflow)) - } - getString(R.string.Unblock_dialog__message, stringBuilder.toString()) + .setNegativeButton(R.string.cancel) { d, _ -> + d.dismiss() } - - AlertDialog.Builder(this) - .setTitle(title) - .setMessage(message) - .setPositiveButton(R.string.continue_2) { d, _ -> - viewModel.unblock(contactsToUnblock) - d.dismiss() - } - .setNegativeButton(R.string.cancel) { d, _ -> - d.dismiss() - } - .show() - } + .show() } override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { @@ -73,15 +45,15 @@ class BlockedContactsActivity: PassphraseRequiredActionBarActivity(), View.OnCli binding.recyclerView.adapter = adapter viewModel.subscribe(this) - .observe(this) { newState -> - adapter.submitList(newState.blockedContacts) - val isEmpty = newState.blockedContacts.isEmpty() - binding.emptyStateMessageTextView.isVisible = isEmpty - binding.nonEmptyStateGroup.isVisible = !isEmpty + .observe(this) { state -> + adapter.submitList(state.blockedContacts) + binding.emptyStateMessageTextView.isVisible = state.emptyStateMessageTextViewVisible + binding.nonEmptyStateGroup.isVisible = state.nonEmptyStateGroupVisible + binding.unblockButton.isEnabled = state.unblockButtonEnabled } - binding.unblockButton.setOnClickListener(this) + binding.unblockButton.setOnClickListener { unblock() } } - -} \ No newline at end of file +} + \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsAdapter.kt index 50af49b557..d400ab915c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsAdapter.kt @@ -11,16 +11,14 @@ import network.loki.messenger.databinding.BlockedContactLayoutBinding import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.mms.GlideApp -class BlockedContactsAdapter: ListAdapter(RecipientDiffer()) { +class BlockedContactsAdapter(val viewModel: BlockedContactsViewModel) : ListAdapter(RecipientDiffer()) { class RecipientDiffer: DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Recipient, newItem: Recipient) = oldItem === newItem override fun areContentsTheSame(oldItem: Recipient, newItem: Recipient) = oldItem == newItem } - private val selectedItems = mutableListOf() - - fun getSelectedItems() = selectedItems + fun getSelectedItems() = viewModel.state.selectedItems override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val itemView = LayoutInflater.from(parent.context).inflate(R.layout.blocked_contact_layout, parent, false) @@ -28,19 +26,15 @@ class BlockedContactsAdapter: ListAdapter(capacity = Channel.CONFLATED) - private val _contacts = MutableLiveData(BlockedContactsViewState(emptyList())) + private val _state = MutableLiveData(BlockedContactsViewState(emptyList(), emptySet())) + + val state get() = _state.value!! fun subscribe(context: Context): LiveData { executor.launch(IO) { @@ -45,21 +48,66 @@ class BlockedContactsViewModel @Inject constructor(private val storage: Storage) } executor.launch(IO) { for (update in listUpdateChannel) { - val blockedContactState = BlockedContactsViewState(storage.blockedContacts().sortedBy { it.name }) + val blockedContactState = state.copy( + blockedContacts = storage.blockedContacts().sortedBy { it.name } + ) withContext(Main) { - _contacts.value = blockedContactState + _state.value = blockedContactState } } } - return _contacts + return _state } - fun unblock(toUnblock: List) { - storage.unblock(toUnblock) + fun unblock() { + storage.unblock(state.selectedItems) + _state.value = state.copy(selectedItems = emptySet()) + } + + fun select(selectedItem: Recipient, isSelected: Boolean) { + _state.value = state.run { + if (isSelected) copy(selectedItems = selectedItems + selectedItem) + else copy(selectedItems = selectedItems - selectedItem) + } + } + + fun getTitle(context: Context): String = + if (state.selectedItems.size == 1) { + context.getString(R.string.Unblock_dialog__title_single, state.selectedItems.first().name) + } else { + context.getString(R.string.Unblock_dialog__title_multiple) + } + + fun getMessage(context: Context): String { + if (state.selectedItems.size == 1) { + return context.getString(R.string.Unblock_dialog__message, state.selectedItems.first().name) + } + val stringBuilder = StringBuilder() + val iterator = state.selectedItems.iterator() + var numberAdded = 0 + while (iterator.hasNext() && numberAdded < 3) { + val nextRecipient = iterator.next() + if (numberAdded > 0) stringBuilder.append(", ") + + stringBuilder.append(nextRecipient.name) + numberAdded++ + } + val overflow = state.selectedItems.size - numberAdded + if (overflow > 0) { + stringBuilder.append(" ") + val string = context.resources.getQuantityString(R.plurals.Unblock_dialog__message_multiple_overflow, overflow) + stringBuilder.append(string.format(overflow)) + } + return context.getString(R.string.Unblock_dialog__message, stringBuilder.toString()) } data class BlockedContactsViewState( - val blockedContacts: List - ) - -} \ No newline at end of file + val blockedContacts: List, + val selectedItems: Set + ) { + val isEmpty get() = blockedContacts.isEmpty() + val unblockButtonEnabled get() = selectedItems.isNotEmpty() + val emptyStateMessageTextViewVisible get() = blockedContacts.isEmpty() + val nonEmptyStateGroupVisible get() = blockedContacts.isNotEmpty() + } +} diff --git a/app/src/main/res/color/button_destructive.xml b/app/src/main/res/color/button_destructive.xml new file mode 100644 index 0000000000..cefbfed23a --- /dev/null +++ b/app/src/main/res/color/button_destructive.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/destructive_outline_button_medium_background.xml b/app/src/main/res/drawable/destructive_outline_button_medium_background.xml index 7db4da2ec4..ac41ee6217 100644 --- a/app/src/main/res/drawable/destructive_outline_button_medium_background.xml +++ b/app/src/main/res/drawable/destructive_outline_button_medium_background.xml @@ -7,5 +7,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9fa6059885..f4b9d6dbaa 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -113,7 +113,7 @@ diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index 48d15a18ac..dc78aec1e2 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -202,6 +202,6 @@ interface StorageProtocol { fun removeReaction(emoji: String, messageTimestamp: Long, author: String, notifyUnread: Boolean) fun updateReactionIfNeeded(message: Message, sender: String, openGroupSentTimestamp: Long) fun deleteReactions(messageId: Long, mms: Boolean) - fun unblock(toUnblock: List) + fun unblock(toUnblock: Iterable) fun blockedContacts(): List } From 8f55ac93f8c5bb6d2db208989d13d44f63f22d3c Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 22 May 2023 14:53:05 +0930 Subject: [PATCH 44/83] Fix accept button color --- app/src/main/res/values/styles.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9fa6059885..1e97e737b7 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 204089862b..59525f7844 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -303,6 +303,8 @@ ?dividerVertical #F2F2F2 @color/classic_accent + ?android:colorControlHighlight + @style/Widget.Session.TabLayout - - - - - + @@ -312,7 +311,6 @@ ?dividerVertical #F2F2F2 @color/ocean_accent - ?android:colorControlHighlight @style/Widget.Session.TabLayout @@ -338,6 +336,7 @@ @color/classic_dark_1 @color/classic_dark_3 @color/classic_dark_3 + @color/classic_dark_3 @style/Dark.Popup @null @style/ThemeOverlay.AppCompat.Dark.ActionBar @@ -410,6 +409,7 @@ @color/classic_light_5 @color/classic_light_3 @color/classic_light_3 + @color/classic_light_3 @style/Classic.Light.BottomSheet ?android:textColorPrimary ?actionBarPopupTheme @@ -496,6 +496,7 @@ @color/ocean_dark_1 @color/ocean_dark_4 @color/ocean_dark_4 + @color/ocean_dark_4 @style/Ocean.Dark.BottomSheet ?actionBarPopupTheme ?android:textColorPrimary @@ -576,6 +577,7 @@ @color/ocean_light_6 @color/ocean_light_3 @color/ocean_light_4 + @color/ocean_light_4 @style/Ocean.Light.BottomSheet @style/Light.Popup ?actionBarPopupTheme From c92ef09d09bcf21930a8fb5f3f834a13e5fb686d Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Mon, 5 Jun 2023 14:31:41 +1000 Subject: [PATCH 69/83] [SES-570] Fixed an issue where quotes weren't using their quoted message media --- .../thoughtcrime/securesms/database/MmsDatabase.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index 9e854698f5..e8f65dae06 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.database.SmsDatabase.InsertListener import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord import org.thoughtcrime.securesms.database.model.MessageRecord +import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord import org.thoughtcrime.securesms.database.model.Quote import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get @@ -1405,11 +1406,13 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa val retrievedQuote = get(context).mmsSmsDatabase().getMessageFor(quoteId, quoteAuthor) val quoteText = retrievedQuote?.body val quoteMissing = retrievedQuote == null - val attachments = get(context).attachmentDatabase().getAttachment(cursor) - val quoteAttachments: List? = - Stream.of(attachments).filter { obj: DatabaseAttachment? -> obj!!.isQuote } + val quoteDeck = ( + (retrievedQuote as? MmsMessageRecord)?.slideDeck ?: + Stream.of(get(context).attachmentDatabase().getAttachment(cursor)) + .filter { obj: DatabaseAttachment? -> obj!!.isQuote } .toList() - val quoteDeck = SlideDeck(context, quoteAttachments!!) + .let { SlideDeck(context, it) } + ) return Quote( quoteId, fromExternal(context, quoteAuthor), From a6cfe5817dbaa5ecabad1e0223165a93388a16d3 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 5 Jun 2023 14:58:56 +0930 Subject: [PATCH 70/83] Change unset profile pic in dialog --- .../securesms/preferences/SettingsActivity.kt | 24 ++++++++++++++---- app/src/main/res/drawable/ic_pictures.xml | 18 +++++++++++++ .../main/res/layout/dialog_change_avatar.xml | 25 +++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 app/src/main/res/drawable/ic_pictures.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt index 6b6497982d..5a03cebc37 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt @@ -26,8 +26,10 @@ import nl.komponents.kovenant.all import nl.komponents.kovenant.ui.alwaysUi import nl.komponents.kovenant.ui.successUi import org.session.libsession.avatars.AvatarHelper +import org.session.libsession.avatars.ProfileContactPhoto import org.session.libsession.utilities.* import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol +import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.avatar.AvatarSelection import org.thoughtcrime.securesms.components.ProfilePictureView @@ -100,10 +102,12 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { private fun setupProfilePictureView(view: ProfilePictureView) { view.glide = glide - view.publicKey = hexEncodedPublicKey - view.displayName = getDisplayName() - view.isLarge = true - view.update() + view.apply { + publicKey = hexEncodedPublicKey + displayName = getDisplayName() + isLarge = true + update() + } } override fun onSaveInstanceState(outState: Bundle) { @@ -273,7 +277,17 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { } } .show().apply { - findViewById(R.id.profile_picture_view)?.let(::setupProfilePictureView) + val profilePic = findViewById(R.id.profile_picture_view) + ?.also(::setupProfilePictureView) + + val pictureIcon = findViewById(R.id.ic_pictures) + + val recipient = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false) + + val photoSet = (recipient.contactPhoto as ProfileContactPhoto).avatarObject !in setOf("0", "") + + profilePic?.isVisible = photoSet + pictureIcon?.isVisible = !photoSet } } diff --git a/app/src/main/res/drawable/ic_pictures.xml b/app/src/main/res/drawable/ic_pictures.xml new file mode 100644 index 0000000000..967d0a65b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_pictures.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/dialog_change_avatar.xml b/app/src/main/res/layout/dialog_change_avatar.xml index afe3672f15..60705698f1 100644 --- a/app/src/main/res/layout/dialog_change_avatar.xml +++ b/app/src/main/res/layout/dialog_change_avatar.xml @@ -5,6 +5,31 @@ android:layout_height="wrap_content" android:layout_width="match_parent"> + + + + + + + + Date: Mon, 5 Jun 2023 17:15:05 +1000 Subject: [PATCH 71/83] Commented out the plus button on the replace profile modal --- .../main/res/layout/dialog_change_avatar.xml | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/app/src/main/res/layout/dialog_change_avatar.xml b/app/src/main/res/layout/dialog_change_avatar.xml index 2eb8adeebc..8cb97bcf6a 100644 --- a/app/src/main/res/layout/dialog_change_avatar.xml +++ b/app/src/main/res/layout/dialog_change_avatar.xml @@ -23,23 +23,24 @@ android:background="@color/transparent" android:src="@drawable/ic_pictures"/> - - - + + + + + + + + + + + + + + + + + + From e5db7fc886224caa7462812fba679bb774e3efc9 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 5 Jun 2023 19:15:42 +0930 Subject: [PATCH 72/83] Fix dialog theme so it sets window color and not background of every child view --- .../main/res/drawable/default_dialog_background.xml | 10 ---------- .../res/drawable/default_dialog_background_inset.xml | 6 ------ app/src/main/res/values/styles.xml | 3 +-- app/src/main/res/values/themes.xml | 6 +----- 4 files changed, 2 insertions(+), 23 deletions(-) delete mode 100644 app/src/main/res/drawable/default_dialog_background.xml delete mode 100644 app/src/main/res/drawable/default_dialog_background_inset.xml diff --git a/app/src/main/res/drawable/default_dialog_background.xml b/app/src/main/res/drawable/default_dialog_background.xml deleted file mode 100644 index 00953c88a4..0000000000 --- a/app/src/main/res/drawable/default_dialog_background.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/default_dialog_background_inset.xml b/app/src/main/res/drawable/default_dialog_background_inset.xml deleted file mode 100644 index 0ff315ebd3..0000000000 --- a/app/src/main/res/drawable/default_dialog_background_inset.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ffef598093..f57a0d973b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -23,14 +23,13 @@ diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 59525f7844..37c2e6e150 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -246,12 +246,8 @@ true - - From 6edf0d46f8626c27028564527ce21235adb239d2 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 6 Jun 2023 09:30:43 +1000 Subject: [PATCH 73/83] build: increment build number --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b861220339..3574612481 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -160,8 +160,8 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.4' } -def canonicalVersionCode = 335 -def canonicalVersionName = "1.16.7" +def canonicalVersionCode = 336 +def canonicalVersionName = "1.16.8" def postFixSize = 10 def abiPostFix = ['armeabi-v7a' : 1, From cea65f3e4573b6e2da6958a79add6b035f687da0 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 6 Jun 2023 16:34:23 +1000 Subject: [PATCH 74/83] Fixed an issue where a bunch of dialog backgrounds were missing --- .../securesms/conversation/v2/utilities/BaseDialog.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt index e1456a7f94..406459985a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt @@ -14,7 +14,6 @@ open class BaseDialog : DialogFragment() { val builder = AlertDialog.Builder(requireContext()) setContentView(builder) val result = builder.create() - result.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) val isLightMode = UiModeUtilities.isDayUiMode(requireContext()) result.window?.setDimAmount(if (isLightMode) 0.1f else 0.75f) return result From 9ce89087a5dc6823b5849cb8d016550dbe5bd502 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 6 Jun 2023 16:57:27 +1000 Subject: [PATCH 75/83] Updated the dialog dim amount to match the style guide --- .../securesms/conversation/v2/DeleteOptionsBottomSheet.kt | 3 +-- .../securesms/conversation/v2/ModalUrlBottomSheet.kt | 3 +-- .../securesms/conversation/v2/utilities/BaseDialog.kt | 3 +-- .../securesms/home/ConversationOptionsBottomSheet.kt | 3 +-- .../org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt index 66f33cf299..b6212b8542 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt @@ -69,7 +69,6 @@ class DeleteOptionsBottomSheet : BottomSheetDialogFragment(), View.OnClickListen override fun onStart() { super.onStart() val window = dialog?.window ?: return - val isLightMode = UiModeUtilities.isDayUiMode(requireContext()) - window.setDimAmount(if (isLightMode) 0.1f else 0.75f) + window.setDimAmount(0.6f) } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt index 28c86b3311..54deea1c8d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt @@ -60,8 +60,7 @@ class ModalUrlBottomSheet(private val url: String): BottomSheetDialogFragment(), override fun onStart() { super.onStart() val window = dialog?.window ?: return - val isLightMode = UiModeUtilities.isDayUiMode(requireContext()) - window.setDimAmount(if (isLightMode) 0.1f else 0.75f) + window.setDimAmount(0.6f) } override fun onClick(v: View?) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt index 406459985a..c3a9689a00 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt @@ -14,8 +14,7 @@ open class BaseDialog : DialogFragment() { val builder = AlertDialog.Builder(requireContext()) setContentView(builder) val result = builder.create() - val isLightMode = UiModeUtilities.isDayUiMode(requireContext()) - result.window?.setDimAmount(if (isLightMode) 0.1f else 0.75f) + result.window?.setDimAmount(0.6f) return result } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt index fc85f544fe..7e9d2640a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt @@ -88,7 +88,6 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto override fun onStart() { super.onStart() val window = dialog?.window ?: return - val isLightMode = UiModeUtilities.isDayUiMode(requireContext()) - window.setDimAmount(if (isLightMode) 0.1f else 0.75f) + window.setDimAmount(0.6f) } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt index f3915abff6..bc9a9beced 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt @@ -117,8 +117,7 @@ class UserDetailsBottomSheet: BottomSheetDialogFragment() { override fun onStart() { super.onStart() val window = dialog?.window ?: return - val isLightMode = UiModeUtilities.isDayUiMode(requireContext()) - window.setDimAmount(if (isLightMode) 0.1f else 0.75f) + window.setDimAmount(0.6f) } fun saveNickName(recipient: Recipient) = with(binding) { From 082c087105a192a7d10ba6cadcb0fc267cf0bd60 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 6 Jun 2023 17:30:10 +1000 Subject: [PATCH 76/83] Added the custom dialog windowBackground back (fix permission dialogs) --- .../main/res/drawable/default_dialog_background.xml | 10 ++++++++++ app/src/main/res/values/styles.xml | 1 + app/src/main/res/values/themes.xml | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/default_dialog_background.xml diff --git a/app/src/main/res/drawable/default_dialog_background.xml b/app/src/main/res/drawable/default_dialog_background.xml new file mode 100644 index 0000000000..00953c88a4 --- /dev/null +++ b/app/src/main/res/drawable/default_dialog_background.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index f57a0d973b..a9bf9f4ab2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -23,6 +23,7 @@ From 22a30f19072ea3cd103aa41f7c4722b6435a0ab0 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 6 Jun 2023 18:29:02 +1000 Subject: [PATCH 77/83] Fixed the MediaSendFragment progress dialog --- app/src/main/res/layout/progress_dialog.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/progress_dialog.xml b/app/src/main/res/layout/progress_dialog.xml index 29678e121f..c8c704ce0e 100644 --- a/app/src/main/res/layout/progress_dialog.xml +++ b/app/src/main/res/layout/progress_dialog.xml @@ -11,6 +11,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" - app:SpinKit_Color="?android:textColorPrimary" /> + app:SpinKit_Color="?colorAccent" /> \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 1b56ed788d..edf8108d60 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -248,7 +248,7 @@ From 11c1fd382d3ca48564198dfb17388d9d4aee2f00 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Wed, 7 Jun 2023 13:31:22 +1000 Subject: [PATCH 78/83] Fixed a few issues with the OpenGroupPoller Fixed an issue where the admin/moderator status wasn't getting stored if set before joining a community Fixed an issue where multiple pollers for the same server could run at the same time when joining multiple rooms within the same app run (very noticeable when restoring/linking) --- .../securesms/groups/OpenGroupManager.kt | 25 ++- .../messaging/jobs/BackgroundGroupAddJob.kt | 8 +- .../messaging/open_groups/OpenGroupApi.kt | 21 +- .../pollers/OpenGroupPoller.kt | 180 ++++++++++-------- 4 files changed, 134 insertions(+), 100 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt index ef47269107..6a342eacda 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt @@ -41,11 +41,13 @@ object OpenGroupManager { isPolling = true val storage = MessagingModuleConfiguration.shared.storage val servers = storage.getAllOpenGroups().values.map { it.server }.toSet() - servers.forEach { server -> - pollers[server]?.stop() // Shouldn't be necessary - val poller = OpenGroupPoller(server, executorService) - poller.startIfNeeded() - pollers[server] = poller + synchronized(pollUpdaterLock) { + servers.forEach { server -> + pollers[server]?.stop() // Shouldn't be necessary + val poller = OpenGroupPoller(server, executorService) + poller.startIfNeeded() + pollers[server] = poller + } } } @@ -60,7 +62,7 @@ object OpenGroupManager { @WorkerThread fun add(server: String, room: String, publicKey: String, context: Context): OpenGroupApi.RoomInfo? { val openGroupID = "$server.$room" - var threadID = GroupManager.getOpenGroupThreadID(openGroupID, context) + val threadID = GroupManager.getOpenGroupThreadID(openGroupID, context) val storage = MessagingModuleConfiguration.shared.storage val threadDB = DatabaseComponent.get(context).lokiThreadDatabase() // Check it it's added already @@ -76,13 +78,16 @@ object OpenGroupManager { // Get capabilities & room info val (capabilities, info) = OpenGroupApi.getCapabilitiesAndRoomInfo(room, server).get() storage.setServerCapabilities(server, capabilities.capabilities) - storage.setUserCount(room, server, info.activeUsers) // Create the group locally if not available already if (threadID < 0) { - threadID = GroupManager.createOpenGroup(openGroupID, context, null, info.name).threadId + GroupManager.createOpenGroup(openGroupID, context, null, info.name) } - val openGroup = OpenGroup(server = server, room = room, publicKey = publicKey, name = info.name, imageId = info.imageId, canWrite = info.write, infoUpdates = info.infoUpdates) - threadDB.setOpenGroupChat(openGroup, threadID) + OpenGroupPoller.handleRoomPollInfo( + server = server, + roomToken = room, + pollInfo = info.toPollInfo(), + createGroupIfMissingWithPublicKey = publicKey + ) return info } diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt index 5154101328..c5ec1bc74e 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/BackgroundGroupAddJob.kt @@ -39,13 +39,7 @@ class BackgroundGroupAddJob(val joinUrl: String): Job { delegate?.handleJobFailed(this, dispatcherName, DuplicateGroupException()) return } - // get image - storage.setOpenGroupPublicKey(openGroup.server, openGroup.serverPublicKey) - val info = storage.addOpenGroup(openGroup.joinUrl()) - val imageId = info?.imageId - if (imageId != null && storage.getGroupAvatarDownloadJob(openGroup.server, openGroup.room, imageId) == null) { - JobQueue.shared.add(GroupAvatarDownloadJob(openGroup.server, openGroup.room, imageId)) - } + storage.addOpenGroup(openGroup.joinUrl()) Log.d(KEY, "onOpenGroupAdded(${openGroup.server})") storage.onOpenGroupAdded(openGroup.server) } catch (e: Exception) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt index ca60fd3cbf..a05addcee2 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt @@ -109,7 +109,26 @@ object OpenGroupApi { val defaultWrite: Boolean = false, val upload: Boolean = false, val defaultUpload: Boolean = false, - ) + ) { + fun toPollInfo(): RoomPollInfo { + return RoomPollInfo( + token = token, + activeUsers = activeUsers, + admin = admin, + globalAdmin = globalAdmin, + moderator = moderator, + globalModerator = globalModerator, + read = read, + defaultRead = defaultRead, + defaultAccessible = defaultAccessible, + write = write, + defaultWrite = defaultWrite, + upload = upload, + defaultUpload = defaultUpload, + details = this + ) + } + } @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class) data class PinnedMessage( diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt index 562ddda699..fb7b3b6c8a 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt @@ -30,6 +30,7 @@ import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.successBackground +import java.util.UUID import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit @@ -39,15 +40,97 @@ class OpenGroupPoller(private val server: String, private val executorService: S var isCaughtUp = false var secondToLastJob: MessageReceiveJob? = null private var future: ScheduledFuture<*>? = null + private var runId: UUID = UUID.randomUUID() companion object { private const val pollInterval: Long = 4000L const val maxInactivityPeriod = 14 * 24 * 60 * 60 * 1000 + + public fun handleRoomPollInfo( + server: String, + roomToken: String, + pollInfo: OpenGroupApi.RoomPollInfo, + createGroupIfMissingWithPublicKey: String? = null + ) { + val storage = MessagingModuleConfiguration.shared.storage + val groupId = "$server.$roomToken" + val dbGroupId = GroupUtil.getEncodedOpenGroupID(groupId.toByteArray()) + val existingOpenGroup = storage.getOpenGroup(roomToken, server) + + // If we don't have an existing group and don't have a 'createGroupIfMissingWithPublicKey' + // value then don't process the poll info + val publicKey = ((existingOpenGroup?.publicKey ?: createGroupIfMissingWithPublicKey) ?: return) + + val openGroup = OpenGroup( + server = server, + room = pollInfo.token, + name = ((pollInfo.details?.name ?: existingOpenGroup?.name) ?: ""), + publicKey = publicKey, + imageId = (pollInfo.details?.imageId ?: existingOpenGroup?.imageId), + canWrite = pollInfo.write, + infoUpdates = ((pollInfo.details?.infoUpdates ?: existingOpenGroup?.infoUpdates) ?: 0) + ) + // - Open Group changes + storage.updateOpenGroup(openGroup) + + // - User Count + storage.setUserCount(roomToken, server, pollInfo.activeUsers) + + // - Moderators + pollInfo.details?.moderators?.let { moderatorList -> + storage.setGroupMemberRoles(moderatorList.map { + GroupMember(groupId, it, GroupMemberRole.MODERATOR) + }) + } + pollInfo.details?.hiddenModerators?.let { moderatorList -> + storage.setGroupMemberRoles(moderatorList.map { + GroupMember(groupId, it, GroupMemberRole.HIDDEN_MODERATOR) + }) + } + // - Admins + pollInfo.details?.admins?.let { moderatorList -> + storage.setGroupMemberRoles(moderatorList.map { + GroupMember(groupId, it, GroupMemberRole.ADMIN) + }) + } + pollInfo.details?.hiddenAdmins?.let { moderatorList -> + storage.setGroupMemberRoles(moderatorList.map { + GroupMember(groupId, it, GroupMemberRole.HIDDEN_ADMIN) + }) + } + + // Update the group avatar + if ( + ( + pollInfo.details != null && + pollInfo.details.imageId != null && ( + pollInfo.details.imageId != existingOpenGroup?.imageId || + !storage.hasDownloadedProfilePicture(dbGroupId) + ) && + storage.getGroupAvatarDownloadJob(openGroup.server, openGroup.room, pollInfo.details.imageId) == null + ) || ( + pollInfo.details == null && + existingOpenGroup?.imageId != null && + !storage.hasDownloadedProfilePicture(dbGroupId) && + storage.getGroupAvatarDownloadJob(openGroup.server, openGroup.room, existingOpenGroup.imageId) == null + ) + ) { + JobQueue.shared.add(GroupAvatarDownloadJob(server, roomToken, openGroup.imageId)) + } + else if ( + pollInfo.details != null && + pollInfo.details.imageId == null && + existingOpenGroup?.imageId != null + ) { + storage.removeProfilePicture(dbGroupId) + } + } } fun startIfNeeded() { if (hasStarted) { return } hasStarted = true + runId = UUID.randomUUID() future = executorService?.schedule(::poll, 0, TimeUnit.MILLISECONDS) } @@ -57,6 +140,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S } fun poll(isPostCapabilitiesRetry: Boolean = false): Promise { + val currentRunId = runId val storage = MessagingModuleConfiguration.shared.storage val rooms = storage.getAllOpenGroups().values.filter { it.server == server }.map { it.room } @@ -86,22 +170,30 @@ class OpenGroupPoller(private val server: String, private val executorService: S isCaughtUp = true } } - executorService?.schedule(this@OpenGroupPoller::poll, pollInterval, TimeUnit.MILLISECONDS) + + // Only poll again if it's the same poller run + if (currentRunId == runId) { + future = executorService?.schedule(this@OpenGroupPoller::poll, pollInterval, TimeUnit.MILLISECONDS) + } }.fail { - updateCapabilitiesIfNeeded(isPostCapabilitiesRetry, it) + updateCapabilitiesIfNeeded(isPostCapabilitiesRetry, currentRunId, it) }.map { } } - private fun updateCapabilitiesIfNeeded(isPostCapabilitiesRetry: Boolean, exception: Exception) { + private fun updateCapabilitiesIfNeeded(isPostCapabilitiesRetry: Boolean, currentRunId: UUID, exception: Exception) { if (exception is OnionRequestAPI.HTTPRequestFailedBlindingRequiredException) { if (!isPostCapabilitiesRetry) { OpenGroupApi.getCapabilities(server).map { handleCapabilities(server, it) } - executorService?.schedule({ poll(isPostCapabilitiesRetry = true) }, pollInterval, TimeUnit.MILLISECONDS) + + // Only poll again if it's the same poller run + if (currentRunId == runId) { + future = executorService?.schedule({ poll(isPostCapabilitiesRetry = true) }, pollInterval, TimeUnit.MILLISECONDS) + } } - } else { - executorService?.schedule(this@OpenGroupPoller::poll, pollInterval, TimeUnit.MILLISECONDS) + } else if (currentRunId == runId) { + future = executorService?.schedule(this@OpenGroupPoller::poll, pollInterval, TimeUnit.MILLISECONDS) } } @@ -110,82 +202,6 @@ class OpenGroupPoller(private val server: String, private val executorService: S storage.setServerCapabilities(server, capabilities.capabilities) } - private fun handleRoomPollInfo( - server: String, - roomToken: String, - pollInfo: OpenGroupApi.RoomPollInfo - ) { - val storage = MessagingModuleConfiguration.shared.storage - val groupId = "$server.$roomToken" - val dbGroupId = GroupUtil.getEncodedOpenGroupID(groupId.toByteArray()) - - val existingOpenGroup = storage.getOpenGroup(roomToken, server) - val publicKey = existingOpenGroup?.publicKey ?: return - val openGroup = OpenGroup( - server = server, - room = pollInfo.token, - name = if (pollInfo.details != null) { pollInfo.details.name } else { existingOpenGroup.name }, - publicKey = publicKey, - imageId = if (pollInfo.details != null) { pollInfo.details.imageId } else { existingOpenGroup.imageId }, - canWrite = pollInfo.write, - infoUpdates = if (pollInfo.details != null) { pollInfo.details.infoUpdates } else { existingOpenGroup.infoUpdates } - ) - // - Open Group changes - storage.updateOpenGroup(openGroup) - - // - User Count - storage.setUserCount(roomToken, server, pollInfo.activeUsers) - - // - Moderators - pollInfo.details?.moderators?.let { moderatorList -> - storage.setGroupMemberRoles(moderatorList.map { - GroupMember(groupId, it, GroupMemberRole.MODERATOR) - }) - } - pollInfo.details?.hiddenModerators?.let { moderatorList -> - storage.setGroupMemberRoles(moderatorList.map { - GroupMember(groupId, it, GroupMemberRole.HIDDEN_MODERATOR) - }) - } - // - Admins - pollInfo.details?.admins?.let { moderatorList -> - storage.setGroupMemberRoles(moderatorList.map { - GroupMember(groupId, it, GroupMemberRole.ADMIN) - }) - } - pollInfo.details?.hiddenAdmins?.let { moderatorList -> - storage.setGroupMemberRoles(moderatorList.map { - GroupMember(groupId, it, GroupMemberRole.HIDDEN_ADMIN) - }) - } - - // Update the group avatar - if ( - ( - pollInfo.details != null && - pollInfo.details.imageId != null && ( - pollInfo.details.imageId != existingOpenGroup.imageId || - !storage.hasDownloadedProfilePicture(dbGroupId) - ) && - storage.getGroupAvatarDownloadJob(openGroup.server, openGroup.room, pollInfo.details.imageId) == null - ) || ( - pollInfo.details == null && - existingOpenGroup.imageId != null && - !storage.hasDownloadedProfilePicture(dbGroupId) && - storage.getGroupAvatarDownloadJob(openGroup.server, openGroup.room, existingOpenGroup.imageId) == null - ) - ) { - JobQueue.shared.add(GroupAvatarDownloadJob(server, roomToken, existingOpenGroup.imageId)) - } - else if ( - pollInfo.details != null && - pollInfo.details.imageId == null && - existingOpenGroup.imageId != null - ) { - storage.removeProfilePicture(dbGroupId) - } - } - private fun handleMessages( server: String, roomToken: String, From 7699e47f7be4f715a3b0a72cb7dcd257c9864018 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Wed, 7 Jun 2023 15:02:32 +1000 Subject: [PATCH 79/83] Responded to PR comments --- .../securesms/groups/OpenGroupManager.kt | 6 ++-- .../messaging/open_groups/OpenGroupApi.kt | 34 +++++++++---------- .../pollers/OpenGroupPoller.kt | 12 ++++--- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt index 6a342eacda..dbdf2615ae 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt @@ -15,7 +15,7 @@ import java.util.concurrent.Executors object OpenGroupManager { private val executorService = Executors.newScheduledThreadPool(4) - private var pollers = mutableMapOf() // One for each server + private val pollers = mutableMapOf() // One for each server private var isPolling = false private val pollUpdaterLock = Any() @@ -44,9 +44,7 @@ object OpenGroupManager { synchronized(pollUpdaterLock) { servers.forEach { server -> pollers[server]?.stop() // Shouldn't be necessary - val poller = OpenGroupPoller(server, executorService) - poller.startIfNeeded() - pollers[server] = poller + pollers[server] = OpenGroupPoller(server, executorService).apply { startIfNeeded() } } } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt index a05addcee2..dc6d1475f8 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt @@ -110,24 +110,22 @@ object OpenGroupApi { val upload: Boolean = false, val defaultUpload: Boolean = false, ) { - fun toPollInfo(): RoomPollInfo { - return RoomPollInfo( - token = token, - activeUsers = activeUsers, - admin = admin, - globalAdmin = globalAdmin, - moderator = moderator, - globalModerator = globalModerator, - read = read, - defaultRead = defaultRead, - defaultAccessible = defaultAccessible, - write = write, - defaultWrite = defaultWrite, - upload = upload, - defaultUpload = defaultUpload, - details = this - ) - } + fun toPollInfo() = RoomPollInfo( + token = token, + activeUsers = activeUsers, + admin = admin, + globalAdmin = globalAdmin, + moderator = moderator, + globalModerator = globalModerator, + read = read, + defaultRead = defaultRead, + defaultAccessible = defaultAccessible, + write = write, + defaultWrite = defaultWrite, + upload = upload, + defaultUpload = defaultUpload, + details = this + ) } @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt index fb7b3b6c8a..387381c9cc 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt @@ -40,7 +40,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S var isCaughtUp = false var secondToLastJob: MessageReceiveJob? = null private var future: ScheduledFuture<*>? = null - private var runId: UUID = UUID.randomUUID() + @Volatile private var runId: UUID = UUID.randomUUID() companion object { private const val pollInterval: Long = 4000L @@ -59,16 +59,20 @@ class OpenGroupPoller(private val server: String, private val executorService: S // If we don't have an existing group and don't have a 'createGroupIfMissingWithPublicKey' // value then don't process the poll info - val publicKey = ((existingOpenGroup?.publicKey ?: createGroupIfMissingWithPublicKey) ?: return) + val publicKey = existingOpenGroup?.publicKey ?: createGroupIfMissingWithPublicKey + val name = pollInfo.details?.name ?: existingOpenGroup?.name + val infoUpdates = pollInfo.details?.infoUpdates ?: existingOpenGroup?.infoUpdates + + if (publicKey == null) return val openGroup = OpenGroup( server = server, room = pollInfo.token, - name = ((pollInfo.details?.name ?: existingOpenGroup?.name) ?: ""), + name = name ?: "", publicKey = publicKey, imageId = (pollInfo.details?.imageId ?: existingOpenGroup?.imageId), canWrite = pollInfo.write, - infoUpdates = ((pollInfo.details?.infoUpdates ?: existingOpenGroup?.infoUpdates) ?: 0) + infoUpdates = infoUpdates ?: 0 ) // - Open Group changes storage.updateOpenGroup(openGroup) From 80104f6db82fd925816c1baf070a2491a9c07cc7 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Thu, 8 Jun 2023 16:33:34 +1000 Subject: [PATCH 80/83] [SES-627] Fixed an issue where the DocumentView could run off the screen --- .../v2/messages/VisibleMessageView.kt | 2 -- app/src/main/res/layout/view_visible_message.xml | 16 ++++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index ce6019e4c6..319140731a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -338,11 +338,9 @@ class VisibleMessageView : LinearLayout { val container = binding.messageInnerContainer val content = binding.messageContentView.root val expiration = binding.expirationTimerView - val spacing = binding.messageContentSpacing container.removeAllViewsInLayout() container.addView(if (message.isOutgoing) expiration else content) container.addView(if (message.isOutgoing) content else expiration) - container.addView(spacing, if (message.isOutgoing) 0 else 2) val containerParams = container.layoutParams as ConstraintLayout.LayoutParams containerParams.horizontalBias = if (message.isOutgoing) 1f else 0f container.layoutParams = containerParams diff --git a/app/src/main/res/layout/view_visible_message.xml b/app/src/main/res/layout/view_visible_message.xml index 34b28140a7..d328d19ab3 100644 --- a/app/src/main/res/layout/view_visible_message.xml +++ b/app/src/main/res/layout/view_visible_message.xml @@ -79,8 +79,9 @@ + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1"/> - - + tools:visibility="visible" + tools:src="@drawable/timer60" + tools:tint="@color/black"/> From f0486061b112537ae2b400c3764cd0d2daed2431 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Thu, 8 Jun 2023 17:38:52 +1000 Subject: [PATCH 81/83] build: increment build number --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3574612481..8a42419732 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -160,8 +160,8 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.4' } -def canonicalVersionCode = 336 -def canonicalVersionName = "1.16.8" +def canonicalVersionCode = 338 +def canonicalVersionName = "1.16.9" def postFixSize = 10 def abiPostFix = ['armeabi-v7a' : 1, From cc015c45bd0442718fbcd18e1a7c6a45de2aec99 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 14 Jun 2023 10:34:49 +0930 Subject: [PATCH 82/83] Add 50 dp buffer to isScrolledToBottom (#1228) --- .../org/thoughtcrime/securesms/util/GeneralUtilities.kt | 7 +++++++ .../java/org/session/libsession/utilities/ViewUtils.kt | 5 ----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/GeneralUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/util/GeneralUtilities.kt index 00e3e44418..a38c93831e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/GeneralUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/GeneralUtilities.kt @@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.util import android.content.res.Resources import android.os.Build import androidx.annotation.ColorRes +import androidx.recyclerview.widget.RecyclerView +import kotlin.math.max import kotlin.math.roundToInt fun Resources.getColorWithID(@ColorRes id: Int, theme: Resources.Theme?): Int { @@ -30,3 +32,8 @@ fun toDp(px: Float, resources: Resources): Float { val scale = resources.displayMetrics.density return (px / scale) } + +val RecyclerView.isScrolledToBottom: Boolean + get() = computeVerticalScrollOffset().coerceAtLeast(0) + + computeVerticalScrollExtent() + + toPx(50, resources) >= computeVerticalScrollRange() diff --git a/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt b/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt index dfe0c3b451..80c0293238 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt @@ -4,8 +4,6 @@ import android.content.Context import android.util.TypedValue import androidx.annotation.AttrRes import androidx.annotation.ColorInt -import androidx.recyclerview.widget.RecyclerView -import kotlin.math.max @ColorInt fun Context.getColorFromAttr( @@ -16,6 +14,3 @@ fun Context.getColorFromAttr( theme.resolveAttribute(attrColor, typedValue, resolveRefs) return typedValue.data } - -val RecyclerView.isScrolledToBottom: Boolean - get() = max(0, computeVerticalScrollOffset()) + computeVerticalScrollExtent() >= computeVerticalScrollRange() From 92a6447b8a46814cfdd4b0505e3a7cf2cf05e55b Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 19 Jun 2023 11:51:14 +0930 Subject: [PATCH 83/83] Add button downstates throughout (#1220) --- .../preferences/BlockedContactsPreference.kt | 19 ++++++-------- .../main/res/color/prominent_button_color.xml | 5 ++++ .../borderless_button_medium_background.xml | 11 ++++++++ ...tructive_dialog_text_button_background.xml | 19 +++++++------- .../filled_button_medium_background.xml | 10 ++++++++ ...minent_filled_button_medium_background.xml | 19 +++++++------- ...mportant_dialog_text_button_background.xml | 19 +++++++------- ...rtant_outline_button_medium_background.xml | 22 ++++++++-------- .../res/layout-sw400dp/activity_landing.xml | 2 +- .../main/res/layout-sw400dp/activity_seed.xml | 9 +++---- app/src/main/res/layout/activity_home.xml | 1 + app/src/main/res/layout/activity_landing.xml | 2 +- app/src/main/res/layout/activity_pn_mode.xml | 2 +- app/src/main/res/layout/activity_seed.xml | 10 ++++---- app/src/main/res/layout/activity_settings.xml | 10 ++++++++ .../layout/blocked_contacts_preference.xml | 9 ++++--- .../main/res/layout/export_logs_widget.xml | 4 +-- .../main/res/layout/fragment_create_group.xml | 21 +++++----------- .../res/layout/fragment_join_community.xml | 5 +++- .../layout/fragment_new_conversation_home.xml | 5 ++++ .../main/res/layout/fragment_new_message.xml | 4 +++ .../res/layout/view_global_search_input.xml | 4 ++- app/src/main/res/values/styles.xml | 25 +++++++------------ 23 files changed, 132 insertions(+), 105 deletions(-) create mode 100644 app/src/main/res/color/prominent_button_color.xml create mode 100644 app/src/main/res/drawable/borderless_button_medium_background.xml create mode 100644 app/src/main/res/drawable/filled_button_medium_background.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsPreference.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsPreference.kt index 254d34978d..e985ba6d4f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsPreference.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/BlockedContactsPreference.kt @@ -9,20 +9,15 @@ import androidx.preference.PreferenceViewHolder class BlockedContactsPreference @JvmOverloads constructor( context: Context, - attributeSet: AttributeSet? = null) : PreferenceCategory(context, attributeSet), View.OnClickListener { - - override fun onClick(v: View?) { - if (v is BlockedContactsLayout) { - val intent = Intent(context, BlockedContactsActivity::class.java) - context.startActivity(intent) - } - } + attributeSet: AttributeSet? = null +) : PreferenceCategory(context, attributeSet) { override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - val itemView = holder.itemView - itemView.setOnClickListener(this) + holder.itemView.setOnClickListener { + val intent = Intent(context, BlockedContactsActivity::class.java) + context.startActivity(intent) + } } - -} \ No newline at end of file +} diff --git a/app/src/main/res/color/prominent_button_color.xml b/app/src/main/res/color/prominent_button_color.xml new file mode 100644 index 0000000000..8f2e692fda --- /dev/null +++ b/app/src/main/res/color/prominent_button_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/borderless_button_medium_background.xml b/app/src/main/res/drawable/borderless_button_medium_background.xml new file mode 100644 index 0000000000..6c72f9e72b --- /dev/null +++ b/app/src/main/res/drawable/borderless_button_medium_background.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/destructive_dialog_text_button_background.xml b/app/src/main/res/drawable/destructive_dialog_text_button_background.xml index 1eff84a69b..f3e13c8000 100644 --- a/app/src/main/res/drawable/destructive_dialog_text_button_background.xml +++ b/app/src/main/res/drawable/destructive_dialog_text_button_background.xml @@ -1,11 +1,10 @@ - - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/app/src/main/res/drawable/filled_button_medium_background.xml b/app/src/main/res/drawable/filled_button_medium_background.xml new file mode 100644 index 0000000000..10eb6de679 --- /dev/null +++ b/app/src/main/res/drawable/filled_button_medium_background.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/prominent_filled_button_medium_background.xml b/app/src/main/res/drawable/prominent_filled_button_medium_background.xml index a06a0d11e5..698a67c0a9 100644 --- a/app/src/main/res/drawable/prominent_filled_button_medium_background.xml +++ b/app/src/main/res/drawable/prominent_filled_button_medium_background.xml @@ -1,11 +1,10 @@ - - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/app/src/main/res/drawable/unimportant_dialog_text_button_background.xml b/app/src/main/res/drawable/unimportant_dialog_text_button_background.xml index 1eff84a69b..f3e13c8000 100644 --- a/app/src/main/res/drawable/unimportant_dialog_text_button_background.xml +++ b/app/src/main/res/drawable/unimportant_dialog_text_button_background.xml @@ -1,11 +1,10 @@ - - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/app/src/main/res/drawable/unimportant_outline_button_medium_background.xml b/app/src/main/res/drawable/unimportant_outline_button_medium_background.xml index 6e0de35a5b..d12f7408d9 100644 --- a/app/src/main/res/drawable/unimportant_outline_button_medium_background.xml +++ b/app/src/main/res/drawable/unimportant_outline_button_medium_background.xml @@ -1,11 +1,13 @@ - - - - - - - - \ No newline at end of file + + + + + + + + + diff --git a/app/src/main/res/layout-sw400dp/activity_landing.xml b/app/src/main/res/layout-sw400dp/activity_landing.xml index 1e89cd967d..5e5a36704a 100644 --- a/app/src/main/res/layout-sw400dp/activity_landing.xml +++ b/app/src/main/res/layout-sw400dp/activity_landing.xml @@ -52,6 +52,7 @@ android:text="@string/activity_landing_restore_button_title" />