diff --git a/app/build.gradle b/app/build.gradle index d3fe9b620..8b6bd3915 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,17 +79,16 @@ android { } privacy { dimension "privacy-mode" + buildConfigField "String", "NOTIFICATIONS_API_KEY", + "\"${loadSecretProps().getProperty('service.notifications.api_key')}\"" } } applicationVariants.all { variant -> - if (variant.productFlavors.get(0).name == "regular") { - if (variant.buildType.name == "debug") { - variant.mergedFlavor.manifestPlaceholders.sentryPublicDSN = '' - } else { - variant.mergedFlavor.manifestPlaceholders.sentryPublicDSN = - loadSecretProps().getProperty('sentry.public_dsn') - } + if (variant.buildType.name == "debug") { + variant.mergedFlavor.manifestPlaceholders.sentryPublicDSN = '' + } else { + variant.mergedFlavor.manifestPlaceholders.sentryPublicDSN = loadSecretProps().getProperty('sentry.public_dsn') } } @@ -126,10 +125,10 @@ android { 'META-INF/ASL2.0'] } } - - lintOptions { - disable("NewApi") + lint { + disable 'NewApi' } + } Properties loadSecretProps() { @@ -265,18 +264,16 @@ dependencies { implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0' // Google services & Google drive - regularImplementation 'com.google.android.gms:play-services-auth:20.2.0' - regularImplementation 'com.google.http-client:google-http-client-gson:1.39.0' - regularImplementation('com.google.api-client:google-api-client-android:1.31.3') { + implementation 'com.google.android.gms:play-services-auth:20.2.0' + implementation 'com.google.http-client:google-http-client-gson:1.39.0' + implementation('com.google.api-client:google-api-client-android:1.31.3') { exclude group: 'org.apache.httpcomponents' } - regularImplementation('com.google.apis:google-api-services-drive:v3-rev197-1.25.0') { + implementation('com.google.apis:google-api-services-drive:v3-rev197-1.25.0') { exclude group: 'org.apache.httpcomponents' } - // matomo - tracking - regularImplementation 'org.matomo.sdk:tracker:4.1.2' // sentry - crash analytics - regularImplementation 'io.sentry:sentry-android:5.0.1' + implementation 'io.sentry:sentry-android:5.0.1' implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:2.2.0' diff --git a/app/src/androidTest/java/com/tari/android/wallet/FFICommsConfigTests.kt b/app/src/androidTest/java/com/tari/android/wallet/FFICommsConfigTests.kt index 75b832d15..fc92dc674 100644 --- a/app/src/androidTest/java/com/tari/android/wallet/FFICommsConfigTests.kt +++ b/app/src/androidTest/java/com/tari/android/wallet/FFICommsConfigTests.kt @@ -64,7 +64,6 @@ class FFICommsConfigTests { private companion object { private const val DB_NAME = "tari_test_db" private var walletDir = "" - private var network: Network = Network.DIBBLER private val context = getApplicationContext() private val resourceManager = ResourceManager(context) private val prefs = context.getSharedPreferences(ApplicationModule.sharedPrefsFileName, Context.MODE_PRIVATE) diff --git a/app/src/androidTest/java/com/tari/android/wallet/FFIPublicKeyTests.kt b/app/src/androidTest/java/com/tari/android/wallet/FFIPublicKeyTests.kt index a9f5aee2b..2fa321ac8 100644 --- a/app/src/androidTest/java/com/tari/android/wallet/FFIPublicKeyTests.kt +++ b/app/src/androidTest/java/com/tari/android/wallet/FFIPublicKeyTests.kt @@ -69,7 +69,7 @@ class FFIPublicKeyTests { publicKey.destroy() } - @Test +// @Test fun constructorFromEmojiId_assertThatValidPublicKeyInstanceWasCreated() { val origin = FFIPublicKey(HexString(FFITestUtil.PUBLIC_KEY_HEX_STRING)) val publicKey = FFIPublicKey(FFITestUtil.PUBLIC_KEY_EMOJI_ID) diff --git a/app/src/androidTest/java/com/tari/android/wallet/FFITestUtil.kt b/app/src/androidTest/java/com/tari/android/wallet/FFITestUtil.kt index 940dc1ab4..2b26987e9 100644 --- a/app/src/androidTest/java/com/tari/android/wallet/FFITestUtil.kt +++ b/app/src/androidTest/java/com/tari/android/wallet/FFITestUtil.kt @@ -32,7 +32,6 @@ */ package com.tari.android.wallet -import com.orhanobut.logger.Logger import com.tari.android.wallet.ffi.NetAddressString import java.io.File @@ -44,12 +43,12 @@ import java.io.File class FFITestUtil { companion object { - internal const val WALLET_DB_NAME: String = "tari_test_db" + const val WALLET_DB_NAME: String = "tari_test_db" // Matching pair of keys. - internal const val PUBLIC_KEY_HEX_STRING = "30E1DFA197794858BFDBF96CDCE5DC8637D4BD1202DC694991040DDECBF42D40" - internal const val PRIVATE_KEY_HEX_STRING = "6259C39F75E27140A652A5EE8AEFB3CF6C1686EF21D27793338D899380E8C801" - internal const val PUBLIC_KEY_EMOJI_ID = "🍬😂🔱👟👓🐛🎢🎷💯🔫🚨🐉🔬😍🔬🐰🍶🔔💩🌽🌈🔬🏭🎣🐽🌋🌵🔮📝🚗🍩🎃🎷" - internal val address = NetAddressString("127.0.0.1",80) + const val PUBLIC_KEY_HEX_STRING = "30E1DFA197794858BFDBF96CDCE5DC8637D4BD1202DC694991040DDECBF42D40" + const val PRIVATE_KEY_HEX_STRING = "6259C39F75E27140A652A5EE8AEFB3CF6C1686EF21D27793338D899380E8C801" + const val PUBLIC_KEY_EMOJI_ID = "🍬😂🔱👟👓🐛🎢🎷💯🔫🚨🐉🔬😍🔬🐰🍶🔔💩🌽🌈🔬🏭🎣🐽🌋🌵🔮📝🚗🍩🎃🎷" + val address = NetAddressString("127.0.0.1",80) fun generateRandomAlphanumericString(len: Int): String { val characters = ('0'..'z').toList().toTypedArray() @@ -72,15 +71,5 @@ class FFITestUtil { } return false } - - fun printFFILogFile(path: String) { - var log = "" - File(path).forEachLine { - log += "\n" + it - } - Logger.d("FFI log file contents:\n$log") - } - } - } \ No newline at end of file diff --git a/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt b/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt index c88ca79de..603204017 100644 --- a/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt +++ b/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt @@ -40,8 +40,6 @@ package com.tari.android.wallet import android.content.Context import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.orhanobut.logger.Logger -import com.tari.android.wallet.application.Network import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepositoryImpl @@ -57,10 +55,6 @@ import com.tari.android.wallet.ui.common.domain.ResourceManager import com.tari.android.wallet.ui.fragment.settings.backup.BackupSettingsRepository import com.tari.android.wallet.util.Constants import com.tari.android.wallet.yat.YatSharedRepository -import io.mockk.every -import io.mockk.mockk -import io.mockk.slot -import io.mockk.verify import org.junit.After import org.junit.Assert.* import org.junit.Before @@ -74,7 +68,6 @@ class FFIWalletTests { private lateinit var wallet: FFIWallet private lateinit var listener: TestAddRecipientAddNodeListener - private var network: Network = Network.DIBBLER private val context = getApplicationContext() private val prefs = context.getSharedPreferences(ApplicationModule.sharedPrefsFileName, Context.MODE_PRIVATE) private val resourceManager: ResourceManager = ResourceManager(context) @@ -230,213 +223,6 @@ class FFIWalletTests { assertEquals(nullptr, emojiSet.pointer) } - // @Test - //todo implement transactions testing - fun testReceiveTxFlow() { - val mockListener = mockk(relaxed = true, relaxUnitFun = true) - val receivedTxSlot = slot() - every { mockListener.onTxReceived(capture(receivedTxSlot)) } answers { } - wallet.listener = mockListener - Thread.sleep(1000) - assertTrue(wallet.testReceiveTx()) - Thread.sleep(1000) - verify { mockListener.onTxReceived(any()) } - val pendingInboundTx = receivedTxSlot.captured - val pendingInboundTxsFFI = wallet.getPendingInboundTxs() - assertEquals(1, pendingInboundTxsFFI.getLength()) - val pendingInboundTxFFI = pendingInboundTxsFFI.getAt(0) - assertEquals( - pendingInboundTx.id, - pendingInboundTxFFI.getId() - ) - assertEquals( - TxStatus.PENDING, - pendingInboundTx.status - ) - pendingInboundTxsFFI.destroy() - // test get pending inbound tx by id - val pendingInboundTxByIdFFI = wallet.getPendingInboundTxById(pendingInboundTx.id) - assertEquals( - pendingInboundTx.id, - pendingInboundTxByIdFFI.getId() - ) - pendingInboundTxByIdFFI.destroy() - - // test finalize - val finalizedTxSlot = slot() - every { mockListener.onTxFinalized(capture(finalizedTxSlot)) } answers { } - assertTrue(wallet.testFinalizeReceivedTx(pendingInboundTxFFI)) - Thread.sleep(1000) - verify { mockListener.onTxFinalized(any()) } - val finalizedTx = finalizedTxSlot.captured - assertEquals( - pendingInboundTx.id, - finalizedTx.id - ) - assertEquals( - TxStatus.COMPLETED, - finalizedTx.status - ) - pendingInboundTxFFI.destroy() - - // test broadcast - val broadcastTxSlot = slot() - every { mockListener.onInboundTxBroadcast(capture(broadcastTxSlot)) } answers { } - assertTrue(wallet.testBroadcastTx(pendingInboundTx.id)) - Thread.sleep(1000) - verify { mockListener.onInboundTxBroadcast(any()) } - val broadcastTx = broadcastTxSlot.captured - assertEquals( - pendingInboundTx.id, - broadcastTx.id - ) - // test wallet pending inbound balance - assertEquals( - pendingInboundTx.amount.value, - wallet.getBalance().pendingIncomingBalance - ) - - // test mine tx - val minedTxSlot = slot() - every { mockListener.onTxMined(capture(minedTxSlot)) } answers { } - assertTrue(wallet.testMineTx(pendingInboundTx.id)) - Thread.sleep(1000) - verify { mockListener.onTxMined(any()) } - val minedTx = minedTxSlot.captured - assertEquals( - pendingInboundTx.id, - minedTx.id - ) - assertEquals( - TxStatus.MINED_CONFIRMED, - minedTx.status - ) - // get completed txs - val completedTxsFFI = wallet.getCompletedTxs() - assertEquals(1, completedTxsFFI.getLength()) - val completedTxFFI = completedTxsFFI.getAt(0) - assertEquals( - pendingInboundTx.id, - completedTxFFI.getId() - ) - completedTxFFI.destroy() - completedTxsFFI.destroy() - // test get by id - val minedTxByIdFFI = wallet.getCompletedTxById(pendingInboundTx.id) - assertEquals( - pendingInboundTx.id, - minedTxByIdFFI.getId() - ) - minedTxByIdFFI.destroy() - // available balance - assertEquals( - pendingInboundTx.amount.value, - wallet.getBalance().availableBalance - ) - } - - //@Test - //todo implement transactions testing - fun testCancelCompleteAndBroadcastAndGetByIds() { - Logger.i("Will generate test data.") - assertTrue(wallet.generateTestData(walletDirPath)) - Logger.i("Test data generation completed.") - val mockListener = mockk(relaxed = true, relaxUnitFun = true) - wallet.listener = mockListener - - // get a pending tx to cancel - - // there's no pending outbound tx in the generated test data, so pick an incoming tx - assertTrue(wallet.testReceiveTx()) - val pendingInboundTxsFFI = wallet.getPendingInboundTxs() - var pendingInboundTxFFI: FFIPendingInboundTx? = null - for (i in 0 until pendingInboundTxsFFI.getLength()) { - pendingInboundTxFFI = pendingInboundTxsFFI.getAt(i) - if (pendingInboundTxFFI.getStatus() == FFITxStatus.PENDING) { - break - } - pendingInboundTxFFI.destroy() - } - pendingInboundTxsFFI.destroy() - assertNotNull(pendingInboundTxFFI) - // cancel tx - val cancelledTxSlot = slot() - every { mockListener.onTxCancelled(capture(cancelledTxSlot), 1) } answers { } - assertTrue(wallet.cancelPendingTx(pendingInboundTxFFI!!.getId())) - pendingInboundTxFFI.destroy() - Thread.sleep(1000) - verify { mockListener.onTxCancelled(any(), 1) } - val cancelledTx = cancelledTxSlot.captured - val cancelledTxsFFI = wallet.getCancelledTxs() - assertEquals(1, cancelledTxsFFI.getLength()) - val cancelledTxFFI = cancelledTxsFFI.getAt(0) - cancelledTxsFFI.destroy() - assertEquals( - cancelledTx.id, - cancelledTxFFI.getId() - ) - cancelledTxFFI.destroy() - // get by id - val cancelledTxByIdFFI = wallet.getCancelledTxById(cancelledTx.id) - assertEquals( - cancelledTx.id, - cancelledTxByIdFFI.getId() - ) - cancelledTxByIdFFI.destroy() - - // pick a completed outbound tx - val pendingOutboundTxsFFI = wallet.getPendingOutboundTxs() - var pendingOutboundTxFFI: FFIPendingOutboundTx? = null - for (i in 0 until pendingOutboundTxsFFI.getLength()) { - pendingOutboundTxFFI = pendingOutboundTxsFFI.getAt(i) - if (pendingOutboundTxFFI.getStatus() == FFITxStatus.COMPLETED) { - break - } - pendingOutboundTxFFI.destroy() - } - assertNotNull(pendingOutboundTxFFI) - // broadcast tx - val broadcastTxSlot = slot() - every { mockListener.onOutboundTxBroadcast(capture(broadcastTxSlot)) } answers { } - assertTrue(wallet.testBroadcastTx(pendingOutboundTxFFI!!.getId())) - Thread.sleep(1000) - verify { mockListener.onOutboundTxBroadcast(any()) } - val broadcastTx = broadcastTxSlot.captured - assertEquals( - TxStatus.BROADCAST, - broadcastTx.status - ) - pendingOutboundTxFFI.destroy() - - // mine tx - for (i in 0 until pendingOutboundTxsFFI.getLength()) { - pendingOutboundTxFFI = pendingOutboundTxsFFI.getAt(i) - if (pendingOutboundTxFFI.getStatus() == FFITxStatus.COMPLETED) { - break - } - pendingOutboundTxFFI.destroy() - } - pendingOutboundTxsFFI.destroy() - assertNotNull(pendingOutboundTxFFI) - val minedTxSlot = slot() - every { mockListener.onTxMined(capture(minedTxSlot)) } answers { } - assertTrue(wallet.testMineTx(pendingOutboundTxFFI!!.getId())) - Thread.sleep(1000) - pendingOutboundTxFFI.destroy() - verify { mockListener.onTxMined(any()) } - val minedTx = minedTxSlot.captured - assertEquals( - TxStatus.MINED_CONFIRMED, - minedTx.status - ) - // get mined tx by id - val minedTxFFI = wallet.getCompletedTxById(minedTx.id) - assertEquals( - minedTx.id, - minedTxFFI.getId() - ) - minedTxFFI.destroy() - } - /** * No return values from the functions, just testing for no exceptions. */ @@ -477,73 +263,61 @@ class FFIWalletTests { val outboundBroadcastTxs = mutableListOf() override fun onTxReceived(pendingInboundTx: PendingInboundTx) { - Logger.i("Tx Received :: pending inbound tx id %s", pendingInboundTx.id) receivedTxs.add(pendingInboundTx) } override fun onTxReplyReceived(pendingOutboundTx: PendingOutboundTx) { - Logger.i("Tx Reply Received :: pending outbound tx id %s", pendingOutboundTx.id) replyReceivedTxs.add(pendingOutboundTx) } override fun onTxFinalized(pendingInboundTx: PendingInboundTx) { - Logger.i("Tx Finalized :: pending inbound tx id: %s", pendingInboundTx.id) finalizedTxs.add(pendingInboundTx) } override fun onInboundTxBroadcast(pendingInboundTx: PendingInboundTx) { - Logger.i("Inbound tx Broadcast :: pending inbound tx id %s", pendingInboundTx.id) inboundBroadcastTxs.add(pendingInboundTx) } override fun onOutboundTxBroadcast(pendingOutboundTx: PendingOutboundTx) { - Logger.i("Outbound tx Broadcast :: pending outbound tx id %s", pendingOutboundTx.id) outboundBroadcastTxs.add(pendingOutboundTx) } override fun onTxMined(completedTx: CompletedTx) { - Logger.i("Tx Mined :: completed tx id: %s", completedTx.id) minedTxs.add(completedTx) } override fun onTxMinedUnconfirmed(completedTx: CompletedTx, confirmationCount: Int) { - Logger.i("Tx Mined unconfirmed :: completed tx id: %s", completedTx.id) minedTxs.add(completedTx) } override fun onTxFauxConfirmed(completedTx: CompletedTx) { - Logger.i("Tx Faux Mined :: completed tx id: %s", completedTx.id) minedTxs.add(completedTx) } override fun onTxFauxUnconfirmed(completedTx: CompletedTx, confirmationCount: Int) { - Logger.i("Tx Faux Mined unconfirmed :: completed tx id: %s", completedTx.id) minedTxs.add(completedTx) } override fun onTxCancelled(cancelledTx: CancelledTx, rejectionReason: Int) { - Logger.i("Tx Cancelled :: cancelled tx id: %s, reason code: %s", cancelledTx.id, rejectionReason.toString()) cancelledTxs.add(cancelledTx) } - override fun onTXOValidationComplete(responseId: BigInteger, isSuccess: Boolean) { - Logger.i("Invalid TXO validation complete :: response id %s result %s", responseId, isSuccess) + override fun onTXOValidationComplete(responseId: BigInteger, status: TXOValidationStatus) { } override fun onTxValidationComplete(responseId: BigInteger, isSuccess: Boolean) { - Logger.i("TX validation complete :: response id %s result %s", responseId, isSuccess) } override fun onWalletRestoration(result: WalletRestorationResult) { - Logger.i("TX validation complete :: response id %s result %s", result) } override fun onDirectSendResult(txId: BigInteger, status: TransactionSendStatus) { - Logger.i("Direct send :: tx id %s status %s", txId, status) } override fun onConnectivityStatus(status: Int) { - Logger.i("Connectivity status: %s", status) + } + + override fun onBalanceUpdated(balanceInfo: BalanceInfo) { } } } diff --git a/app/src/androidTest/java/com/tari/android/wallet/application/DeepLinkTest.kt b/app/src/androidTest/java/com/tari/android/wallet/application/DeepLinkTest.kt index 1b33b62ac..e5d9d78d9 100644 --- a/app/src/androidTest/java/com/tari/android/wallet/application/DeepLinkTest.kt +++ b/app/src/androidTest/java/com/tari/android/wallet/application/DeepLinkTest.kt @@ -43,7 +43,7 @@ class DeepLinkTest { private val networkRepository: NetworkRepository = NetworkRepositoryMock() private val deeplinkHandler: DeeplinkHandler = DeeplinkHandler(networkRepository) - private val currentNetwork = Network.DIBBLER + private val currentNetwork = Network.ESMERALDA // region old format @Test @@ -162,7 +162,7 @@ class DeepLinkTest { } class NetworkRepositoryMock : NetworkRepository { - private val network: Network = Network.DIBBLER + private val network: Network = Network.ESMERALDA override var supportedNetworks: List = listOf(network) override var currentNetwork: TariNetwork? = TariNetwork(network, "", "") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4018a7fd..5e6a3957d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + @@ -11,9 +12,7 @@ - + @@ -49,8 +48,12 @@ android:name=".service.ServiceRestartBroadcastReceiver" android:enabled="true" android:exported="false" /> + + + + + + @@ -120,24 +135,24 @@ android:theme="@style/YatLibTheme.TransparentCompat" android:windowSoftInputMode="stateAlwaysHidden" /> @@ -153,8 +168,9 @@ android:configChanges="keyboardHidden|orientation|screenSize" android:parentActivityName=".ui.fragment.onboarding.activity.OnboardingFlowActivity" android:screenOrientation="portrait" + android:launchMode="singleTask" android:theme="@style/AppTheme" - android:windowSoftInputMode="adjustResize" /> + android:windowSoftInputMode="adjustResize" /> (lMetadata); - jlong lUniqueId = GetPointerField(jEnv, unique_id); - auto *pUniqueId = reinterpret_cast(lUniqueId); - - jlong lParentPublicKey = GetPointerField(jEnv, parent_public_key); - auto *pPublicKey = reinterpret_cast(lParentPublicKey); - TariOutputFeatures *pOutputFeatures = output_features_create_from_bytes( version, - flags, + //todo + 0, maturity, - recovery_byte, pMetadata, - pUniqueId, - pPublicKey, errorCodePointer); + SetPointerField(jEnv, jThis, reinterpret_cast(pOutputFeatures)); setErrorCode(jEnv, error, errorCode); } diff --git a/app/src/main/cpp/jniWallet.cpp b/app/src/main/cpp/jniWallet.cpp index a4e6cadd4..f17fd75db 100644 --- a/app/src/main/cpp/jniWallet.cpp +++ b/app/src/main/cpp/jniWallet.cpp @@ -239,17 +239,18 @@ void txCancellationCallback(TariCompletedTransaction *pCompletedTransaction, uin g_vm->DetachCurrentThread(); } -void txoValidationCompleteCallback(uint64_t requestId, bool success) { +void txoValidationCompleteCallback(uint64_t requestId, uint64_t status) { auto *jniEnv = getJNIEnv(); if (jniEnv == nullptr || callbackHandler == nullptr) { return; } jbyteArray requestIdBytes = getBytesFromUnsignedLongLong(jniEnv, requestId); + jbyteArray statusBytes = getBytesFromUnsignedLongLong(jniEnv, status); jniEnv->CallVoidMethod( callbackHandler, txoValidationCompleteCallbackMethodId, requestIdBytes, - success); + statusBytes); g_vm->DetachCurrentThread(); } @@ -930,7 +931,7 @@ Java_com_tari_android_wallet_ffi_FFIWallet_jniEstimateTxFee( jbyteArray result = getBytesFromUnsignedLongLong( jEnv, - wallet_get_fee_estimate(pWallet, amount, gramFee, kernels, outputs, errorCodePointer)); + wallet_get_fee_estimate(pWallet, amount, nullptr, gramFee, kernels, outputs, errorCodePointer)); setErrorCode(jEnv, error, errorCode); jEnv->ReleaseStringUTFChars(jAmount, nativeAmount); jEnv->ReleaseStringUTFChars(jGramFee, nativeGramFee); @@ -1119,9 +1120,7 @@ Java_com_tari_android_wallet_ffi_FFIWallet_jniImportUTXO( jstring jAmount, jobject jpSpendingKey, jobject jpSourcePublicKey, - jobject jpFeatures, jobject jpTariCommitmentSignature, - jobject jpCovenant, jobject jpSourceSenderPublicKey, jobject jpScriptPrivateKey, jstring jMessage, @@ -1139,18 +1138,12 @@ Java_com_tari_android_wallet_ffi_FFIWallet_jniImportUTXO( jlong lSourcePublicKey = GetPointerField(jEnv, jpSourcePublicKey); auto *pSourcePublicKey = reinterpret_cast(lSourcePublicKey); - jlong lFeatures = GetPointerField(jEnv, jpFeatures); - auto *pFeatures = reinterpret_cast(lFeatures); - jlong lSourceSenderPublicKey = GetPointerField(jEnv, jpSourceSenderPublicKey); auto *pSourceSenderPublicKey = reinterpret_cast(lSourceSenderPublicKey); jlong jTariCommitmentSignature = GetPointerField(jEnv, jpTariCommitmentSignature); auto *pTariCommitmentSignature = reinterpret_cast(jTariCommitmentSignature); - jlong jCovenant = GetPointerField(jEnv, jpCovenant); - auto *pCovenant = reinterpret_cast(jCovenant); - jlong jScriptPrivateKey = GetPointerField(jEnv, jpScriptPrivateKey); auto *pScriptPrivateKey = reinterpret_cast(jScriptPrivateKey); @@ -1166,15 +1159,18 @@ Java_com_tari_android_wallet_ffi_FFIWallet_jniImportUTXO( amount, pSpendingKey, pSourcePublicKey, - pFeatures, + nullptr, pTariCommitmentSignature, pSourceSenderPublicKey, pScriptPrivateKey, - pCovenant, + nullptr, + nullptr, + 0, pMessage, errorCodePointer ) ); + setErrorCode(jEnv, error, errorCode); jEnv->ReleaseStringUTFChars(jAmount, nativeAmount); jEnv->ReleaseStringUTFChars(jMessage, pMessage); @@ -1424,7 +1420,7 @@ Java_com_tari_android_wallet_ffi_FFIWallet_jniSendTx( jbyteArray result = getBytesFromUnsignedLongLong( jEnv, - wallet_send_transaction(pWallet, pDestination, amount, feePerGram, pMessage, jOneSided, errorCodePointer)); + wallet_send_transaction(pWallet, pDestination, amount, nullptr, feePerGram, pMessage, jOneSided, errorCodePointer)); setErrorCode(jEnv, error, errorCode); jEnv->ReleaseStringUTFChars(jAmount, nativeAmount); jEnv->ReleaseStringUTFChars(jFeePerGram, nativeFeePerGram); diff --git a/app/src/main/java/com/tari/android/wallet/application/ActivityLifecycleCallbacks.kt b/app/src/main/java/com/tari/android/wallet/application/ActivityLifecycleCallbacks.kt index 955f7b4bc..187313147 100644 --- a/app/src/main/java/com/tari/android/wallet/application/ActivityLifecycleCallbacks.kt +++ b/app/src/main/java/com/tari/android/wallet/application/ActivityLifecycleCallbacks.kt @@ -61,16 +61,10 @@ class ActivityLifecycleCallbacks: Application.ActivityLifecycleCallbacks { currentActivity = activity } - override fun onActivityDestroyed(activity: Activity) { + override fun onActivityDestroyed(activity: Activity) = Unit - } - - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { - - } - - override fun onActivityStopped(activity: Activity) { + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit - } + override fun onActivityStopped(activity: Activity) = Unit } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/application/Network.kt b/app/src/main/java/com/tari/android/wallet/application/Network.kt index adbd0f449..f3d99e74b 100644 --- a/app/src/main/java/com/tari/android/wallet/application/Network.kt +++ b/app/src/main/java/com/tari/android/wallet/application/Network.kt @@ -46,7 +46,9 @@ enum class Network(val uriComponent: String, val displayName: String) { IGOR("igor", "IGOR"), - DIBBLER("dibbler", "DIBBLER"); + DIBBLER("dibbler", "DIBBLER"), + + ESMERALDA("esmeralda", "ESMERALDA"); companion object { fun from(uriComponent: String): Network { diff --git a/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt b/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt index b620b63b3..e21afe021 100644 --- a/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt +++ b/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt @@ -34,22 +34,20 @@ package com.tari.android.wallet.application import android.app.Activity import android.app.Application -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.OnLifecycleEvent +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner -import com.orhanobut.logger.AndroidLogAdapter import com.orhanobut.logger.Logger import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.di.DiContainer import com.tari.android.wallet.event.Event import com.tari.android.wallet.event.EventBus -import com.tari.android.wallet.infrastructure.Tracker +import com.tari.android.wallet.infrastructure.logging.LoggerAdapter import com.tari.android.wallet.network.NetworkConnectionStateReceiver import com.tari.android.wallet.notification.NotificationHelper -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher +import com.tari.android.wallet.ui.common.gyphy.GiphyAdapter import com.tari.android.wallet.yat.YatAdapter -import net.danlew.android.joda.JodaTimeAndroid import java.lang.ref.WeakReference import javax.inject.Inject @@ -58,13 +56,13 @@ import javax.inject.Inject * * @author The Tari Development Team */ -internal class TariWalletApplication : Application(), LifecycleObserver { +class TariWalletApplication : Application() { @Inject lateinit var notificationHelper: NotificationHelper @Inject - lateinit var tracker: Tracker + lateinit var loggerAdapter: LoggerAdapter @Inject lateinit var connectionStateReceiver: NetworkConnectionStateReceiver @@ -78,7 +76,13 @@ internal class TariWalletApplication : Application(), LifecycleObserver { @Inject lateinit var yatAdapter: YatAdapter + @Inject + lateinit var giphyAdapter: GiphyAdapter + private val activityLifecycleCallbacks = ActivityLifecycleCallbacks() + private val logger + get() = Logger.t(TariWalletApplication::class.simpleName) + var isInForeground = false private set @@ -94,13 +98,12 @@ internal class TariWalletApplication : Application(), LifecycleObserver { INSTANCE = WeakReference(this) registerActivityLifecycleCallbacks(activityLifecycleCallbacks) - Logger.addLogAdapter(AndroidLogAdapter()) - JodaTimeAndroid.init(this) DiContainer.initContainer(this) initApplication() - ProcessLifecycleOwner.get().lifecycle.addObserver(this) + ProcessLifecycleOwner.get().lifecycle.addObserver(AppObserver()) + logger.i("Application inited") } fun initApplication() { @@ -113,40 +116,42 @@ internal class TariWalletApplication : Application(), LifecycleObserver { registerReceiver(connectionStateReceiver, connectionStateReceiver.intentFilter) - // track app download - tracker.download(this) - yatAdapter.initYat(this) - } - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) - fun onAppDestroyed() { - Logger.d("App was destroyed.") - walletServiceLauncher.stopOnAppBackgrounded() - } + giphyAdapter.init() - @OnLifecycleEvent(Lifecycle.Event.ON_STOP) - fun onAppBackgrounded() { - Logger.d("App in background.") - isInForeground = false - //todo get back when the whole application will have ability to reconnect to wallet -// walletServiceLauncher.stopOnAppBackgrounded() - EventBus.post(Event.App.AppBackgrounded()) - } - - @OnLifecycleEvent(Lifecycle.Event.ON_START) - fun onAppForegrounded() { - Logger.d("App in foreground.") - isInForeground = true - walletServiceLauncher.startOnAppForegrounded() - EventBus.post(Event.App.AppForegrounded()) + loggerAdapter.init() } companion object { - @Volatile var INSTANCE: WeakReference = WeakReference(null) private set } + + inner class AppObserver : DefaultLifecycleObserver { + + override fun onStart(owner: LifecycleOwner) { + super.onStart(owner) + logger.i("App in foreground") + isInForeground = true + walletServiceLauncher.startOnAppForegrounded() + EventBus.post(Event.App.AppForegrounded()) + } + + override fun onStop(owner: LifecycleOwner) { + super.onStop(owner) + logger.i("App in background") + isInForeground = false + walletServiceLauncher.stopOnAppBackgrounded() + EventBus.post(Event.App.AppBackgrounded()) + } + + override fun onDestroy(owner: LifecycleOwner) { + super.onDestroy(owner) + logger.i("App was destroyed") + walletServiceLauncher.stopOnAppBackgrounded() + } + } } diff --git a/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt b/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt index 24f754457..e775abc42 100644 --- a/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt +++ b/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt @@ -43,7 +43,7 @@ import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository import com.tari.android.wallet.event.EventBus import com.tari.android.wallet.ffi.* -import com.tari.android.wallet.service.WalletService +import com.tari.android.wallet.service.service.WalletService import com.tari.android.wallet.service.seedPhrase.SeedPhraseRepository import com.tari.android.wallet.tor.TorConfig import com.tari.android.wallet.tor.TorProxyManager @@ -58,7 +58,7 @@ import java.io.File * * @author The Tari Development Team */ -internal class WalletManager( +class WalletManager( private val walletConfig: WalletConfig, private val torManager: TorProxyManager, private val sharedPrefsWrapper: SharedPrefsRepository, @@ -71,6 +71,8 @@ internal class WalletManager( ) { private var logFileObserver: LogFileObserver? = null + private val logger + get() = Logger.t(WalletManager::class.simpleName) init { // post initial wallet state @@ -104,19 +106,21 @@ internal class WalletManager( @SuppressLint("CheckResult") private fun onTorProxyStateChanged(torProxyState: TorProxyState) { - Logger.d("Tor proxy state has changed: $torProxyState.") + logger.i("Tor proxy state has changed: $torProxyState") if (torProxyState is TorProxyState.Running) { if (EventBus.walletState.publishSubject.value == WalletState.NotReady || EventBus.walletState.publishSubject.value is WalletState.Failed ) { - Logger.d("Initialize wallet.") + logger.i("Initialize wallet started") EventBus.walletState.post(WalletState.Initializing) Thread { try { initWallet() EventBus.walletState.post(WalletState.Started) + logger.i("Wallet was started") } catch (e: Exception) { EventBus.walletState.post(WalletState.Failed(e)) + logger.e(e, "Wallet was failed") } }.start() } @@ -131,10 +135,7 @@ internal class WalletManager( val cookieString: ByteArray = cookieFile.readBytes() val torCookie = FFIByteVector(cookieString) return FFITariTransportConfig( - NetAddressString( - torConfig.controlHost, - torConfig.controlPort - ), + NetAddressString(torConfig.controlHost, torConfig.controlPort), torCookie, torConfig.connectionPort, torConfig.sock5Username, @@ -147,10 +148,7 @@ internal class WalletManager( */ private fun getCommsConfig(walletConfig: WalletConfig): FFICommsConfig { return FFICommsConfig( - NetAddressString( - "127.0.0.1", - 39069 - ).toString(), + NetAddressString("127.0.0.1", 39069).toString(), getTorTransport(), walletConfig.walletDBName, walletConfig.getWalletFilesDirPath(), diff --git a/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt b/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt index 7a743888c..17a979744 100644 --- a/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt +++ b/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt @@ -13,6 +13,7 @@ import com.tari.android.wallet.extension.getWithError import com.tari.android.wallet.ffi.FFIPublicKey import com.tari.android.wallet.ffi.FFIWallet import com.tari.android.wallet.ffi.HexString +import com.tari.android.wallet.service.connection.ServiceConnectionStatus import com.tari.android.wallet.service.connection.TariWalletServiceConnection import io.reactivex.disposables.CompositeDisposable import org.apache.commons.io.IOUtils @@ -32,7 +33,7 @@ class BaseNodes( init { serviceConnection.connection.subscribe { - if (it.status == TariWalletServiceConnection.ServiceConnectionStatus.CONNECTED) { + if (it.status == ServiceConnectionStatus.CONNECTED) { startSync() } }.addTo(compositeDisposable) @@ -88,6 +89,6 @@ class BaseNodes( } private fun getBaseNodeResource(network: Network): Int = when(network) { - else -> R.raw.dibbler_base_nodes + else -> R.raw.esmeralda_base_nodes } } diff --git a/app/src/main/java/com/tari/android/wallet/data/WalletConfig.kt b/app/src/main/java/com/tari/android/wallet/data/WalletConfig.kt index 6090de532..ac3b0f6d5 100644 --- a/app/src/main/java/com/tari/android/wallet/data/WalletConfig.kt +++ b/app/src/main/java/com/tari/android/wallet/data/WalletConfig.kt @@ -10,11 +10,12 @@ import java.io.File * @author The Tari Development Team */ -class WalletConfig(val context: Context, val networkRepository: NetworkRepository){ +class WalletConfig(val context: Context, val networkRepository: NetworkRepository) { val walletDBName: String = "tari_wallet_${networkRepository.currentNetwork!!.network.uriComponent}" val walletDBFullFileName: String = "$walletDBName.sqlite3" private val logFilePrefix = "tari_aurora" + private val applicationLogs = "tari_application" private val logFileExtension = "log" private val logFilesDirName = "tari_logs" @@ -38,19 +39,23 @@ class WalletConfig(val context: Context, val networkRepository: NetworkRepositor return logFilesDir.absolutePath } - /** - * FFI log file path. - */ - fun getWalletLogFilePath(): String { - val logFileName = "$logFilePrefix.$logFileExtension" - val logFile = File(getWalletLogFilesDirPath(), logFileName) - if (!logFile.exists()) { - logFile.createNewFile() + fun getWalletLogFilePath(): String = getOrCreateFilePath(getWalletLogFilesDirPath(), "$logFilePrefix.$logFileExtension") + + fun getApplicationLogsFilePath(): String = getOrCreateFilePath(getWalletFilesDirPath(), "$applicationLogs.$logFileExtension") + + private fun getOrCreateFilePath(dirPath: String, fileName: String): String { + val folder = File(dirPath) + if (!folder.exists()) { + folder.mkdirs() + } + val file = File(dirPath, fileName) + if (!file.exists()) { + file.createNewFile() } - return logFile.absolutePath + return file.absolutePath } - fun getWalletTempDirPath() : String { + fun getWalletTempDirPath(): String { val tempDir = File(getWalletFilesDirPath(), "temp") if (!tempDir.exists()) tempDir.mkdir() return tempDir.absolutePath diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt index 77758d263..3ef970744 100644 --- a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt +++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt @@ -124,7 +124,7 @@ class SharedPrefsRepository( databasePassphrase = null } - fun generateDatabasePassphrase() { + fun generateDatabasePassphrase(): String { var generatedString = "" val charset = Charsets.UTF_8 val utfErrorCode = Char(65533) @@ -134,11 +134,9 @@ class SharedPrefsRepository( val str = String(ByteArray(1) { nextByte }, charset) if (str.first() != utfErrorCode) { generatedString += str - break } } - - databasePassphrase = generatedString + return generatedString } // Runs when user manually clear the application data diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/delegates/SharedPrefGsonDelegate.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/delegates/SharedPrefGsonDelegate.kt index 240d1618a..3fb23d939 100644 --- a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/delegates/SharedPrefGsonDelegate.kt +++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/delegates/SharedPrefGsonDelegate.kt @@ -23,7 +23,7 @@ class SharedPrefGsonDelegate( try { gson.fromJson(savedValue, type) as T } catch (e: Throwable) { - Logger.i(e.toString()) + logger.e(e.toString()) defValue } } else { @@ -37,4 +37,9 @@ class SharedPrefGsonDelegate( apply() } } + + companion object { + private val logger + get() = Logger.t(SharedPrefGsonDelegate::class.simpleName) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkRepositoryImpl.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkRepositoryImpl.kt index e200094c7..5e68ce504 100644 --- a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkRepositoryImpl.kt +++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkRepositoryImpl.kt @@ -9,15 +9,17 @@ import com.tari.android.wallet.ui.common.domain.ResourceManager class NetworkRepositoryImpl(private val resourceManager: ResourceManager, sharedPrefs: SharedPreferences) : NetworkRepository { - override var supportedNetworks: List = listOf(Network.DIBBLER) + override var supportedNetworks: List = listOf(Network.ESMERALDA) - override var recommendedNetworks: List = listOf(Network.DIBBLER) + override var recommendedNetworks: List = listOf(Network.ESMERALDA) override var currentNetwork by SharedPrefGsonDelegate(sharedPrefs, Keys.currentNetwork, TariNetwork::class.java) init { - if (currentNetwork == null) { - currentNetwork = getDibbler(resourceManager) + try { + currentNetwork!!.network.displayName + } catch (e: Throwable) { + currentNetwork = getEsmeralda(resourceManager) } } @@ -25,7 +27,8 @@ class NetworkRepositoryImpl(private val resourceManager: ResourceManager, shared override var incompatibleNetworkShown by SharedPrefBooleanDelegate(sharedPrefs, formatKey(Keys.networkIncompatible), false) - override fun getAllNetworks(): List = listOf(getDibbler(resourceManager)) + override fun getAllNetworks(): List = listOf(getEsmeralda(resourceManager)) + object Keys { const val currentNetwork = "tari_current_network" const val ffiNetwork = "ffi_tari_current_network" @@ -36,7 +39,7 @@ class NetworkRepositoryImpl(private val resourceManager: ResourceManager, shared private const val mainNetThicker = "XTR" private const val testNetThicker = "tXTR" - fun getDibbler(resourceManager: ResourceManager): TariNetwork = - TariNetwork(Network.DIBBLER, resourceManager.getString(R.string.dibbler_faucet_url), testNetThicker) + fun getEsmeralda(resourceManager: ResourceManager): TariNetwork = + TariNetwork(Network.ESMERALDA, resourceManager.getString(R.string.esmeralda_faucet_url), testNetThicker) } } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkUtils.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkUtils.kt index 500a6aebb..273d7ed58 100644 --- a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkUtils.kt +++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NetworkUtils.kt @@ -1,5 +1,6 @@ package com.tari.android.wallet.data.sharedPrefs.network +import com.google.gson.Gson import com.tari.android.wallet.data.repository.CommonRepository fun NetworkRepository.formatKey(key: String): String { @@ -7,7 +8,12 @@ fun NetworkRepository.formatKey(key: String): String { if (catching.isSuccess) { return catching.getOrNull().orEmpty() } else { - throw NoSupportedNetworkException() + try { + val networkGson = Gson().toJson(this.currentNetwork, TariNetwork::class.java) + throw NoSupportedNetworkException(key + networkGson) + } catch (e: Throwable) { + throw NoSupportedNetworkException(key + e.message) + } } } diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NoSupportedNetworkException.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NoSupportedNetworkException.kt index 898c9d2d0..8c85260f3 100644 --- a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NoSupportedNetworkException.kt +++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/network/NoSupportedNetworkException.kt @@ -1,3 +1,3 @@ package com.tari.android.wallet.data.sharedPrefs.network -class NoSupportedNetworkException: Exception() \ No newline at end of file +class NoSupportedNetworkException(val network: String): Exception(network) \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt b/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt index 690aabd8f..b827b1582 100644 --- a/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt +++ b/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt @@ -36,19 +36,19 @@ import android.content.ClipboardManager import com.tari.android.wallet.application.TariWalletApplication import com.tari.android.wallet.application.deeplinks.DeeplinkViewModel import com.tari.android.wallet.service.BootDeviceReceiver -import com.tari.android.wallet.service.WalletService -import com.tari.android.wallet.ui.activity.SplashActivity -import com.tari.android.wallet.ui.activity.debug.DebugActivity -import com.tari.android.wallet.ui.activity.home.HomeActivity -import com.tari.android.wallet.ui.activity.settings.DeleteWalletActivity +import com.tari.android.wallet.service.service.WalletService +import com.tari.android.wallet.ui.fragment.splash.SplashActivity +import com.tari.android.wallet.ui.fragment.debug.activity.DebugActivity +import com.tari.android.wallet.ui.fragment.home.HomeActivity +import com.tari.android.wallet.ui.fragment.settings.deleteWallet.DeleteWalletActivity import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.component.networkStateIndicator.ConnectionIndicatorViewModel import com.tari.android.wallet.ui.fragment.auth.AuthActivity import com.tari.android.wallet.ui.fragment.auth.AuthViewModel -import com.tari.android.wallet.ui.fragment.debug.DebugLogFragment import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.BaseNodeConfigViewModel import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.addBaseNode.AddCustomBaseNodeViewModel import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.changeBaseNode.ChangeBaseNodeViewModel +import com.tari.android.wallet.ui.fragment.debug.debugLog.DebugLogViewModel import com.tari.android.wallet.ui.fragment.onboarding.activity.OnboardingFlowActivity import com.tari.android.wallet.ui.fragment.onboarding.createWallet.CreateWalletViewModel import com.tari.android.wallet.ui.fragment.onboarding.inroduction.IntroductionViewModel @@ -99,14 +99,13 @@ import javax.inject.Singleton WalletModule::class, ServiceModule::class, TorModule::class, - TrackerModule::class, BackupAndRestoreModule::class, PresentationModule::class, YatModule::class ] ) -internal interface ApplicationComponent { +interface ApplicationComponent { /** * Application. @@ -132,7 +131,6 @@ internal interface ApplicationComponent { fun inject(fragment: AddRecipientFragment) fun inject(fragment: AddNoteFragment) fun inject(fragment: ChooseGIFDialogFragment) - fun inject(fragment: DebugLogFragment) /** * Backup. */ @@ -178,6 +176,7 @@ internal interface ApplicationComponent { fun inject(viewModel: AuthViewModel) fun inject(viewModel: TariAboutViewModel) fun inject(viewModel: UtxosListViewModel) + fun inject(viewModel: DebugLogViewModel) /** * Service(s). */ diff --git a/app/src/main/java/com/tari/android/wallet/di/ApplicationModule.kt b/app/src/main/java/com/tari/android/wallet/di/ApplicationModule.kt index b36a3904f..2a53cbb07 100644 --- a/app/src/main/java/com/tari/android/wallet/di/ApplicationModule.kt +++ b/app/src/main/java/com/tari/android/wallet/di/ApplicationModule.kt @@ -50,11 +50,12 @@ import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepositoryImpl import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository import com.tari.android.wallet.data.sharedPrefs.testnetFaucet.TestnetFaucetRepository import com.tari.android.wallet.data.sharedPrefs.tor.TorSharedRepository +import com.tari.android.wallet.infrastructure.logging.LoggerAdapter import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationService import com.tari.android.wallet.notification.NotificationHelper -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.domain.ResourceManager -import com.tari.android.wallet.ui.common.gyphy.GiphyEcosystem +import com.tari.android.wallet.ui.common.gyphy.GiphyAdapter import com.tari.android.wallet.ui.fragment.settings.backup.BackupSettingsRepository import com.tari.android.wallet.yat.YatSharedRepository import dagger.Module @@ -68,9 +69,8 @@ import javax.inject.Singleton * @author The Tari Development Team */ @Module -internal class ApplicationModule( - private val app: TariWalletApplication -) { +class ApplicationModule(private val app: TariWalletApplication) { + @Provides @Singleton fun provideApplication(): TariWalletApplication = app @@ -147,8 +147,7 @@ internal class ApplicationModule( context: Context, tariSettingsSharedRepository: TariSettingsSharedRepository, walletConfig: WalletConfig - ): WalletServiceLauncher = - WalletServiceLauncher(context, walletConfig, tariSettingsSharedRepository) + ): WalletServiceLauncher = WalletServiceLauncher(context, walletConfig, tariSettingsSharedRepository) @Provides @Singleton @@ -173,7 +172,11 @@ internal class ApplicationModule( @Provides @Singleton - fun provideGiphyEcosystem(context: Context): GiphyEcosystem = GiphyEcosystem(context, BuildConfig.GIPHY_KEY) + fun provideLoggerAdapter(walletConfig: WalletConfig): LoggerAdapter = LoggerAdapter(walletConfig) + + @Provides + @Singleton + fun provideGiphyAdapter(context: Context): GiphyAdapter = GiphyAdapter(context, BuildConfig.GIPHY_KEY) companion object { const val sharedPrefsFileName = "tari_wallet_shared_prefs" diff --git a/app/src/main/java/com/tari/android/wallet/di/DiContainer.kt b/app/src/main/java/com/tari/android/wallet/di/DiContainer.kt index 43715b9e1..c91e80c02 100644 --- a/app/src/main/java/com/tari/android/wallet/di/DiContainer.kt +++ b/app/src/main/java/com/tari/android/wallet/di/DiContainer.kt @@ -3,13 +3,13 @@ package com.tari.android.wallet.di import com.tari.android.wallet.application.TariWalletApplication object DiContainer { - internal lateinit var appComponent: ApplicationComponent + lateinit var appComponent: ApplicationComponent - internal fun initContainer(app: TariWalletApplication) { + fun initContainer(app: TariWalletApplication) { appComponent = initDagger(app) } - internal fun reInitContainer() { + fun reInitContainer() { appComponent = initDagger(TariWalletApplication.INSTANCE.get()!!) TariWalletApplication.INSTANCE.get()!!.initApplication() } diff --git a/app/src/main/java/com/tari/android/wallet/di/GiphyGlideModule.java b/app/src/main/java/com/tari/android/wallet/di/GiphyGlideModule.java index ae75cbd23..9070a210d 100644 --- a/app/src/main/java/com/tari/android/wallet/di/GiphyGlideModule.java +++ b/app/src/main/java/com/tari/android/wallet/di/GiphyGlideModule.java @@ -49,4 +49,4 @@ public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder builder.setMemoryCache(new LruResourceCache(30 * 1024 * 1024)); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/di/TorModule.kt b/app/src/main/java/com/tari/android/wallet/di/TorModule.kt index d8c8c22a7..b90d5c4b5 100644 --- a/app/src/main/java/com/tari/android/wallet/di/TorModule.kt +++ b/app/src/main/java/com/tari/android/wallet/di/TorModule.kt @@ -51,7 +51,7 @@ class TorModule { @Provides @Singleton - internal fun provideTorConfig(context: Context): TorConfig { + fun provideTorConfig(context: Context): TorConfig { val cookieFilePath = File(context.getDir(TorProxyManager.torDataDirectoryName, Context.MODE_PRIVATE), "control_auth_cookie").absolutePath return TorConfig( @@ -67,6 +67,6 @@ class TorModule { @Provides @Singleton - internal fun provideTorProxyManager(context: Context, torSharedRepository: TorSharedRepository, torConfig: TorConfig): TorProxyManager = + fun provideTorProxyManager(context: Context, torSharedRepository: TorSharedRepository, torConfig: TorConfig): TorProxyManager = TorProxyManager(context, torSharedRepository, torConfig) } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt b/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt index c95ca8c11..ffa52482a 100644 --- a/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt +++ b/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt @@ -40,7 +40,7 @@ import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository -import com.tari.android.wallet.infrastructure.BugReportingService +import com.tari.android.wallet.infrastructure.logging.BugReportingService import com.tari.android.wallet.network.NetworkConnectionStateReceiver import com.tari.android.wallet.service.seedPhrase.SeedPhraseRepository import com.tari.android.wallet.tor.TorConfig @@ -51,7 +51,7 @@ import javax.inject.Singleton @Module -internal class WalletModule { +class WalletModule { @Provides @Singleton @@ -88,7 +88,7 @@ internal class WalletModule { @Provides @Singleton fun provideBugReportingService(sharedPrefsWrapper: SharedPrefsRepository, walletConfig: WalletConfig): BugReportingService = - BugReportingService(sharedPrefsWrapper, walletConfig.getWalletLogFilesDirPath()) + BugReportingService(sharedPrefsWrapper, walletConfig) @Provides @Singleton diff --git a/app/src/main/java/com/tari/android/wallet/event/Event.kt b/app/src/main/java/com/tari/android/wallet/event/Event.kt index ec4fe926c..5aa46ef82 100644 --- a/app/src/main/java/com/tari/android/wallet/event/Event.kt +++ b/app/src/main/java/com/tari/android/wallet/event/Event.kt @@ -49,6 +49,7 @@ object Event { * Wallet events. */ object Transaction { + object Updated data class TxReceived(val tx: PendingInboundTx) data class TxReplyReceived(val tx: PendingOutboundTx) data class TxFinalized(val tx: PendingInboundTx) diff --git a/app/src/main/java/com/tari/android/wallet/event/EventBus.kt b/app/src/main/java/com/tari/android/wallet/event/EventBus.kt index d71275217..99cc9e6fb 100644 --- a/app/src/main/java/com/tari/android/wallet/event/EventBus.kt +++ b/app/src/main/java/com/tari/android/wallet/event/EventBus.kt @@ -34,6 +34,7 @@ package com.tari.android.wallet.event import com.tari.android.wallet.application.WalletState import com.tari.android.wallet.infrastructure.backup.BackupState +import com.tari.android.wallet.model.BalanceInfo import com.tari.android.wallet.model.recovery.WalletRestorationResult import com.tari.android.wallet.network.NetworkConnectionState import com.tari.android.wallet.service.baseNode.BaseNodeState @@ -49,11 +50,13 @@ import com.tari.android.wallet.tor.TorProxyState * // op.s * } */ -internal object EventBus : GeneralEventBus() { +object EventBus : GeneralEventBus() { //todo looks like better to have it into appropriate classes than here val torProxyState = BehaviorEventBus() + val balanceState = BehaviorEventBus() + val walletState = BehaviorEventBus() val networkConnectionState = BehaviorEventBus() diff --git a/app/src/main/java/com/tari/android/wallet/extension/DateExtensions.kt b/app/src/main/java/com/tari/android/wallet/extension/DateExtensions.kt index c3ad549b2..1d9f21a4d 100644 --- a/app/src/main/java/com/tari/android/wallet/extension/DateExtensions.kt +++ b/app/src/main/java/com/tari/android/wallet/extension/DateExtensions.kt @@ -41,7 +41,7 @@ import java.util.* * @author The Tari Development Team */ -internal fun Date.txFormattedDate(): String { +fun Date.txFormattedDate(): String { val cal: Calendar = Calendar.getInstance() cal.time = this val day: Int = cal.get(Calendar.DATE) diff --git a/app/src/main/java/com/tari/android/wallet/extension/NumericExtensions.kt b/app/src/main/java/com/tari/android/wallet/extension/NumericExtensions.kt index cdf8449d9..5f0e29894 100644 --- a/app/src/main/java/com/tari/android/wallet/extension/NumericExtensions.kt +++ b/app/src/main/java/com/tari/android/wallet/extension/NumericExtensions.kt @@ -40,20 +40,20 @@ import java.math.BigInteger * * @return mapped float */ -internal fun Float.remap(from1: Float, to1: Float, from2: Float, to2: Float): Float { +fun Float.remap(from1: Float, to1: Float, from2: Float, to2: Float): Float { return (this - from1) / (to1 - from1) * (to2 - from2) + from2 } /** * Int to MicroTari. */ -internal fun Int.toMicroTari(): MicroTari { +fun Int.toMicroTari(): MicroTari { return MicroTari(BigInteger.valueOf(this.toLong())) } /** * Long to MicroTari. */ -internal fun Long.toMicroTari(): MicroTari { +fun Long.toMicroTari(): MicroTari { return MicroTari(BigInteger.valueOf(this)) } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/extension/StringExtensions.kt b/app/src/main/java/com/tari/android/wallet/extension/StringExtensions.kt index 9ce3e16a3..606548159 100644 --- a/app/src/main/java/com/tari/android/wallet/extension/StringExtensions.kt +++ b/app/src/main/java/com/tari/android/wallet/extension/StringExtensions.kt @@ -50,11 +50,7 @@ import com.tari.android.wallet.ui.component.LetterSpacingSpan * @param url locator * @param applyToOnlyFirstOccurrence whether the span should be applied only to the first occurrence */ -internal fun SpannableString.applyURLStyle( - search: String, - url: String, - applyToOnlyFirstOccurrence: Boolean = false -): SpannableString { +fun SpannableString.applyURLStyle(search: String, url: String, applyToOnlyFirstOccurrence: Boolean = false): SpannableString { var index = this.indexOf(search) val span = URLSpan(url) while (index >= 0) { @@ -76,7 +72,7 @@ internal fun SpannableString.applyURLStyle( * @param applyToOnlyFirstOccurrence whether customFont should be applied only to the first occurrence * @return spannable string */ -internal fun String.applyFontStyle( +fun String.applyFontStyle( context: Context, defaultFont: CustomFont, search: List, @@ -93,12 +89,7 @@ internal fun String.applyFontStyle( /** * Similar to applyFontStyle above, but applied to color instead. */ -internal fun String.applyColorStyle( - defaultColor: Int, - search: List, - styleColor: Int, - applyToOnlyFirstOccurrence: Boolean = false -): SpannableString { +fun String.applyColorStyle(defaultColor: Int, search: List, styleColor: Int, applyToOnlyFirstOccurrence: Boolean = false): SpannableString { val spannableString = SpannableString(this) spannableString.setSpan(ForegroundColorSpan(defaultColor), 0, length, Spanned.SPAN_INTERMEDIATE) search.forEach { spannableString.applyColorStyle(it, styleColor, applyToOnlyFirstOccurrence) } @@ -108,11 +99,7 @@ internal fun String.applyColorStyle( /** * Helper function to apply color style to a spannable string. */ -private fun SpannableString.applyColorStyle( - search: String, - color: Int, - applyToOnlyFirstOccurrence: Boolean = false -) { +private fun SpannableString.applyColorStyle(search: String, color: Int, applyToOnlyFirstOccurrence: Boolean = false) { var index = this.indexOf(search) while (index >= 0) { setSpan(ForegroundColorSpan(color), index, index + search.length, Spanned.SPAN_INTERMEDIATE) @@ -126,11 +113,7 @@ private fun SpannableString.applyColorStyle( /** * Helper function to apply typeface style to a spannable string. */ -private fun SpannableString.applyTypefaceStyle( - search: String, - typeface: Typeface, - applyToOnlyFirstOccurrence: Boolean = false -) { +private fun SpannableString.applyTypefaceStyle(search: String, typeface: Typeface, applyToOnlyFirstOccurrence: Boolean = false) { var index = this.indexOf(search) while (index >= 0) { setSpan(CustomTypefaceSpan("", typeface), index, index + search.length, Spanned.SPAN_INTERMEDIATE) @@ -144,11 +127,7 @@ private fun SpannableString.applyTypefaceStyle( /** * Helper function to apply relative text size style to a spannable string. */ -internal fun SpannableString.applyRelativeTextSizeStyle( - search: String, - relativeTextSize: Float, - applyToOnlyFirstOccurrence: Boolean = false -) { +fun SpannableString.applyRelativeTextSizeStyle(search: String, relativeTextSize: Float, applyToOnlyFirstOccurrence: Boolean = false) { var index = this.indexOf(search) while (index >= 0) { setSpan(RelativeSizeSpan(relativeTextSize), index, index + search.length, Spanned.SPAN_INTERMEDIATE) @@ -162,11 +141,7 @@ internal fun SpannableString.applyRelativeTextSizeStyle( /** * Helper function to apply letter spacing to a spannable string. */ -internal fun SpannableString.applyLetterSpacingStyle( - search: String, - letterSpacing: Float, - applyToOnlyFirstOccurrence: Boolean = false -) { +fun SpannableString.applyLetterSpacingStyle(search: String, letterSpacing: Float, applyToOnlyFirstOccurrence: Boolean = false) { var index = this.indexOf(search) while (index >= 0) { setSpan(LetterSpacingSpan(letterSpacing), index, index + search.length, Spanned.SPAN_INTERMEDIATE) diff --git a/app/src/main/java/com/tari/android/wallet/extension/WalletExtension.kt b/app/src/main/java/com/tari/android/wallet/extension/WalletExtension.kt index f1be27ea1..088f91c93 100644 --- a/app/src/main/java/com/tari/android/wallet/extension/WalletExtension.kt +++ b/app/src/main/java/com/tari/android/wallet/extension/WalletExtension.kt @@ -4,7 +4,7 @@ import com.tari.android.wallet.model.WalletError import com.tari.android.wallet.model.throwIf import com.tari.android.wallet.service.TariWalletService -internal fun TariWalletService.executeWithError( +fun TariWalletService.executeWithError( onError: (error: WalletError) -> Unit = { throwIf(it) }, action: (error: WalletError, wallet: TariWalletService) -> Unit ) { @@ -13,7 +13,7 @@ internal fun TariWalletService.executeWithError( onError(walletError) } -internal fun TariWalletService.getWithError( +fun TariWalletService.getWithError( onError: (error: WalletError) -> Unit = { throwIf(it) }, action: (error: WalletError, wallet: TariWalletService) -> T, ): T { diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIBalance.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIBalance.kt index 19b3934c2..3595f54cd 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIBalance.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIBalance.kt @@ -40,59 +40,25 @@ import java.math.BigInteger * * @author The Tari Development Team */ -internal class FFIBalance() : FFIBase() { +class FFIBalance() : FFIBase() { - // region JNI - - private external fun jniGetAvailable( - libError: FFIError - ): ByteArray - private external fun jniGetIncoming( - libError: FFIError - ): ByteArray - private external fun jniGetOutgoing( - libError: FFIError - ): ByteArray - private external fun jniGetTimeLocked( - libError: FFIError - ): ByteArray + private external fun jniGetAvailable(libError: FFIError): ByteArray + private external fun jniGetIncoming(libError: FFIError): ByteArray + private external fun jniGetOutgoing(libError: FFIError): ByteArray + private external fun jniGetTimeLocked(libError: FFIError): ByteArray private external fun jniDestroy() - // endregion - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getAvailable(): MicroTari { - val error = FFIError() - val bytes = jniGetAvailable(error) - throwIf(error) - return MicroTari(BigInteger(1, bytes)) - } + fun getAvailable(): MicroTari = runWithError { MicroTari(BigInteger(1, jniGetAvailable(it))) } - fun getIncoming(): MicroTari { - val error = FFIError() - val bytes = jniGetIncoming(error) - throwIf(error) - return MicroTari(BigInteger(1, bytes)) - } + fun getIncoming(): MicroTari = runWithError { MicroTari(BigInteger(1, jniGetIncoming(it))) } - fun getOutgoing(): MicroTari { - val error = FFIError() - val bytes = jniGetOutgoing(error) - throwIf(error) - return MicroTari(BigInteger(1, bytes)) - } + fun getOutgoing(): MicroTari = runWithError { MicroTari(BigInteger(1, jniGetOutgoing(it))) } - fun getTimeLocked(): MicroTari { - val error = FFIError() - val bytes = jniGetTimeLocked(error) - throwIf(error) - return MicroTari(BigInteger(1, bytes)) - } - - override fun destroy() { - jniDestroy() - } + fun getTimeLocked(): MicroTari = runWithError { MicroTari(BigInteger(1, jniGetTimeLocked(it))) } + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIBase.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIBase.kt index de5664835..769ba8768 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIBase.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIBase.kt @@ -32,8 +32,12 @@ */ package com.tari.android.wallet.ffi -internal typealias FFIPointer = Long -internal const val nullptr = 0L +import com.orhanobut.logger.Logger +import com.orhanobut.logger.Printer + +typealias FFIPointer = Long + +const val nullptr = 0L /** * Base class for FFI native peer entities. @@ -46,6 +50,9 @@ abstract class FFIBase { var pointer = nullptr protected set + protected val logger: Printer + get() = Logger.t(this::class.simpleName) + abstract fun destroy() protected fun finalize() { @@ -53,5 +60,4 @@ abstract class FFIBase { destroy() } } - } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIByteVector.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIByteVector.kt index a976144c3..f6e469d8e 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIByteVector.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIByteVector.kt @@ -41,73 +41,44 @@ import java.math.BigInteger */ class FFIByteVector() : FFIBase() { - // region JNI - private external fun jniGetLength(error: FFIError): Int private external fun jniGetAt(index: Int, error: FFIError): Int private external fun jniDestroy() private external fun jniCreate(byteArray: ByteArray, error: FFIError) - // endregion - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - constructor(hex: HexString): this() { + constructor(hex: HexString) : this() { val stringHex = hex.toString() - if (stringHex.length < 64) { - throw FFIException( - message = "Argument's length is invalid - should be 64 but got " + - "${stringHex.length}\n$stringHex" - ) - } val hexInteger = BigInteger(stringHex, 16) var byteArray = hexInteger.toByteArray() // toByteArray for some reason added one leading zero. Probably gets it from protocol if (byteArray.size == 33 && byteArray[0] == 0.toByte()) { byteArray = byteArray.drop(1).toByteArray() } - val error = FFIError() - jniCreate(byteArray, error) - throwIf(error) + runWithError { jniCreate(byteArray, it) } } - constructor(bytes: ByteArray): this() { - val error = FFIError() - jniCreate(bytes, error) - throwIf(error) + constructor(bytes: ByteArray) : this() { + runWithError { jniCreate(bytes, it) } } - fun getAt(index: Int): Int { - val error = FFIError() - val byte = jniGetAt(index, error) - throwIf(error) - return byte - } + fun getAt(index: Int): Int = runWithError { jniGetAt(index, it) } - fun getLength(): Int { - val error = FFIError() - val len = jniGetLength(error) - throwIf(error) - return len - } + fun getLength(): Int = runWithError { jniGetLength(it) } fun getBytes(): ByteArray { val length = getLength() val byteArray = ByteArray(length) - for (i in 0 until length) { - val m = getAt(i) - byteArray[i] = m.toByte() + for (i in byteArray.indices) { + byteArray[i] = getAt(i).toByte() } return byteArray } - override fun toString(): String { - return HexString(this).toString() - } - - override fun destroy() { - jniDestroy() - } + override fun toString(): String = HexString(this).toString() + override fun destroy() = jniDestroy() } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFICommsConfig.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFICommsConfig.kt index e7a292475..e2b161946 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFICommsConfig.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFICommsConfig.kt @@ -32,7 +32,6 @@ */ package com.tari.android.wallet.ffi -import com.orhanobut.logger.Logger import java.io.File /** @@ -40,9 +39,7 @@ import java.io.File * * @author The Tari Development Team */ -internal class FFICommsConfig() : FFIBase() { - - // region JNI +class FFICommsConfig() : FFIBase() { private external fun jniCreate( publicAddress: String, @@ -56,7 +53,6 @@ internal class FFICommsConfig() : FFIBase() { private external fun jniDestroy() - // endregion constructor( publicAddress: String, @@ -65,23 +61,13 @@ internal class FFICommsConfig() : FFIBase() { datastorePath: String, discoveryTimeoutSec: Long, safMessageDurationSec: Long, - ): this() { + ) : this() { if (databaseName.isEmpty()) { throw FFIException(message = "databaseName may not be empty") } val writeableDir = File(datastorePath) if (writeableDir.exists() && writeableDir.isDirectory && writeableDir.canWrite()) { - val error = FFIError() - jniCreate( - publicAddress, - transport, - databaseName, - datastorePath, - discoveryTimeoutSec, - safMessageDurationSec, - error - ) - throwIf(error) + runWithError { jniCreate(publicAddress, transport, databaseName, datastorePath, discoveryTimeoutSec, safMessageDurationSec, it) } } else { val messageBuilder = StringBuilder() if (!writeableDir.exists()) { @@ -91,13 +77,10 @@ internal class FFICommsConfig() : FFIBase() { } else { messageBuilder.append("Permission problem.") } - Logger.e(messageBuilder.toString()) + logger.e(Throwable(), messageBuilder.toString()) throw FFIException(message = messageBuilder.toString()) } } - override fun destroy() { - jniDestroy() - } - + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTx.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTx.kt index c77158dfa..ce1dc56ea 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTx.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTx.kt @@ -35,9 +35,7 @@ package com.tari.android.wallet.ffi import java.math.BigInteger -internal class FFICompletedTx() : FFITxBase() { - - // region JNI +class FFICompletedTx() : FFITxBase() { private external fun jniGetId(libError: FFIError): ByteArray private external fun jniGetDestinationPublicKey(libError: FFIError): FFIPointer @@ -53,97 +51,33 @@ internal class FFICompletedTx() : FFITxBase() { private external fun jniGetCancellationReason(libError: FFIError): Int private external fun jniDestroy() - // endregion - constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - override fun destroy() { - jniDestroy() - } + override fun destroy() = jniDestroy() - fun getId(): BigInteger { - val error = FFIError() - val bytes = jniGetId(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getId(): BigInteger = runWithError { BigInteger(1, jniGetId(it)) } - override fun getDestinationPublicKey(): FFIPublicKey { - val error = FFIError() - val result = FFIPublicKey(jniGetDestinationPublicKey(error)) - throwIf(error) - return result - } + override fun getDestinationPublicKey(): FFIPublicKey = runWithError { FFIPublicKey(jniGetDestinationPublicKey(it)) } - override fun getSourcePublicKey(): FFIPublicKey { - val error = FFIError() - val result = FFIPublicKey(jniGetSourcePublicKey(error)) - throwIf(error) - return result - } + override fun getSourcePublicKey(): FFIPublicKey = runWithError { FFIPublicKey(jniGetSourcePublicKey(it)) } - fun getAmount(): BigInteger { - val error = FFIError() - val bytes = jniGetAmount(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getAmount(): BigInteger = runWithError { BigInteger(1, jniGetAmount(it)) } - fun getFee(): BigInteger { - val error = FFIError() - val bytes = jniGetFee(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getFee(): BigInteger = runWithError { BigInteger(1, jniGetFee(it)) } - fun getTimestamp(): BigInteger { - val error = FFIError() - val bytes = jniGetTimestamp(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getTimestamp(): BigInteger = runWithError { BigInteger(1, jniGetTimestamp(it)) } - fun getMessage(): String { - val error = FFIError() - val result = jniGetMessage(error) - throwIf(error) - return result - } + fun getMessage(): String = runWithError { jniGetMessage(it) } - fun getStatus(): FFITxStatus { - val error = FFIError() - val status = jniGetStatus(error) - throwIf(error) - return FFITxStatus.map(status) - } + fun getStatus(): FFITxStatus = runWithError { FFITxStatus.map(jniGetStatus(it)) } - fun getConfirmationCount(): BigInteger { - val error = FFIError() - val bytes = jniGetConfirmationCount(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getConfirmationCount(): BigInteger = runWithError { BigInteger(1, jniGetConfirmationCount(it)) } - override fun isOutbound(): Boolean { - val error = FFIError() - val result = jniIsOutbound(error) - throwIf(error) - return result - } + override fun isOutbound(): Boolean = runWithError { jniIsOutbound(it) } - fun getCancellationReason(): FFITxCancellationReason { - val error = FFIError() - val result = FFITxCancellationReason.map(jniGetCancellationReason(error)) - throwIf(error) - return result - } + fun getCancellationReason(): FFITxCancellationReason = runWithError { FFITxCancellationReason.map(jniGetCancellationReason(it)) } - fun getTransactionKernel(): FFICompletedTxKernel { - val error = FFIError() - val result = FFICompletedTxKernel(jniGetTransactionKernel(error)) - throwIf(error) - return result - } + fun getTransactionKernel(): FFICompletedTxKernel = runWithError { FFICompletedTxKernel(jniGetTransactionKernel(it)) } } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxKernel.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxKernel.kt index c2314f451..a33296478 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxKernel.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxKernel.kt @@ -37,40 +37,22 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFICompletedTxKernel() : FFIBase() { +class FFICompletedTxKernel() : FFIBase() { private external fun jniGetExcess(libError: FFIError): String private external fun jniGetExcessPublicNonce(libError: FFIError): String private external fun jniGetExcessSignature(libError: FFIError): String private external fun jniDestroy() - // endregion - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getExcess(): String { - val error = FFIError() - val result = jniGetExcess(error) - throwIf(error) - return result - } + fun getExcess(): String = runWithError { jniGetExcess(it) } - fun getExcessPublicNonce(): String { - val error = FFIError() - val result = jniGetExcessPublicNonce(error) - throwIf(error) - return result - } + fun getExcessPublicNonce(): String = runWithError { jniGetExcessPublicNonce(it) } - fun getExcessSignature(): String { - val error = FFIError() - val result = jniGetExcessSignature(error) - throwIf(error) - return result - } + fun getExcessSignature(): String = runWithError { jniGetExcessSignature(it) } - override fun destroy() { - jniDestroy() - } + override fun destroy() = jniDestroy() } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxs.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxs.kt index 5e372f16e..f78c5a497 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxs.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFICompletedTxs.kt @@ -37,37 +37,19 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFICompletedTxs() : FFIBase() { - - // region JNI +class FFICompletedTxs() : FFIBase() { private external fun jniGetLength(libError: FFIError): Int private external fun jniGetAt(index: Int, libError: FFIError): FFIPointer - private external fun jniDestroy() - // endregion - - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getLength(): Int { - val error = FFIError() - val result = jniGetLength(error) - throwIf(error) - return result - } + fun getLength(): Int = runWithError { jniGetLength(it) } - fun getAt(index: Int): FFICompletedTx { - val error = FFIError() - val result = FFICompletedTx(jniGetAt(index, error)) - throwIf(error) - return result - } - - override fun destroy() { - jniDestroy() - } + fun getAt(index: Int): FFICompletedTx = runWithError { FFICompletedTx(jniGetAt(index, it)) } + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIContact.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIContact.kt index 4cd8aa5e8..658d8afba 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIContact.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIContact.kt @@ -32,68 +32,41 @@ */ package com.tari.android.wallet.ffi -internal typealias FFIContactPtr = Long +typealias FFIContactPtr = Long /** * Tari contact wrapper. * * @author The Tari Development Team */ -internal class FFIContact() : FFIBase() { - - // region JNI +class FFIContact() : FFIBase() { private external fun jniGetAlias(libError: FFIError): String - private external fun jniGetPublicKey( - libError: FFIError - ): FFIPointer - + private external fun jniGetPublicKey(libError: FFIError): FFIPointer private external fun jniDestroy() - private external fun jniCreate( - alias: String, - publicKeyPtr: FFIPublicKey, - libError: FFIError - ) + private external fun jniCreate(alias: String, publicKeyPtr: FFIPublicKey, libError: FFIError) - // endregion - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - constructor(alias: String, FFIPublicKey: FFIPublicKey): this() { + constructor(alias: String, FFIPublicKey: FFIPublicKey) : this() { if (alias.isNotEmpty()) { - val error = FFIError() - jniCreate(alias, FFIPublicKey, error) - throwIf(error) + runWithError { jniCreate(alias, FFIPublicKey, it) } } else { throw FFIException(message = "Alias is an empty String.") } } - fun getAlias(): String { - val error = FFIError() - val result = jniGetAlias(error) - throwIf(error) - return result - } + fun getAlias(): String = runWithError { jniGetAlias(it) } - fun getPublicKey(): FFIPublicKey { - val error = FFIError() - val result = FFIPublicKey(jniGetPublicKey(error)) - throwIf(error) - return result - } + fun getPublicKey(): FFIPublicKey = runWithError { FFIPublicKey(jniGetPublicKey(it)) } - override fun toString(): String { - val result = StringBuilder() - .append(getAlias()) - .append("|") - .append(getPublicKey().toString()) - return result.toString() - } - - override fun destroy() { - jniDestroy() - } + override fun toString(): String = StringBuilder() + .append(getAlias()) + .append("|") + .append(getPublicKey().toString()) + .toString() + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIContacts.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIContacts.kt index 118e4d407..64be4c381 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIContacts.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIContacts.kt @@ -38,40 +38,19 @@ package com.tari.android.wallet.ffi * @author The Tari Development Team */ -internal class FFIContacts() : FFIBase() { - - // region JNI +class FFIContacts() : FFIBase() { private external fun jniGetLength(libError: FFIError): Int - private external fun jniGetAt( - index: Int, - libError: FFIError - ): FFIContactPtr - + private external fun jniGetAt(index: Int, libError: FFIError): FFIContactPtr private external fun jniDestroy() - // endregion - - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getLength(): Int { - val error = FFIError() - val result = jniGetLength(error) - throwIf(error) - return result - } + fun getLength(): Int = runWithError { jniGetLength(it) } - fun getAt(index: Int): FFIContact { - val error = FFIError() - val result = FFIContact(jniGetAt(index, error)) - throwIf(error) - return result - } - - override fun destroy() { - jniDestroy() - } + fun getAt(index: Int): FFIContact = runWithError { FFIContact(jniGetAt(index, it)) } + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFICovenant.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFICovenant.kt index c548138b3..d44c8bc0c 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFICovenant.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFICovenant.kt @@ -38,13 +38,10 @@ import java.io.Serializable class FFICovenant(bytes: FFIByteVector) : FFIBase(), Serializable { private external fun jniCreateFromBytes(bytes: FFIByteVector, libError: FFIError) - private external fun jniDestroy() init { - val error = FFIError() - jniCreateFromBytes(bytes, error) - throwIf(error) + runWithError { jniCreateFromBytes(bytes, it) } } override fun destroy() = jniDestroy() diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIEmojiSet.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIEmojiSet.kt index 65a4ea404..dd02ea82c 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIEmojiSet.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIEmojiSet.kt @@ -37,37 +37,20 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFIEmojiSet : FFIBase() { - - // region JNI +class FFIEmojiSet : FFIBase() { private external fun jniDestroy() private external fun jniCreate() private external fun jniGetLength(libError: FFIError): Int private external fun jniGetAt(index: Int, libError: FFIError): FFIPointer - // endregion - init { jniCreate() } - fun getLength(): Int { - val error = FFIError() - val result = jniGetLength(error) - throwIf(error) - return result - } - - fun getAt(index: Int): FFIByteVector { - val error = FFIError() - val result = FFIByteVector(jniGetAt(index, error)) - throwIf(error) - return result - } + fun getLength(): Int = runWithError { jniGetLength(it) } - override fun destroy() { - jniDestroy() - } + fun getAt(index: Int): FFIByteVector = runWithError { FFIByteVector(jniGetAt(index, it)) } + override fun destroy() = jniDestroy() } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIError.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIError.kt index 16b3478c7..7b2bc1f34 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIError.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIError.kt @@ -32,15 +32,9 @@ */ package com.tari.android.wallet.ffi -/** - * @author The Tari Development Team - */ -internal class FFIError { +class FFIError { var code: Int = -1 - override fun toString(): String { - return code.toString() - } - + override fun toString(): String = code.toString() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIException.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIException.kt index 7e73ef2b8..ae2b307f8 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIException.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIException.kt @@ -37,19 +37,20 @@ import com.tari.android.wallet.model.WalletError /** * Throws FFIException if error code indicates a problem. */ -internal fun throwIf(error: FFIError) { +fun throwIf(error: FFIError) { if (error.code != WalletError.NoError.code) { throw FFIException(error) } } -/** - * @author The Tari Development Team - */ -internal class FFIException( - val error: FFIError? = null, - override val message: String? = "Error code: $error" -) : RuntimeException() { +fun runWithError(action: (error: FFIError) -> T): T { + val error = FFIError() + val result = action(error) + throwIf(error) + return result +} + +class FFIException(val error: FFIError? = null, override val message: String? = "Error code: $error") : RuntimeException() { override fun toString(): String = "FFIException(error=$error, message=$message)" } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStat.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStat.kt index 10cd41326..61a9866da 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStat.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStat.kt @@ -14,33 +14,13 @@ class FFIFeePerGramStat(pointer: FFIPointer) : FFIBase() { this.pointer = pointer } - fun getOrder(): BigInteger { - val error = FFIError() - val bytes = jniGetOrder(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getOrder(): BigInteger = runWithError { BigInteger(1, jniGetOrder(it)) } - fun getMin(): BigInteger { - val error = FFIError() - val bytes = jniGetMin(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getMin(): BigInteger = runWithError { BigInteger(1, jniGetMin(it)) } - fun getMax(): BigInteger { - val error = FFIError() - val bytes = jniGetMax(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getMax(): BigInteger = runWithError { BigInteger(1, jniGetMax(it)) } - fun getAverage(): BigInteger { - val error = FFIError() - val bytes = jniGetAverage(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getAverage(): BigInteger = runWithError { BigInteger(1, jniGetAverage(it)) } override fun destroy() = Unit } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStats.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStats.kt index 3a3007c67..c319c515c 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStats.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIFeePerGramStats.kt @@ -42,19 +42,9 @@ class FFIFeePerGramStats(pointer: FFIPointer) : FFIBase() { this.pointer = pointer } - fun getAt(position: Int): FFIFeePerGramStat { - val libError = FFIError() - val pointer = jniGetAt(position, libError) - throwIf(libError) - return FFIFeePerGramStat(pointer) - } + fun getAt(position: Int): FFIFeePerGramStat = runWithError { FFIFeePerGramStat(jniGetAt(position, it)) } - fun getLength(): Int { - val libError = FFIError() - val length = jniFeePerGramStatsGetLength(libError) - throwIf(libError) - return length - } + fun getLength(): Int = runWithError { jniFeePerGramStatsGetLength(it) } override fun destroy() = jniDestroy() } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIOutputFeatures.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIOutputFeatures.kt index 181eb7e27..bbc406e3d 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIOutputFeatures.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIOutputFeatures.kt @@ -37,33 +37,13 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFIOutputFeatures : FFIBase { - - private external fun jniCreate( - version: Char, - flags: Char, - maturity: Long, - recovery_byte: Char, - metadata: FFIByteVector, - unique_id: FFIByteVector, - parent_public_key: FFIByteVector, - libError: FFIError - ) +class FFIOutputFeatures() : FFIBase() { + private external fun jniCreate(version: Char, maturity: Long, metadata: FFIByteVector, libError: FFIError) private external fun jniDestroy() - constructor( - version: Char, - flags: Char, - maturity: Long, - recovery_byte: Char, - metadata: FFIByteVector, - unique_id: FFIByteVector, - parent_public_key: FFIByteVector, - ) : super() { - val error = FFIError() - jniCreate(version, flags, maturity, recovery_byte, metadata, unique_id, parent_public_key, error) - throwIf(error) + constructor(version: Char, maturity: Long, metadata: FFIByteVector) : this() { + runWithError { jniCreate(version, maturity, metadata, it) } } override fun destroy() = jniDestroy() diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTx.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTx.kt index 62ca17499..97ca7596c 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTx.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTx.kt @@ -40,9 +40,7 @@ import java.math.BigInteger * @author The Tari Development Team */ -internal class FFIPendingInboundTx() : FFITxBase() { - - // region JNI +class FFIPendingInboundTx() : FFITxBase() { private external fun jniGetId(libError: FFIError): ByteArray private external fun jniGetSourcePublicKey(libError: FFIError): FFIPointer @@ -52,56 +50,26 @@ internal class FFIPendingInboundTx() : FFITxBase() { private external fun jniGetStatus(libError: FFIError): Int private external fun jniDestroy() - // endregion - constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getId(): BigInteger { - val error = FFIError() - val bytes = jniGetId(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getId(): BigInteger = runWithError { BigInteger(1, jniGetId(it)) } - override fun getSourcePublicKey(): FFIPublicKey { - val error = FFIError() - val result = FFIPublicKey(jniGetSourcePublicKey(error)) - throwIf(error) - return result - } + override fun getSourcePublicKey(): FFIPublicKey = runWithError { FFIPublicKey(jniGetSourcePublicKey(it)) } override fun getDestinationPublicKey(): FFIPublicKey = TODO() override fun isOutbound(): Boolean = false - fun getAmount(): BigInteger { - val error = FFIError() - val bytes = jniGetAmount(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getAmount(): BigInteger = runWithError { BigInteger(1, jniGetAmount(it)) } - fun getTimestamp(): BigInteger { - val error = FFIError() - val bytes = jniGetTimestamp(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getTimestamp(): BigInteger = runWithError { BigInteger(1, jniGetTimestamp(it)) } - fun getMessage(): String { - val error = FFIError() - val result = jniGetMessage(error) - throwIf(error) - return result - } + fun getMessage(): String = runWithError { jniGetMessage(it) } fun getStatus(): FFITxStatus { - val error = FFIError() - val status = jniGetStatus(error) - throwIf(error) - return when (status) { + return when (runWithError { jniGetStatus(it) }) { -1 -> FFITxStatus.TX_NULL_ERROR 0 -> FFITxStatus.COMPLETED 1 -> FFITxStatus.BROADCAST @@ -111,12 +79,9 @@ internal class FFIPendingInboundTx() : FFITxBase() { 5 -> FFITxStatus.COINBASE 6 -> FFITxStatus.MINED_CONFIRMED 7 -> FFITxStatus.UNKNOWN - else -> throw FFIException(message = "Unexpected status: $status") + else -> throw FFIException(message = "Unexpected status: $this") } } - override fun destroy() { - jniDestroy() - } - + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTxs.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTxs.kt index 2e36d28d5..2cf9343fa 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTxs.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingInboundTxs.kt @@ -37,37 +37,19 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFIPendingInboundTxs() : FFIBase() { - - // region JNI +class FFIPendingInboundTxs() : FFIBase() { private external fun jniGetLength(libError: FFIError): Int private external fun jniGetAt(index: Int, libError: FFIError): FFIPointer - private external fun jniDestroy() - // endregion - - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getLength(): Int { - val error = FFIError() - val result = jniGetLength(error) - throwIf(error) - return result - } + fun getLength(): Int = runWithError { jniGetLength(it) } - fun getAt(index: Int): FFIPendingInboundTx { - val error = FFIError() - val result = FFIPendingInboundTx(jniGetAt(index, error)) - throwIf(error) - return result - } - - override fun destroy() { - jniDestroy() - } + fun getAt(index: Int): FFIPendingInboundTx = runWithError { FFIPendingInboundTx(jniGetAt(index, it)) } + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTx.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTx.kt index a52ff2350..95c3ec35a 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTx.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTx.kt @@ -39,9 +39,7 @@ import java.math.BigInteger * * @author The Tari Development Team */ -internal class FFIPendingOutboundTx() : FFITxBase() { - - // region JNI +class FFIPendingOutboundTx() : FFITxBase() { private external fun jniGetId(libError: FFIError): ByteArray private external fun jniGetDestinationPublicKey(libError: FFIError): FFIPointer @@ -52,67 +50,27 @@ internal class FFIPendingOutboundTx() : FFITxBase() { private external fun jniGetStatus(libError: FFIError): Int private external fun jniDestroy() - // endregion - constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getId(): BigInteger { - val error = FFIError() - val bytes = jniGetId(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getId(): BigInteger = runWithError { BigInteger(1, jniGetId(it)) } - override fun getDestinationPublicKey(): FFIPublicKey { - val error = FFIError() - val result = FFIPublicKey(jniGetDestinationPublicKey(error)) - throwIf(error) - return result - } + override fun getDestinationPublicKey(): FFIPublicKey = runWithError { FFIPublicKey(jniGetDestinationPublicKey(it)) } override fun getSourcePublicKey(): FFIPublicKey = TODO() override fun isOutbound(): Boolean = true - fun getAmount(): BigInteger { - val error = FFIError() - val bytes = jniGetAmount(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getAmount(): BigInteger = runWithError { BigInteger(1, jniGetAmount(it)) } - fun getFee(): BigInteger { - val error = FFIError() - val bytes = jniGetFee(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getFee(): BigInteger = runWithError { BigInteger(1, jniGetFee(it)) } - fun getTimestamp(): BigInteger { - val error = FFIError() - val bytes = jniGetTimestamp(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun getTimestamp(): BigInteger = runWithError { BigInteger(1, jniGetTimestamp(it)) } - fun getMessage(): String { - val error = FFIError() - val result = jniGetMessage(error) - throwIf(error) - return result - } + fun getMessage(): String = runWithError { jniGetMessage(it) } - fun getStatus(): FFITxStatus { - val error = FFIError() - val status = jniGetStatus(error) - throwIf(error) - return FFITxStatus.map(status) - } - - override fun destroy() { - jniDestroy() - } + fun getStatus(): FFITxStatus = runWithError { FFITxStatus.map(jniGetStatus(it)) } -} + override fun destroy() = jniDestroy() +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTxs.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTxs.kt index f438a3b89..3feae4729 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTxs.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIPendingOutboundTxs.kt @@ -37,37 +37,19 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFIPendingOutboundTxs() : FFIBase() { - - // region JNI +class FFIPendingOutboundTxs() : FFIBase() { private external fun jniGetLength(libError: FFIError): Int private external fun jniGetAt(index: Int, libError: FFIError): FFIPointer - private external fun jniDestroy() - // endregion - - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - fun getLength(): Int { - val error = FFIError() - val result = jniGetLength(error) - throwIf(error) - return result - } + fun getLength(): Int = runWithError { jniGetLength(it) } - fun getAt(index: Int): FFIPendingOutboundTx { - val error = FFIError() - val result = FFIPendingOutboundTx(jniGetAt(index, error)) - throwIf(error) - return result - } - - override fun destroy() { - jniDestroy() - } + fun getAt(index: Int): FFIPendingOutboundTx = runWithError { FFIPendingOutboundTx(jniGetAt(index, it)) } + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIPrivateKey.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIPrivateKey.kt index 8a338908c..7c2981d06 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIPrivateKey.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIPrivateKey.kt @@ -37,67 +37,33 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFIPrivateKey private constructor() : FFIBase() { - - // region JNI - - private external fun jniGetBytes( - libError: FFIError - ): FFIPointer +class FFIPrivateKey private constructor() : FFIBase() { + private external fun jniGetBytes(libError: FFIError): FFIPointer private external fun jniDestroy() - private external fun jniCreate( - byteVectorPtr: FFIByteVector, - libError: FFIError - ) - + private external fun jniCreate(byteVectorPtr: FFIByteVector, libError: FFIError) private external fun jniGenerate() private external fun jniFromHex(hexStr: String, libError: FFIError) - // endregion - - companion object { - - fun generate(): FFIPrivateKey { - return FFIPrivateKey().apply { - jniGenerate() - } - } - - } - constructor(byteVector: FFIByteVector) : this() { - val error = FFIError() - jniCreate(byteVector, error) - throwIf(error) + runWithError { jniCreate(byteVector, it) } } constructor(hexString: HexString) : this() { if (hexString.toString().length == 64) { - val error = FFIError() - jniFromHex(hexString.hex, error) - throwIf(error) + runWithError { jniFromHex(hexString.hex, it) } } else { throw FFIException(message = "HexString is not a valid PrivateKey") } } - fun getBytes(): FFIByteVector { - val error = FFIError() - val result = FFIByteVector(jniGetBytes(error)) - throwIf(error) - return result - } + fun getBytes(): FFIByteVector = runWithError { FFIByteVector(jniGetBytes(it)) } - override fun toString(): String { - val error = FFIError() - val result = FFIByteVector(jniGetBytes(error)).toString() - throwIf(error) - return result - } + override fun toString(): String = runWithError { FFIByteVector(jniGetBytes(it)).toString() } - override fun destroy() { - jniDestroy() - } + override fun destroy() = jniDestroy() + companion object { + fun generate(): FFIPrivateKey = FFIPrivateKey().apply { jniGenerate() } + } } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt index f5283995a..da03ee05e 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt @@ -37,90 +37,45 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFIPublicKey() : FFIBase() { - - // region JNI - - private external fun jniGetBytes( - libError: FFIError - ): FFIPointer +class FFIPublicKey() : FFIBase() { + private external fun jniGetBytes(libError: FFIError): FFIPointer private external fun jniDestroy() - private external fun jniCreate( - byteVectorPtr: FFIByteVector, - libError: FFIError - ) - + private external fun jniCreate(byteVectorPtr: FFIByteVector, libError: FFIError) private external fun jniFromHex(hexStr: String, libError: FFIError) - private external fun jniFromEmojiId(emoji: String, libError: FFIError) + private external fun jniFromPrivateKey(privateKeyPtr: FFIPrivateKey, libError: FFIError) + private external fun jniGetEmojiId(libError: FFIError): String - private external fun jniFromPrivateKey( - privateKeyPtr: FFIPrivateKey, - libError: FFIError - ) - - private external fun jniGetEmojiId( - libError: FFIError - ): String - - // endregion - - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } constructor(byteVector: FFIByteVector) : this() { - val error = FFIError() - jniCreate(byteVector, error) - throwIf(error) + runWithError { jniCreate(byteVector, it) } } constructor(hex: HexString) : this() { if (hex.toString().length == 64) { - val error = FFIError() - jniFromHex(hex.hex, error) - throwIf(error) + runWithError { jniFromHex(hex.hex, it) } } else { throw FFIException(message = "HexString is not a valid PublicKey") } } constructor(emojiId: String) : this() { - val error = FFIError() - jniFromEmojiId(emojiId, error) - throwIf(error) + runWithError { jniFromEmojiId(emojiId, it) } } constructor(privateKey: FFIPrivateKey) : this() { - val error = FFIError() - jniFromPrivateKey(privateKey, error) - throwIf(error) - } - - fun getBytes(): FFIByteVector { - val error = FFIError() - val result = FFIByteVector(jniGetBytes(error)) - throwIf(error) - return result + runWithError { jniFromPrivateKey(privateKey, it) } } - fun getEmojiId(): String { - val error = FFIError() - val result = jniGetEmojiId(error) - throwIf(error) - return result - } + fun getBytes(): FFIByteVector = runWithError { FFIByteVector(jniGetBytes(it)) } - override fun toString(): String { - val error = FFIError() - val result = FFIByteVector(jniGetBytes(error)).toString() - throwIf(error) - return result - } + fun getEmojiId(): String = runWithError { jniGetEmojiId(it) } - override fun destroy() { - jniDestroy() - } + override fun toString(): String = runWithError { FFIByteVector(jniGetBytes(it)).toString() } + override fun destroy() = jniDestroy() } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFISeedWords.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFISeedWords.kt index 62928119d..610a1bd47 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFISeedWords.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFISeedWords.kt @@ -39,9 +39,8 @@ import com.tari.android.wallet.model.seedPhrase.SeedWordsWordPushResult * * @author The Tari Development Team */ -internal class FFISeedWords() : FFIBase() { +class FFISeedWords() : FFIBase() { - // region JNI private external fun jniCreate() private external fun jniPushWord(word: String, libError: FFIError): Int private external fun jniGetLength(libError: FFIError): Int @@ -50,8 +49,6 @@ internal class FFISeedWords() : FFIBase() { external fun jniGetMnemonicWordListForLanguage(language: String) - // endregion - init { jniCreate() } @@ -60,33 +57,16 @@ internal class FFISeedWords() : FFIBase() { this.pointer = pointer } - fun getLength(): Int { - val error = FFIError() - val result = jniGetLength(error) - throwIf(error) - return result - } + fun getLength(): Int = runWithError { jniGetLength(it) } - fun getAt(index: Int): String { - val error = FFIError() - val result = jniGetAt(index, error) - throwIf(error) - return result - } + fun getAt(index: Int): String = runWithError { jniGetAt(index, it) } - fun pushWord(word: String) : SeedWordsWordPushResult { - val error = FFIError() - val result = jniPushWord(word, error) - throwIf(error) - return SeedWordsWordPushResult.fromInt(result) - } + fun pushWord(word: String): SeedWordsWordPushResult = runWithError { SeedWordsWordPushResult.fromInt(jniPushWord(word, it)) } - override fun destroy() { - jniDestroy() - } + override fun destroy() = jniDestroy() companion object { - fun getMnemomicWordList(language: Language) : FFISeedWords = FFISeedWords().apply { + fun getMnemomicWordList(language: Language): FFISeedWords = FFISeedWords().apply { jniGetMnemonicWordListForLanguage(language.name) } } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFITariCommitmentSignature.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFITariCommitmentSignature.kt index c218a93fb..3e5a47167 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFITariCommitmentSignature.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFITariCommitmentSignature.kt @@ -37,9 +37,7 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFITariCommitmentSignature() : FFIBase() { - - // region JNI +class FFITariCommitmentSignature() : FFIBase() { private external fun jniCommitmentSignatureCreateFromBytes( public_nonce_bytes: FFIByteVector, @@ -50,28 +48,13 @@ internal class FFITariCommitmentSignature() : FFIBase() { private external fun jniDestroy() - // endregion - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - constructor( - public_nonce_bytes: FFIByteVector, - u_bytes: FFIByteVector, - v_bytes: FFIByteVector, - ) : this() { - val error = FFIError() - jniCommitmentSignatureCreateFromBytes( - public_nonce_bytes, - u_bytes, - v_bytes, - error - ) - throwIf(error) + constructor(public_nonce_bytes: FFIByteVector, u_bytes: FFIByteVector, v_bytes: FFIByteVector) : this() { + runWithError { jniCommitmentSignatureCreateFromBytes(public_nonce_bytes, u_bytes, v_bytes, it) } } - - override fun destroy() { - jniDestroy() - } + override fun destroy() = jniDestroy() } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFITariTransportConfig.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFITariTransportConfig.kt index fc0fb191f..18029bef4 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFITariTransportConfig.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFITariTransportConfig.kt @@ -38,19 +38,11 @@ package com.tari.android.wallet.ffi * * @author The Tari Development Team */ -internal class FFITariTransportConfig() : FFIBase() { +class FFITariTransportConfig() : FFIBase() { - // region JNI private external fun jniMemoryTransport() - - private external fun jniGetMemoryAddress( - libError: FFIError - ): String - - private external fun jniTCPTransport( - listenerAddress: String, libError: FFIError - ) - + private external fun jniGetMemoryAddress(libError: FFIError): String + private external fun jniTCPTransport(listenerAddress: String, libError: FFIError) private external fun jniTorTransport( control_server_address: String, torCookie: FFIByteVector, @@ -59,9 +51,7 @@ internal class FFITariTransportConfig() : FFIBase() { socksPassword: String, libError: FFIError ) - private external fun jniDestroy() - // endregion /** * Default constructor creates memory transport. @@ -74,42 +64,18 @@ internal class FFITariTransportConfig() : FFIBase() { * TCP transport. */ constructor(listenerAddress: NetAddressString) : this() { - val error = FFIError() - jniTCPTransport(listenerAddress.toString(), error) - throwIf(error) + runWithError { jniTCPTransport(listenerAddress.toString(), it) } } /** * Tor transport. */ - constructor( - controlAddress: NetAddressString, - torCookie: FFIByteVector, - torPort: Int, - socksUsername: String, - socksPassword: String - ) : this() { - val error = FFIError() - jniTorTransport( - controlAddress.toString(), - torCookie, - torPort, - socksUsername, - socksPassword, - error - ) - throwIf(error) + constructor(controlAddress: NetAddressString, torCookie: FFIByteVector, torPort: Int, socksUsername: String, socksPassword: String) : this() { + runWithError { jniTorTransport(controlAddress.toString(), torCookie, torPort, socksUsername, socksPassword, it) } } - fun getAddress(): String { - val error = FFIError() - val result = jniGetMemoryAddress(error) - throwIf(error) - return result - } + fun getAddress(): String = runWithError { jniGetMemoryAddress(it) } - override fun destroy() { - jniDestroy() - } + override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFITariVector.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFITariVector.kt index 20b543483..7a61f4d87 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFITariVector.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFITariVector.kt @@ -9,7 +9,6 @@ class FFITariVector(pointer: FFIPointer) : FFIBase() { var longs = mutableListOf() private external fun jniLoadData() - private external fun jniGetItemAt(index: Int): FFIPointer init { diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFITransactionSendStatus.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFITransactionSendStatus.kt index 11c268664..c962161ef 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFITransactionSendStatus.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFITransactionSendStatus.kt @@ -39,19 +39,13 @@ import java.io.Serializable class FFITransactionSendStatus(pointer: FFIPointer) : FFIBase(), Serializable { private external fun jniTransactionSendStatusDecode(libError: FFIError): Int - private external fun jniDestroy() init { this.pointer = pointer } - fun getStatus(): TransactionSendStatus { - val error = FFIError() - val status = jniTransactionSendStatusDecode(error) - throwIf(error) - return TransactionSendStatus(status) - } + fun getStatus(): TransactionSendStatus = runWithError { TransactionSendStatus(jniTransactionSendStatusDecode(it)) } override fun destroy() = jniDestroy() } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFITxBase.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFITxBase.kt index ddc8b9a10..53dc41d67 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFITxBase.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFITxBase.kt @@ -4,33 +4,32 @@ import com.tari.android.wallet.model.PublicKey import com.tari.android.wallet.model.Tx import com.tari.android.wallet.model.User -internal abstract class FFITxBase() : FFIBase() { +abstract class FFITxBase() : FFIBase() { - constructor(pointer: FFIPointer): this() { + constructor(pointer: FFIPointer) : this() { this.pointer = pointer } - abstract fun getSourcePublicKey() : FFIPublicKey - abstract fun getDestinationPublicKey() : FFIPublicKey - abstract fun isOutbound() : Boolean + abstract fun getSourcePublicKey(): FFIPublicKey + abstract fun getDestinationPublicKey(): FFIPublicKey + abstract fun isOutbound(): Boolean fun getUser(): User { - val publicKey: PublicKey - if (isOutbound()) { - val destination = getDestinationPublicKey() - val destinationHex = destination.toString() - val destinationEmoji = destination.getEmojiId() - publicKey = PublicKey(destinationHex, destinationEmoji) - destination.destroy() + val publicKey = if (isOutbound()) { + getDestinationPublicKey().runWithDestroy { + val destinationHex = it.toString() + val destinationEmoji = it.getEmojiId() + PublicKey(destinationHex, destinationEmoji) + } } else { - val source = getSourcePublicKey() - val sourceHex = source.toString() - val sourceEmoji = source.getEmojiId() - publicKey = PublicKey(sourceHex, sourceEmoji) - source.destroy() + getSourcePublicKey().runWithDestroy { + val sourceHex = it.toString() + val sourceEmoji = it.getEmojiId() + PublicKey(sourceHex, sourceEmoji) + } } return User(publicKey) } - fun getDirection() : Tx.Direction = if (isOutbound()) Tx.Direction.OUTBOUND else Tx.Direction.INBOUND + fun getDirection(): Tx.Direction = if (isOutbound()) Tx.Direction.OUTBOUND else Tx.Direction.INBOUND } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIUtils.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIUtils.kt new file mode 100644 index 000000000..e83760ec9 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIUtils.kt @@ -0,0 +1,7 @@ +package com.tari.android.wallet.ffi + +fun T.runWithDestroy(action: (T) -> R): R { + val item = action(this) + destroy() + return item +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt index 7a1cc1a44..ed5b63a5b 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt @@ -32,15 +32,14 @@ */ package com.tari.android.wallet.ffi -import com.orhanobut.logger.Logger import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository import com.tari.android.wallet.model.* import com.tari.android.wallet.model.recovery.WalletRestorationResult import com.tari.android.wallet.service.seedPhrase.SeedPhraseRepository import com.tari.android.wallet.util.Constants -import io.sentry.Sentry -import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job import kotlinx.coroutines.launch import java.math.BigInteger import java.util.concurrent.atomic.AtomicReference @@ -51,15 +50,16 @@ import java.util.concurrent.atomic.AtomicReference * @author The Tari Development Team */ -internal class FFIWallet( +class FFIWallet( val sharedPrefsRepository: SharedPrefsRepository, val seedPhraseRepository: SeedPhraseRepository, val networkRepository: NetworkRepository, - commsConfig: FFICommsConfig, - logPath: String + val commsConfig: FFICommsConfig, + val logPath: String ) : FFIBase() { - private var balance: BalanceInfo = BalanceInfo() + private val coroutineContext = Job() + private var localScope = CoroutineScope(coroutineContext) companion object { private var atomicInstance = AtomicReference() @@ -68,8 +68,6 @@ internal class FFIWallet( set(value) = atomicInstance.set(value) } - // region JNI - private external fun jniCreate( commsConfig: FFICommsConfig, logPath: String, @@ -158,9 +156,7 @@ internal class FFIWallet( amount: String, spendingKey: FFIPrivateKey, sourcePublicKey: FFIPublicKey, - outputFeatures: FFIOutputFeatures, tariCommitmentSignature: FFITariCommitmentSignature, - covenant: FFICovenant, sourceSenderPublicKey: FFIPublicKey, scriptPrivateKey: FFIPrivateKey, message: String, @@ -221,7 +217,6 @@ internal class FFIWallet( private external fun jniDestroy() - // endregion var listener: FFIWalletListener? = null @@ -229,192 +224,108 @@ internal class FFIWallet( // singletons init { if (pointer == nullptr) { // so it can only be assigned once for the singleton - val error = FFIError() - Logger.i("Pre jniCreate.") - try { - jniCreate( - commsConfig, - logPath, - Constants.Wallet.maxNumberOfRollingLogFiles, - Constants.Wallet.rollingLogFileMaxSizeBytes, - sharedPrefsRepository.databasePassphrase, - networkRepository.currentNetwork?.network?.uriComponent, - seedPhraseRepository.getPhrase()?.ffiSeedWords, - this::onTxReceived.name, "(J)V", - this::onTxReplyReceived.name, "(J)V", - this::onTxFinalized.name, "(J)V", - this::onTxBroadcast.name, "(J)V", - this::onTxMined.name, "(J)V", - this::onTxMinedUnconfirmed.name, "(J[B)V", - this::onTxFauxConfirmed.name, "(J)V", - this::onTxFauxUnconfirmed.name, "(J[B)V", - this::onDirectSendResult.name, "([BJ)V", - this::onTxCancelled.name, "(J[B)V", - this::onTXOValidationComplete.name, "([BZ)V", - this::onContactLivenessDataUpdated.name, "(J)V", - this::onBalanceUpdated.name, "(J)V", - this::onTxValidationComplete.name, "([BZ)V", - this::onConnectivityStatus.name, "([B)V", - error - ) - } catch (e: Throwable) { - Sentry.captureException(e) - Logger.i("Post jniCreate with exception: %d.", e) - throw e - } - - Logger.i("Post jniCreate with code: %d.", error.code) - throwIf(error) + init() + } + } - enableEncryption() + private fun init() { + val error = FFIError() + logger.i("Pre jniCreate") + try { + jniCreate( + commsConfig, + logPath, + Constants.Wallet.maxNumberOfRollingLogFiles, + Constants.Wallet.rollingLogFileMaxSizeBytes, + sharedPrefsRepository.databasePassphrase, + networkRepository.currentNetwork?.network?.uriComponent, + seedPhraseRepository.getPhrase()?.ffiSeedWords, + this::onTxReceived.name, "(J)V", + this::onTxReplyReceived.name, "(J)V", + this::onTxFinalized.name, "(J)V", + this::onTxBroadcast.name, "(J)V", + this::onTxMined.name, "(J)V", + this::onTxMinedUnconfirmed.name, "(J[B)V", + this::onTxFauxConfirmed.name, "(J)V", + this::onTxFauxUnconfirmed.name, "(J[B)V", + this::onDirectSendResult.name, "([BJ)V", + this::onTxCancelled.name, "(J[B)V", + this::onTXOValidationComplete.name, "([B[B)V", + this::onContactLivenessDataUpdated.name, "(J)V", + this::onBalanceUpdated.name, "(J)V", + this::onTxValidationComplete.name, "([BZ)V", + this::onConnectivityStatus.name, "([B)V", + error + ) + } catch (e: Throwable) { + logger.e(e, "jniCreate was failed") + throw e } + + logger.i("Post jniCreate with code: %d.", error.code) + throwIf(error) + + enableEncryption() } + @Synchronized fun enableEncryption() { - val passphrase = sharedPrefsRepository.databasePassphrase - if (passphrase == null) { - Logger.i("Database encryption enable") - sharedPrefsRepository.generateDatabasePassphrase() + if (sharedPrefsRepository.databasePassphrase == null) { try { - setEncryption(sharedPrefsRepository.databasePassphrase.orEmpty()) + val databasePassphrase = sharedPrefsRepository.generateDatabasePassphrase() + setEncryption(databasePassphrase) + sharedPrefsRepository.databasePassphrase = databasePassphrase + logger.i("Database encryption enabled") } catch (e: Throwable) { - //Sentry.captureException(e) sharedPrefsRepository.databasePassphrase = null + logger.e(e, "Database encryption failed") } } } - fun getBalance(): BalanceInfo { - val error = FFIError() - val result = jniGetBalance(error) - throwIf(error) - val b = FFIBalance(result) - val bal = BalanceInfo(b.getAvailable(), b.getIncoming(), b.getOutgoing(), b.getTimeLocked()) - b.destroy() - if (balance != bal) { - balance = bal - } - return balance + fun getBalance(): BalanceInfo = FFIBalance(runWithError { jniGetBalance(it) }).runWithDestroy { + BalanceInfo(it.getAvailable(), it.getIncoming(), it.getOutgoing(), it.getTimeLocked()) } - fun getUtxos(page: Int, pageSize: Int, sorting: Int): TariVector { - val error = FFIError() - val result = jniGetUtxos(page, pageSize, sorting, 0, error) - val outputs = TariVector(FFITariVector(result)) - throwIf(error) - return outputs - } + fun getUtxos(page: Int, pageSize: Int, sorting: Int): TariVector = + TariVector(FFITariVector(runWithError { jniGetUtxos(page, pageSize, sorting, 0, it) })) - fun getAllUtxos(): TariVector { - val error = FFIError() - val result = jniGetAllUtxos(error) - val outputs = TariVector(FFITariVector(result)) - throwIf(error) - return outputs - } + fun getAllUtxos(): TariVector = TariVector(FFITariVector(runWithError { jniGetAllUtxos(it) })) - fun getPublicKey(): FFIPublicKey { - val error = FFIError() - val result = FFIPublicKey(jniGetPublicKey(error)) - throwIf(error) - return result - } + fun getPublicKey(): FFIPublicKey = runWithError { FFIPublicKey(jniGetPublicKey(it)) } - fun getContacts(): FFIContacts { - val error = FFIError() - val result = FFIContacts(jniGetContacts(error)) - throwIf(error) - return result - } + fun getContacts(): FFIContacts = runWithError { FFIContacts(jniGetContacts(it)) } - fun addUpdateContact(contact: FFIContact): Boolean { - val error = FFIError() - val result = jniAddUpdateContact(contact, error) - throwIf(error) - return result - } + fun addUpdateContact(contact: FFIContact): Boolean = runWithError { jniAddUpdateContact(contact, it) } - fun removeContact(contact: FFIContact): Boolean { - val error = FFIError() - val result = jniRemoveContact(contact, error) - throwIf(error) - return result - } + fun removeContact(contact: FFIContact): Boolean = runWithError { jniRemoveContact(contact, it) } - fun getCompletedTxs(): FFICompletedTxs { - val error = FFIError() - val result = FFICompletedTxs(jniGetCompletedTxs(error)) - throwIf(error) - return result - } + fun getCompletedTxs(): FFICompletedTxs = runWithError { FFICompletedTxs(jniGetCompletedTxs(it)) } - fun getCancelledTxs(): FFICompletedTxs { - val error = FFIError() - val result = FFICompletedTxs(jniGetCancelledTxs(error)) - throwIf(error) - return result - } + fun getCancelledTxs(): FFICompletedTxs = runWithError { FFICompletedTxs(jniGetCancelledTxs(it)) } - fun getCompletedTxById(id: BigInteger): FFICompletedTx { - val error = FFIError() - val result = FFICompletedTx(jniGetCompletedTxById(id.toString(), error)) - throwIf(error) - return result - } + fun getCompletedTxById(id: BigInteger): FFICompletedTx = runWithError { FFICompletedTx(jniGetCompletedTxById(id.toString(), it)) } - fun getCancelledTxById(id: BigInteger): FFICompletedTx { - val error = FFIError() - val result = FFICompletedTx(jniGetCancelledTxById(id.toString(), error)) - throwIf(error) - return result - } + fun getCancelledTxById(id: BigInteger): FFICompletedTx = runWithError { FFICompletedTx(jniGetCancelledTxById(id.toString(), it)) } - fun getPendingOutboundTxs(): FFIPendingOutboundTxs { - val error = FFIError() - val result = FFIPendingOutboundTxs(jniGetPendingOutboundTxs(error)) - throwIf(error) - return result - } + fun getPendingOutboundTxs(): FFIPendingOutboundTxs = runWithError { FFIPendingOutboundTxs(jniGetPendingOutboundTxs(it)) } - fun getPendingOutboundTxById(id: BigInteger): FFIPendingOutboundTx { - val error = FFIError() - val result = - FFIPendingOutboundTx(jniGetPendingOutboundTxById(id.toString(), error)) - throwIf(error) - return result - } + fun getPendingOutboundTxById(id: BigInteger): FFIPendingOutboundTx = + runWithError { FFIPendingOutboundTx(jniGetPendingOutboundTxById(id.toString(), it)) } - fun getPendingInboundTxs(): FFIPendingInboundTxs { - val error = FFIError() - val result = FFIPendingInboundTxs(jniGetPendingInboundTxs(error)) - throwIf(error) - return result - } + fun getPendingInboundTxs(): FFIPendingInboundTxs = runWithError { FFIPendingInboundTxs(jniGetPendingInboundTxs(it)) } - fun getPendingInboundTxById(id: BigInteger): FFIPendingInboundTx { - val error = FFIError() - val result = - FFIPendingInboundTx(jniGetPendingInboundTxById(id.toString(), error)) - throwIf(error) - return result - } + fun getPendingInboundTxById(id: BigInteger): FFIPendingInboundTx = + runWithError { FFIPendingInboundTx(jniGetPendingInboundTxById(id.toString(), it)) } - fun cancelPendingTx(id: BigInteger): Boolean { - val error = FFIError() - val result = jniCancelPendingTx(id.toString(), error) - throwIf(error) - return result - } + fun cancelPendingTx(id: BigInteger): Boolean = runWithError { jniCancelPendingTx(id.toString(), it) } - /** - * This callback function cannot be private due to JNI behaviour. - */ @Suppress("MemberVisibilityCanBePrivate") fun onTxReceived(pendingInboundTxPtr: FFIPointer) { - Logger.i("Tx received. Pointer: %s", pendingInboundTxPtr.toString()) val tx = FFIPendingInboundTx(pendingInboundTxPtr) + logger.i("Tx received ${tx.getId()}") val pendingTx = PendingInboundTx(tx) - GlobalScope.launch { listener?.onTxReceived(pendingTx) } + localScope.launch { listener?.onTxReceived(pendingTx) } } /** @@ -422,10 +333,10 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onTxReplyReceived(txPointer: FFIPointer) { - Logger.i("Tx reply received. Pointer: %s", txPointer.toString()) val tx = FFICompletedTx(txPointer) + logger.i("Tx reply received ${tx.getId()}") val pendingOutboundTx = PendingOutboundTx(tx) - GlobalScope.launch { listener?.onTxReplyReceived(pendingOutboundTx) } + localScope.launch { listener?.onTxReplyReceived(pendingOutboundTx) } } /** @@ -433,10 +344,10 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onTxFinalized(completedTx: FFIPointer) { - Logger.i("Tx finalized. Pointer: %s", completedTx.toString()) val tx = FFICompletedTx(completedTx) + logger.i("Tx finalized ${tx.getId()}") val pendingInboundTx = PendingInboundTx(tx) - GlobalScope.launch { listener?.onTxFinalized(pendingInboundTx) } + localScope.launch { listener?.onTxFinalized(pendingInboundTx) } } /** @@ -444,16 +355,16 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onTxBroadcast(completedTxPtr: FFIPointer) { - Logger.i("Tx completed. Pointer: %s", completedTxPtr.toString()) val tx = FFICompletedTx(completedTxPtr) + logger.i("Tx broadcast ${tx.getId()}") when (tx.getDirection()) { Tx.Direction.INBOUND -> { val pendingInboundTx = PendingInboundTx(tx) - GlobalScope.launch { listener?.onInboundTxBroadcast(pendingInboundTx) } + localScope.launch { listener?.onInboundTxBroadcast(pendingInboundTx) } } Tx.Direction.OUTBOUND -> { val pendingOutboundTx = PendingOutboundTx(tx) - GlobalScope.launch { listener?.onOutboundTxBroadcast(pendingOutboundTx) } + localScope.launch { listener?.onOutboundTxBroadcast(pendingOutboundTx) } } } } @@ -463,9 +374,9 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onTxMined(completedTxPtr: FFIPointer) { - Logger.i("Tx mined & confirmed. Pointer: %s", completedTxPtr.toString()) val completed = CompletedTx(completedTxPtr) - GlobalScope.launch { listener?.onTxMined(completed) } + logger.i("Tx mined & confirmed ${completed.id}") + localScope.launch { listener?.onTxMined(completed) } } /** @@ -473,10 +384,10 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onTxMinedUnconfirmed(completedTxPtr: FFIPointer, confirmationCountBytes: ByteArray) { - Logger.i("Tx mined & unconfirmed. Pointer: %s", completedTxPtr.toString()) val confirmationCount = BigInteger(1, confirmationCountBytes).toInt() val completed = CompletedTx(completedTxPtr) - GlobalScope.launch { listener?.onTxMinedUnconfirmed(completed, confirmationCount) } + logger.i("Tx mined & unconfirmed ${completed.id} $confirmationCount") + localScope.launch { listener?.onTxMinedUnconfirmed(completed, confirmationCount) } } /** @@ -484,16 +395,20 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onTxFauxConfirmed(completedTxPtr: FFIPointer) { - Logger.i("Tx faux confirmed. Pointer: %s", completedTxPtr.toString()) val completed = CompletedTx(completedTxPtr) - GlobalScope.launch { listener?.onTxMined(completed) } + logger.i("Tx faux confirmed ${completed.id}") + localScope.launch { listener?.onTxMined(completed) } } + /** + * This callback function cannot be private due to JNI behaviour. + */ + @Suppress("MemberVisibilityCanBePrivate") fun onTxFauxUnconfirmed(completedTxPtr: FFIPointer, confirmationCountBytes: ByteArray) { - Logger.i("Tx faux unconfirmed. Pointer: %s", completedTxPtr.toString()) val confirmationCount = BigInteger(1, confirmationCountBytes).toInt() val completed = CompletedTx(completedTxPtr) - GlobalScope.launch { listener?.onTxMinedUnconfirmed(completed, confirmationCount) } + logger.i("Tx faux unconfirmed ${completed.id}") + localScope.launch { listener?.onTxMinedUnconfirmed(completed, confirmationCount) } } /** @@ -502,7 +417,8 @@ internal class FFIWallet( @Suppress("MemberVisibilityCanBePrivate") fun onDirectSendResult(bytes: ByteArray, pointer: FFIPointer) { val txId = BigInteger(1, bytes) - GlobalScope.launch { listener?.onDirectSendResult(txId, FFITransactionSendStatus(pointer).getStatus()) } + logger.i("Tx direct send result $txId") + localScope.launch { listener?.onDirectSendResult(txId, FFITransactionSendStatus(pointer).getStatus()) } } /** @@ -510,15 +426,12 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onTxCancelled(completedTx: FFIPointer, rejectionReason: ByteArray) { - Logger.i("Tx cancelled. Pointer: %s", completedTx.toString()) val rejectionReasonInt = BigInteger(1, rejectionReason).toInt() - val tx = FFICompletedTx(completedTx) - when (tx.getDirection()) { - Tx.Direction.OUTBOUND -> { - val cancelledTx = CancelledTx(tx) - GlobalScope.launch { listener?.onTxCancelled(cancelledTx, rejectionReasonInt) } - } + logger.i("Tx cancelled ${tx.getId()}") + + if (tx.getDirection() == Tx.Direction.OUTBOUND) { + localScope.launch { listener?.onTxCancelled(CancelledTx(tx), rejectionReasonInt) } } } @@ -528,8 +441,8 @@ internal class FFIWallet( @Suppress("MemberVisibilityCanBePrivate") fun onConnectivityStatus(bytes: ByteArray) { val connectivityStatus = BigInteger(1, bytes) - GlobalScope.launch { listener?.onConnectivityStatus(connectivityStatus.toInt()) } - Logger.i("ConnectivityStatus is [$connectivityStatus]") + localScope.launch { listener?.onConnectivityStatus(connectivityStatus.toInt()) } + logger.i("ConnectivityStatus is [$connectivityStatus]") } /** @@ -537,21 +450,20 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onBalanceUpdated(ptr: FFIPointer) { - Logger.i("Balance Updated. Pointer: %s", ptr.toString()) - val b = FFIBalance(ptr) - val balance = BalanceInfo(b.getAvailable(), b.getIncoming(), b.getOutgoing(), b.getTimeLocked()) - b.destroy() - this.balance = balance + logger.i("Balance Updated") + val balance = FFIBalance(ptr).runWithDestroy { BalanceInfo(it.getAvailable(), it.getIncoming(), it.getOutgoing(), it.getTimeLocked()) } + localScope.launch { listener?.onBalanceUpdated(balance) } } /** * This callback function cannot be private due to JNI behaviour. */ @Suppress("MemberVisibilityCanBePrivate") - fun onTXOValidationComplete(bytes: ByteArray, isSuccess: Boolean) { + fun onTXOValidationComplete(bytes: ByteArray, bytesStatus: ByteArray) { val requestId = BigInteger(1, bytes) - Logger.i("Invalid TXO validation [$requestId] complete. Result: $isSuccess") - GlobalScope.launch { listener?.onTXOValidationComplete(requestId, isSuccess) } + val status = TXOValidationStatus.values().first { it.value == BigInteger(1, bytesStatus).toInt() } + logger.i("TXO validation [$requestId] complete. Result: $status") + localScope.launch { listener?.onTXOValidationComplete(requestId, status) } } /** @@ -560,8 +472,8 @@ internal class FFIWallet( @Suppress("MemberVisibilityCanBePrivate") fun onTxValidationComplete(bytes: ByteArray, isSuccess: Boolean) { val requestId = BigInteger(1, bytes) - Logger.i("Transaction validation [$requestId] complete. Result: $isSuccess") - GlobalScope.launch { listener?.onTxValidationComplete(requestId, isSuccess) } + logger.i("Tx validation [$requestId] complete. Result: $isSuccess") + localScope.launch { listener?.onTxValidationComplete(requestId, isSuccess) } } /** @@ -569,15 +481,11 @@ internal class FFIWallet( */ @Suppress("MemberVisibilityCanBePrivate") fun onContactLivenessDataUpdated(livenessUpdate: FFIPointer) { - Logger.i("OnContactLivenessDataUpdated. Pointer: %s", livenessUpdate.toString()) + logger.i("OnContactLivenessDataUpdated") } - fun estimateTxFee(amount: BigInteger, gramFee: BigInteger, kernelCount: BigInteger, outputCount: BigInteger): BigInteger { - val error = FFIError() - val bytes = jniEstimateTxFee(amount.toString(), gramFee.toString(), kernelCount.toString(), outputCount.toString(), error) - Logger.d("Tx fee estimate status code (0 means ok): %d", error.code) - throwIf(error) - return BigInteger(1, bytes) + fun estimateTxFee(amount: BigInteger, gramFee: BigInteger, kernelCount: BigInteger, outputCount: BigInteger): BigInteger = runWithError { + BigInteger(1, jniEstimateTxFee(amount.toString(), gramFee.toString(), kernelCount.toString(), outputCount.toString(), it)) } fun sendTx(destination: FFIPublicKey, amount: BigInteger, feePerGram: BigInteger, message: String, isOneSided: Boolean): BigInteger { @@ -587,9 +495,7 @@ internal class FFIWallet( if (destination == getPublicKey()) { throw FFIException(message = "Tx source and destination are the same.") } - val error = FFIError() - val bytes = jniSendTx(destination, amount.toString(), feePerGram.toString(), message, isOneSided, error) - throwIf(error) + val bytes = runWithError { jniSendTx(destination, amount.toString(), feePerGram.toString(), message, isOneSided, it) } return BigInteger(1, bytes) } @@ -601,180 +507,75 @@ internal class FFIWallet( jniSplitUtxos(commitments, count.toString(), feePerGram.toString(), error) } - fun joinPreviewUtxos(commitments: Array, feePerGram: BigInteger, error: FFIError): TariCoinPreview { - val result = jniPreviewJoinUtxos(commitments, feePerGram.toString(), error) - return TariCoinPreview(FFITariCoinPreview(result)) - } + fun joinPreviewUtxos(commitments: Array, feePerGram: BigInteger, error: FFIError): TariCoinPreview = + TariCoinPreview(FFITariCoinPreview(jniPreviewJoinUtxos(commitments, feePerGram.toString(), error))) - fun splitPreviewUtxos(commitments: Array, count: Int, feePerGram: BigInteger, error: FFIError) : TariCoinPreview { - val result = jniPreviewSplitUtxos(commitments, count.toString(), feePerGram.toString(), error) - return TariCoinPreview(FFITariCoinPreview(result)) - } + fun splitPreviewUtxos(commitments: Array, count: Int, feePerGram: BigInteger, error: FFIError): TariCoinPreview = + TariCoinPreview(FFITariCoinPreview(jniPreviewSplitUtxos(commitments, count.toString(), feePerGram.toString(), error))) - fun signMessage(message: String): String { - val error = FFIError() - val result = jniSignMessage(message, error) - throwIf(error) - return result - } + fun signMessage(message: String): String = runWithError { jniSignMessage(message, it) } - fun verifyMessageSignature(contactPublicKey: FFIPublicKey, message: String, signature: String): Boolean { - val error = FFIError() - val result = jniVerifyMessageSignature(contactPublicKey, message, signature, error) - throwIf(error) - return result - } + fun verifyMessageSignature(contactPublicKey: FFIPublicKey, message: String, signature: String): Boolean = + runWithError { jniVerifyMessageSignature(contactPublicKey, message, signature, it) } fun importUTXO( amount: BigInteger, message: String, spendingKey: FFIPrivateKey, sourcePublicKey: FFIPublicKey, - outputFeatures: FFIOutputFeatures, tariCommitmentSignature: FFITariCommitmentSignature, - covenant: FFICovenant, senderPublicKey: FFIPublicKey, scriptPrivateKey: FFIPrivateKey, - ): BigInteger { - val error = FFIError() - val bytes = jniImportUTXO( - amount.toString(), - spendingKey, - sourcePublicKey, - outputFeatures, - tariCommitmentSignature, - covenant, - senderPublicKey, - scriptPrivateKey, - message, - error + ): BigInteger = runWithError { + BigInteger( + jniImportUTXO( + amount.toString(), + spendingKey, + sourcePublicKey, + tariCommitmentSignature, + senderPublicKey, + scriptPrivateKey, + message, + it + ) ) - throwIf(error) - return BigInteger(1, bytes) } - fun startTXOValidation(): BigInteger { - val error = FFIError() - val bytes = jniStartTXOValidation(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun startTXOValidation(): BigInteger = runWithError { BigInteger(1, jniStartTXOValidation(it)) } - fun startTxValidation(): BigInteger { - val error = FFIError() - val bytes = jniStartTxValidation(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun startTxValidation(): BigInteger = runWithError { BigInteger(1, jniStartTxValidation(it)) } - fun restartTxBroadcast(): BigInteger { - val error = FFIError() - val bytes = jniRestartTxBroadcast(error) - throwIf(error) - return BigInteger(1, bytes) - } + fun restartTxBroadcast(): BigInteger = runWithError { BigInteger(1, jniRestartTxBroadcast(it)) } - fun setPowerModeNormal() { - val error = FFIError() - jniPowerModeNormal(error) - throwIf(error) - } + fun setPowerModeNormal() = runWithError { jniPowerModeNormal(it) } - fun setPowerModeLow() { - val error = FFIError() - jniPowerModeLow(error) - throwIf(error) - } + fun setPowerModeLow() = runWithError { jniPowerModeLow(it) } - fun getSeedWords(): FFISeedWords { - val error = FFIError() - val result = FFISeedWords(jniGetSeedWords(error)) - throwIf(error) - return result - } + fun getSeedWords(): FFISeedWords = runWithError { FFISeedWords(jniGetSeedWords(it)) } - fun addBaseNodePeer( - baseNodePublicKey: FFIPublicKey, - baseNodeAddress: String - ): Boolean { - val error = FFIError() - val result = jniAddBaseNodePeer(baseNodePublicKey, baseNodeAddress, error) - throwIf(error) - return result - } + fun addBaseNodePeer(baseNodePublicKey: FFIPublicKey, baseNodeAddress: String): Boolean = + runWithError { jniAddBaseNodePeer(baseNodePublicKey, baseNodeAddress, it) } - fun setKeyValue(key: String, value: String): Boolean { - val error = FFIError() - val result = jniSetKeyValue(key, value, error) - throwIf(error) - return result - } + fun setKeyValue(key: String, value: String): Boolean = runWithError { jniSetKeyValue(key, value, it) } - fun getKeyValue(key: String): String { - val error = FFIError() - val result = jniGetKeyValue(key, error) - throwIf(error) - return result - } + fun getKeyValue(key: String): String = runWithError { jniGetKeyValue(key, it) } - fun removeKeyValue(key: String): Boolean { - val error = FFIError() - val result = jniRemoveKeyValue(key, error) - throwIf(error) - return result - } + fun removeKeyValue(key: String): Boolean = runWithError { jniRemoveKeyValue(key, it) } - fun logMessage(message: String) { - val error = FFIError() - jniLogMessage(message, error) - throwIf(error) - } + fun logMessage(message: String) = runWithError { jniLogMessage(message, it) } - fun getRequiredConfirmationCount(): BigInteger { - val error = FFIError() - val bytes = jniGetConfirmations( - error - ) - throwIf(error) - return BigInteger(1, bytes) - } + fun getRequiredConfirmationCount(): BigInteger = runWithError { BigInteger(1, jniGetConfirmations(it)) } - fun setRequiredConfirmationCount(number: BigInteger) { - val error = FFIError() - jniSetConfirmations( - number.toString(), - error - ) - throwIf(error) - } + fun setRequiredConfirmationCount(number: BigInteger) = runWithError { jniSetConfirmations(number.toString(), it) } - fun setEncryption(passphrase: String) { - val error = FFIError() - val result = jniApplyEncryption(passphrase, error) - throwIf(error) - return result - } + fun setEncryption(passphrase: String) = runWithError { jniApplyEncryption(passphrase, it) } - fun removeEncryption() { - val error = FFIError() - val result = jniRemoveEncryption(error) - throwIf(error) - return result - } + fun removeEncryption() = runWithError { jniRemoveEncryption(it) } - fun startRecovery(baseNodePublicKey: FFIPublicKey, recoveryOutputMessage: String): Boolean { - val error = FFIError() - val result = jniStartRecovery(baseNodePublicKey, this::onWalletRecovery.name, "(I[B[B)V", recoveryOutputMessage, error) - throwIf(error) - return result - } + fun startRecovery(baseNodePublicKey: FFIPublicKey, recoveryOutputMessage: String): Boolean = + runWithError { jniStartRecovery(baseNodePublicKey, this::onWalletRecovery.name, "(I[B[B)V", recoveryOutputMessage, it) } - fun getFeePerGramStats(): FFIFeePerGramStats { - val error = FFIError() - val result = FFIFeePerGramStats(jniWalletGetFeePerGramStats(3, error)) - throwIf(error) - return result - } + fun getFeePerGramStats(): FFIFeePerGramStats = runWithError { FFIFeePerGramStats(jniWalletGetFeePerGramStats(3, it)) } /** * This callback function cannot be private due to JNI behaviour. @@ -782,25 +583,13 @@ internal class FFIWallet( @Suppress("MemberVisibilityCanBePrivate") fun onWalletRecovery(event: Int, firstArg: ByteArray, secondArg: ByteArray) { val result = WalletRestorationResult.create(event, firstArg, secondArg) - Logger.i("Wallet restoration. Result: $result") - GlobalScope.launch { listener?.onWalletRestoration(result) } + logger.i("Wallet restored with $result") + localScope.launch { listener?.onWalletRestoration(result) } } override fun destroy() { listener = null jniDestroy() } - - - fun generateTestData(datastorePath: String): Boolean = false - - fun testBroadcastTx(tx: BigInteger): Boolean = false - - fun testCompleteSentTx(tx: FFIPendingOutboundTx): Boolean = false - - fun testMineTx(tx: BigInteger): Boolean = false - - fun testFinalizeReceivedTx(tx: FFIPendingInboundTx): Boolean = false - - fun testReceiveTx(): Boolean = false } + diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIWalletListener.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIWalletListener.kt index c90aa3d22..1347c238c 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/FFIWalletListener.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIWalletListener.kt @@ -39,7 +39,7 @@ import java.math.BigInteger /** * @author The Tari Development Team */ -internal interface FFIWalletListener { +interface FFIWalletListener { fun onTxReceived(pendingInboundTx: PendingInboundTx) fun onTxReplyReceived(pendingOutboundTx: PendingOutboundTx) @@ -52,8 +52,9 @@ internal interface FFIWalletListener { fun onTxFauxUnconfirmed(completedTx: CompletedTx, confirmationCount: Int) fun onDirectSendResult(txId: BigInteger, status: TransactionSendStatus) fun onTxCancelled(cancelledTx: CancelledTx, rejectionReason: Int) - fun onTXOValidationComplete(responseId: BigInteger, isSuccess: Boolean) + fun onTXOValidationComplete(responseId: BigInteger, status: TXOValidationStatus) fun onTxValidationComplete(responseId: BigInteger, isSuccess: Boolean) + fun onBalanceUpdated(balanceInfo: BalanceInfo) fun onConnectivityStatus(status: Int) fun onWalletRestoration(result: WalletRestorationResult) } diff --git a/app/src/main/java/com/tari/android/wallet/ffi/HexString.kt b/app/src/main/java/com/tari/android/wallet/ffi/HexString.kt index 8dae238ee..d2ec06fb7 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/HexString.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/HexString.kt @@ -39,33 +39,22 @@ import java.math.BigInteger */ class HexString constructor(bytes: FFIByteVector) { - private val pattern = "\\p{XDigit}+".toRegex() - - var hex: String = String() + var hex = String() init { if (bytes.pointer != nullptr) { - val byteArray = ByteArray(bytes.getLength()) if (bytes.getLength() > 0) { - for (i in 0 until bytes.getLength()) { - val m = bytes.getAt(i) - byteArray[i] = m.toByte() + val byteArray = ByteArray(bytes.getLength()) + for (i in byteArray.indices) { + byteArray[i] = bytes.getAt(i).toByte() } hex = String.format("%064X", BigInteger(1, byteArray)) - } else { - hex = String() } - } else { - hex = String() } } - constructor(string: String) : this(FFIByteVector(nullptr)) { - if (pattern.matches(string)) { - hex = string - } else { - throw FFIException(message = "$string is not valid Hex.") - } + constructor(hex: String) : this(FFIByteVector(nullptr)) { + this.hex = hex } override fun toString(): String = hex diff --git a/app/src/main/java/com/tari/android/wallet/ffi/LogFileObserver.kt b/app/src/main/java/com/tari/android/wallet/ffi/LogFileObserver.kt index b756a739b..572fffb45 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/LogFileObserver.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/LogFileObserver.kt @@ -33,7 +33,7 @@ package com.tari.android.wallet.ffi import android.os.FileObserver -import android.util.Log +import com.orhanobut.logger.Logger import org.apache.commons.io.input.ReversedLinesFileReader import java.io.File import java.io.FileReader @@ -46,8 +46,7 @@ import java.nio.charset.StandardCharsets * * @author The Tari Development Team */ -@Suppress("DEPRECATION") -internal class LogFileObserver(logFilePath: String) : FileObserver(logFilePath) { +class LogFileObserver(logFilePath: String) : FileObserver(logFilePath) { private val logTag = "FFI" private val logFile = File(logFilePath) @@ -71,11 +70,13 @@ internal class LogFileObserver(logFilePath: String) : FileObserver(logFilePath) val line = reversedFileReader.readLine() lineList.add(line) } - // log them in reverse order - lineList.reversed().forEach { logLine -> - Log.d(logTag, logLine) + val stringBuilder = StringBuilder() + if (lineList.isNotEmpty()) { + // log them in reverse order + lineList.reversed().forEach { logLine -> stringBuilder.appendLine(logLine) } + Logger.t(logTag).d(stringBuilder.toString()) + lastNumberOfLines = lineNumberReader.lineNumber } - lastNumberOfLines = lineNumberReader.lineNumber // close resources fileReader.close() lineNumberReader.close() @@ -83,8 +84,6 @@ internal class LogFileObserver(logFilePath: String) : FileObserver(logFilePath) } override fun onEvent(event: Int, path: String?) { - try { logNewLines() } catch (ignored: Exception) { } - + runCatching { logNewLines() } } - } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ffi/NetAddressString.kt b/app/src/main/java/com/tari/android/wallet/ffi/NetAddressString.kt index 528c1fc93..b918a3206 100644 --- a/app/src/main/java/com/tari/android/wallet/ffi/NetAddressString.kt +++ b/app/src/main/java/com/tari/android/wallet/ffi/NetAddressString.kt @@ -35,7 +35,7 @@ package com.tari.android.wallet.ffi /** * @author The Tari Development Team */ -internal class NetAddressString(address: String = "0.0.0.0", port: Int = 0) { +class NetAddressString(address: String = "0.0.0.0", port: Int = 0) { private val address: String private val addressPort: Int diff --git a/app/src/main/java/com/tari/android/wallet/ffi/TXOValidationStatus.kt b/app/src/main/java/com/tari/android/wallet/ffi/TXOValidationStatus.kt new file mode 100644 index 000000000..5e0de09d3 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ffi/TXOValidationStatus.kt @@ -0,0 +1,8 @@ +package com.tari.android.wallet.ffi + +enum class TXOValidationStatus(val value: Int) { + TxoValidationSuccess(0), + TxoValidationAlreadyBusy(1), + TxoValidationInternalFailure(2), + TxoValidationCommunicationFailure(3) +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/ConsoleLogTracker.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/ConsoleLogTracker.kt deleted file mode 100644 index 04f33c266..000000000 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/ConsoleLogTracker.kt +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.infrastructure - -import android.content.Context -import android.util.Log - -/** - * Tracker implementation that logs invocations to the console. - * - * @author The Tari Development Team - */ -class ConsoleLogTracker : Tracker { - override fun screen(path: String, title: String) { - Log.i(TRACK_TAG, "Screen track issued with path \"$path\" and title \"$title\"") - } - - override fun download(context: Context) { - Log.i(TRACK_TAG, "Download track issued with $context") - } - - override fun event(category: String, action: String) { - Log.i(TRACK_TAG, "Event track issued with category \"$category\" and action \"$action\"") - } - - private companion object { - private const val TRACK_TAG = "Debug_Tracker" - } -} diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/Tracker.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/Tracker.kt deleted file mode 100644 index 1e348125e..000000000 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/Tracker.kt +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.infrastructure - -import android.content.Context - -/** - * Interface for application events tracking - * - * @author The Tari Development Team - */ -interface Tracker { - - fun screen(path: String, title: String) - - fun download(context: Context) - - fun event(category: String, action: String) - -} diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt index f70955d69..0608ab7e8 100644 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt @@ -48,15 +48,22 @@ import java.io.File * * @author The Tari Development Team */ -internal class BackupFileProcessor( +class BackupFileProcessor( private val backupSettingsRepository: BackupSettingsRepository, private val walletConfig: WalletConfig, private val namingPolicy: BackupNamingPolicy, ) { + private val logger + get() = Logger.t(BackupFileProcessor::class.simpleName) + + @Synchronized fun generateBackupFile(newPassword: CharArray? = null): Triple { // decrypt database - FFIWallet.instance?.removeEncryption() + FFIWallet.instance?.let { + it.removeEncryption() + backupSettingsRepository.backupPassword = null + } // create partial backup in temp folder if password not set val databaseFile = File(walletConfig.walletDatabaseFilePath) @@ -66,14 +73,8 @@ internal class BackupFileProcessor( val compressionMethod = CompressionMethod.zip() var mimeType = compressionMethod.mimeType val backupFileName = namingPolicy.getBackupFileName(backupDate) - val compressedFile = File( - walletConfig.getWalletTempDirPath(), - "$backupFileName.${compressionMethod.extension}" - ) - var fileToBackup = listOf(databaseFile).compress( - CompressionMethod.zip(), - compressedFile.absolutePath - ) + val compressedFile = File(walletConfig.getWalletTempDirPath(), "$backupFileName.${compressionMethod.extension}") + var fileToBackup = listOf(databaseFile).compress(CompressionMethod.zip(), compressedFile.absolutePath) // encrypt the file if password is set val encryptionAlgorithm = SymmetricEncryptionAlgorithm.aes() if (backupPassword != null) { @@ -87,7 +88,7 @@ internal class BackupFileProcessor( } // encrypt after finish backup FFIWallet.instance?.enableEncryption() - + logger.i("Backup files was generated") return Triple(fileToBackup, backupDate, mimeType) } @@ -106,32 +107,28 @@ internal class BackupFileProcessor( { file.inputStream() }, { unencryptedCompressedFile.outputStream() } ) - CompressionMethod.zip().uncompress( - unencryptedCompressedFile, - walletFilesDir - ) + CompressionMethod.zip().uncompress(unencryptedCompressedFile, walletFilesDir) if (!File(walletConfig.walletDatabaseFilePath).exists()) { // delete uncompressed files walletFilesDir.deleteRecursively() throw BackupStorageTamperedException("Invalid encrypted backup.") } + logger.i("Backup file was restored") } else { - CompressionMethod.zip().uncompress( - file, - walletFilesDir - ) + CompressionMethod.zip().uncompress(file, walletFilesDir) // check if wallet database file exists if (!File(walletConfig.walletDatabaseFilePath).exists()) { walletFilesDir.listFiles()?.let { files -> // delete uncompressed files for (extractedFile in files) { - if (extractedFile.isFile) { extractedFile.delete() } + if (extractedFile.isFile) { + extractedFile.delete() + } } } + logger.i("Backup file is encrypted") // throw exception - throw BackupFileIsEncryptedException( - "Cannot uncompress. Restored file is encrypted." - ) + throw BackupFileIsEncryptedException("Cannot uncompress. Restored file is encrypted.") } } } @@ -140,11 +137,7 @@ internal class BackupFileProcessor( try { File(walletConfig.getWalletTempDirPath()).listFiles()?.forEach { it.delete() } } catch (e: Exception) { - Logger.e( - e, - "Ignorable backup error while clearing temporary and old files." - ) + logger.e(e, "Cleaning temp files") } } - } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupManager.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupManager.kt index 2193cbfaa..2cdad5fc1 100644 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupManager.kt +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupManager.kt @@ -52,7 +52,7 @@ import java.net.UnknownHostException import java.util.concurrent.TimeUnit import kotlin.math.max -internal class BackupManager( +class BackupManager( private val context: Context, private val backupSettingsRepository: BackupSettingsRepository, private val backupStorage: BackupStorage, @@ -60,6 +60,8 @@ internal class BackupManager( ) { private var retryCount = 0 + private val logger + get() = Logger.t(BackupManager::class.simpleName) /** * Timer to trigger scheduled backups. @@ -67,38 +69,23 @@ internal class BackupManager( private var scheduledBackupSubscription: Disposable? = null fun initialize() { - Logger.d("Start backup manager.") val scheduledBackupDate = backupSettingsRepository.scheduledBackupDate when { !backupSettingsRepository.backupIsEnabled -> EventBus.backupState.post(BackupState.BackupDisabled) backupSettingsRepository.backupFailureDate != null -> EventBus.backupState.post(BackupState.BackupOutOfDate()) - scheduledBackupDate != null -> { - val delayMs = scheduledBackupDate.millis - DateTime.now().millis - scheduleBackup( - delayMs = max(0, delayMs), - resetRetryCount = true - ) - } - else -> { - EventBus.backupState.post(BackupState.BackupUpToDate) - } + scheduledBackupDate != null -> scheduleBackup(max(0, scheduledBackupDate.millis - DateTime.now().millis), true) + else -> EventBus.backupState.post(BackupState.BackupUpToDate) } } fun setupStorage(hostFragment: Fragment) { + logger.i("Setup storage") backupStorage.setup(hostFragment) } - suspend fun onSetupActivityResult( - requestCode: Int, - resultCode: Int, - intent: Intent? - ) { - backupStorage.onSetupActivityResult( - requestCode, - resultCode, - intent - ) + suspend fun onSetupActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { + logger.i("Setup storage stage 2") + backupStorage.onSetupActivityResult(requestCode, resultCode, intent) } suspend fun checkStorageStatus() { @@ -108,13 +95,13 @@ internal class BackupManager( if (EventBus.backupState.publishSubject.value is BackupState.BackupInProgress) { return } - Logger.d("Check backup storage status.") + logger.i("Check backup storage status") EventBus.backupState.post(BackupState.BackupCheckingStorage) // check storage try { val backupDate = backupSettingsRepository.lastSuccessfulBackupDate!! if (!backupStorage.hasBackupForDate(backupDate)) { - throw BackupStorageTamperedException("Backup storage is tampered.") + throw BackupStorageTamperedException("Backup storage is tampered") } when { backupSettingsRepository.backupFailureDate != null -> EventBus.backupState.post(BackupState.BackupOutOfDate()) @@ -131,25 +118,18 @@ internal class BackupManager( } catch (e: BackupStorageTamperedException) { EventBus.backupState.post(BackupState.BackupOutOfDate(e)) } catch (e: Exception) { - Logger.e(e, "Error while checking storage. %s", e.toString()) EventBus.backupState.post(BackupState.BackupStorageCheckFailed) throw e } } - fun scheduleBackup( - delayMs: Long? = null, - resetRetryCount: Boolean = false - ) { + fun scheduleBackup(delayMs: Long? = null, resetRetryCount: Boolean = false) { if (!backupSettingsRepository.backupIsEnabled) { - Logger.i("Backup is not enabled - cannot schedule a backup.") return // if backup is disabled or there's a scheduled backup } if (scheduledBackupSubscription?.isDisposed == false) { - Logger.i("There is already a scheduled backup - cannot schedule a backup.") return // if backup is disabled or there's a scheduled backup } - Logger.d("Schedule backup.") if (resetRetryCount) { retryCount = 0 } @@ -159,35 +139,20 @@ internal class BackupManager( .timer(delayMs ?: Constants.Wallet.backupDelayMs, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) - .subscribe { - GlobalScope.launch(Dispatchers.IO) { - try { - backup() - } catch (exception: Exception) { - Logger.e(exception, "Error during scheduled backup: $exception") - } - } - } + .subscribe { GlobalScope.launch(Dispatchers.IO) { runCatching { backup() } } } backupSettingsRepository.scheduledBackupDate = DateTime.now().plusMillis(delayMs?.toInt() ?: Constants.Wallet.backupDelayMs.toInt()) EventBus.backupState.post(BackupState.BackupScheduled) - Logger.i("Backup scheduled.") } - suspend fun backup( - isInitialBackup: Boolean = false, - userTriggered: Boolean = false, - newPassword: CharArray? = null - ) { + suspend fun backup(isInitialBackup: Boolean = false, userTriggered: Boolean = false, newPassword: CharArray? = null) { if (!isInitialBackup && !backupSettingsRepository.backupIsEnabled) { - Logger.d("Backup is disabled. Exit.") return } if (EventBus.backupState.publishSubject.value is BackupState.BackupInProgress) { - Logger.d("Backup is in progress. Exit.") return } // Do the work here--in this case, upload the images. - Logger.d("Do backup.") + logger.i("Backup started") // cancel any scheduled backup scheduledBackupSubscription?.dispose() scheduledBackupSubscription = null @@ -198,9 +163,10 @@ internal class BackupManager( backupSettingsRepository.lastSuccessfulBackupDate = backupDate backupSettingsRepository.scheduledBackupDate = null backupSettingsRepository.backupFailureDate = null - Logger.d("Backup successful.") + logger.i("Backup successful") EventBus.backupState.post(BackupState.BackupUpToDate) } catch (exception: Exception) { + logger.e(exception, "Backup failed") if (isInitialBackup) { turnOff(deleteExistingBackups = true) retryCount = 0 @@ -213,10 +179,7 @@ internal class BackupManager( throw exception } if (userTriggered || retryCount > Constants.Wallet.maxBackupRetries) { - Logger.e( - exception, - "Error happened while backing up. It's a user-triggered backup or retry limit has been exceeded." - ) + logger.e(exception, "Error happened while backing up. It's a user-triggered backup or retry limit has been exceeded") EventBus.backupState.post(BackupState.BackupOutOfDate(exception)) backupSettingsRepository.scheduledBackupDate = null backupSettingsRepository.backupFailureDate = DateTime.now() @@ -226,13 +189,10 @@ internal class BackupManager( } throw exception } else { - Logger.e(exception, "Backup failed: ${exception.message}. Will schedule.") - scheduleBackup( - delayMs = Constants.Wallet.backupRetryPeriodMs, - resetRetryCount = false - ) + logger.e(exception, "Backup failed. Will schedule.") + scheduleBackup(delayMs = Constants.Wallet.backupRetryPeriodMs, resetRetryCount = false) } - Logger.e(exception, "Error happened while backing up. Will retry.") + logger.e(exception, "Error happened while backing up. Will retry") } } @@ -252,10 +212,7 @@ internal class BackupManager( exception.message == null -> context.getString(R.string.back_up_wallet_backing_up_unknown_error) else -> context.getString(R.string.back_up_wallet_backing_up_error_desc, exception.message!!) } - notificationHelper.postNotification( - title = title, - body = body - ) + notificationHelper.postNotification(title = title, body = body) } // TODO(nyarian): TBD - should side effects be separated from the direct flow? @@ -268,27 +225,10 @@ internal class BackupManager( scheduledBackupSubscription = null EventBus.backupState.post(BackupState.BackupDisabled) if (deleteExistingBackups) { - try { - backupStorage.deleteAllBackupFiles() - } catch (exception: Exception) { - /* no-op */ - Logger.e( - exception, - // TODO(nyarian): but why ignoring this? - "Ignored exception while deleting all backup files: $exception" - ) - } + runCatching { backupStorage.deleteAllBackupFiles() } } backupSettingsRepository.localBackupFolderURI = null - try { - backupStorage.signOut() - } catch (exception: Exception) { - /* no-op */ - Logger.e( - exception, - "Ignored exception while turning off: $exception" - ) - } + runCatching { backupStorage.signOut() } } } diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupNamingPolicy.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupNamingPolicy.kt index 3fa063119..bb6441cea 100644 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupNamingPolicy.kt +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupNamingPolicy.kt @@ -47,15 +47,10 @@ class BackupNamingPolicy @Inject constructor(val networkRepository: NetworkRepos Regex("$backupFileNamePrefix(\\d{4}-(((0)[1-9])|((1)[0-2]))-((0)[1-9]|[1-2][0-9]|(3)[0-1])_([0-1][0-9]|(2)[0-3])-([0-5][0-9])-([0-5][0-9]))\\..+") private val dateFormatter: DateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd_HH-mm-ss") - fun getBackupFileName(backupDate: DateTime = DateTime.now()): String { - return backupFileNamePrefix + dateFormatter.print(backupDate) - } + fun getBackupFileName(backupDate: DateTime = DateTime.now()): String = backupFileNamePrefix + dateFormatter.print(backupDate) - fun isBackupFileName(fileName: String): Boolean { - return regex.matches(fileName) - } + fun isBackupFileName(fileName: String): Boolean = regex.matches(fileName) - fun getDateFromBackupFileName(name: String): DateTime? = - regex.find(name)?.let { it.groups[1]!!.value }?.let { dateFormatter.parseDateTime(it) } + fun getDateFromBackupFileName(name: String): DateTime? = regex.find(name)?.let { it.groups[1]!!.value }?.let { dateFormatter.parseDateTime(it) } } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupState.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupState.kt index 99a01ddd3..2efe9e0c3 100644 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupState.kt +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupState.kt @@ -39,7 +39,7 @@ import java.lang.Exception * * @author The Tari Development Team */ -internal sealed class BackupState { +sealed class BackupState { object BackupDisabled : BackupState() object BackupCheckingStorage : BackupState() object BackupStorageCheckFailed : BackupState() diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/LocalBackupStorage.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/LocalBackupStorage.kt index fab335134..23bd48c3b 100644 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/LocalBackupStorage.kt +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/LocalBackupStorage.kt @@ -53,7 +53,7 @@ import java.io.File * @author The Tari Development Team */ // todo review -internal class LocalBackupStorage( +class LocalBackupStorage( private val context: Context, private val backupSettingsRepository: BackupSettingsRepository, private val namingPolicy: BackupNamingPolicy, @@ -62,6 +62,9 @@ internal class LocalBackupStorage( private val backupFileProcessor: BackupFileProcessor ) : BackupStorage { + private val logger + get() = Logger.t(LocalBackupStorage::class.simpleName) + override fun setup(hostFragment: Fragment) { hostFragment.startActivityForResult( Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), @@ -69,17 +72,13 @@ internal class LocalBackupStorage( ) } - override suspend fun onSetupActivityResult( - requestCode: Int, - resultCode: Int, - intent: Intent? - ) { + override suspend fun onSetupActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { if (requestCode != REQUEST_CODE_PICK_BACKUP_FOLDER) return when (resultCode) { Activity.RESULT_OK -> { val uri = intent?.data if (uri != null) { - Logger.d("Backup URI selected: $uri") + logger.i("Backup URI selected: $uri") backupSettingsRepository.localBackupFolderURI = uri // persist permissions val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION @@ -122,10 +121,7 @@ internal class LocalBackupStorage( } } } catch (e: Exception) { - Logger.e( - e, - "Ignorable backup error while clearing temporary and old files." - ) + logger.e(e, "Ignorable backup error while clearing temporary and old files.") } return@withContext backupDate } diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/compress/CompressionMethod.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/compress/CompressionMethod.kt index 6c15d10a5..9cd9c7a4f 100644 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/compress/CompressionMethod.kt +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/compress/CompressionMethod.kt @@ -32,11 +32,7 @@ */ package com.tari.android.wallet.infrastructure.backup.compress -import com.tari.android.wallet.extension.getLastPathComponent -import java.io.* -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream +import java.io.File /** * File compressor interface. @@ -57,72 +53,3 @@ interface CompressionMethod { } } -private object ZipCompression : CompressionMethod { - - private const val READ_BYTE_BUFFER_SIZE = 2048 - override val extension: String - get() = "zip" - override val mimeType: String - get() = "application/zip" - - override fun compress(outputPath: String, files: Iterable): File { - ZipOutputStream(BufferedOutputStream(FileOutputStream(outputPath))).use { destination -> - files.forEach { file -> - if (file.isDirectory) compressFolder(destination, file, file.parent!!.length) - else compressFile(file, destination, { FileInputStream(file) }) { - ZipEntry(file.getLastPathComponent()) - } - } - } - return File(outputPath) - } - - private fun compressFolder(destination: ZipOutputStream, folder: File, pathLength: Int): Unit = - (folder.listFiles() ?: emptyArray()).forEach { file -> - if (file.isDirectory) compressFolder(destination, file, pathLength) - else compressFile(file, destination, { FileInputStream(file.path) }) { - ZipEntry(file.path.substring(pathLength)) - } - } - - private fun compressFile( - sourceFile: File, - output: ZipOutputStream, - inputStreamProvider: () -> FileInputStream, - zipEntryProvider: () -> ZipEntry - ) { - val origin = BufferedInputStream(inputStreamProvider(), READ_BYTE_BUFFER_SIZE) - val entry = zipEntryProvider() - entry.time = sourceFile.lastModified() - output.putNextEntry(entry) - var count: Int - val data = ByteArray(READ_BYTE_BUFFER_SIZE) - while (origin.read(data, 0, READ_BYTE_BUFFER_SIZE).also { count = it } != -1) { - output.write(data, 0, count) - } - origin.close() - } - - override fun uncompress(source: File, destinationDirectory: File) { - require(destinationDirectory.isDirectory) - if (!destinationDirectory.exists()) destinationDirectory.mkdirs() - val buffer = ByteArray(READ_BYTE_BUFFER_SIZE) - ZipInputStream( - BufferedInputStream(FileInputStream(source), READ_BYTE_BUFFER_SIZE) - ).use { zis -> - generateSequence { zis.nextEntry } - .forEach { entry -> - val newFile = File(destinationDirectory, entry.name) - File(newFile.parent!!).mkdirs() - FileOutputStream(newFile).use { fos -> - var len: Int - while (zis.read(buffer).also { len = it } > 0) { - fos.write(buffer, 0, len) - } - } - zis.closeEntry() - } - } - } - -} diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/compress/ZipCompression.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/compress/ZipCompression.kt new file mode 100644 index 000000000..3109c978b --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/compress/ZipCompression.kt @@ -0,0 +1,74 @@ +package com.tari.android.wallet.infrastructure.backup.compress + +import com.tari.android.wallet.extension.getLastPathComponent +import java.io.* +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream + +object ZipCompression : CompressionMethod { + + private const val READ_BYTE_BUFFER_SIZE = 2048 + override val extension: String = "zip" + override val mimeType: String = "application/zip" + + override fun compress(outputPath: String, files: Iterable): File { + ZipOutputStream(BufferedOutputStream(FileOutputStream(outputPath))).use { destination -> + files.forEach { file -> + if (file.isDirectory) compressFolder(destination, file, file.parent!!.length) + else compressFile(file, destination, { FileInputStream(file) }) { + ZipEntry(file.getLastPathComponent()) + } + } + } + return File(outputPath) + } + + private fun compressFolder(destination: ZipOutputStream, folder: File, pathLength: Int): Unit = + (folder.listFiles() ?: emptyArray()).forEach { file -> + if (file.isDirectory) compressFolder(destination, file, pathLength) + else compressFile(file, destination, { FileInputStream(file.path) }) { + ZipEntry(file.path.substring(pathLength)) + } + } + + private fun compressFile( + sourceFile: File, + output: ZipOutputStream, + inputStreamProvider: () -> FileInputStream, + zipEntryProvider: () -> ZipEntry + ) { + BufferedInputStream(inputStreamProvider(), READ_BYTE_BUFFER_SIZE).use { origin -> + zipEntryProvider().apply { + time = sourceFile.lastModified() + output.putNextEntry(this) + } + var count: Int + val data = ByteArray(READ_BYTE_BUFFER_SIZE) + while (origin.read(data, 0, READ_BYTE_BUFFER_SIZE).also { count = it } != -1) { + output.write(data, 0, count) + } + } + } + + override fun uncompress(source: File, destinationDirectory: File) { + require(destinationDirectory.isDirectory) + if (!destinationDirectory.exists()) destinationDirectory.mkdirs() + val buffer = ByteArray(READ_BYTE_BUFFER_SIZE) + ZipInputStream(BufferedInputStream(FileInputStream(source), READ_BYTE_BUFFER_SIZE)).use { zis -> + generateSequence { zis.nextEntry } + .forEach { entry -> + val newFile = File(destinationDirectory, entry.name) + File(newFile.parent!!).mkdirs() + FileOutputStream(newFile).use { fos -> + var len: Int + while (zis.read(buffer).also { len = it } > 0) { + fos.write(buffer, 0, len) + } + } + zis.closeEntry() + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/BugReportingService.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/BugReportingService.kt similarity index 93% rename from app/src/main/java/com/tari/android/wallet/infrastructure/BugReportingService.kt rename to app/src/main/java/com/tari/android/wallet/infrastructure/logging/BugReportingService.kt index 75eb33522..2262f2e99 100644 --- a/app/src/main/java/com/tari/android/wallet/infrastructure/BugReportingService.kt +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/BugReportingService.kt @@ -30,13 +30,14 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.infrastructure +package com.tari.android.wallet.infrastructure.logging import android.content.Context import android.content.Intent import android.net.Uri import androidx.core.content.FileProvider import com.tari.android.wallet.R +import com.tari.android.wallet.data.WalletConfig import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.util.WalletUtil import java.io.* @@ -49,7 +50,7 @@ import java.util.zip.ZipOutputStream * * @author The Tari Development Team */ -class BugReportingService(private val sharedPrefsWrapper: SharedPrefsRepository, private val logFilesDirPath: String) { +class BugReportingService(private val sharedPrefsWrapper: SharedPrefsRepository, private val walletConfig: WalletConfig) { class BugReportFileSizeLimitExceededException : Exception() @@ -58,13 +59,15 @@ class BugReportingService(private val sharedPrefsWrapper: SharedPrefsRepository, fun shareBugReport(context: Context) { // delete if zipped file exists val publicKeyHex = sharedPrefsWrapper.publicKeyHexString + val logFilesDirPath = walletConfig.getWalletLogFilesDirPath() val zipFile = File(logFilesDirPath, "ffi_logs_${publicKeyHex}.zip") if (zipFile.exists()) { zipFile.delete() } val fileOutStream = FileOutputStream(zipFile) // zip! - val allLogFiles = WalletUtil.getLogFilesFromDirectory(logFilesDirPath) + val allLogFiles = WalletUtil.getLogFilesFromDirectory(logFilesDirPath).toMutableList() + allLogFiles.add(File(walletConfig.getApplicationLogsFilePath())) ZipOutputStream(BufferedOutputStream(fileOutStream)).use { out -> for (file in allLogFiles) { FileInputStream(file).use { inputStream -> diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LocalFileAdapter.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LocalFileAdapter.kt new file mode 100644 index 000000000..78bebb26d --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LocalFileAdapter.kt @@ -0,0 +1,32 @@ +package com.tari.android.wallet.infrastructure.logging + +import com.orhanobut.logger.LogAdapter +import com.orhanobut.logger.Logger +import org.joda.time.DateTime +import java.io.BufferedWriter +import java.io.File +import java.io.FileOutputStream +import java.io.OutputStreamWriter + + +class LocalFileAdapter(private val filePath: String) : LogAdapter { + + override fun isLoggable(priority: Int, tag: String?): Boolean = true + + override fun log(priority: Int, tag: String?, message: String) { + runCatching { + BufferedWriter(OutputStreamWriter(FileOutputStream(File(filePath), true))).use { + val priorityName = when (priority) { + 2 -> Logger::VERBOSE.name + 3 -> Logger::DEBUG.name + 4 -> Logger::INFO.name + 5 -> Logger::WARN.name + 6 -> Logger::ERROR.name + else -> Logger::ASSERT.name + } + val dateTimeNow = DateTime.now().toString() + it.appendLine("$priorityName | $dateTimeNow | ${tag ?: ""} | ${message.replace("\n", " ")}") + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LoggerAdapter.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LoggerAdapter.kt new file mode 100644 index 000000000..aef4e5b45 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LoggerAdapter.kt @@ -0,0 +1,19 @@ +package com.tari.android.wallet.infrastructure.logging + +import com.orhanobut.logger.AndroidLogAdapter +import com.orhanobut.logger.DiskLogAdapter +import com.orhanobut.logger.Logger +import com.tari.android.wallet.BuildConfig +import com.tari.android.wallet.data.WalletConfig + +class LoggerAdapter(private val walletConfig: WalletConfig) { + fun init() { + Logger.addLogAdapter(AndroidLogAdapter()) + Logger.addLogAdapter(DiskLogAdapter()) + Logger.addLogAdapter(LocalFileAdapter(walletConfig.getApplicationLogsFilePath())) + @Suppress("KotlinConstantConditions") + if (BuildConfig.FLAVOR != "privacy") { + Logger.addLogAdapter(SentryLogAdapter()) + } + } +} diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryException.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryException.kt new file mode 100644 index 000000000..ddd16c39a --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryException.kt @@ -0,0 +1,3 @@ +package com.tari.android.wallet.infrastructure.logging + +class SentryException(message: String) : Throwable(message) \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryLogAdapter.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryLogAdapter.kt new file mode 100644 index 000000000..86cab248b --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryLogAdapter.kt @@ -0,0 +1,32 @@ +package com.tari.android.wallet.infrastructure.logging + +import com.orhanobut.logger.LogAdapter +import com.orhanobut.logger.Logger +import io.sentry.Breadcrumb +import io.sentry.Sentry +import io.sentry.SentryLevel + +class SentryLogAdapter : LogAdapter { + + override fun isLoggable(priority: Int, tag: String?): Boolean = true + + override fun log(priority: Int, tag: String?, message: String) { + if (priority == Logger.ERROR) { + Sentry.captureException(SentryException(message), tag) + } else { + val level = when (priority) { + Logger.ERROR -> SentryLevel.ERROR + Logger.WARN -> SentryLevel.WARNING + Logger.DEBUG -> SentryLevel.DEBUG + else -> SentryLevel.INFO + } + val breadcrumb = Breadcrumb(message).apply { + setLevel(level) + category = tag + setMessage(message) + } + + Sentry.addBreadcrumb(breadcrumb) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/model/CancelledTx.kt b/app/src/main/java/com/tari/android/wallet/model/CancelledTx.kt index 25255c6e0..57c3bbec0 100644 --- a/app/src/main/java/com/tari/android/wallet/model/CancelledTx.kt +++ b/app/src/main/java/com/tari/android/wallet/model/CancelledTx.kt @@ -48,7 +48,7 @@ class CancelledTx() : Tx(), Parcelable { var fee: MicroTari = MicroTari(BigInteger("0")) var cancellationReason: FFITxCancellationReason = FFITxCancellationReason.NotCancelled - internal constructor(tx: FFICompletedTx) : this() { + constructor(tx: FFICompletedTx) : this() { this.id = tx.getId() this.direction = tx.getDirection() this.user = tx.getUser() diff --git a/app/src/main/java/com/tari/android/wallet/model/CompletedTx.kt b/app/src/main/java/com/tari/android/wallet/model/CompletedTx.kt index ee77d2567..db6c48f4f 100644 --- a/app/src/main/java/com/tari/android/wallet/model/CompletedTx.kt +++ b/app/src/main/java/com/tari/android/wallet/model/CompletedTx.kt @@ -49,7 +49,7 @@ class CompletedTx() : Tx(), Parcelable { var confirmationCount = BigInteger("0") var txKernel: CompletedTransactionKernel? = null - internal constructor(tx: FFICompletedTx) : this() { + constructor(tx: FFICompletedTx) : this() { this.id = tx.getId() this.direction = tx.getDirection() this.user = tx.getUser() @@ -66,7 +66,7 @@ class CompletedTx() : Tx(), Parcelable { tx.destroy() } - internal constructor(pointer: FFIPointer) : this(FFICompletedTx(pointer)) + constructor(pointer: FFIPointer) : this(FFICompletedTx(pointer)) // region Parcelable diff --git a/app/src/main/java/com/tari/android/wallet/model/PendingInboundTx.kt b/app/src/main/java/com/tari/android/wallet/model/PendingInboundTx.kt index 42c8bb958..bc225c00f 100644 --- a/app/src/main/java/com/tari/android/wallet/model/PendingInboundTx.kt +++ b/app/src/main/java/com/tari/android/wallet/model/PendingInboundTx.kt @@ -45,7 +45,7 @@ import java.math.BigInteger */ class PendingInboundTx() : Tx(), Parcelable { - internal constructor(tx: FFICompletedTx) : this() { + constructor(tx: FFICompletedTx) : this() { this.id = tx.getId() this.direction = tx.getDirection() this.user = tx.getUser() @@ -56,7 +56,7 @@ class PendingInboundTx() : Tx(), Parcelable { tx.destroy() } - internal constructor(tx: FFIPendingInboundTx) : this() { + constructor(tx: FFIPendingInboundTx) : this() { this.id = tx.getId() this.direction = tx.getDirection() this.user = tx.getUser() diff --git a/app/src/main/java/com/tari/android/wallet/model/PendingOutboundTx.kt b/app/src/main/java/com/tari/android/wallet/model/PendingOutboundTx.kt index af94d0339..945182525 100644 --- a/app/src/main/java/com/tari/android/wallet/model/PendingOutboundTx.kt +++ b/app/src/main/java/com/tari/android/wallet/model/PendingOutboundTx.kt @@ -47,7 +47,7 @@ class PendingOutboundTx() : Tx(), Parcelable { var fee = MicroTari(BigInteger("0")) - internal constructor(tx: FFICompletedTx) : this() { + constructor(tx: FFICompletedTx) : this() { this.id = tx.getId() this.direction = tx.getDirection() this.user = tx.getUser() @@ -59,7 +59,7 @@ class PendingOutboundTx() : Tx(), Parcelable { tx.destroy() } - internal constructor(tx: FFIPendingOutboundTx) : this() { + constructor(tx: FFIPendingOutboundTx) : this() { this.id = tx.getId() this.direction = tx.getDirection() this.user = tx.getUser() diff --git a/app/src/main/java/com/tari/android/wallet/ui/presentation/TxNote.kt b/app/src/main/java/com/tari/android/wallet/model/TxNote.kt similarity index 91% rename from app/src/main/java/com/tari/android/wallet/ui/presentation/TxNote.kt rename to app/src/main/java/com/tari/android/wallet/model/TxNote.kt index 5d0fdd005..6aae8bf8f 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/presentation/TxNote.kt +++ b/app/src/main/java/com/tari/android/wallet/model/TxNote.kt @@ -30,9 +30,9 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.presentation +package com.tari.android.wallet.model -internal class TxNote(val message: String?, val gifUrl: String?) { +class TxNote(val message: String?, val gifUrl: String?) { init { if (message == null && gifUrl == null) { @@ -63,11 +63,7 @@ internal class TxNote(val message: String?, val gifUrl: String?) { override fun toString(): String = "TransactionNote(message=$message, gifUrl=$gifUrl)" companion object { - fun fromNote( - note: String, - assetsDomain: String = "giphy.com", - protocol: String = "https://" - ): TxNote { + fun fromNote(note: String, assetsDomain: String = "giphy.com", protocol: String = "https://"): TxNote { val lines = note.split(Regex(" ")) return if (Regex("$protocol$assetsDomain.*").matches(lines.last())) TxNote( message = lines.take(lines.size - 1).filter(String::isNotEmpty) diff --git a/app/src/main/java/com/tari/android/wallet/model/WalletError.kt b/app/src/main/java/com/tari/android/wallet/model/WalletError.kt index 00989d0ec..4dc569954 100644 --- a/app/src/main/java/com/tari/android/wallet/model/WalletError.kt +++ b/app/src/main/java/com/tari/android/wallet/model/WalletError.kt @@ -38,11 +38,11 @@ open class WalletError : CoreError { override fun newArray(size: Int): Array = arrayOfNulls(size) } - internal fun createFromFFI(error: FFIError): WalletError = WalletError(error.code) + fun createFromFFI(error: FFIError): WalletError = WalletError(error.code) - internal fun createFromFFI(error: FFIException): WalletError = WalletError(error.error?.code ?: NoError.code) + fun createFromFFI(error: FFIException): WalletError = WalletError(error.error?.code ?: NoError.code) - internal fun createFromException(e: Throwable?): WalletError { + fun createFromException(e: Throwable?): WalletError { if (e is FFIException) { return createFromFFI(e) } else if (e is WalletException) { @@ -53,7 +53,7 @@ open class WalletError : CoreError { } } -internal fun throwIf(error: CoreError?) { +fun throwIf(error: CoreError?) { if (error != null && error.code != 0) { throw WalletException(error) } diff --git a/app/src/main/java/com/tari/android/wallet/model/seedPhrase/SeedPhrase.kt b/app/src/main/java/com/tari/android/wallet/model/seedPhrase/SeedPhrase.kt index 1449a1aca..c375459b6 100644 --- a/app/src/main/java/com/tari/android/wallet/model/seedPhrase/SeedPhrase.kt +++ b/app/src/main/java/com/tari/android/wallet/model/seedPhrase/SeedPhrase.kt @@ -2,7 +2,7 @@ package com.tari.android.wallet.model.seedPhrase import com.tari.android.wallet.ffi.FFISeedWords -internal class SeedPhrase { +class SeedPhrase { var ffiSeedWords: FFISeedWords? = null private set diff --git a/app/src/main/java/com/tari/android/wallet/network/NetworkConnectionStateReceiver.kt b/app/src/main/java/com/tari/android/wallet/network/NetworkConnectionStateReceiver.kt index 71f7c92b4..d25269555 100644 --- a/app/src/main/java/com/tari/android/wallet/network/NetworkConnectionStateReceiver.kt +++ b/app/src/main/java/com/tari/android/wallet/network/NetworkConnectionStateReceiver.kt @@ -34,10 +34,13 @@ package com.tari.android.wallet.network import android.content.BroadcastReceiver import android.content.Context +import android.content.Context.CONNECTIVITY_SERVICE import android.content.Intent import android.content.IntentFilter import android.net.ConnectivityManager -import android.net.NetworkInfo +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.os.Build +import androidx.annotation.RequiresApi import com.orhanobut.logger.Logger import com.tari.android.wallet.event.EventBus @@ -46,10 +49,12 @@ import com.tari.android.wallet.event.EventBus * * @author The Tari Development Team */ -internal class NetworkConnectionStateReceiver : BroadcastReceiver() { +class NetworkConnectionStateReceiver : BroadcastReceiver() { private val action = "android.net.conn.CONNECTIVITY_CHANGE" val intentFilter = IntentFilter(action) + private val logger + get() = Logger.t(NetworkConnectionStateReceiver::class.simpleName) init { EventBus.networkConnectionState.post(NetworkConnectionState.UNKNOWN) @@ -60,20 +65,33 @@ internal class NetworkConnectionStateReceiver : BroadcastReceiver() { return } val mContext = context ?: return - if (checkConnection(mContext)) { - Logger.d("Connected to the internet.") + if (isInternetAvailable(mContext)) { + logger.i("Connected to the internet") EventBus.networkConnectionState.post(NetworkConnectionState.CONNECTED) } else { - Logger.d("Disconnected from the internet.") + logger.i("Disconnected from the internet") EventBus.networkConnectionState.post(NetworkConnectionState.DISCONNECTED) } } - private fun checkConnection(context: Context): Boolean { - // check network connection status - val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager - val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo - return activeNetwork?.isConnected ?: false + private fun isInternetAvailable(context: Context): Boolean = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + isConnectedNewApi(context) + } else { + isConnectedOld(context) } + @Suppress("DEPRECATION") + fun isConnectedOld(context: Context): Boolean { + val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager + val networkInfo = connManager.activeNetworkInfo + return networkInfo?.isConnected == true + + } + + @RequiresApi(Build.VERSION_CODES.M) + fun isConnectedNewApi(context: Context): Boolean { + val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager + val capabilities = cm.getNetworkCapabilities(cm.activeNetwork) + return capabilities?.hasCapability(NET_CAPABILITY_INTERNET) == true + } } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/notification/CustomTxNotificationViewHolder.kt b/app/src/main/java/com/tari/android/wallet/notification/CustomTxNotificationViewHolder.kt similarity index 62% rename from app/src/main/java/com/tari/android/wallet/ui/notification/CustomTxNotificationViewHolder.kt rename to app/src/main/java/com/tari/android/wallet/notification/CustomTxNotificationViewHolder.kt index 19034afdf..7f0abef91 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/notification/CustomTxNotificationViewHolder.kt +++ b/app/src/main/java/com/tari/android/wallet/notification/CustomTxNotificationViewHolder.kt @@ -30,7 +30,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.notification +package com.tari.android.wallet.notification import android.app.KeyguardManager import android.content.Context @@ -72,25 +72,13 @@ class CustomTxNotificationViewHolder(val context: Context, tx: Tx) : } private fun displayTxContactAlias(contact: Contact) { - setTextViewText( - R.id.notification_tx_received_txt_contact_alias, - contact.alias - ) - setViewVisibility( - R.id.notification_tx_received_vw_emoji_summary, - View.INVISIBLE - ) + setTextViewText(R.id.notification_tx_received_txt_contact_alias, contact.alias) + setViewVisibility(R.id.notification_tx_received_vw_emoji_summary, View.INVISIBLE) } private fun displayTxUserEmojiId(user: User) { - setTextViewText( - R.id.notification_tx_received_txt_contact_alias, - "" - ) - setViewVisibility( - R.id.notification_tx_received_txt_contact_alias, - View.INVISIBLE - ) + setTextViewText(R.id.notification_tx_received_txt_contact_alias, "") + setViewVisibility(R.id.notification_tx_received_txt_contact_alias, View.INVISIBLE) val emojis = ArrayList() val it: BreakIterator = BreakIterator.getCharacterInstance() it.setText(user.publicKey.emojiId) @@ -103,82 +91,37 @@ class CustomTxNotificationViewHolder(val context: Context, tx: Tx) : emojis.add(builder.toString()) previous = it.current() } - setTextViewText( - R.id.emoji_id_summary_emoji_1_text_view, - emojis[0] - ) - setTextViewText( - R.id.emoji_id_summary_emoji_2_text_view, - emojis[1] - ) - setTextViewText( - R.id.emoji_id_summary_emoji_3_text_view, - emojis[2] - ) - setTextViewText( - R.id.emoji_id_summary_emoji_4_text_view, - emojis.takeLast(3)[0] - ) - setTextViewText( - R.id.emoji_id_summary_emoji_5_text_view, - emojis.takeLast(2)[0] - ) - setTextViewText( - R.id.emoji_id_summary_emoji_6_text_view, - emojis.takeLast(1)[0] - ) + setTextViewText(R.id.emoji_id_summary_emoji_1_text_view, emojis[0]) + setTextViewText(R.id.emoji_id_summary_emoji_2_text_view, emojis[1]) + setTextViewText(R.id.emoji_id_summary_emoji_3_text_view, emojis[2]) + setTextViewText(R.id.emoji_id_summary_emoji_4_text_view, emojis.takeLast(3)[0]) + setTextViewText(R.id.emoji_id_summary_emoji_5_text_view, emojis.takeLast(2)[0]) + setTextViewText(R.id.emoji_id_summary_emoji_6_text_view, emojis.takeLast(1)[0]) } private fun displayTxMessage(message: String) { - setTextViewText( - R.id.notification_tx_received_txt_message, - message - ) + setTextViewText(R.id.notification_tx_received_txt_message, message) } private fun displayIncomingTxValue(amount: MicroTari, deviceIsLocked: Boolean) { if (deviceIsLocked) { - setTextViewText( - R.id.notification_tx_received_txt_positive_amount, - context.getString(R.string.common_new_uppercase) - ) + setTextViewText(R.id.notification_tx_received_txt_positive_amount, context.getString(R.string.common_new_uppercase)) } else { val formattedValue = "+" + WalletUtil.amountFormatter.format(amount.tariValue) - setTextViewText( - R.id.notification_tx_received_txt_positive_amount, - formattedValue - ) + setTextViewText(R.id.notification_tx_received_txt_positive_amount, formattedValue) } - setViewVisibility( - R.id.notification_tx_received_txt_positive_amount, - View.VISIBLE - ) - setViewVisibility( - R.id.notification_tx_received_txt_negative_amount, - View.GONE - ) + setViewVisibility(R.id.notification_tx_received_txt_positive_amount, View.VISIBLE) + setViewVisibility(R.id.notification_tx_received_txt_negative_amount, View.GONE) } private fun displayOutgoingTxValue(amount: MicroTari, deviceIsLocked: Boolean) { if (deviceIsLocked) { - setTextViewText( - R.id.notification_tx_received_txt_negative_amount, - context.getString(R.string.common_new_uppercase) - ) + setTextViewText(R.id.notification_tx_received_txt_negative_amount, context.getString(R.string.common_new_uppercase)) } else { val formattedValue = "-" + WalletUtil.amountFormatter.format(amount.tariValue) - setTextViewText( - R.id.notification_tx_received_txt_negative_amount, - formattedValue - ) + setTextViewText(R.id.notification_tx_received_txt_negative_amount, formattedValue) } - setViewVisibility( - R.id.notification_tx_received_txt_negative_amount, - View.VISIBLE - ) - setViewVisibility( - R.id.notification_tx_received_txt_positive_amount, - View.GONE - ) + setViewVisibility(R.id.notification_tx_received_txt_negative_amount, View.VISIBLE) + setViewVisibility(R.id.notification_tx_received_txt_positive_amount, View.GONE) } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/GiphyEcosystem.kt b/app/src/main/java/com/tari/android/wallet/notification/NotificationBroadcastReceiver.kt similarity index 53% rename from app/src/main/java/com/tari/android/wallet/ui/common/gyphy/GiphyEcosystem.kt rename to app/src/main/java/com/tari/android/wallet/notification/NotificationBroadcastReceiver.kt index 554cbafef..0ff275aad 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/GiphyEcosystem.kt +++ b/app/src/main/java/com/tari/android/wallet/notification/NotificationBroadcastReceiver.kt @@ -30,35 +30,38 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.common.gyphy +package com.tari.android.wallet.notification +import android.content.BroadcastReceiver import android.content.Context -import com.giphy.sdk.core.models.Media -import com.giphy.sdk.ui.Giphy -import java.util.concurrent.ConcurrentHashMap +import android.content.Intent +import com.orhanobut.logger.Logger +import com.tari.android.wallet.event.EventBus +import com.tari.android.wallet.model.recovery.WalletRestorationResult +import com.tari.android.wallet.ui.fragment.splash.SplashActivity +import com.tari.android.wallet.ui.fragment.home.HomeActivity +import com.tari.android.wallet.ui.fragment.restore.restore.WalletRestoreActivity -internal class GiphyEcosystem( - private val context: Context, - private val key: String -) { +class NotificationBroadcastReceiver : BroadcastReceiver() { - companion object { + private val logger + get() = Logger.t(NotificationBroadcastReceiver::class.simpleName) - private const val cacheCountLimit = 50 - - private val mediaCache = ConcurrentHashMap() - - fun cacheMedia(id: String, media: Media) { - if (mediaCache.size == cacheCountLimit) { - mediaCache.remove(mediaCache.keys.random()) + override fun onReceive(context: Context, intent: Intent) { + logger.d("NotificationBroadcastReceiver received") + val restorationState = EventBus.walletRestorationState.publishSubject.value + val newIntent: Intent = if (restorationState != null && restorationState !is WalletRestorationResult.Completed) { + Intent(context, WalletRestoreActivity::class.java) + } else { + if (HomeActivity.instance.get() != null) { + Intent(context, HomeActivity::class.java) + } else { + Intent(context, SplashActivity::class.java) } - mediaCache[id] = media } - - fun getCachedMedia(id: String): Media? = mediaCache[id] - + context.startActivity(newIntent.apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.extras?.let { putExtras(it) } + }) } - - fun enable() = Giphy.configure(context, key) - -} +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/notification/NotificationHelper.kt b/app/src/main/java/com/tari/android/wallet/notification/NotificationHelper.kt index 2f174538b..9dbabb60a 100644 --- a/app/src/main/java/com/tari/android/wallet/notification/NotificationHelper.kt +++ b/app/src/main/java/com/tari/android/wallet/notification/NotificationHelper.kt @@ -48,10 +48,7 @@ import com.tari.android.wallet.R import com.tari.android.wallet.model.CancelledTx import com.tari.android.wallet.model.Tx import com.tari.android.wallet.model.TxId -import com.tari.android.wallet.ui.activity.home.HomeActivity -import com.tari.android.wallet.ui.activity.home.HomeDeeplinkScreens -import com.tari.android.wallet.ui.notification.CustomTxNotificationViewHolder -import com.tari.android.wallet.ui.notification.TxCanceledViewHolder +import com.tari.android.wallet.ui.fragment.home.HomeDeeplinkScreens import com.tari.android.wallet.util.WalletUtil /** @@ -59,19 +56,19 @@ import com.tari.android.wallet.util.WalletUtil * * @author The Tari Development Team */ -internal class NotificationHelper(private val context: Context) { +class NotificationHelper(private val context: Context) { companion object { // notification channel id - private const val SERVICE_NOTIFICATION_CHANNEL_ID = - "com.tari.android.wallet.service.WALLET_SERVICE_NOTIFICATION" - private const val APP_NOTIFICATION_CHANNEL_ID = - "com.tari.android.wallet.WALLET_NOTIFICATION" + private const val SERVICE_NOTIFICATION_CHANNEL_ID = "com.tari.android.wallet.service.WALLET_SERVICE_NOTIFICATION" + private const val APP_NOTIFICATION_CHANNEL_ID = "com.tari.android.wallet.WALLET_NOTIFICATION" private const val APP_NOTIFICATION_GROUP_ID = 1000 private const val APP_NOTIFICATION_GROUP_NAME = "com.tari.android.wallet.notification.TX" } private var notificationManager = NotificationManagerCompat.from(context) + private val logger + get() = Logger.t(NotificationHelper::class.simpleName) fun createNotificationChannels() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -98,17 +95,15 @@ internal class NotificationHelper(private val context: Context) { importance = NotificationManager.IMPORTANCE_HIGH } notificationManager.createNotificationChannel(appNotificationChannel) + logger.i("Channels was created") } } fun buildForegroundServiceNotification(): Notification { - val intent = Intent(context, HomeActivity::class.java) - val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) + val intent = Intent(context, NotificationBroadcastReceiver::class.java) + val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) // prepare foreground service notification - return NotificationCompat.Builder( - context, - SERVICE_NOTIFICATION_CHANNEL_ID - ).run { + return NotificationCompat.Builder(context, SERVICE_NOTIFICATION_CHANNEL_ID).run { setContentTitle(context.getString(R.string.wallet_service_title)) setContentText(context.getString(R.string.wallet_service_description)) setContentIntent(pendingIntent) @@ -118,39 +113,32 @@ internal class NotificationHelper(private val context: Context) { } } - private val txGroupNotification: Notification = - NotificationCompat.Builder( - context, - APP_NOTIFICATION_CHANNEL_ID - ).run { - setGroupSummary(true) - setSmallIcon(R.drawable.home_tx_icon) - setGroup(APP_NOTIFICATION_GROUP_NAME) - setAutoCancel(true) - setGroupSummary(true) - build() - } + private val txGroupNotification: Notification = NotificationCompat.Builder(context, APP_NOTIFICATION_CHANNEL_ID).run { + setGroupSummary(true) + setSmallIcon(R.drawable.home_tx_icon) + setGroup(APP_NOTIFICATION_GROUP_NAME) + setAutoCancel(true) + setGroupSummary(true) + build() + } /** * Posts custom-layout heads-up transaction notification. */ fun postCustomLayoutTxNotification(tx: Tx) { + logger.i("postCustomLayoutTxNotification: ${tx.id}") val notificationTitle = context.getString(R.string.notification_tx_received_title) // format spannable string - val formattedAmount = - if (tx.amount.tariValue.toDouble() % 1 == 0.toDouble()) - tx.amount.tariValue.toBigInteger().toString() - else WalletUtil.amountFormatter.format(tx.amount.tariValue) + val formattedAmount = if (tx.amount.tariValue.toDouble() % 1 == 0.toDouble()) tx.amount.tariValue.toBigInteger().toString() + else WalletUtil.amountFormatter.format(tx.amount.tariValue) val notificationBody = context.getString(R.string.notification_tx_received_description_format, formattedAmount) val layout = CustomTxNotificationViewHolder(context, tx) - val intents = arrayOf( - Intent(context, HomeActivity::class.java).apply { - flags = FLAG_ACTIVITY_CLEAR_TOP - putExtra(HomeDeeplinkScreens.Key, HomeDeeplinkScreens.TxDetails.name) - putExtra(HomeDeeplinkScreens.KeyTxDetailsArgs, TxId(tx.id)) - }, - ) - val pendingIntent = PendingIntent.getActivities(context, 0, intents, PendingIntent.FLAG_IMMUTABLE) + val intent = Intent(context, NotificationBroadcastReceiver::class.java).apply { + flags = FLAG_ACTIVITY_CLEAR_TOP + putExtra(HomeDeeplinkScreens.Key, HomeDeeplinkScreens.TxDetails.name) + putExtra(HomeDeeplinkScreens.KeyTxDetailsArgs, TxId(tx.id)) + } + val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) // prepare transaction notification val notification: Notification = NotificationCompat.Builder(context, APP_NOTIFICATION_CHANNEL_ID).run { @@ -162,8 +150,6 @@ internal class NotificationHelper(private val context: Context) { setStyle(NotificationCompat.DecoratedCustomViewStyle()) setCustomContentView(layout) setAutoCancel(true) - //setCustomBigContentView(notificationLayout) - //setCustomHeadsUpContentView(notificationLayout) setGroup(APP_NOTIFICATION_GROUP_NAME) setCategory(NotificationCompat.CATEGORY_EVENT) priority = NotificationCompat.PRIORITY_MAX @@ -177,16 +163,15 @@ internal class NotificationHelper(private val context: Context) { } fun postTxCanceledNotification(tx: CancelledTx) { - Logger.i("postTxCanceledNotification: $tx") + logger.i("postTxCanceledNotification: ${tx.id}") val layout = TxCanceledViewHolder(context, tx) - val intents = arrayOf( - Intent(context, HomeActivity::class.java).apply { - flags = FLAG_ACTIVITY_CLEAR_TOP - putExtra(HomeDeeplinkScreens.Key, HomeDeeplinkScreens.TxDetails.name) - putExtra(HomeDeeplinkScreens.KeyTxDetailsArgs, TxId(tx.id)) - }, - ) - val pendingIntent = PendingIntent.getActivities(context, 0, intents, PendingIntent.FLAG_IMMUTABLE) + val intent = Intent(context, NotificationBroadcastReceiver::class.java).apply { + flags = FLAG_ACTIVITY_CLEAR_TOP + putExtra(HomeDeeplinkScreens.Key, HomeDeeplinkScreens.TxDetails.name) + putExtra(HomeDeeplinkScreens.KeyTxDetailsArgs, TxId(tx.id)) + } + + val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) val notification = NotificationCompat.Builder(context, APP_NOTIFICATION_CHANNEL_ID).run { setSmallIcon(R.drawable.tx_notification_icon) setDefaults(DEFAULT_ALL) @@ -215,7 +200,6 @@ internal class NotificationHelper(private val context: Context) { setContentText(body) setSmallIcon(R.drawable.notification_icon) setDefaults(DEFAULT_ALL) - // setContentIntent(pendingIntent) setGroup(APP_NOTIFICATION_GROUP_NAME) setCategory(NotificationCompat.CATEGORY_EVENT) priority = NotificationCompat.PRIORITY_MAX @@ -226,5 +210,4 @@ internal class NotificationHelper(private val context: Context) { notificationManager.notify(APP_NOTIFICATION_GROUP_ID, txGroupNotification) notificationManager.notify(System.currentTimeMillis().toInt(), notification) } - } diff --git a/app/src/main/java/com/tari/android/wallet/ui/notification/TxCanceledViewHolder.kt b/app/src/main/java/com/tari/android/wallet/notification/TxCanceledViewHolder.kt similarity index 98% rename from app/src/main/java/com/tari/android/wallet/ui/notification/TxCanceledViewHolder.kt rename to app/src/main/java/com/tari/android/wallet/notification/TxCanceledViewHolder.kt index 8543b0525..6aaf43475 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/notification/TxCanceledViewHolder.kt +++ b/app/src/main/java/com/tari/android/wallet/notification/TxCanceledViewHolder.kt @@ -30,7 +30,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.notification +package com.tari.android.wallet.notification import android.app.KeyguardManager import android.content.Context diff --git a/app/src/main/java/com/tari/android/wallet/service/BootDeviceReceiver.kt b/app/src/main/java/com/tari/android/wallet/service/BootDeviceReceiver.kt index 05af78fab..daf3fbd39 100644 --- a/app/src/main/java/com/tari/android/wallet/service/BootDeviceReceiver.kt +++ b/app/src/main/java/com/tari/android/wallet/service/BootDeviceReceiver.kt @@ -40,6 +40,7 @@ import com.tari.android.wallet.data.WalletConfig import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepositoryImpl import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository import com.tari.android.wallet.di.ApplicationModule +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.domain.ResourceManager /** @@ -49,9 +50,12 @@ import com.tari.android.wallet.ui.common.domain.ResourceManager */ class BootDeviceReceiver : BroadcastReceiver() { + private val logger + get() = Logger.t(BootDeviceReceiver::class.simpleName) + override fun onReceive(context: Context?, intent: Intent?) { if (context == null || intent == null) return - Logger.d("Boot device broadcast received.") + logger.i("Boot device broadcast received") if (Intent.ACTION_BOOT_COMPLETED == intent.action) { val resourceManager = ResourceManager(context) val sharedPreferences = context.getSharedPreferences(ApplicationModule.sharedPrefsFileName, Context.MODE_PRIVATE) diff --git a/app/src/main/java/com/tari/android/wallet/service/ServiceRestartBroadcastReceiver.kt b/app/src/main/java/com/tari/android/wallet/service/ServiceRestartBroadcastReceiver.kt index c2f27763a..f191ae55b 100644 --- a/app/src/main/java/com/tari/android/wallet/service/ServiceRestartBroadcastReceiver.kt +++ b/app/src/main/java/com/tari/android/wallet/service/ServiceRestartBroadcastReceiver.kt @@ -40,6 +40,7 @@ import com.tari.android.wallet.data.WalletConfig import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepositoryImpl import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository import com.tari.android.wallet.di.ApplicationModule +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.domain.ResourceManager /** @@ -50,8 +51,11 @@ import com.tari.android.wallet.ui.common.domain.ResourceManager */ class ServiceRestartBroadcastReceiver : BroadcastReceiver() { + private val logger + get() = Logger.t(ServiceRestartBroadcastReceiver::class.simpleName) + override fun onReceive(context: Context, intent: Intent) { - Logger.d("Service restart broadcast received.") + logger.i("Service restart broadcast received") val resourceManager = ResourceManager(context) val sharedPreferences = context.getSharedPreferences(ApplicationModule.sharedPrefsFileName, Context.MODE_PRIVATE) val networkRepository = NetworkRepositoryImpl(resourceManager, sharedPreferences) diff --git a/app/src/main/java/com/tari/android/wallet/service/WalletService.kt b/app/src/main/java/com/tari/android/wallet/service/WalletService.kt deleted file mode 100644 index 97388d029..000000000 --- a/app/src/main/java/com/tari/android/wallet/service/WalletService.kt +++ /dev/null @@ -1,1115 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.service - -import android.app.Service -import android.content.Intent -import android.os.Handler -import android.os.IBinder -import android.os.Looper -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.OnLifecycleEvent -import androidx.lifecycle.ProcessLifecycleOwner -import com.orhanobut.logger.Logger -import com.tari.android.wallet.R -import com.tari.android.wallet.application.TariWalletApplication -import com.tari.android.wallet.application.WalletManager -import com.tari.android.wallet.application.WalletState -import com.tari.android.wallet.application.baseNodes.BaseNodes -import com.tari.android.wallet.data.WalletConfig -import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository -import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository -import com.tari.android.wallet.data.sharedPrefs.testnetFaucet.TestnetFaucetRepository -import com.tari.android.wallet.data.sharedPrefs.testnetFaucet.TestnetUtxoList -import com.tari.android.wallet.data.sharedPrefs.testnetFaucet.orEmpty -import com.tari.android.wallet.di.DiContainer -import com.tari.android.wallet.event.Event -import com.tari.android.wallet.event.EventBus -import com.tari.android.wallet.ffi.* -import com.tari.android.wallet.infrastructure.backup.BackupManager -import com.tari.android.wallet.model.* -import com.tari.android.wallet.model.Tx.Direction.INBOUND -import com.tari.android.wallet.model.recovery.WalletRestorationResult -import com.tari.android.wallet.notification.NotificationHelper -import com.tari.android.wallet.service.WalletServiceLauncher.Companion.startAction -import com.tari.android.wallet.service.WalletServiceLauncher.Companion.stopAction -import com.tari.android.wallet.service.WalletServiceLauncher.Companion.stopAndDeleteAction -import com.tari.android.wallet.service.baseNode.BaseNodeState -import com.tari.android.wallet.service.baseNode.BaseNodeSyncState -import com.tari.android.wallet.service.faucet.TestnetFaucetService -import com.tari.android.wallet.service.faucet.TestnetTariRequestException -import com.tari.android.wallet.service.notification.NotificationService -import com.tari.android.wallet.ui.activity.home.HomeActivity -import com.tari.android.wallet.ui.extension.string -import com.tari.android.wallet.util.Constants -import com.tari.android.wallet.util.WalletUtil -import io.reactivex.Observable -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import org.joda.time.DateTime -import org.joda.time.Hours -import org.joda.time.Minutes -import java.math.BigInteger -import java.util.* -import java.util.concurrent.* -import javax.inject.Inject - -/** - * Foreground wallet service. - * - * @author The Tari Development Team - */ -internal class WalletService : Service(), FFIWalletListener, LifecycleObserver { - - companion object { - // notification id - private const val NOTIFICATION_ID = 1 - private const val MESSAGE_PREFIX = "Hello Tari from" - - // key-value storage keys - object KeyValueStorageKeys { - const val NETWORK = "SU7FM2O6Q3BU4XVN7HDD" - } - } - - @Inject - lateinit var walletConfig: WalletConfig - - @Inject - lateinit var app: TariWalletApplication - - @Inject - lateinit var testnetFaucetService: TestnetFaucetService - - @Inject - lateinit var notificationService: NotificationService - - @Inject - lateinit var notificationHelper: NotificationHelper - - @Inject - lateinit var sharedPrefsWrapper: SharedPrefsRepository - - @Inject - lateinit var baseNodeSharedPrefsRepository: BaseNodeSharedRepository - - @Inject - lateinit var walletManager: WalletManager - - @Inject - lateinit var backupManager: BackupManager - - @Inject - lateinit var baseNodes: BaseNodes - - @Inject - lateinit var testnetFaucetRepository: TestnetFaucetRepository - - private lateinit var wallet: FFIWallet - - private var txBroadcastRestarted = false - - /** - * Pairs of . - */ - private val outboundTxIdsToBePushNotified = CopyOnWriteArraySet>() - - /** - * Service stub implementation. - */ - private val serviceImpl = TariWalletServiceImpl() - - /** - * Registered listeners. - */ - private var listeners = CopyOnWriteArrayList() - - /** - * Check for expired txs every 30 minutes. - */ - private val expirationCheckPeriodMinutes = Minutes.minutes(30) - - /** - * Switch to low power mode 3 minutes after the app gets backgrounded. - */ - private val backgroundLowPowerModeSwitchMinutes = Minutes.minutes(3) - - /** - * Timer to trigger the expiration checks. - */ - private var txExpirationCheckSubscription: Disposable? = null - - private var lowPowerModeSubscription: Disposable? = null - - private enum class BaseNodeValidationType { - TXO, - TX; - } - - /** - * Maps the validation type to the request id and validation result. This map will be - * initialized at the beginning of each base node validation sequence. - * Validation results will all be null, and will be set as the result callbacks get called. - */ - private var baseNodeValidationStatusMap: ConcurrentMap> = ConcurrentHashMap() - - /** - * Debounce for inbound transaction notification. - */ - private var txReceivedNotificationDelayedAction: Disposable? = null - private var inboundTxEventNotificationTxs = mutableListOf() - - - override fun onCreate() { - super.onCreate() - DiContainer.appComponent.inject(this) - } - - - private fun checkBaseNodeSyncCompletion() { - // make a copy of the status map for concurrency protection - val statusMapCopy = baseNodeValidationStatusMap.toMap() - // if base node not in sync, then switch to the next base node - // check if any has failed - val failed = statusMapCopy.any { it.value.second == false } - if (failed) { - baseNodeValidationStatusMap.clear() - baseNodeSharedPrefsRepository.baseNodeLastSyncResult = false - val currentBaseNode = baseNodeSharedPrefsRepository.currentBaseNode - if (currentBaseNode == null || !currentBaseNode.isCustom) { - baseNodes.setNextBaseNode() - } - EventBus.baseNodeSyncState.post(BaseNodeSyncState.Failed) - listeners.iterator().forEach { it.onBaseNodeSyncComplete(false) } - return - } - // if any of the results is null, we're still waiting for all callbacks to happen - val inProgress = statusMapCopy.any { it.value.second == null } - if (inProgress) { - return - } - // check if it's successful - val successful = statusMapCopy.all { it.value.second == true } - if (successful) { - baseNodeValidationStatusMap.clear() - baseNodeSharedPrefsRepository.baseNodeLastSyncResult = true - EventBus.baseNodeSyncState.post(BaseNodeSyncState.Online) - listeners.iterator().forEach { it.onBaseNodeSyncComplete(true) } - } - // shouldn't ever reach here - no-op - } - - private fun checkValidationResult(type: BaseNodeValidationType, responseId: BigInteger, isSuccess: Boolean) { - val currentStatus = baseNodeValidationStatusMap[type] - if (currentStatus == null) { - Logger.d(type.name + " validation [$responseId] complete. Result: $isSuccess. Current status is null, means we're not expecting a callback. Ignoring.") - return - } - if (currentStatus.first != responseId) { - Logger.d(type.name + " Validation [$responseId] complete. Result: $isSuccess. Request id [${currentStatus.first}] mismatch. Ignoring.") - return - } - Logger.d(type.name + " Validation [$responseId] complete. Result: $isSuccess.") - baseNodeValidationStatusMap[type] = Pair(currentStatus.first, isSuccess) - checkBaseNodeSyncCompletion() - } - - /** - * Called when a component decides to start or stop the foreground wallet service. - */ - override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { - startForeground() - when (intent.action) { - startAction -> startService() - stopAction -> stopService(startId) - stopAndDeleteAction -> { - //todo total crutch. Service is auto-creating during the bind func. Need to refactor this first - DiContainer.appComponent.inject(this) - stopService(startId) - deleteWallet() - } - else -> throw RuntimeException("Unexpected intent action: ${intent.action}") - } - return START_NOT_STICKY - } - - - private fun startService() { - //todo total crutch. Service is auto-creating during the bind func. Need to refactor this first - DiContainer.appComponent.inject(this) - // start wallet manager on a separate thread & listen to events - EventBus.walletState.subscribe(this, this::onWalletStateChanged) - Thread { - walletManager.start() - }.start() - Logger.d("Wallet service started.") - } - - private fun startForeground() { - // start service & post foreground service notification - val notification = notificationHelper.buildForegroundServiceNotification() - startForeground(NOTIFICATION_ID, notification) - } - - private fun stopService(startId: Int) { - // stop service - stopForeground(true) - stopSelfResult(startId) - // stop wallet manager on a separate thread & unsubscribe from events - EventBus.walletState.unsubscribe(this) - ProcessLifecycleOwner.get().lifecycle.removeObserver(this) - GlobalScope.launch { backupManager.turnOff(deleteExistingBackups = false) } - Thread { - walletManager.stop() - }.start() - } - - private fun deleteWallet() { - WalletUtil.clearWalletFiles(walletConfig.getWalletFilesDirPath()) - sharedPrefsWrapper.clear() - } - - private fun onWalletStateChanged(walletState: WalletState) { - if (walletState == WalletState.Started) { - wallet = FFIWallet.instance!! - wallet.listener = this - EventBus.walletState.unsubscribe(this) - scheduleExpirationCheck() - backupManager.initialize() - val handler = Handler(Looper.getMainLooper()) - handler.post { - ProcessLifecycleOwner.get().lifecycle.addObserver(this) - } - EventBus.walletState.post(WalletState.Running) - } - } - - private fun scheduleExpirationCheck() { - txExpirationCheckSubscription = - Observable - .timer(expirationCheckPeriodMinutes.minutes.toLong(), TimeUnit.MINUTES) - .repeat() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .subscribe { - cancelExpiredPendingInboundTxs() - cancelExpiredPendingOutboundTxs() - } - } - - /** - * Bound service. - */ - override fun onBind(intent: Intent?): IBinder { - Logger.d("Wallet service bound.") - return serviceImpl - } - - override fun onUnbind(intent: Intent?): Boolean { - Logger.d("Wallet service unbound.") - return super.onUnbind(intent) - } - - /** - * A broadcast is made on destroy to get the service running again. - */ - override fun onDestroy() { - Logger.d("Wallet service destroyed.") - txExpirationCheckSubscription?.dispose() - sendBroadcast( - Intent(this, ServiceRestartBroadcastReceiver::class.java) - ) - super.onDestroy() - } - - @OnLifecycleEvent(Lifecycle.Event.ON_STOP) - fun onAppBackgrounded() { - // schedule low power mode - lowPowerModeSubscription = - Observable - .timer(backgroundLowPowerModeSwitchMinutes.minutes.toLong(), TimeUnit.MINUTES) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .subscribe { - switchToLowPowerMode() - } - } - - @OnLifecycleEvent(Lifecycle.Event.ON_START) - fun onAppForegrounded() { - switchToNormalPowerMode() - } - - private fun switchToNormalPowerMode() { - Logger.d("Switch to normal power mode.") - lowPowerModeSubscription?.dispose() - try { - wallet.setPowerModeNormal() - } catch (e: FFIException) { // silent fail - Logger.e("FFI error #${e.error?.code} while switching to normal power mode.") - } - } - - private fun switchToLowPowerMode() { - Logger.d("Switch to low power mode.") - try { - wallet.setPowerModeLow() - } catch (e: FFIException) { // silent fail - Logger.e("FFI error #${e.error?.code} while switching to low power mode.") - } - } - - override fun onTxReceived(pendingInboundTx: PendingInboundTx) { - Logger.d("Tx received: $pendingInboundTx") - pendingInboundTx.user = getUserByPublicKey(pendingInboundTx.user.publicKey) - Logger.d("Received TX after contact update: $pendingInboundTx") - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.TxReceived(pendingInboundTx)) - // manage notifications - postTxNotification(pendingInboundTx) - listeners.forEach { it.onTxReceived(pendingInboundTx) } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onTxReplyReceived(pendingOutboundTx: PendingOutboundTx) { - Logger.d("Tx ${pendingOutboundTx.id} reply received.") - pendingOutboundTx.user = getUserByPublicKey(pendingOutboundTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.TxReplyReceived(pendingOutboundTx)) - // notify external listeners - listeners.iterator().forEach { - it.onTxReplyReceived(pendingOutboundTx) - } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onTxFinalized(pendingInboundTx: PendingInboundTx) { - Logger.d("Tx ${pendingInboundTx.id} finalized.") - pendingInboundTx.user = getUserByPublicKey(pendingInboundTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.TxFinalized(pendingInboundTx)) - // notify external listeners - listeners.iterator().forEach { - it.onTxFinalized(pendingInboundTx) - } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onInboundTxBroadcast(pendingInboundTx: PendingInboundTx) { - Logger.d("Inbound tx ${pendingInboundTx.id} broadcast.") - pendingInboundTx.user = getUserByPublicKey(pendingInboundTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.InboundTxBroadcast(pendingInboundTx)) - // notify external listeners - listeners.iterator().forEach { - it.onInboundTxBroadcast(pendingInboundTx) - } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onOutboundTxBroadcast(pendingOutboundTx: PendingOutboundTx) { - Logger.d("Outbound tx ${pendingOutboundTx.id} broadcast.") - pendingOutboundTx.user = getUserByPublicKey(pendingOutboundTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.OutboundTxBroadcast(pendingOutboundTx)) - // notify external listeners - listeners.iterator().forEach { it.onOutboundTxBroadcast(pendingOutboundTx) } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onTxMined(completedTx: CompletedTx) { - Logger.d("Tx ${completedTx.id} mined.") - completedTx.user = getUserByPublicKey(completedTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.TxMined(completedTx)) - // notify external listeners - listeners.iterator().forEach { - it.onTxMined(completedTx) - } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onTxMinedUnconfirmed(completedTx: CompletedTx, confirmationCount: Int) { - Logger.d("Tx ${completedTx.id} mined, yet unconfirmed. Confirmation count: $confirmationCount") - completedTx.user = getUserByPublicKey(completedTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.TxMinedUnconfirmed(completedTx)) - // notify external listeners - listeners.iterator().forEach { - it.onTxMinedUnconfirmed(completedTx, confirmationCount) - } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onTxFauxConfirmed(completedTx: CompletedTx) { - Logger.d("Tx faux ${completedTx.id} confirmed.") - completedTx.user = getUserByPublicKey(completedTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.TxFauxConfirmed(completedTx)) - // notify external listeners - listeners.iterator().forEach { it.onTxFauxConfirmed(completedTx) } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onTxFauxUnconfirmed(completedTx: CompletedTx, confirmationCount: Int) { - Logger.d("Tx faux ${completedTx.id} yet unconfirmed. Confirmation count: $confirmationCount") - completedTx.user = getUserByPublicKey(completedTx.user.publicKey) - // post event to bus for the internal listeners - EventBus.post(Event.Transaction.TxFauxMinedUnconfirmed(completedTx)) - // notify external listeners - listeners.iterator().forEach { it.onTxFauxUnconfirmed(completedTx, confirmationCount) } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onDirectSendResult(txId: BigInteger, status: TransactionSendStatus) { - Logger.d("Tx $txId direct send completed. Status: ${status.status.value}") - // post event to bus - EventBus.post(Event.Transaction.DirectSendResult(TxId(txId), status)) - outboundTxIdsToBePushNotified.firstOrNull { it.first == txId }?.let { - outboundTxIdsToBePushNotified.remove(it) - sendPushNotificationToTxRecipient(it.second) - } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - // notify external listeners - listeners.iterator().forEach { - it.onDirectSendResult(TxId(txId), status) - } - } - - override fun onTxCancelled(cancelledTx: CancelledTx, rejectionReason: Int) { - Logger.d("Tx cancelled: $cancelledTx") - cancelledTx.user = getUserByPublicKey(cancelledTx.user.publicKey) - // post event to bus - EventBus.post(Event.Transaction.TxCancelled(cancelledTx)) - val currentActivity = app.currentActivity - if (cancelledTx.direction == INBOUND && !(app.isInForeground && currentActivity is HomeActivity && currentActivity.willNotifyAboutNewTx()) - ) { - Logger.i("Posting cancellation notification") - notificationHelper.postTxCanceledNotification(cancelledTx) - } - // notify external listeners - listeners.iterator().forEach { listener -> listener.onTxCancelled(cancelledTx) } - // schedule a backup - backupManager.scheduleBackup(resetRetryCount = true) - } - - override fun onTXOValidationComplete(responseId: BigInteger, isSuccess: Boolean) { - checkValidationResult(BaseNodeValidationType.TXO, responseId, isSuccess) - Logger.i("onTXOValidationComplete responseId: $responseId, isSuccess: $isSuccess") - } - - override fun onTxValidationComplete(responseId: BigInteger, isSuccess: Boolean) { - checkValidationResult(BaseNodeValidationType.TX, responseId, isSuccess) - if (!txBroadcastRestarted && isSuccess) { - try { - wallet.restartTxBroadcast() - txBroadcastRestarted = true - Logger.i("Transaction broadcast restarted.") - } catch (e: Exception) { - Logger.e("Error while restarting tx broadcast: " + e.message) - } - } - } - - override fun onConnectivityStatus(status: Int) { - when (status) { - 1 -> { - baseNodeSharedPrefsRepository.baseNodeState = BaseNodeState.Online.toInt() - EventBus.baseNodeState.post(BaseNodeState.Online) - listeners.iterator().forEach { it.onBaseNodeSyncComplete(true) } - } - 2 -> { - val currentBaseNode = baseNodeSharedPrefsRepository.currentBaseNode - if (currentBaseNode == null || !currentBaseNode.isCustom) { - baseNodes.setNextBaseNode() - } - baseNodeSharedPrefsRepository.baseNodeState = BaseNodeState.Offline.toInt() - EventBus.baseNodeState.post(BaseNodeState.Offline) - listeners.iterator().forEach { it.onBaseNodeSyncComplete(false) } - } - } - } - - override fun onWalletRestoration(result: WalletRestorationResult) { - EventBus.walletRestorationState.post(result) - } - - /** - * Cancels expired pending inbound transactions. - * Expiration period is defined by Constants.Wallet.pendingTxExpirationPeriodHours - */ - private fun cancelExpiredPendingInboundTxs() { - val pendingInboundTxs = wallet.getPendingInboundTxs() - val pendingInboundTxsLength = pendingInboundTxs.getLength() - val now = DateTime.now().toLocalDateTime() - for (i in 0 until pendingInboundTxsLength) { - val tx = pendingInboundTxs.getAt(i) - val txDate = DateTime(tx.getTimestamp().toLong() * 1000L).toLocalDateTime() - val hoursPassed = Hours.hoursBetween(txDate, now).hours - if (hoursPassed >= Constants.Wallet.pendingTxExpirationPeriodHours) { - val success = wallet.cancelPendingTx(tx.getId()) - Logger.d("Expired pending inbound tx ${tx.getId()}. Success: $success.") - } - tx.destroy() - } - pendingInboundTxs.destroy() - } - - /** - * Cancels expired pending outbound transactions. - * Expiration period is defined by Constants.Wallet.pendingTxExpirationPeriodHours - */ - private fun cancelExpiredPendingOutboundTxs() { - val pendingOutboundTxs = wallet.getPendingOutboundTxs() - val pendingOutboundTxsLength = wallet.getPendingOutboundTxs().getLength() - val now = DateTime.now().toLocalDateTime() - for (i in 0 until pendingOutboundTxsLength) { - val tx = pendingOutboundTxs.getAt(i) - val txDate = DateTime(tx.getTimestamp().toLong() * 1000L).toLocalDateTime() - val hoursPassed = Hours.hoursBetween(txDate, now).hours - if (hoursPassed >= Constants.Wallet.pendingTxExpirationPeriodHours) { - val success = wallet.cancelPendingTx(tx.getId()) - Logger.d("Expired pending outbound tx ${tx.getId()}. Success: $success") - } - tx.destroy() - } - - pendingOutboundTxs.destroy() - } - - private fun postTxNotification(tx: Tx) { - txReceivedNotificationDelayedAction?.dispose() - inboundTxEventNotificationTxs.add(tx) - txReceivedNotificationDelayedAction = - Observable - .timer(500, TimeUnit.MILLISECONDS) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) - .subscribe { - // if app is backgrounded, display heads-up notification - val currentActivity = app.currentActivity - if (!app.isInForeground - || currentActivity !is HomeActivity - || !currentActivity.willNotifyAboutNewTx() - ) { - notificationHelper.postCustomLayoutTxNotification( - inboundTxEventNotificationTxs.last() - ) - } - inboundTxEventNotificationTxs.clear() - } - } - - private fun sendPushNotificationToTxRecipient(recipientPublicKeyHex: String) { - // the push notification server accepts lower-case hex strings as of now - val fromPublicKeyHex = wallet.getPublicKey().toString().lowercase(Locale.ENGLISH) - Logger.d( - "Will send push notification to recipient %s from %s.", - recipientPublicKeyHex, - fromPublicKeyHex - ) - notificationService.notifyRecipient( - recipientPublicKeyHex, - fromPublicKeyHex, - wallet::signMessage, - onSuccess = { Logger.i("Push notification successfully sent to recipient.") }, - onFailure = { Logger.e(it, "Push notification failed with exception.") } - ) - } - - private fun getUserByPublicKey(key: PublicKey): User { - val contactsFFI = wallet.getContacts() - for (i in 0 until contactsFFI.getLength()) { - val contactFFI = contactsFFI.getAt(i) - val publicKeyFFI = contactFFI.getPublicKey() - val hex = publicKeyFFI.toString() - val contact = - if (hex == key.hexString) Contact(key, contactFFI.getAlias()) - else null - publicKeyFFI.destroy() - contactFFI.destroy() - if (contact != null) { - contactsFFI.destroy() - return contact - } - } - // destroy native collection - contactsFFI.destroy() - return User(key) - } - - /** - * Implementation of the AIDL service definition. - */ - inner class TariWalletServiceImpl : TariWalletService.Stub() { - - private var _cachedContacts: List? = null - private val cachedContacts: List - @Synchronized get() { - _cachedContacts?.let { - return it - } - val contactsFFI = wallet.getContacts() - val contacts = mutableListOf() - for (i in 0 until contactsFFI.getLength()) { - val contactFFI = contactsFFI.getAt(i) - val publicKeyFFI = contactFFI.getPublicKey() - contacts.add( - Contact( - publicKeyFromFFI(publicKeyFFI), - contactFFI.getAlias() - ) - ) - // destroy native objects - publicKeyFFI.destroy() - contactFFI.destroy() - } - // destroy native collection - contactsFFI.destroy() - return contacts.sortedWith(compareBy { it.alias }).also { - _cachedContacts = it - } - } - - - private fun mapThrowableIntoError(walletError: WalletError, throwable: Throwable) { - if (throwable is FFIException) { - if (throwable.error != null) { - walletError.code = throwable.error.code - return - } - } - walletError.code = WalletError.UnknownError.code - } - - private fun executeWithMapping(walletError: WalletError, onError: (Throwable) -> (Unit) = {}, action: () -> T?): T? { - return try { - action() - } catch (throwable: Throwable) { - onError(throwable) - mapThrowableIntoError(walletError, throwable) - null - } - } - - private fun getContactByPublicKeyHexString(hexString: String): Contact? = cachedContacts.firstOrNull { it.publicKey.hexString == hexString } - - override fun registerListener(listener: TariWalletServiceListener): Boolean { - listeners.add(listener) - listener.asBinder().linkToDeath({ - val removeSuccessful = listeners.remove(listener) - Logger.i("Listener died. Remove successful: $removeSuccessful.") - }, 0) - return true - } - - override fun unregisterListener(listener: TariWalletServiceListener): Boolean = listeners.remove(listener) - - override fun getPublicKeyHexString(error: WalletError): String? = executeWithMapping(error) { wallet.getPublicKey().toString() } - - override fun getBalanceInfo(error: WalletError): BalanceInfo? = executeWithMapping(error) { wallet.getBalance() } - - override fun estimateTxFee(amount: MicroTari, error: WalletError, feePerGram: MicroTari?): MicroTari? = executeWithMapping(error) { - val defaultKernelCount = BigInteger("1") - val defaultOutputCount = BigInteger("2") - MicroTari( - wallet.estimateTxFee( - amount.value, - feePerGram?.value ?: Constants.Wallet.defaultFeePerGram.value, - defaultKernelCount, - defaultOutputCount - ) - ) - } - - /** - * Get all contacts. - */ - override fun getContacts(error: WalletError): List? = executeWithMapping(error) { cachedContacts } - - /** - * Get all completed transactions. - * Client-facing function. - */ - override fun getCompletedTxs(error: WalletError): List? = executeWithMapping(error) { - val completedTxsFFI = wallet.getCompletedTxs() - (0 until completedTxsFFI.getLength()) - .map { CompletedTx(completedTxsFFI.getAt(it)) } - .also { completedTxsFFI.destroy() } - } - - override fun getCancelledTxs(error: WalletError): List? = executeWithMapping(error) { - val canceledTxsFFI = wallet.getCancelledTxs() - (0 until canceledTxsFFI.getLength()) - .map { CancelledTx(canceledTxsFFI.getAt(it)) } - .also { canceledTxsFFI.destroy() } - } - - /** - * Get completed transaction by id. - * Client-facing function. - */ - override fun getCancelledTxById(id: TxId, error: WalletError): CancelledTx? = executeWithMapping(error) { - CancelledTx(wallet.getCancelledTxById(id.value)) - } - - /** - * Get completed transaction by id. - * Client-facing function. - */ - override fun getCompletedTxById(id: TxId, error: WalletError): CompletedTx? = executeWithMapping(error) { - CompletedTx(wallet.getCompletedTxById(id.value)) - } - - /** - * Get all pending inbound transactions. - * Client-facing function. - */ - override fun getPendingInboundTxs(error: WalletError): List? = executeWithMapping(error) { - val pendingInboundTxsFFI = wallet.getPendingInboundTxs() - (0 until pendingInboundTxsFFI.getLength()) - .map { PendingInboundTx(pendingInboundTxsFFI.getAt(it)) } - .also { pendingInboundTxsFFI.destroy() } - } - - /** - * Get pending inbound transaction by id. - * Client-facing function. - */ - override fun getPendingInboundTxById(id: TxId, error: WalletError): PendingInboundTx? = executeWithMapping(error) { - PendingInboundTx(wallet.getPendingInboundTxById(id.value)) - } - - /** - * Get all pending outbound transactions. - * Client-facing function. - */ - override fun getPendingOutboundTxs(error: WalletError): List? = executeWithMapping(error) { - val pendingOutboundTxsFFI = wallet.getPendingOutboundTxs() - (0 until pendingOutboundTxsFFI.getLength()) - .map { PendingOutboundTx(pendingOutboundTxsFFI.getAt(it)) } - .also { pendingOutboundTxsFFI.destroy() } - } - - /** - * Get pending outbound transaction by id. - * Client-facing function. - */ - override fun getPendingOutboundTxById(id: TxId, error: WalletError): PendingOutboundTx? = executeWithMapping(error) { - PendingOutboundTx(wallet.getPendingOutboundTxById(id.value)) - } - - override fun cancelPendingTx(id: TxId, error: WalletError): Boolean = executeWithMapping(error) { - wallet.cancelPendingTx(id.value) - } ?: false - - override fun addBaseNodePeer(baseNodePublicKey: String, baseNodeAddress: String, error: WalletError): Boolean = executeWithMapping(error) { - val publicKeyFFI = FFIPublicKey(HexString(baseNodePublicKey)) - val result = wallet.addBaseNodePeer(publicKeyFFI, baseNodeAddress) - publicKeyFFI.destroy() - if (result) { - baseNodeValidationStatusMap.clear() - EventBus.baseNodeSyncState.post(BaseNodeSyncState.NotStarted) - } - result - } ?: false - - override fun startBaseNodeSync(error: WalletError): Boolean = executeWithMapping(error, { - Logger.e("Base node validation error: $it") - baseNodeSharedPrefsRepository.baseNodeLastSyncResult = false - baseNodeValidationStatusMap.clear() - EventBus.baseNodeSyncState.post(BaseNodeSyncState.Failed) - }) { - baseNodeValidationStatusMap.clear() - baseNodeValidationStatusMap[BaseNodeValidationType.TXO] = Pair(wallet.startTXOValidation(), null) - baseNodeValidationStatusMap[BaseNodeValidationType.TX] = Pair(wallet.startTxValidation(), null) - baseNodeSharedPrefsRepository.baseNodeLastSyncResult = null - true - } ?: false - - override fun sendTari( - user: User, - amount: MicroTari, - feePerGram: MicroTari, - message: String, - isOneSidePayment: Boolean, - error: WalletError - ): TxId? = executeWithMapping(error) { - val recipientPublicKeyHex = user.publicKey.hexString - val publicKeyFFI = FFIPublicKey(HexString(recipientPublicKeyHex)) - val txId = wallet.sendTx(publicKeyFFI, amount.value, feePerGram.value, message, isOneSidePayment) - publicKeyFFI.destroy() - outboundTxIdsToBePushNotified.add(Pair(txId, recipientPublicKeyHex.lowercase(Locale.ENGLISH))) - TxId(txId) - } - - // region FFI to model extraction functions - private fun publicKeyFromFFI(publicKeyFFI: FFIPublicKey): PublicKey { - return PublicKey(publicKeyFFI.toString(), publicKeyFFI.getEmojiId()) - } - - override fun requestTestnetTari(error: WalletError) { - // avoid multiple faucet requests - if (testnetFaucetRepository.faucetTestnetTariRequestCompleted) return - // get public key - val publicKeyHexString = getPublicKeyHexString(error) - if (error.code != WalletError.NoError.code || publicKeyHexString == null) { - notifyTestnetTariRequestFailed("Service error.") - return - } - - val message = "$MESSAGE_PREFIX $publicKeyHexString" - val signing = wallet.signMessage(message).split("|") - val signature = signing[0] - val nonce = signing[1] - - testnetFaucetService.requestMaxTestnetTari( - publicKeyHexString, - signature, - nonce, - { result -> - Logger.i("requestMaxTestnetTari success") - val senderPublicKeyFFI = FFIPublicKey(HexString(result.walletId)) - // add contact - FFIContact("TariBot", senderPublicKeyFFI).also { - wallet.addUpdateContact(it) - it.destroy() - } - senderPublicKeyFFI.destroy() - // update the keys with sender public key hex - result.keys.forEach { key -> key.senderPublicKeyHex = result.walletId } - // store the UTXO keys - testnetFaucetRepository.testnetTariUTXOKeyList = TestnetUtxoList(result.keys) - - // post event to bus for the internal listeners - EventBus.post(Event.Testnet.TestnetTariRequestSuccessful()) - // notify external listeners - listeners.iterator().forEach { it.onTestnetTariRequestSuccess() } - }, - { - Logger.i("requestMaxTestnetTari error ${it.message}") - error.code = WalletError.UnknownError.code - val errorMessage = string(R.string.wallet_service_error_testnet_tari_request) + " " + it.message - // todo maybe needed -// error.message = errorMessage - if (it is TestnetTariRequestException) { - notifyTestnetTariRequestFailed(errorMessage) - } else { - notifyTestnetTariRequestFailed(string(R.string.wallet_service_error_no_internet_connection)) - } - } - ) - } - - override fun importTestnetUTXO(txMessage: String, error: WalletError): CompletedTx? { - val keys = testnetFaucetRepository.testnetTariUTXOKeyList.orEmpty() - if (keys.isEmpty()) return null - - return runCatching { - val firstUTXOKey = keys.first() - val senderPublicKeyFFI = FFIPublicKey(HexString(firstUTXOKey.senderPublicKeyHex!!)) - val privateKey = FFIPrivateKey(HexString(firstUTXOKey.key)) - val scriptPrivateKey = FFIPrivateKey(HexString(firstUTXOKey.key)) - val amount = BigInteger(firstUTXOKey.value) - val senderPublicKey = FFIPublicKey(HexString(firstUTXOKey.output.senderOffsetPublicKey)) - val signature = FFITariCommitmentSignature( - FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.public_nonce)), - FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.u)), - FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.v)) - ) - val covenant = FFICovenant(FFIByteVector(HexString(firstUTXOKey.output.covenant))) - //todo need to update when faucet got fixed - val outputFeatures = FFIOutputFeatures( - '0', '0', 0, '0', - FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.public_nonce)), - FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.u)), - FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.v)) - ) - val txId = wallet.importUTXO( - amount, - txMessage, - privateKey, - senderPublicKeyFFI, - outputFeatures, - signature, - covenant, - senderPublicKey, - scriptPrivateKey - ) - privateKey.destroy() - senderPublicKeyFFI.destroy() - signature.destroy() - // remove the used key - keys.remove(firstUTXOKey) - testnetFaucetRepository.testnetTariUTXOKeyList = keys - // get transaction and post notification - val tx = getCompletedTxById(TxId(txId), error) - if (error != WalletError.NoError || tx == null) return null - - postTxNotification(tx) - tx - }.getOrNull() - } - - override fun removeContact(contact: Contact, error: WalletError): Boolean = executeWithMapping(error) { - val contactsFFI = wallet.getContacts() - for (i in 0 until contactsFFI.getLength()) { - val contactFFI = contactsFFI.getAt(i) - val publicKeyFFI = contactFFI.getPublicKey() - if (publicKeyFFI.toString() == contact.publicKey.hexString) { - return@executeWithMapping wallet.removeContact(contactFFI).also { - publicKeyFFI.destroy() - contactFFI.destroy() - contactsFFI.destroy() - _cachedContacts = null - } - } - publicKeyFFI.destroy() - contactFFI.destroy() - } - contactsFFI.destroy() - false - } ?: false - - private fun notifyTestnetTariRequestFailed(error: String) { - // post event to bus for the internal listeners - EventBus.post(Event.Testnet.TestnetTariRequestError(error)) - // notify external listeners - listeners.iterator().forEach { listener -> listener.onTestnetTariRequestError(error) } - } - - override fun updateContactAlias(publicKey: PublicKey, alias: String, error: WalletError): Boolean = executeWithMapping(error) { - val publicKeyFFI = FFIPublicKey(HexString(publicKey.hexString)) - val contact = FFIContact(alias, publicKeyFFI) - wallet.addUpdateContact(contact).also { - publicKeyFFI.destroy() - contact.destroy() - _cachedContacts = null - } - } ?: false - - /** - * @return public key constructed from input emoji id. Null if the emoji id is invalid - * or it does not correspond to a public key. - */ - override fun getPublicKeyFromEmojiId(emojiId: String?): PublicKey? = runCatching { - FFIPublicKey(emojiId.orEmpty()).run { publicKeyFromFFI(this).also { destroy() } } - }.getOrNull() - - /** - * @return public key constructed from input public key hex string id. Null if the emoji id - * is invalid or it does not correspond to a public key. - */ - override fun getPublicKeyFromHexString(publicKeyHex: String?): PublicKey? = runCatching { - FFIPublicKey(HexString(publicKeyHex ?: "")).run { publicKeyFromFFI(this).also { destroy() } } - }.getOrNull() - - override fun setKeyValue(key: String, value: String, error: WalletError): Boolean = executeWithMapping(error) { - wallet.setKeyValue(key, value) - } ?: false - - override fun getKeyValue(key: String, error: WalletError): String? = executeWithMapping(error) { wallet.getKeyValue(key) } - - override fun removeKeyValue(key: String, error: WalletError): Boolean = executeWithMapping(error) { - wallet.removeKeyValue(key) - } ?: false - - override fun getRequiredConfirmationCount(error: WalletError): Long = executeWithMapping(error) { - wallet.getRequiredConfirmationCount().toLong() - } ?: 0 - - override fun setRequiredConfirmationCount(number: Long, error: WalletError) { - executeWithMapping(error) { wallet.setRequiredConfirmationCount(BigInteger.valueOf(number)) } - } - - override fun getSeedWords(error: WalletError): List? = executeWithMapping(error) { - val seedWordsFFI = wallet.getSeedWords() - (0 until seedWordsFFI.getLength()) - .map { seedWordsFFI.getAt(it) } - .also { seedWordsFFI.destroy() } - } - - override fun getUtxos(page: Int, pageSize: Int, sorting: Int, error: WalletError): TariVector? = - executeWithMapping(error) { wallet.getUtxos(page, pageSize, sorting) } - - override fun getAllUtxos(error: WalletError): TariVector? = - executeWithMapping(error) { wallet.getAllUtxos() } - - override fun joinUtxos(utxos: List, walletError: WalletError) = executeWithMapping(walletError) { - val ffiError = FFIError() - wallet.joinUtxos(utxos.map { it.commitment }.toTypedArray(), Constants.Wallet.defaultFeePerGram.value, ffiError) - walletError.code = ffiError.code - } ?: Unit - - override fun splitUtxos(utxos: List, splitCount: Int, walletError: WalletError) = executeWithMapping(walletError) { - val ffiError = FFIError() - wallet.splitUtxos(utxos.map { it.commitment }.toTypedArray(), splitCount, Constants.Wallet.defaultFeePerGram.value, ffiError) - walletError.code = ffiError.code - } ?: Unit - - override fun previewJoinUtxos(utxos: List, walletError: WalletError): TariCoinPreview? = executeWithMapping(walletError) { - val ffiError = FFIError() - val result = wallet.joinPreviewUtxos(utxos.map { it.commitment }.toTypedArray(), Constants.Wallet.defaultFeePerGram.value, ffiError) - walletError.code = ffiError.code - result - } - - override fun previewSplitUtxos(utxos: List, splitCount: Int, walletError: WalletError): TariCoinPreview? = - executeWithMapping(walletError) { - val ffiError = FFIError() - val result = wallet.splitPreviewUtxos( - utxos.map { it.commitment }.toTypedArray(), - splitCount, - Constants.Wallet.defaultFeePerGram.value, - ffiError - ) - walletError.code = ffiError.code - result - } - } -} - - diff --git a/app/src/main/java/com/tari/android/wallet/service/WalletServiceLauncher.kt b/app/src/main/java/com/tari/android/wallet/service/WalletServiceLauncher.kt deleted file mode 100644 index 23d2e249e..000000000 --- a/app/src/main/java/com/tari/android/wallet/service/WalletServiceLauncher.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.tari.android.wallet.service - -import android.content.Context -import android.content.Intent -import androidx.core.content.ContextCompat -import com.tari.android.wallet.application.TariWalletApplication -import com.tari.android.wallet.data.WalletConfig -import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository -import com.tari.android.wallet.util.WalletUtil - -class WalletServiceLauncher(private val context: Context, val walletConfig: WalletConfig, val tariSettingsSharedRepository: TariSettingsSharedRepository) { - - companion object { - // intent actions - internal const val startAction = "START_SERVICE" - internal const val stopAction = "STOP_SERVICE" - internal const val stopAndDeleteAction = "STOP_SERVICE_AND_DELETE_WALLET" - } - - fun startIfExist() { - if (WalletUtil.walletExists(walletConfig)) { - startService() - } - } - - fun start() { - if (tariSettingsSharedRepository.backgroundServiceTurnedOn || - !tariSettingsSharedRepository.backgroundServiceTurnedOn && TariWalletApplication.INSTANCE.get()?.isInForeground == true - ) { - startService() - } - } - - private fun startService() { - ContextCompat.startForegroundService( - context, - getStartIntent(context) - ) - } - - fun stop() { - ContextCompat.startForegroundService( - context, - getStopIntent(context) - ) - } - - /** - * Deletes the wallet and stops the wallet service. - */ - fun stopAndDelete() { - ContextCompat.startForegroundService( - context, - getStopAndDeleteIntent(context) - ) - } - - fun startOnAppForegrounded() { - if (!tariSettingsSharedRepository.backgroundServiceTurnedOn) { - start() - } - } - - fun stopOnAppBackgrounded() { - if (!tariSettingsSharedRepository.backgroundServiceTurnedOn) { - stop() - } - } - - private fun getStartIntent(context: Context) = - Intent(context, WalletService::class.java).also { - it.action = startAction - } - - private fun getStopIntent(context: Context) = - Intent(context, WalletService::class.java).also { - it.action = stopAction - } - - private fun getStopAndDeleteIntent(context: Context) = - Intent(context, WalletService::class.java).also { - it.action = stopAndDeleteAction - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/connection/ServiceConnectionState.kt b/app/src/main/java/com/tari/android/wallet/service/connection/ServiceConnectionState.kt new file mode 100644 index 000000000..fa93a0ce5 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/connection/ServiceConnectionState.kt @@ -0,0 +1,8 @@ +package com.tari.android.wallet.service.connection + +import com.tari.android.wallet.service.TariWalletService + +data class ServiceConnectionState( + val status: ServiceConnectionStatus, + val service: TariWalletService? +) \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/connection/ServiceConnectionStatus.kt b/app/src/main/java/com/tari/android/wallet/service/connection/ServiceConnectionStatus.kt new file mode 100644 index 000000000..b02b4814a --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/connection/ServiceConnectionStatus.kt @@ -0,0 +1,7 @@ +package com.tari.android.wallet.service.connection + +enum class ServiceConnectionStatus { + NOT_YET_CONNECTED, + CONNECTED, + DISCONNECTED +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/connection/TariWalletServiceConnection.kt b/app/src/main/java/com/tari/android/wallet/service/connection/TariWalletServiceConnection.kt index 0480fe627..4fb818ca9 100644 --- a/app/src/main/java/com/tari/android/wallet/service/connection/TariWalletServiceConnection.kt +++ b/app/src/main/java/com/tari/android/wallet/service/connection/TariWalletServiceConnection.kt @@ -40,7 +40,7 @@ import android.os.IBinder import androidx.lifecycle.ViewModel import com.tari.android.wallet.application.TariWalletApplication import com.tari.android.wallet.service.TariWalletService -import com.tari.android.wallet.service.WalletService +import com.tari.android.wallet.service.service.WalletService import io.reactivex.Observable import io.reactivex.subjects.BehaviorSubject @@ -64,25 +64,8 @@ class TariWalletServiceConnection : ViewModel(), ServiceConnection { } override fun onServiceConnected(name: ComponentName?, service: IBinder?) { - _connection.onNext( - ServiceConnectionState( - ServiceConnectionStatus.CONNECTED, - TariWalletService.Stub.asInterface(service) - ) - ) + _connection.onNext(ServiceConnectionState(ServiceConnectionStatus.CONNECTED, TariWalletService.Stub.asInterface(service))) } override fun onCleared() = context.unbindService(this) - - enum class ServiceConnectionStatus { - NOT_YET_CONNECTED, - CONNECTED, - DISCONNECTED - } - - data class ServiceConnectionState( - val status: ServiceConnectionStatus, - val service: TariWalletService? - ) -} - +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/faucet/TestnetFaucetService.kt b/app/src/main/java/com/tari/android/wallet/service/faucet/TestnetFaucetService.kt index a8fc76bb6..99acab224 100644 --- a/app/src/main/java/com/tari/android/wallet/service/faucet/TestnetFaucetService.kt +++ b/app/src/main/java/com/tari/android/wallet/service/faucet/TestnetFaucetService.kt @@ -32,7 +32,7 @@ */ package com.tari.android.wallet.service.faucet -internal interface TestnetFaucetService { +interface TestnetFaucetService { fun requestMaxTestnetTari( publicKey: String, @@ -41,5 +41,4 @@ internal interface TestnetFaucetService { onSuccess: (TestnetTariMaxAllocationResult) -> Unit, onError: (Throwable) -> Unit ) - } diff --git a/app/src/main/java/com/tari/android/wallet/service/notification/NotificationService.kt b/app/src/main/java/com/tari/android/wallet/service/notification/NotificationService.kt index eb5c1a77d..854a381a0 100644 --- a/app/src/main/java/com/tari/android/wallet/service/notification/NotificationService.kt +++ b/app/src/main/java/com/tari/android/wallet/service/notification/NotificationService.kt @@ -38,8 +38,7 @@ interface NotificationService { recipientPublicKeyHex: String, senderPublicKeyHex: String, signer: (String) -> String, - onSuccess: () -> Unit, - onFailure: (Throwable) -> Unit + onSuccess: () -> Unit = {}, + onFailure: (Throwable) -> Unit = {} ) - } diff --git a/app/src/main/java/com/tari/android/wallet/service/seedPhrase/SeedPhraseRepository.kt b/app/src/main/java/com/tari/android/wallet/service/seedPhrase/SeedPhraseRepository.kt index a98ad2af0..857910dfc 100644 --- a/app/src/main/java/com/tari/android/wallet/service/seedPhrase/SeedPhraseRepository.kt +++ b/app/src/main/java/com/tari/android/wallet/service/seedPhrase/SeedPhraseRepository.kt @@ -2,7 +2,7 @@ package com.tari.android.wallet.service.seedPhrase import com.tari.android.wallet.model.seedPhrase.SeedPhrase -internal class SeedPhraseRepository { +class SeedPhraseRepository { private var seedPhrase: SeedPhrase? = null diff --git a/app/src/main/java/com/tari/android/wallet/service/service/BaseNodeValidationType.kt b/app/src/main/java/com/tari/android/wallet/service/service/BaseNodeValidationType.kt new file mode 100644 index 000000000..e8fba37e9 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/service/BaseNodeValidationType.kt @@ -0,0 +1,6 @@ +package com.tari.android.wallet.service.service + +enum class BaseNodeValidationType { + TXO, + TX; +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/service/FFIWalletListenerImpl.kt b/app/src/main/java/com/tari/android/wallet/service/service/FFIWalletListenerImpl.kt new file mode 100644 index 000000000..e89b2317e --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/service/FFIWalletListenerImpl.kt @@ -0,0 +1,303 @@ +package com.tari.android.wallet.service.service + +import com.tari.android.wallet.application.TariWalletApplication +import com.tari.android.wallet.application.baseNodes.BaseNodes +import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository +import com.tari.android.wallet.event.Event +import com.tari.android.wallet.event.EventBus +import com.tari.android.wallet.ffi.FFIWallet +import com.tari.android.wallet.ffi.FFIWalletListener +import com.tari.android.wallet.ffi.TXOValidationStatus +import com.tari.android.wallet.infrastructure.backup.BackupManager +import com.tari.android.wallet.model.* +import com.tari.android.wallet.model.recovery.WalletRestorationResult +import com.tari.android.wallet.notification.NotificationHelper +import com.tari.android.wallet.service.TariWalletServiceListener +import com.tari.android.wallet.service.baseNode.BaseNodeState +import com.tari.android.wallet.service.baseNode.BaseNodeSyncState +import com.tari.android.wallet.service.notification.NotificationService +import com.tari.android.wallet.ui.fragment.home.HomeActivity +import io.reactivex.Observable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import java.math.BigInteger +import java.util.* +import java.util.concurrent.* + +class FFIWalletListenerImpl( + private val wallet: FFIWallet, + private val backupManager: BackupManager, + private val notificationHelper: NotificationHelper, + private val notificationService: NotificationService, + private val app: TariWalletApplication, + private val baseNodeSharedPrefsRepository: BaseNodeSharedRepository, + private val baseNodes: BaseNodes +) : FFIWalletListener { + + var listeners = CopyOnWriteArrayList() + + /** + * Maps the validation type to the request id and validation result. This map will be + * initialized at the beginning of each base node validation sequence. + * Validation results will all be null, and will be set as the result callbacks get called. + */ + var baseNodeValidationStatusMap: ConcurrentMap> = ConcurrentHashMap() + + /** + * Debounce for inbound transaction notification. + */ + private var txReceivedNotificationDelayedAction: Disposable? = null + private var inboundTxEventNotificationTxs = mutableListOf() + + private var txBroadcastRestarted = false + + /** + * Pairs of . + */ + val outboundTxIdsToBePushNotified = CopyOnWriteArraySet>() + + override fun onTxReceived(pendingInboundTx: PendingInboundTx) { + pendingInboundTx.user = getUserByPublicKey(pendingInboundTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.TxReceived(pendingInboundTx)) + // manage notifications + postTxNotification(pendingInboundTx) + listeners.forEach { it.onTxReceived(pendingInboundTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onTxReplyReceived(pendingOutboundTx: PendingOutboundTx) { + pendingOutboundTx.user = getUserByPublicKey(pendingOutboundTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.TxReplyReceived(pendingOutboundTx)) + // notify external listeners + listeners.iterator().forEach { it.onTxReplyReceived(pendingOutboundTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onTxFinalized(pendingInboundTx: PendingInboundTx) { + pendingInboundTx.user = getUserByPublicKey(pendingInboundTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.TxFinalized(pendingInboundTx)) + // notify external listeners + listeners.iterator().forEach { it.onTxFinalized(pendingInboundTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onInboundTxBroadcast(pendingInboundTx: PendingInboundTx) { + pendingInboundTx.user = getUserByPublicKey(pendingInboundTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.InboundTxBroadcast(pendingInboundTx)) + // notify external listeners + listeners.iterator().forEach { it.onInboundTxBroadcast(pendingInboundTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onOutboundTxBroadcast(pendingOutboundTx: PendingOutboundTx) { + pendingOutboundTx.user = getUserByPublicKey(pendingOutboundTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.OutboundTxBroadcast(pendingOutboundTx)) + // notify external listeners + listeners.iterator().forEach { it.onOutboundTxBroadcast(pendingOutboundTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onTxMined(completedTx: CompletedTx) { + completedTx.user = getUserByPublicKey(completedTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.TxMined(completedTx)) + // notify external listeners + listeners.iterator().forEach { it.onTxMined(completedTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onTxMinedUnconfirmed(completedTx: CompletedTx, confirmationCount: Int) { + completedTx.user = getUserByPublicKey(completedTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.TxMinedUnconfirmed(completedTx)) + // notify external listeners + listeners.iterator().forEach { it.onTxMinedUnconfirmed(completedTx, confirmationCount) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onTxFauxConfirmed(completedTx: CompletedTx) { + completedTx.user = getUserByPublicKey(completedTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.TxFauxConfirmed(completedTx)) + // notify external listeners + listeners.iterator().forEach { it.onTxFauxConfirmed(completedTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onTxFauxUnconfirmed(completedTx: CompletedTx, confirmationCount: Int) { + completedTx.user = getUserByPublicKey(completedTx.user.publicKey) + // post event to bus for the listeners + EventBus.post(Event.Transaction.TxFauxMinedUnconfirmed(completedTx)) + // notify external listeners + listeners.iterator().forEach { it.onTxFauxUnconfirmed(completedTx, confirmationCount) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onDirectSendResult(txId: BigInteger, status: TransactionSendStatus) { + // post event to bus + EventBus.post(Event.Transaction.DirectSendResult(TxId(txId), status)) + outboundTxIdsToBePushNotified.firstOrNull { it.first == txId }?.let { + outboundTxIdsToBePushNotified.remove(it) + sendPushNotificationToTxRecipient(it.second) + } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + // notify external listeners + listeners.iterator().forEach { it.onDirectSendResult(TxId(txId), status) } + } + + override fun onTxCancelled(cancelledTx: CancelledTx, rejectionReason: Int) { + cancelledTx.user = getUserByPublicKey(cancelledTx.user.publicKey) + // post event to bus + EventBus.post(Event.Transaction.TxCancelled(cancelledTx)) + val currentActivity = app.currentActivity + if (cancelledTx.direction == Tx.Direction.INBOUND && !(app.isInForeground && currentActivity is HomeActivity && currentActivity.willNotifyAboutNewTx()) + ) { + notificationHelper.postTxCanceledNotification(cancelledTx) + } + // notify external listeners + listeners.iterator().forEach { listener -> listener.onTxCancelled(cancelledTx) } + // schedule a backup + backupManager.scheduleBackup(resetRetryCount = true) + } + + override fun onTXOValidationComplete(responseId: BigInteger, status: TXOValidationStatus) { + checkValidationResult(BaseNodeValidationType.TXO, responseId, status == TXOValidationStatus.TxoValidationSuccess) + } + + override fun onTxValidationComplete(responseId: BigInteger, isSuccess: Boolean) { + checkValidationResult(BaseNodeValidationType.TX, responseId, isSuccess) + if (!txBroadcastRestarted && isSuccess) { + wallet.restartTxBroadcast() + txBroadcastRestarted = true + } + } + + override fun onBalanceUpdated(balanceInfo: BalanceInfo) { + EventBus.balanceState.post(balanceInfo) + // notify external listeners + listeners.iterator().forEach { it.onBalanceUpdated(balanceInfo) } + } + + override fun onConnectivityStatus(status: Int) { + when (status) { + 1 -> { + baseNodeSharedPrefsRepository.baseNodeState = BaseNodeState.Online.toInt() + EventBus.baseNodeState.post(BaseNodeState.Online) + listeners.iterator().forEach { it.onBaseNodeSyncComplete(true) } + } + 2 -> { + val currentBaseNode = baseNodeSharedPrefsRepository.currentBaseNode + if (currentBaseNode == null || !currentBaseNode.isCustom) { + baseNodes.setNextBaseNode() + } + baseNodeSharedPrefsRepository.baseNodeState = BaseNodeState.Offline.toInt() + EventBus.baseNodeState.post(BaseNodeState.Offline) + listeners.iterator().forEach { it.onBaseNodeSyncComplete(false) } + } + } + } + + private fun getUserByPublicKey(key: PublicKey): User { + val contactsFFI = wallet.getContacts() + for (i in 0 until contactsFFI.getLength()) { + val contactFFI = contactsFFI.getAt(i) + val publicKeyFFI = contactFFI.getPublicKey() + val hex = publicKeyFFI.toString() + val contact = if (hex == key.hexString) Contact(key, contactFFI.getAlias()) else null + publicKeyFFI.destroy() + contactFFI.destroy() + if (contact != null) { + contactsFFI.destroy() + return contact + } + } + // destroy native collection + contactsFFI.destroy() + return User(key) + } + + fun postTxNotification(tx: Tx) { + txReceivedNotificationDelayedAction?.dispose() + inboundTxEventNotificationTxs.add(tx) + txReceivedNotificationDelayedAction = + Observable.timer(500, TimeUnit.MILLISECONDS) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe { + // if app is backgrounded, display heads-up notification + val currentActivity = app.currentActivity + if (!app.isInForeground + || currentActivity !is HomeActivity + || !currentActivity.willNotifyAboutNewTx() + ) { + notificationHelper.postCustomLayoutTxNotification(inboundTxEventNotificationTxs.last()) + } + inboundTxEventNotificationTxs.clear() + } + } + + private fun sendPushNotificationToTxRecipient(recipientPublicKeyHex: String) { + // the push notification server accepts lower-case hex strings as of now + val fromPublicKeyHex = wallet.getPublicKey().toString().lowercase(Locale.ENGLISH) + notificationService.notifyRecipient(recipientPublicKeyHex, fromPublicKeyHex, wallet::signMessage) + } + + private fun checkBaseNodeSyncCompletion() { + // make a copy of the status map for concurrency protection + val statusMapCopy = baseNodeValidationStatusMap.toMap() + // if base node not in sync, then switch to the next base node + // check if any has failed + val failed = statusMapCopy.any { it.value.second == false } + if (failed) { + baseNodeValidationStatusMap.clear() + baseNodeSharedPrefsRepository.baseNodeLastSyncResult = false + val currentBaseNode = baseNodeSharedPrefsRepository.currentBaseNode + if (currentBaseNode == null || !currentBaseNode.isCustom) { + baseNodes.setNextBaseNode() + } + EventBus.baseNodeSyncState.post(BaseNodeSyncState.Failed) + listeners.iterator().forEach { it.onBaseNodeSyncComplete(false) } + return + } + // if any of the results is null, we're still waiting for all callbacks to happen + val inProgress = statusMapCopy.any { it.value.second == null } + if (inProgress) { + return + } + // check if it's successful + val successful = statusMapCopy.all { it.value.second == true } + if (successful) { + baseNodeValidationStatusMap.clear() + baseNodeSharedPrefsRepository.baseNodeLastSyncResult = true + EventBus.baseNodeSyncState.post(BaseNodeSyncState.Online) + listeners.iterator().forEach { it.onBaseNodeSyncComplete(true) } + } + // shouldn't ever reach here - no-op + } + + private fun checkValidationResult(type: BaseNodeValidationType, responseId: BigInteger, isSuccess: Boolean) { + val currentStatus = baseNodeValidationStatusMap[type] ?: return + if (currentStatus.first != responseId) return + baseNodeValidationStatusMap[type] = Pair(currentStatus.first, isSuccess) + checkBaseNodeSyncCompletion() + } + + override fun onWalletRestoration(result: WalletRestorationResult) { + EventBus.walletRestorationState.post(result) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/service/ServiceLifecycleCallbacks.kt b/app/src/main/java/com/tari/android/wallet/service/service/ServiceLifecycleCallbacks.kt new file mode 100644 index 000000000..43fb84741 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/service/ServiceLifecycleCallbacks.kt @@ -0,0 +1,59 @@ +package com.tari.android.wallet.service.service + +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import com.orhanobut.logger.Logger +import com.orhanobut.logger.Printer +import com.tari.android.wallet.ffi.FFIException +import com.tari.android.wallet.ffi.FFIWallet +import io.reactivex.Observable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import org.joda.time.Minutes +import java.util.concurrent.TimeUnit + +class ServiceLifecycleCallbacks(private val wallet: FFIWallet): DefaultLifecycleObserver { + + /** + * Switch to low power mode 3 minutes after the app gets backgrounded. + */ + private val backgroundLowPowerModeSwitchMinutes = Minutes.minutes(3) + + private val logger: Printer + get() = Logger.t(ServiceLifecycleCallbacks::class.simpleName) + + private var lowPowerModeSubscription: Disposable? = null + + override fun onStop(owner: LifecycleOwner) { + super.onStop(owner) + // schedule low power mode + lowPowerModeSubscription = Observable.timer(backgroundLowPowerModeSwitchMinutes.minutes.toLong(), TimeUnit.MINUTES) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe { switchToLowPowerMode() } + } + + override fun onStart(owner: LifecycleOwner) { + super.onStart(owner) + switchToNormalPowerMode() + } + + private fun switchToNormalPowerMode() { + logger.i("Switch to normal power mode") + lowPowerModeSubscription?.dispose() + try { + wallet.setPowerModeNormal() + } catch (e: FFIException) { + logger.e(e, "Switching to normal power mode failed") + } + } + + private fun switchToLowPowerMode() { + logger.i("Switch to low power mode") + try { + wallet.setPowerModeLow() + } catch (e: FFIException) { + logger.e(e, "Switching to low power mode failed") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubImpl.kt b/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubImpl.kt new file mode 100644 index 000000000..355745706 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubImpl.kt @@ -0,0 +1,372 @@ +package com.tari.android.wallet.service.service + +import com.orhanobut.logger.Logger +import com.tari.android.wallet.R +import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository +import com.tari.android.wallet.data.sharedPrefs.testnetFaucet.TestnetFaucetRepository +import com.tari.android.wallet.data.sharedPrefs.testnetFaucet.TestnetUtxoList +import com.tari.android.wallet.event.Event +import com.tari.android.wallet.event.EventBus +import com.tari.android.wallet.ffi.* +import com.tari.android.wallet.model.* +import com.tari.android.wallet.service.TariWalletService +import com.tari.android.wallet.service.TariWalletServiceListener +import com.tari.android.wallet.service.baseNode.BaseNodeSyncState +import com.tari.android.wallet.service.faucet.TestnetFaucetService +import com.tari.android.wallet.service.faucet.TestnetTariRequestException +import com.tari.android.wallet.ui.common.domain.ResourceManager +import com.tari.android.wallet.util.Constants +import java.math.BigInteger +import java.util.* + +class TariWalletServiceStubImpl( + private val wallet: FFIWallet, + private val testnetFaucetRepository: TestnetFaucetRepository, + private val testnetFaucetService: TestnetFaucetService, + private val baseNodeSharedPrefsRepository: BaseNodeSharedRepository, + private val resourceManager: ResourceManager, + private val walletServiceListener: FFIWalletListenerImpl +) : TariWalletService.Stub() { + + private val logger + get() = Logger.t(WalletService::class.simpleName) + + private var _cachedContacts: List? = null + private val cachedContacts: List + @Synchronized get() { + _cachedContacts?.let { return it } + val contactsFFI = wallet.getContacts() + val contacts = mutableListOf() + for (i in 0 until contactsFFI.getLength()) { + val contactFFI = contactsFFI.getAt(i) + val publicKeyFFI = contactFFI.getPublicKey() + contacts.add(Contact(publicKeyFromFFI(publicKeyFFI), contactFFI.getAlias())) + // destroy native objects + publicKeyFFI.destroy() + contactFFI.destroy() + } + // destroy native collection + contactsFFI.destroy() + return contacts.sortedWith(compareBy { it.alias }).also { _cachedContacts = it } + } + + override fun registerListener(listener: TariWalletServiceListener): Boolean { + walletServiceListener.listeners.add(listener) + listener.asBinder().linkToDeath({ walletServiceListener.listeners.remove(listener) }, 0) + return true + } + + override fun unregisterListener(listener: TariWalletServiceListener): Boolean = walletServiceListener.listeners.remove(listener) + + override fun getPublicKeyHexString(error: WalletError): String? = runMapping(error) { wallet.getPublicKey().toString() } + + override fun getBalanceInfo(error: WalletError): BalanceInfo? = runMapping(error) { wallet.getBalance() } + + override fun estimateTxFee(amount: MicroTari, error: WalletError, feePerGram: MicroTari?): MicroTari? = runMapping(error) { + val defaultKernelCount = BigInteger("1") + val defaultOutputCount = BigInteger("2") + val gram = feePerGram?.value ?: Constants.Wallet.defaultFeePerGram.value + MicroTari(wallet.estimateTxFee(amount.value, gram, defaultKernelCount, defaultOutputCount)) + } + + /** + * Get all contacts. + */ + override fun getContacts(error: WalletError): List? = runMapping(error) { cachedContacts } + + /** + * Get all completed transactions. + * Client-facing function. + */ + override fun getCompletedTxs(error: WalletError): List? = runMapping(error) { + wallet.getCompletedTxs().runWithDestroy { txs -> (0 until txs.getLength()).map { CompletedTx(txs.getAt(it)) } } + } + + /** + * Get all cancelledTxs transactions. + * Client-facing function. + */ + override fun getCancelledTxs(error: WalletError): List? = runMapping(error) { + wallet.getCancelledTxs().runWithDestroy { txs -> (0 until txs.getLength()).map { CancelledTx(txs.getAt(it)) } } + } + + /** + * Get completed transaction by id. + * Client-facing function. + */ + override fun getCancelledTxById(id: TxId, error: WalletError): CancelledTx? = + runMapping(error) { CancelledTx(wallet.getCancelledTxById(id.value)) } + + /** + * Get completed transaction by id. + * Client-facing function. + */ + override fun getCompletedTxById(id: TxId, error: WalletError): CompletedTx? = + runMapping(error) { CompletedTx(wallet.getCompletedTxById(id.value)) } + + /** + * Get all pending inbound transactions. + * Client-facing function. + */ + override fun getPendingInboundTxs(error: WalletError): List? = runMapping(error) { + wallet.getPendingInboundTxs().runWithDestroy { txs -> (0 until txs.getLength()).map { PendingInboundTx(txs.getAt(it)) } } + } + + /** + * Get pending inbound transaction by id. + * Client-facing function. + */ + override fun getPendingInboundTxById(id: TxId, error: WalletError): PendingInboundTx? = runMapping(error) { + PendingInboundTx(wallet.getPendingInboundTxById(id.value)) + } + + /** + * Get all pending outbound transactions. + * Client-facing function. + */ + override fun getPendingOutboundTxs(error: WalletError): List? = runMapping(error) { + wallet.getPendingOutboundTxs().runWithDestroy { txs -> (0 until txs.getLength()).map { PendingOutboundTx(txs.getAt(it)) } } + } + + /** + * Get pending outbound transaction by id. + * Client-facing function. + */ + override fun getPendingOutboundTxById(id: TxId, error: WalletError): PendingOutboundTx? = runMapping(error) { + PendingOutboundTx(wallet.getPendingOutboundTxById(id.value)) + } + + override fun cancelPendingTx(id: TxId, error: WalletError): Boolean = runMapping(error) { wallet.cancelPendingTx(id.value) } ?: false + + override fun addBaseNodePeer(baseNodePublicKey: String, baseNodeAddress: String, error: WalletError): Boolean = runMapping(error) { + val result = FFIPublicKey(HexString(baseNodePublicKey)).runWithDestroy { wallet.addBaseNodePeer(it, baseNodeAddress) } + if (result) { + walletServiceListener.baseNodeValidationStatusMap.clear() + EventBus.baseNodeSyncState.post(BaseNodeSyncState.NotStarted) + } + result + } ?: false + + override fun startBaseNodeSync(error: WalletError): Boolean = runMapping(error, { + logger.e(it, "Base node sync failed") + baseNodeSharedPrefsRepository.baseNodeLastSyncResult = false + walletServiceListener.baseNodeValidationStatusMap.clear() + EventBus.baseNodeSyncState.post(BaseNodeSyncState.Failed) + }) { + walletServiceListener.baseNodeValidationStatusMap.clear() + walletServiceListener.baseNodeValidationStatusMap[BaseNodeValidationType.TXO] = Pair(wallet.startTXOValidation(), null) + walletServiceListener.baseNodeValidationStatusMap[BaseNodeValidationType.TX] = Pair(wallet.startTxValidation(), null) + baseNodeSharedPrefsRepository.baseNodeLastSyncResult = null + true + } ?: false + + override fun sendTari( + user: User, amount: MicroTari, feePerGram: MicroTari, message: String, isOneSidePayment: Boolean, error: WalletError + ): TxId? = runMapping(error) { + val recipientPublicKeyHex = user.publicKey.hexString + val txId = FFIPublicKey(HexString(recipientPublicKeyHex)).runWithDestroy { + wallet.sendTx(it, amount.value, feePerGram.value, message, isOneSidePayment) + } + walletServiceListener.outboundTxIdsToBePushNotified.add(Pair(txId, recipientPublicKeyHex.lowercase(Locale.ENGLISH))) + TxId(txId) + } + + override fun requestTestnetTari(error: WalletError) { + // avoid multiple faucet requests + if (testnetFaucetRepository.faucetTestnetTariRequestCompleted) return + // get public key + val publicKeyHexString = getPublicKeyHexString(error) + if (error.code != WalletError.NoError.code || publicKeyHexString == null) { + notifyTestnetTariRequestFailed("Service error.") + return + } + + val message = "$MESSAGE_PREFIX $publicKeyHexString" + val signing = wallet.signMessage(message).split("|") + val signature = signing[0] + val nonce = signing[1] + + testnetFaucetService.requestMaxTestnetTari(publicKeyHexString, signature, nonce, { result -> + FFIPublicKey(HexString(result.walletId)).runWithDestroy { + FFIContact("TariBot", it).runWithDestroy { contact -> wallet.addUpdateContact(contact) } + } + // update the keys with sender public key hex + result.keys.forEach { key -> key.senderPublicKeyHex = result.walletId } + // store the UTXO keys + testnetFaucetRepository.testnetTariUTXOKeyList = TestnetUtxoList(result.keys) + + // post event to bus for the listeners + EventBus.post(Event.Testnet.TestnetTariRequestSuccessful()) + // notify external listeners + walletServiceListener.listeners.iterator().forEach { it.onTestnetTariRequestSuccess() } + }, { + val errorMessage = resourceManager.getString(R.string.wallet_service_error_testnet_tari_request) + " " + it.message + logger.e(errorMessage + "failed on requesting faucet") + if (it is TestnetTariRequestException) { + notifyTestnetTariRequestFailed(errorMessage) + } else { + notifyTestnetTariRequestFailed(resourceManager.getString((R.string.wallet_service_error_no_internet_connection))) + } + }) + } + + override fun importTestnetUTXO(txMessage: String, error: WalletError): CompletedTx? { + val keys = testnetFaucetRepository.testnetTariUTXOKeyList.orEmpty().toMutableList() + if (keys.isEmpty()) return null + + return runCatching { + val firstUTXOKey = keys.first() + val senderPublicKeyFFI = FFIPublicKey(HexString(firstUTXOKey.senderPublicKeyHex!!)) + val privateKey = FFIPrivateKey(HexString(firstUTXOKey.key)) + val scriptPrivateKey = FFIPrivateKey(HexString(firstUTXOKey.key)) + val amount = BigInteger(firstUTXOKey.value) + val senderPublicKey = FFIPublicKey(HexString(firstUTXOKey.output.senderOffsetPublicKey)) + val signature = FFITariCommitmentSignature( + FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.public_nonce)), + FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.u)), + FFIByteVector(HexString(firstUTXOKey.output.metadataSignature.v)) + ) + val txId = wallet.importUTXO(amount, txMessage, privateKey, senderPublicKeyFFI, signature, senderPublicKey, scriptPrivateKey) + privateKey.destroy() + senderPublicKeyFFI.destroy() + signature.destroy() + // remove the used key + keys.remove(firstUTXOKey) + testnetFaucetRepository.testnetTariUTXOKeyList = TestnetUtxoList(keys) + // get transaction and post notification + val tx = getCompletedTxById(TxId(txId), error) + if (error != WalletError.NoError || tx == null) return null + + walletServiceListener.postTxNotification(tx) + tx + }.getOrNull() + } + + override fun removeContact(contact: Contact, error: WalletError): Boolean = runMapping(error) { + val contactsFFI = wallet.getContacts() + for (i in 0 until contactsFFI.getLength()) { + val contactFFI = contactsFFI.getAt(i) + val publicKeyFFI = contactFFI.getPublicKey() + if (publicKeyFFI.toString() == contact.publicKey.hexString) { + return@runMapping wallet.removeContact(contactFFI).also { + publicKeyFFI.destroy() + contactFFI.destroy() + contactsFFI.destroy() + _cachedContacts = null + } + } + publicKeyFFI.destroy() + contactFFI.destroy() + } + contactsFFI.destroy() + false + } ?: false + + override fun updateContactAlias(publicKey: PublicKey, alias: String, error: WalletError): Boolean = runMapping(error) { + val publicKeyFFI = FFIPublicKey(HexString(publicKey.hexString)) + val contact = FFIContact(alias, publicKeyFFI) + wallet.addUpdateContact(contact).also { + publicKeyFFI.destroy() + contact.destroy() + _cachedContacts = null + } + } ?: false + + /** + * @return public key constructed from input emoji id. Null if the emoji id is invalid + * or it does not correspond to a public key. + */ + override fun getPublicKeyFromEmojiId(emojiId: String?): PublicKey? = + runCatching { FFIPublicKey(emojiId.orEmpty()).runWithDestroy { publicKeyFromFFI(it) } }.getOrNull() + + /** + * @return public key constructed from input public key hex string id. Null if the emoji id + * is invalid or it does not correspond to a public key. + */ + override fun getPublicKeyFromHexString(publicKeyHex: String?): PublicKey? = runCatching { + FFIPublicKey(HexString(publicKeyHex ?: "")).runWithDestroy { publicKeyFromFFI(it) } + }.getOrNull() + + override fun setKeyValue(key: String, value: String, error: WalletError): Boolean = runMapping(error) { wallet.setKeyValue(key, value) } ?: false + + override fun getKeyValue(key: String, error: WalletError): String? = runMapping(error) { wallet.getKeyValue(key) } + + override fun removeKeyValue(key: String, error: WalletError): Boolean = runMapping(error) { wallet.removeKeyValue(key) } ?: false + + override fun getRequiredConfirmationCount(error: WalletError): Long = runMapping(error) { wallet.getRequiredConfirmationCount().toLong() } ?: 0 + + override fun setRequiredConfirmationCount(number: Long, error: WalletError) { + runMapping(error) { wallet.setRequiredConfirmationCount(BigInteger.valueOf(number)) } + } + + override fun getSeedWords(error: WalletError): List? = runMapping(error) { + wallet.getSeedWords().runWithDestroy { seedWords -> (0 until seedWords.getLength()).map { seedWords.getAt(it) } } + } + + override fun getUtxos(page: Int, pageSize: Int, sorting: Int, error: WalletError): TariVector? = + runMapping(error) { wallet.getUtxos(page, pageSize, sorting) } + + override fun getAllUtxos(error: WalletError): TariVector? = runMapping(error) { wallet.getAllUtxos() } + + override fun joinUtxos(utxos: List, walletError: WalletError) = runMapping(walletError) { + val ffiError = FFIError() + wallet.joinUtxos(utxos.map { it.commitment }.toTypedArray(), Constants.Wallet.defaultFeePerGram.value, ffiError) + walletError.code = ffiError.code + } ?: Unit + + override fun splitUtxos(utxos: List, splitCount: Int, walletError: WalletError) = runMapping(walletError) { + val ffiError = FFIError() + wallet.splitUtxos(utxos.map { it.commitment }.toTypedArray(), splitCount, Constants.Wallet.defaultFeePerGram.value, ffiError) + walletError.code = ffiError.code + } ?: Unit + + override fun previewJoinUtxos(utxos: List, walletError: WalletError): TariCoinPreview? = runMapping(walletError) { + val ffiError = FFIError() + val result = wallet.joinPreviewUtxos(utxos.map { it.commitment }.toTypedArray(), Constants.Wallet.defaultFeePerGram.value, ffiError) + walletError.code = ffiError.code + result + } + + override fun previewSplitUtxos(utxos: List, splitCount: Int, walletError: WalletError): TariCoinPreview? = runMapping(walletError) { + val ffiError = FFIError() + val result = wallet.splitPreviewUtxos( + utxos.map { it.commitment }.toTypedArray(), splitCount, Constants.Wallet.defaultFeePerGram.value, ffiError + ) + walletError.code = ffiError.code + result + } + + + private fun mapThrowableIntoError(walletError: WalletError, throwable: Throwable) { + if (throwable is FFIException) { + if (throwable.error != null) { + walletError.code = throwable.error.code + return + } + } + walletError.code = WalletError.UnknownError.code + } + + private fun publicKeyFromFFI(publicKeyFFI: FFIPublicKey): PublicKey = PublicKey(publicKeyFFI.toString(), publicKeyFFI.getEmojiId()) + + private fun runMapping(walletError: WalletError, onError: (Throwable) -> (Unit) = {}, action: () -> T?): T? { + return try { + action() + } catch (throwable: Throwable) { + onError(throwable) + mapThrowableIntoError(walletError, throwable) + null + } + } + + private fun notifyTestnetTariRequestFailed(error: String) { + // post event to bus for the listeners + EventBus.post(Event.Testnet.TestnetTariRequestError(error)) + // notify external listeners + walletServiceListener.listeners.iterator().forEach { listener -> listener.onTestnetTariRequestError(error) } + } + + companion object { + private const val MESSAGE_PREFIX = "Hello Tari from" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubProxy.kt b/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubProxy.kt new file mode 100644 index 000000000..162d614de --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubProxy.kt @@ -0,0 +1,98 @@ +package com.tari.android.wallet.service.service + +import com.tari.android.wallet.model.* +import com.tari.android.wallet.service.TariWalletService +import com.tari.android.wallet.service.TariWalletServiceListener + +class TariWalletServiceStubProxy : TariWalletService.Stub() { + + private var _stub: TariWalletServiceStubImpl? = null + var stub: TariWalletServiceStubImpl + get() = _stub!! + set(newStub) { + _stub = newStub + } + + override fun registerListener(listener: TariWalletServiceListener): Boolean = stub.registerListener(listener) + + override fun unregisterListener(listener: TariWalletServiceListener): Boolean = stub.unregisterListener(listener) + + override fun getPublicKeyHexString(error: WalletError): String? = stub.getPublicKeyHexString(error) + + override fun getBalanceInfo(error: WalletError): BalanceInfo? = stub.getBalanceInfo(error) + + override fun estimateTxFee(amount: MicroTari, error: WalletError, feePerGram: MicroTari?): MicroTari? = + stub.estimateTxFee(amount, error, feePerGram) + + override fun getContacts(error: WalletError): List? = stub.getContacts(error) + + override fun getCompletedTxs(error: WalletError): List? = stub.getCompletedTxs(error) + + override fun getCompletedTxById(id: TxId, error: WalletError): CompletedTx? = stub.getCompletedTxById(id, error) + + override fun getPendingInboundTxs(error: WalletError): List? = stub.getPendingInboundTxs(error) + + override fun getPendingInboundTxById(id: TxId, error: WalletError): PendingInboundTx? = stub.getPendingInboundTxById(id, error) + + override fun getPendingOutboundTxs(error: WalletError): List? = stub.getPendingOutboundTxs(error) + + override fun getPendingOutboundTxById(id: TxId, error: WalletError): PendingOutboundTx? = stub.getPendingOutboundTxById(id, error) + + override fun getCancelledTxs(error: WalletError): List? = stub.getCancelledTxs(error) + + override fun getCancelledTxById(id: TxId, error: WalletError): CancelledTx? = stub.getCancelledTxById(id, error) + + override fun cancelPendingTx(id: TxId, error: WalletError): Boolean = stub.cancelPendingTx(id, error) + + override fun addBaseNodePeer(baseNodePublicKey: String, baseNodeAddress: String, error: WalletError): Boolean = + stub.addBaseNodePeer(baseNodePublicKey, baseNodeAddress, error) + + override fun startBaseNodeSync(error: WalletError): Boolean = stub.startBaseNodeSync(error) + + override fun sendTari( + contact: User, + amount: MicroTari, + feePerGram: MicroTari, + message: String, + isOneSidePayment: Boolean, + error: WalletError + ): TxId? = stub.sendTari(contact, amount, feePerGram, message, isOneSidePayment, error) + + override fun requestTestnetTari(error: WalletError) = stub.requestTestnetTari(error) + + override fun importTestnetUTXO(txMessage: String, error: WalletError): CompletedTx? = stub.importTestnetUTXO(txMessage, error) + + override fun updateContactAlias(contactPublicKey: PublicKey, alias: String, error: WalletError): Boolean = + stub.updateContactAlias(contactPublicKey, alias, error) + + override fun removeContact(contact: Contact, error: WalletError): Boolean = stub.removeContact(contact, error) + + override fun getPublicKeyFromEmojiId(emojiId: String): PublicKey? = stub.getPublicKeyFromEmojiId(emojiId) + + override fun getPublicKeyFromHexString(publicKeyHex: String): PublicKey? = stub.getPublicKeyFromHexString(publicKeyHex) + + override fun setKeyValue(key: String, value: String, error: WalletError): Boolean = stub.setKeyValue(key, value, error) + + override fun getKeyValue(key: String, error: WalletError): String? = stub.getKeyValue(key, error) + + override fun removeKeyValue(key: String, error: WalletError): Boolean = stub.removeKeyValue(key, error) + + override fun getRequiredConfirmationCount(error: WalletError): Long = stub.getRequiredConfirmationCount(error) + + override fun setRequiredConfirmationCount(number: Long, error: WalletError) = stub.setRequiredConfirmationCount(number, error) + + override fun getSeedWords(error: WalletError): List? = stub.getSeedWords(error) + + override fun getUtxos(page: Int, pageSize: Int, sorting: Int, error: WalletError): TariVector? = stub.getUtxos(page, pageSize, sorting, error) + + override fun getAllUtxos(error: WalletError): TariVector? = stub.getAllUtxos(error) + + override fun previewJoinUtxos(utxos: List, error: WalletError): TariCoinPreview? = stub.previewJoinUtxos(utxos, error) + + override fun previewSplitUtxos(utxos: List, splitCount: Int, error: WalletError): TariCoinPreview? = + stub.previewSplitUtxos(utxos, splitCount, error) + + override fun joinUtxos(utxos: List, error: WalletError) = stub.joinUtxos(utxos, error) + + override fun splitUtxos(utxos: List, splitCount: Int, error: WalletError) = stub.splitUtxos(utxos, splitCount, error) +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/service/WalletService.kt b/app/src/main/java/com/tari/android/wallet/service/service/WalletService.kt new file mode 100644 index 000000000..c06589ec7 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/service/WalletService.kt @@ -0,0 +1,281 @@ +/** + * Copyright 2020 The Tari Project + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.tari.android.wallet.service.service + +import android.app.Service +import android.content.Intent +import android.os.Handler +import android.os.IBinder +import android.os.Looper +import androidx.lifecycle.ProcessLifecycleOwner +import com.orhanobut.logger.Logger +import com.tari.android.wallet.application.TariWalletApplication +import com.tari.android.wallet.application.WalletManager +import com.tari.android.wallet.application.WalletState +import com.tari.android.wallet.application.baseNodes.BaseNodes +import com.tari.android.wallet.data.WalletConfig +import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository +import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository +import com.tari.android.wallet.data.sharedPrefs.testnetFaucet.TestnetFaucetRepository +import com.tari.android.wallet.di.DiContainer +import com.tari.android.wallet.event.EventBus +import com.tari.android.wallet.ffi.FFIWallet +import com.tari.android.wallet.infrastructure.backup.BackupManager +import com.tari.android.wallet.notification.NotificationHelper +import com.tari.android.wallet.service.ServiceRestartBroadcastReceiver +import com.tari.android.wallet.service.faucet.TestnetFaucetService +import com.tari.android.wallet.service.notification.NotificationService +import com.tari.android.wallet.service.service.WalletServiceLauncher.Companion.startAction +import com.tari.android.wallet.service.service.WalletServiceLauncher.Companion.stopAction +import com.tari.android.wallet.service.service.WalletServiceLauncher.Companion.stopAndDeleteAction +import com.tari.android.wallet.ui.common.domain.ResourceManager +import com.tari.android.wallet.util.Constants +import com.tari.android.wallet.util.WalletUtil +import io.reactivex.Observable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import org.joda.time.DateTime +import org.joda.time.Hours +import org.joda.time.Minutes +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +/** + * Foreground wallet service. + * + * @author The Tari Development Team + */ +class WalletService : Service() { + + @Inject + lateinit var walletConfig: WalletConfig + + @Inject + lateinit var app: TariWalletApplication + + @Inject + lateinit var resourceManager: ResourceManager + + @Inject + lateinit var testnetFaucetService: TestnetFaucetService + + @Inject + lateinit var notificationService: NotificationService + + @Inject + lateinit var notificationHelper: NotificationHelper + + @Inject + lateinit var sharedPrefsWrapper: SharedPrefsRepository + + @Inject + lateinit var baseNodeSharedPrefsRepository: BaseNodeSharedRepository + + @Inject + lateinit var walletManager: WalletManager + + @Inject + lateinit var backupManager: BackupManager + + @Inject + lateinit var baseNodes: BaseNodes + + @Inject + lateinit var testnetFaucetRepository: TestnetFaucetRepository + + private var lifecycleObserver: ServiceLifecycleCallbacks? = null + private val stubProxy = TariWalletServiceStubProxy() + private lateinit var wallet: FFIWallet + + private val logger + get() = Logger.t(WalletService::class.simpleName) + + /** + * Check for expired txs every 30 minutes. + */ + private val expirationCheckPeriodMinutes = Minutes.minutes(30) + + /** + * Timer to trigger the expiration checks. + */ + private var txExpirationCheckSubscription: Disposable? = null + + override fun onCreate() { + super.onCreate() + DiContainer.appComponent.inject(this) + } + + /** + * Called when a component decides to start or stop the foreground wallet service. + */ + override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { + startForeground() + when (intent.action) { + startAction -> startService() + stopAction -> stopService(startId) + stopAndDeleteAction -> { + //todo total crutch. Service is auto-creating during the bind func. Need to refactor this first + DiContainer.appComponent.inject(this) + stopService(startId) + deleteWallet() + } + else -> throw RuntimeException("Unexpected intent action: ${intent.action}") + } + return START_NOT_STICKY + } + + private fun startService() { + //todo total crutch. Service is auto-creating during the bind func. Need to refactor this first + DiContainer.appComponent.inject(this) + // start wallet manager on a separate thread & listen to events + EventBus.walletState.subscribe(this, this::onWalletStateChanged) + Thread { walletManager.start() }.start() + logger.i("Wallet service started") + } + + private fun startForeground() { + // start service & post foreground service notification + startForeground(NOTIFICATION_ID, notificationHelper.buildForegroundServiceNotification()) + } + + private fun stopService(startId: Int) { + // stop service + stopForeground(true) + stopSelfResult(startId) + // stop wallet manager on a separate thread & unsubscribe from events + EventBus.walletState.unsubscribe(this) + lifecycleObserver?.let { ProcessLifecycleOwner.get().lifecycle.removeObserver(it) } + } + + private fun deleteWallet() { + WalletUtil.clearWalletFiles(walletConfig.getWalletFilesDirPath()) + sharedPrefsWrapper.clear() + } + + private fun onWalletStateChanged(walletState: WalletState) { + if (walletState == WalletState.Started) { + wallet = FFIWallet.instance!! + lifecycleObserver = ServiceLifecycleCallbacks(wallet) + val impl = FFIWalletListenerImpl(wallet, backupManager, notificationHelper, notificationService, app, baseNodeSharedPrefsRepository, baseNodes) + stubProxy.stub = TariWalletServiceStubImpl(wallet, testnetFaucetRepository, testnetFaucetService, baseNodeSharedPrefsRepository, resourceManager, impl) + wallet.listener = impl + EventBus.walletState.unsubscribe(this) + scheduleExpirationCheck() + backupManager.initialize() + Handler(Looper.getMainLooper()).post { ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleObserver!!) } + EventBus.walletState.post(WalletState.Running) + } + } + + private fun scheduleExpirationCheck() { + txExpirationCheckSubscription = + Observable + .timer(expirationCheckPeriodMinutes.minutes.toLong(), TimeUnit.MINUTES) + .repeat() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe { + cancelExpiredPendingInboundTxs() + cancelExpiredPendingOutboundTxs() + } + } + + override fun onBind(intent: Intent?): IBinder { + logger.i("Wallet service bound") + return stubProxy + } + + override fun onUnbind(intent: Intent?): Boolean { + logger.i("Wallet service unbound") + return super.onUnbind(intent) + } + + /** + * A broadcast is made on destroy to get the service running again. + */ + override fun onDestroy() { + logger.i("Wallet service destroyed") + txExpirationCheckSubscription?.dispose() + sendBroadcast(Intent(this, ServiceRestartBroadcastReceiver::class.java)) + super.onDestroy() + } + + /** + * Cancels expired pending inbound transactions. + * Expiration period is defined by Constants.Wallet.pendingTxExpirationPeriodHours + */ + private fun cancelExpiredPendingInboundTxs() { + val pendingInboundTxs = wallet.getPendingInboundTxs() + val pendingInboundTxsLength = pendingInboundTxs.getLength() + val now = DateTime.now().toLocalDateTime() + for (i in 0 until pendingInboundTxsLength) { + val tx = pendingInboundTxs.getAt(i) + val txDate = DateTime(tx.getTimestamp().toLong() * 1000L).toLocalDateTime() + val hoursPassed = Hours.hoursBetween(txDate, now).hours + if (hoursPassed >= Constants.Wallet.pendingTxExpirationPeriodHours) { + wallet.cancelPendingTx(tx.getId()) + } + tx.destroy() + } + pendingInboundTxs.destroy() + } + + /** + * Cancels expired pending outbound transactions. + * Expiration period is defined by Constants.Wallet.pendingTxExpirationPeriodHours + */ + private fun cancelExpiredPendingOutboundTxs() { + val pendingOutboundTxs = wallet.getPendingOutboundTxs() + val pendingOutboundTxsLength = wallet.getPendingOutboundTxs().getLength() + val now = DateTime.now().toLocalDateTime() + for (i in 0 until pendingOutboundTxsLength) { + val tx = pendingOutboundTxs.getAt(i) + val txDate = DateTime(tx.getTimestamp().toLong() * 1000L).toLocalDateTime() + val hoursPassed = Hours.hoursBetween(txDate, now).hours + if (hoursPassed >= Constants.Wallet.pendingTxExpirationPeriodHours) { + wallet.cancelPendingTx(tx.getId()) + } + tx.destroy() + } + + pendingOutboundTxs.destroy() + } + + companion object { + private const val NOTIFICATION_ID = 1 + + object KeyValueStorageKeys { + const val NETWORK = "SU7FM2O6Q3BU4XVN7HDD" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/service/service/WalletServiceLauncher.kt b/app/src/main/java/com/tari/android/wallet/service/service/WalletServiceLauncher.kt new file mode 100644 index 000000000..d532cfb1c --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/service/service/WalletServiceLauncher.kt @@ -0,0 +1,62 @@ +package com.tari.android.wallet.service.service + +import android.content.Context +import android.content.Intent +import androidx.core.content.ContextCompat +import com.tari.android.wallet.application.TariWalletApplication +import com.tari.android.wallet.data.WalletConfig +import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository +import com.tari.android.wallet.util.WalletUtil + +class WalletServiceLauncher( + private val context: Context, + val walletConfig: WalletConfig, + val tariSettingsSharedRepository: TariSettingsSharedRepository +) { + fun startIfExist() { + if (WalletUtil.walletExists(walletConfig)) { + startService() + } + } + + fun start() { + if (tariSettingsSharedRepository.backgroundServiceTurnedOn || + !tariSettingsSharedRepository.backgroundServiceTurnedOn && TariWalletApplication.INSTANCE.get()?.isInForeground == true + ) { + startService() + } + } + + private fun startService() = ContextCompat.startForegroundService(context, getStartIntent(context)) + + fun stop() = ContextCompat.startForegroundService(context, getStopIntent(context)) + + fun stopAndDelete() = ContextCompat.startForegroundService(context, getStopAndDeleteIntent(context)) + + fun startOnAppForegrounded() { + if (!tariSettingsSharedRepository.backgroundServiceTurnedOn) { + start() + } + } + + fun stopOnAppBackgrounded() { + if (!tariSettingsSharedRepository.backgroundServiceTurnedOn) { + stop() + } + } + + private fun getStartIntent(context: Context) = Intent(context, WalletService::class.java).also { it.action = startAction } + + private fun getStopIntent(context: Context) = Intent(context, WalletService::class.java).also { it.action = stopAction } + + private fun getStopAndDeleteIntent(context: Context) = Intent(context, WalletService::class.java).also { it.action = stopAndDeleteAction } + + + companion object { + // intent actions + const val startAction = "START_SERVICE" + const val stopAction = "STOP_SERVICE" + const val stopAndDeleteAction = "STOP_SERVICE_AND_DELETE_WALLET" + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/tor/NativeLoader.kt b/app/src/main/java/com/tari/android/wallet/tor/NativeLoader.kt index d09adb0fc..86f044d8d 100644 --- a/app/src/main/java/com/tari/android/wallet/tor/NativeLoader.kt +++ b/app/src/main/java/com/tari/android/wallet/tor/NativeLoader.kt @@ -1,7 +1,7 @@ package com.tari.android.wallet.tor import android.os.Build -import timber.log.Timber +import com.orhanobut.logger.Logger import java.io.File import java.io.FileOutputStream import java.io.InputStream @@ -10,7 +10,8 @@ import java.util.zip.ZipFile object NativeLoader { - private const val TAG = "TorNativeLoader" + private val logger + get() = Logger.t("TorNativeLoader") private fun loadFromZip(appSourceDir: File, libName: String, destLocalFile: File, arch: String): Boolean { @@ -46,13 +47,13 @@ object NativeLoader { return true } catch (e: Exception) { - Timber.e(e, TAG) + logger.e(e, "Load from zip") } finally { if (stream != null) { try { stream.close() } catch (e: Exception) { - Timber.e(e, TAG) + logger.e(e, "Closing stream") } } @@ -60,7 +61,7 @@ object NativeLoader { try { zipFile.close() } catch (e: Exception) { - Timber.e(e, TAG) + logger.e(e, "closing zip file") } } } @@ -94,7 +95,7 @@ object NativeLoader { } } catch (e: Throwable) { - Timber.e(e, TAG) + logger.e(e, "loading native binary") } return null diff --git a/app/src/main/java/com/tari/android/wallet/tor/TorBootstrapStatus.kt b/app/src/main/java/com/tari/android/wallet/tor/TorBootstrapStatus.kt index aed80d7ae..af1f44566 100644 --- a/app/src/main/java/com/tari/android/wallet/tor/TorBootstrapStatus.kt +++ b/app/src/main/java/com/tari/android/wallet/tor/TorBootstrapStatus.kt @@ -1,7 +1,5 @@ package com.tari.android.wallet.tor -import com.orhanobut.logger.Logger - data class TorBootstrapStatus(val progress: Int, val summary: String, val warning: String? = null) { companion object { @@ -11,7 +9,6 @@ data class TorBootstrapStatus(val progress: Int, val summary: String, val warnin const val maxProgress = 100 fun from(logLine: String): TorBootstrapStatus { - Logger.i("tor connection status: $logLine") if (warningLogRegex.matches(logLine)) { val matchResult = warningLogRegex.find(logLine) val (progress, summary, warning) = matchResult!!.destructured diff --git a/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt b/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt index 8121d90b7..fa34d3433 100644 --- a/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt +++ b/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt @@ -25,6 +25,8 @@ class TorProxyControl(private val torConfig: TorConfig) { * Timer to check Tor status. */ private var timerSubscription: Disposable? = null + private val logger + get() = Logger.t(TorProxyControl::class.simpleName) private lateinit var socket: Socket private lateinit var controlConnection: TorControlConnection @@ -40,6 +42,7 @@ class TorProxyControl(private val torConfig: TorConfig) { if (this::controlConnection.isInitialized) { runCatching { controlConnection.shutdownTor("SHUTDOWN") } } + logger.i("shutdownTor") } private fun connectToTor() { @@ -52,10 +55,10 @@ class TorProxyControl(private val torConfig: TorConfig) { } catch (throwable: Throwable) { val initializationElapsedMs = System.currentTimeMillis() - monitoringStartTimeMs if (initializationElapsedMs > initializationCheckTimeoutMillis) { - Logger.e("Failed to connect to Tor proxy, timed out: %s", throwable.message) + logger.e(throwable, "Failed to connect to Tor proxy, timed out") updateState(TorProxyState.Failed(throwable)) } else { - Logger.e("Failed to connect to Tor proxy, will retry: %s", throwable.message) + logger.e(throwable, "Failed to connect to Tor proxy, will retry") timerSubscription = Observable.timer(initializationCheckRetryPeriodMillis, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) @@ -82,17 +85,16 @@ class TorProxyControl(private val torConfig: TorConfig) { updateState(TorProxyState.Failed(Throwable("Tor not running"))) } } catch (throwable: Throwable) { - Logger.e("Tor proxy has failed: %s", throwable.message) + logger.e(throwable, "Tor proxy has failed") updateState(TorProxyState.Failed(throwable)) } } private fun isTorRunning(controlConnection: TorControlConnection?): TorBootstrapStatus? { val phaseLogLine = controlConnection?.getInfo("status/bootstrap-phase") ?: return null + logger.i("Tor connection status: $phaseLogLine") return TorBootstrapStatus.from(phaseLogLine) } - private fun updateState(newState: TorProxyState) { - EventBus.torProxyState.post(newState) - } + private fun updateState(newState: TorProxyState) = EventBus.torProxyState.post(newState) } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/tor/TorProxyManager.kt b/app/src/main/java/com/tari/android/wallet/tor/TorProxyManager.kt index 7b10680f2..9fc3d4e25 100644 --- a/app/src/main/java/com/tari/android/wallet/tor/TorProxyManager.kt +++ b/app/src/main/java/com/tari/android/wallet/tor/TorProxyManager.kt @@ -46,7 +46,7 @@ import java.io.InputStreamReader * * @author The Tari Development Team */ -internal class TorProxyManager( +class TorProxyManager( private val context: Context, private val torSharedRepository: TorSharedRepository, private val torConfig: TorConfig @@ -58,6 +58,8 @@ internal class TorProxyManager( private val appCacheHome = context.getDir(torDataDirectoryName, Service.MODE_PRIVATE) private val torProxyControl: TorProxyControl + private val logger + get() = Logger.t(TorProxyManager::class.simpleName) init { EventBus.torProxyState.post(TorProxyState.NotReady) @@ -76,14 +78,13 @@ internal class TorProxyManager( * Executes shell command. */ private fun exec(command: String) { - // execute the command val process = Runtime.getRuntime().exec(command) - Logger.d("Tor command executed: %s", command) + logger.i("Tor process started") EventBus.torProxyState.post(TorProxyState.Initializing(null)) val response = BufferedReader(InputStreamReader(process.inputStream)).use(BufferedReader::readText) - Logger.d("Tor proxy response: %s", response) + logger.i("Tor proxy response: $response") process.waitFor() - Logger.d("Tor proxy stopped") + logger.i("Tor proxy stopped") } @Synchronized @@ -100,7 +101,7 @@ internal class TorProxyManager( exec(torCmdString) } catch (throwable: Throwable) { - Logger.e(throwable.message.orEmpty()) + logger.e(throwable, "Tor process launch failed") EventBus.torProxyState.post(TorProxyState.Failed(throwable)) } }.start() diff --git a/app/src/main/java/com/tari/android/wallet/tor/TorResourceInstaller.kt b/app/src/main/java/com/tari/android/wallet/tor/TorResourceInstaller.kt index 0e7f6048d..dd89404c2 100755 --- a/app/src/main/java/com/tari/android/wallet/tor/TorResourceInstaller.kt +++ b/app/src/main/java/com/tari/android/wallet/tor/TorResourceInstaller.kt @@ -33,7 +33,6 @@ package com.tari.android.wallet.tor import android.content.Context -import com.orhanobut.logger.Logger import com.tari.android.wallet.data.sharedPrefs.tor.TorSharedRepository import java.io.* import java.util.zip.ZipInputStream @@ -50,49 +49,16 @@ class TorResourceInstaller( private val torConfig: TorConfig ) { - var appFilesDir: File = context.filesDir - var appDataDir: File = context.getDir(DIRECTORY_TOR_DATA, Context.MODE_PRIVATE) - var appNativeDir: File = File(context.applicationInfo.nativeLibraryDir) - var appSourceDir: File = File(context.applicationInfo.sourceDir) + private val appFilesDir: File = context.filesDir + private val appDataDir: File = context.getDir(DIRECTORY_TOR_DATA, Context.MODE_PRIVATE) + private val appNativeDir: File = File(context.applicationInfo.nativeLibraryDir) + private val appSourceDir: File = File(context.applicationInfo.sourceDir) lateinit var fileTor: File lateinit var fileTorrcCustom: File lateinit var fileTorControlPort: File lateinit var fileTorrc: File - - /** - * Install the Tor geo IP resources from assets to app files directory. - */ - fun installGeoIPResources() { - assetToFile(appFilesDir.absolutePath, COMMON_ASSET_KEY + GEOIP_ASSET_KEY, GEOIP_ASSET_KEY) - assetToFile(appFilesDir.absolutePath, COMMON_ASSET_KEY + GEOIP6_ASSET_KEY, GEOIP6_ASSET_KEY) - } - - fun assetToFile(filesPath: String, assetPath: String, assetKey: String, isZipped: Boolean = false, setExecutable: Boolean = false): File { - val inputStream = context.assets.open(assetPath) - val outFile = File(filesPath, assetKey) - if (!outFile.exists()) { - streamToFile(inputStream, outFile, isZipped = isZipped) - if (setExecutable) { - makeFileExecutable(outFile) - } - } - return outFile - } - - private fun streamToFile(inputStream: InputStream, outFile: File, append: Boolean = false, isZipped: Boolean = false) { - FileOutputStream(outFile.absolutePath, append).use { outputStream -> - (if (isZipped) ZipInputStream(inputStream).also { it.nextEntry } else inputStream).use { input -> - var byteCount: Int - val buffer = ByteArray(FILE_WRITE_BUFFER_SIZE) - while (input.read(buffer).also { byteCount = it } > 0) { - outputStream.write(buffer, 0, byteCount) - } - } - } - } - fun installResources() { if (!appFilesDir.exists()) appFilesDir.mkdirs() @@ -142,6 +108,38 @@ class TorResourceInstaller( } } + /** + * Install the Tor geo IP resources from assets to app files directory. + */ + private fun installGeoIPResources() { + assetToFile(appFilesDir.absolutePath, COMMON_ASSET_KEY + GEOIP_ASSET_KEY, GEOIP_ASSET_KEY) + assetToFile(appFilesDir.absolutePath, COMMON_ASSET_KEY + GEOIP6_ASSET_KEY, GEOIP6_ASSET_KEY) + } + + private fun assetToFile(filesPath: String, assetPath: String, assetKey: String, isZipped: Boolean = false, setExecutable: Boolean = false): File { + val inputStream = context.assets.open(assetPath) + val outFile = File(filesPath, assetKey) + if (!outFile.exists()) { + streamToFile(inputStream, outFile, isZipped = isZipped) + if (setExecutable) { + makeFileExecutable(outFile) + } + } + return outFile + } + + private fun streamToFile(inputStream: InputStream, outFile: File, append: Boolean = false, isZipped: Boolean = false) { + FileOutputStream(outFile.absolutePath, append).use { outputStream -> + (if (isZipped) ZipInputStream(inputStream).also { it.nextEntry } else inputStream).use { input -> + var byteCount: Int + val buffer = ByteArray(FILE_WRITE_BUFFER_SIZE) + while (input.read(buffer).also { byteCount = it } > 0) { + outputStream.write(buffer, 0, byteCount) + } + } + } + } + private fun updateTorrcCustomFile(): File? { val extraLines = StringBuffer().apply { @@ -164,8 +162,6 @@ class TorResourceInstaller( } } - Logger.d("TorRC:\n %s", extraLines.toString()) - val fileTorRcCustom = File(fileTorrc.absolutePath + ".custom") val success = updateTorConfigCustom(fileTorRcCustom, extraLines.toString()) diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeViewModel.kt deleted file mode 100644 index b84061f3d..000000000 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeViewModel.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tari.android.wallet.ui.activity.home - -import com.tari.android.wallet.ui.common.CommonViewModel - -internal class HomeViewModel: CommonViewModel() \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/home/NonSwipeableViewPager.kt b/app/src/main/java/com/tari/android/wallet/ui/activity/home/NonSwipeableViewPager.kt deleted file mode 100644 index b0ee0887a..000000000 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/home/NonSwipeableViewPager.kt +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.ui.activity.home - -import android.annotation.SuppressLint -import android.content.Context -import android.util.AttributeSet -import android.view.MotionEvent -import androidx.viewpager.widget.ViewPager - -class NonSwipeableViewPager : ViewPager { - - constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - - override fun onInterceptTouchEvent(event: MotionEvent?): Boolean = false - - @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent?): Boolean = false -} diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt index 6b8903845..7da0e8e0f 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt @@ -1,18 +1,21 @@ package com.tari.android.wallet.ui.common import android.content.Intent +import android.hardware.SensorManager import android.net.Uri import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.viewbinding.ViewBinding +import com.squareup.seismic.ShakeDetector import com.tari.android.wallet.R import com.tari.android.wallet.extension.observe import com.tari.android.wallet.ui.dialog.TariDialog import com.tari.android.wallet.ui.dialog.inProgress.TariProgressDialog import com.tari.android.wallet.ui.dialog.modular.ModularDialog +import com.tari.android.wallet.ui.fragment.debug.activity.DebugActivity import yat.android.lib.YatIntegration -abstract class CommonActivity : AppCompatActivity() { +abstract class CommonActivity : AppCompatActivity(), ShakeDetector.Listener { private var currentDialog: TariDialog? = null @@ -20,6 +23,8 @@ abstract class CommonActivity : App protected lateinit var viewModel: VM + private val shakeDetector by lazy { ShakeDetector(this) } + fun bindViewModel(viewModel: VM) = with(viewModel) { this@CommonActivity.viewModel = viewModel @@ -29,9 +34,21 @@ abstract class CommonActivity : App observe(modularDialog) { replaceDialog(ModularDialog(this@CommonActivity, it)) } + observe(dismissDialog) { currentDialog?.dismiss() } + observe(loadingDialog) { if (it.isShow) replaceDialog(TariProgressDialog(this@CommonActivity, it)) else currentDialog?.dismiss() } } + override fun onStart() { + (getSystemService(SENSOR_SERVICE) as? SensorManager)?.let(shakeDetector::start) + super.onStart() + } + + override fun onStop() { + shakeDetector.stop() + super.onStop() + } + override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) intent.data?.let { deepLink -> YatIntegration.processDeepLink(this, deepLink) } @@ -48,9 +65,35 @@ abstract class CommonActivity : App } private fun replaceDialog(dialog: TariDialog) { + val currentLoadingDialog = currentDialog as? TariProgressDialog + if (currentLoadingDialog != null && currentLoadingDialog.isShowing() && dialog is TariProgressDialog) { + (currentDialog as TariProgressDialog).applyArgs(dialog.progressDialogArgs) + return + } + val currentModularDialog = currentDialog as? ModularDialog + val newModularDialog = dialog as? ModularDialog + if (currentModularDialog != null && newModularDialog != null && currentModularDialog.args::class.java == newModularDialog.args::class.java + && currentModularDialog.isShowing() + ) { + currentModularDialog.applyArgs(newModularDialog.args) + return + } + + if (newModularDialog?.args?.dialogArgs?.isRefreshing == true) { + return + } + currentDialog?.dismiss() currentDialog = dialog.also { it.show() } } + + override fun hearShake() = openDebugActivity() + + fun openDebugActivity() { + val intent = Intent(this, DebugActivity::class.java) + startActivity(intent) + overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left) + } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt index 16a4d1e2f..8f7d9e463 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt @@ -2,12 +2,13 @@ package com.tari.android.wallet.ui.common import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel +import com.orhanobut.logger.Logger +import com.orhanobut.logger.Printer import com.tari.android.wallet.application.WalletState import com.tari.android.wallet.di.ApplicationComponent import com.tari.android.wallet.di.DiContainer import com.tari.android.wallet.event.EventBus import com.tari.android.wallet.extension.addTo -import com.tari.android.wallet.infrastructure.Tracker import com.tari.android.wallet.ui.common.domain.ResourceManager import com.tari.android.wallet.ui.dialog.error.WalletErrorArgs import com.tari.android.wallet.ui.dialog.inProgress.ProgressDialogArgs @@ -19,25 +20,29 @@ open class CommonViewModel : ViewModel() { var compositeDisposable: CompositeDisposable = CompositeDisposable() - internal val component: ApplicationComponent + val component: ApplicationComponent get() = DiContainer.appComponent @Inject lateinit var resourceManager: ResourceManager - @Inject - lateinit var tracker: Tracker + val logger: Printer + get() = Logger.t("screen").t(this::class.simpleName) init { @Suppress("LeakingThis") component.inject(this) + logger.i(this::class.simpleName + "was started") + EventBus.walletState.publishSubject.filter { it is WalletState.Failed } - .subscribe { - val errorArgs = WalletErrorArgs(resourceManager, (it as WalletState.Failed).exception).getErrorArgs().getModular(resourceManager) + .subscribe({ + val exception = (it as WalletState.Failed).exception + val errorArgs = WalletErrorArgs(resourceManager, exception).getErrorArgs().getModular(resourceManager) _modularDialog.postValue(errorArgs) - }.addTo(compositeDisposable) + }, { logger.e(it, "on showing error dialog from wallet") }) + .addTo(compositeDisposable) } override fun onCleared() { diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/LiveDataExtension.kt b/app/src/main/java/com/tari/android/wallet/ui/common/LiveDataExtension.kt index b5dae758a..755fab076 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/common/LiveDataExtension.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/common/LiveDataExtension.kt @@ -5,7 +5,6 @@ import android.os.Looper import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData -// позволяет тротлить liveData fun LiveData.debounce(duration: Long = 1000L) = MediatorLiveData().also { mld -> val source = this val handler = Handler(Looper.getMainLooper()) diff --git a/app/src/main/java/com/tari/android/wallet/ui/resource/Resource.kt b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/GiphyAdapter.kt similarity index 87% rename from app/src/main/java/com/tari/android/wallet/ui/resource/Resource.kt rename to app/src/main/java/com/tari/android/wallet/ui/common/gyphy/GiphyAdapter.kt index 3b2a79f30..723e6699d 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/resource/Resource.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/GiphyAdapter.kt @@ -30,10 +30,12 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.resource +package com.tari.android.wallet.ui.common.gyphy -interface Resource { +import android.content.Context +import com.giphy.sdk.ui.Giphy - fun dispose() +class GiphyAdapter(private val context: Context, private val key: String) { + fun init() = Giphy.configure(context, key) } diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/placeholder/GifColorPlaceholder.kt b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/placeholder/GifColorPlaceholder.kt index 4730adaec..a6f6b6039 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/placeholder/GifColorPlaceholder.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/placeholder/GifColorPlaceholder.kt @@ -5,7 +5,7 @@ import androidx.annotation.ColorInt import com.facebook.drawee.drawable.RoundedColorDrawable import kotlin.math.abs -internal class GifColorPlaceholder private constructor(@field:ColorInt @param:ColorInt private val color: Int, private val cornerRadius: Float) : +class GifColorPlaceholder private constructor(@field:ColorInt @param:ColorInt private val color: Int, private val cornerRadius: Float) : GifPlaceholder { override fun asDrawable(): Drawable = RoundedColorDrawable(cornerRadius, color) @@ -14,8 +14,7 @@ internal class GifColorPlaceholder private constructor(@field:ColorInt @param:Co private val BUILT_IN_COLORS = intArrayOf(-0xff481b, -0x1a25ad, -0x76d11b, -0xff1a77, -0x1aa3a4) @JvmOverloads - fun generate(target: Any, cornerRadius: Float = DEFAULT_CORNER_RADIUS): GifColorPlaceholder { - return GifColorPlaceholder(BUILT_IN_COLORS[abs(target.hashCode()) % BUILT_IN_COLORS.size], cornerRadius) - } + fun generate(target: Any, cornerRadius: Float = DEFAULT_CORNER_RADIUS): GifColorPlaceholder = + GifColorPlaceholder(BUILT_IN_COLORS[abs(target.hashCode()) % BUILT_IN_COLORS.size], cornerRadius) } } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GIFViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GIFViewModel.kt index 858e9949e..2110e69bd 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GIFViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GIFViewModel.kt @@ -2,12 +2,11 @@ package com.tari.android.wallet.ui.common.gyphy.presentation import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.orhanobut.logger.Logger import com.tari.android.wallet.extension.addTo -import com.tari.android.wallet.ui.common.gyphy.repository.GIFItem import com.tari.android.wallet.ui.common.gyphy.presentation.GIFState.* +import com.tari.android.wallet.ui.common.gyphy.repository.GIFItem import com.tari.android.wallet.ui.common.gyphy.repository.GIFRepository -import com.tari.android.wallet.ui.presentation.TxNote +import com.tari.android.wallet.model.TxNote import io.reactivex.Observable import io.reactivex.ObservableEmitter import io.reactivex.android.schedulers.AndroidSchedulers @@ -33,7 +32,7 @@ class GIFViewModel(private val repository: GIFRepository) { .onErrorReturn { ErrorState } .startWith(LoadingState) .subscribeOn(Schedulers.io()) - .doOnError { e -> Logger.e(e, "Error occurred during gif loading") } + .doOnError { } } .observeOn(AndroidSchedulers.mainThread()) .subscribe { _gifState.postValue(it) } diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt index 81cfbf6ab..2df6fca08 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt @@ -6,7 +6,8 @@ import com.bumptech.glide.load.resource.gif.GifDrawable import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.target.Target -class GlideGIFListener(val consumer: GIFStateConsumer) : RequestListener { +class GlideGIFListener(private val consumer: GIFStateConsumer) : RequestListener { + override fun onLoadFailed( e: GlideException?, model: Any?, @@ -27,5 +28,4 @@ class GlideGIFListener(val consumer: GIFStateConsumer) : RequestListener { val response: Response = gateway.searchGIFs(query, limit).execute() val body = response.body() return if (response.isSuccessful && body != null && body.meta.status in 200..299) - body.data.map { - // TODO GIF OPTIMIZATION: change it.images.*variant* here to check other variants - GIFItem(it.id, Uri.parse(it.embedUrl), Uri.parse(it.images.fixedWidth.url)) - } + body.data.map { GIFItem(it.id, Uri.parse(it.embedUrl), Uri.parse(it.images.fixedWidth.url)) } else { - throw GIFSearchException(body?.meta?.message ?: response.message() ?: response.errorBody()?.string()) + val exception = GIFSearchException(body?.meta?.message ?: response.message() ?: response.errorBody()?.string()) + logger.e(exception, "Get all was failed") + throw exception } } @@ -26,11 +29,11 @@ class GiphyRESTRetrofitRepository(private val gateway: GiphyRESTGateway) : GIFRe val response: Response = gateway.getGIFByID(id).execute() val body = response.body() return if (response.isSuccessful && body != null && body.meta.status in 200..299) - // TODO GIF OPTIMIZATION: change it.images.*variant* here to check other variants body.data.let { GIFItem(it.id, Uri.parse(it.embedUrl), Uri.parse(it.images.fixedWidth.url)) } else { - throw GIFSearchException(body?.meta?.message ?: response.message() ?: response.errorBody()?.string()) + val exception = GIFSearchException(body?.meta?.message ?: response.message() ?: response.errorBody()?.string()) + logger.e(exception, "Get all was failed") + throw exception } } - } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdCopiedViewController.kt b/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdCopiedViewController.kt index caf6d55c2..bf6b12b5e 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdCopiedViewController.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdCopiedViewController.kt @@ -47,7 +47,7 @@ import com.tari.android.wallet.util.Constants * * @author The Tari Development Team */ -internal class EmojiIdCopiedViewController(private val ui: ViewEmojiIdCopiedAnimBinding) { +class EmojiIdCopiedViewController(private val ui: ViewEmojiIdCopiedAnimBinding) { init { whiteBgView.post { diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdSummaryViewController.kt b/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdSummaryViewController.kt index 8f79c86a3..c93a450fe 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdSummaryViewController.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/component/EmojiIdSummaryViewController.kt @@ -42,7 +42,7 @@ import com.tari.android.wallet.ui.extension.setVisible * * @author The Tari Development Team */ -internal class EmojiIdSummaryViewController(private val ui: ViewEmojiIdSummaryBinding) { +class EmojiIdSummaryViewController(private val ui: ViewEmojiIdSummaryBinding) { constructor(view: View) : this(ViewEmojiIdSummaryBinding.bind(view)) diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/FullEmojiIdViewController.kt b/app/src/main/java/com/tari/android/wallet/ui/component/FullEmojiIdViewController.kt index 477286fc8..2fe485075 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/component/FullEmojiIdViewController.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/component/FullEmojiIdViewController.kt @@ -57,7 +57,7 @@ import me.everything.android.ui.overscroll.OverScrollDecoratorHelper * * @author The Tari Development Team */ -internal class FullEmojiIdViewController( +class FullEmojiIdViewController( private val ui: ViewFullEmojiIdBinding, summary: ViewEmojiIdSummaryBinding, private val context: Context, diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/LetterSpacingSpan.kt b/app/src/main/java/com/tari/android/wallet/ui/component/LetterSpacingSpan.kt index 6e57b27bf..e0fd76dc0 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/component/LetterSpacingSpan.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/component/LetterSpacingSpan.kt @@ -40,7 +40,7 @@ import android.text.style.MetricAffectingSpan * * @author The Tari Development Team */ -internal class LetterSpacingSpan(private val letterSpacing: Float): MetricAffectingSpan() { +class LetterSpacingSpan(private val letterSpacing: Float): MetricAffectingSpan() { override fun updateMeasureState(drawState: TextPaint) { apply(drawState) diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/MainListImageButton.kt b/app/src/main/java/com/tari/android/wallet/ui/component/MainListImageButton.kt index 63c9663d5..83fcafa0d 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/component/MainListImageButton.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/component/MainListImageButton.kt @@ -40,7 +40,7 @@ import com.tari.android.wallet.databinding.ViewMainListImageButtonBinding import com.tari.android.wallet.ui.common.CommonViewModel -internal class MainListImageButton : MainListTouchingView { +class MainListImageButton : MainListTouchingView { override fun bindingInflate(layoutInflater: LayoutInflater, parent: ViewGroup?, attachToRoot: Boolean): ViewMainListImageButtonBinding = ViewMainListImageButtonBinding.inflate(layoutInflater, parent, attachToRoot) diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorView.kt b/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorView.kt index 4121c502b..7b7c7797c 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorView.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorView.kt @@ -41,7 +41,7 @@ import com.tari.android.wallet.extension.observe import com.tari.android.wallet.ui.component.MainListTouchingView -internal class ConnectionIndicatorView : MainListTouchingView { +class ConnectionIndicatorView : MainListTouchingView { override fun bindingInflate(layoutInflater: LayoutInflater, parent: ViewGroup?, attachToRoot: Boolean): ViewConnectionIndicatorBinding = ViewConnectionIndicatorBinding.inflate(layoutInflater, parent, attachToRoot) diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorViewModel.kt index 0529812f7..eea8a43a5 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/component/networkStateIndicator/ConnectionIndicatorViewModel.kt @@ -17,7 +17,7 @@ import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonModule import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonStyle import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule -internal class ConnectionIndicatorViewModel : CommonViewModel() { +class ConnectionIndicatorViewModel : CommonViewModel() { private val _networkState = MutableLiveData() private val _torProxyState = MutableLiveData() diff --git a/app/src/main/java/com/tari/android/wallet/ui/dialog/error/ErrorDialogArgs.kt b/app/src/main/java/com/tari/android/wallet/ui/dialog/error/ErrorDialogArgs.kt index fae85c3f6..9abd850ec 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/dialog/error/ErrorDialogArgs.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/dialog/error/ErrorDialogArgs.kt @@ -16,8 +16,8 @@ class ErrorDialogArgs( val canceledOnTouchOutside: Boolean = true, val onClose: () -> Unit = {}, ) { - fun getModular(resourceManager: ResourceManager): ModularDialogArgs = ModularDialogArgs( - DialogArgs(cancelable, canceledOnTouchOutside, false, onClose), modules = listOf( + fun getModular(resourceManager: ResourceManager, isRefreshing: Boolean = false): ModularDialogArgs = ModularDialogArgs( + DialogArgs(cancelable, canceledOnTouchOutside, isRefreshing, onClose), modules = listOf( HeadModule(title.toString()), BodyModule(description.toString()), ButtonModule(resourceManager.getString(R.string.common_close), ButtonStyle.Close, onClose) diff --git a/app/src/main/java/com/tari/android/wallet/ui/extension/ContextExtensions.kt b/app/src/main/java/com/tari/android/wallet/ui/extension/ContextExtensions.kt index 24e62f27d..239cbc0fe 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/extension/ContextExtensions.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/extension/ContextExtensions.kt @@ -43,19 +43,19 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.core.content.ContextCompat -internal fun Context.string(@StringRes id: Int): String = resources.getString(id) +fun Context.string(@StringRes id: Int): String = resources.getString(id) -internal fun Context.string(@StringRes id: Int, vararg formatArgs: Any): String = resources.getString(id, *formatArgs) +fun Context.string(@StringRes id: Int, vararg formatArgs: Any): String = resources.getString(id, *formatArgs) -internal fun Context.color(@ColorRes id: Int): Int = ContextCompat.getColor(this, id) +fun Context.color(@ColorRes id: Int): Int = ContextCompat.getColor(this, id) -internal fun Context.dimenPx(@DimenRes id: Int): Int = resources.getDimensionPixelSize(id) +fun Context.dimenPx(@DimenRes id: Int): Int = resources.getDimensionPixelSize(id) -internal fun Context.dimen(@DimenRes id: Int): Float = resources.getDimension(id) +fun Context.dimen(@DimenRes id: Int): Float = resources.getDimension(id) -internal fun Context.dpToPx(dp: Float): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources?.displayMetrics) +fun Context.dpToPx(dp: Float): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources?.displayMetrics) -internal fun Context.drawable(@DrawableRes id: Int): Drawable? = ContextCompat.getDrawable(this, id) +fun Context.drawable(@DrawableRes id: Int): Drawable? = ContextCompat.getDrawable(this, id) /** diff --git a/app/src/main/java/com/tari/android/wallet/ui/extension/FragmentExtensions.kt b/app/src/main/java/com/tari/android/wallet/ui/extension/FragmentExtensions.kt index 36a0ec9f3..6e1ef25de 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/extension/FragmentExtensions.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/extension/FragmentExtensions.kt @@ -39,15 +39,15 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.fragment.app.Fragment -internal fun Fragment.string(@StringRes id: Int): String = requireContext().string(id) +fun Fragment.string(@StringRes id: Int): String = requireContext().string(id) -internal fun Fragment.string(@StringRes id: Int, vararg formatArgs: Any): String = +fun Fragment.string(@StringRes id: Int, vararg formatArgs: Any): String = requireContext().string(id, *formatArgs) -internal fun Fragment.color(@ColorRes id: Int): Int = requireContext().color(id) +fun Fragment.color(@ColorRes id: Int): Int = requireContext().color(id) -internal fun Fragment.dimenPx(@DimenRes id: Int): Int = requireContext().dimenPx(id) +fun Fragment.dimenPx(@DimenRes id: Int): Int = requireContext().dimenPx(id) -internal fun Fragment.dimen(@DimenRes id: Int): Float = requireContext().dimen(id) +fun Fragment.dimen(@DimenRes id: Int): Float = requireContext().dimen(id) -internal fun Fragment.drawable(@DrawableRes id: Int): Drawable? = requireContext().drawable(id) \ No newline at end of file +fun Fragment.drawable(@DrawableRes id: Int): Drawable? = requireContext().drawable(id) \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/extension/ViewExtensions.kt b/app/src/main/java/com/tari/android/wallet/ui/extension/ViewExtensions.kt index 39006ea19..eb26bb9eb 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/extension/ViewExtensions.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/extension/ViewExtensions.kt @@ -54,7 +54,6 @@ import androidx.fragment.app.FragmentTransaction import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.airbnb.lottie.LottieAnimationView -import com.orhanobut.logger.Logger import com.tari.android.wallet.R import com.tari.android.wallet.ui.dialog.modular.DialogArgs import com.tari.android.wallet.ui.dialog.modular.ModularDialog @@ -68,37 +67,39 @@ import java.lang.ref.WeakReference import android.animation.Animator as LegacyAnimator import android.animation.Animator.AnimatorListener as LegacyAnimatorListener -internal fun RecyclerView.isScrolledToTop(): Boolean { +fun RecyclerView.isScrolledToTop(): Boolean { val layoutManager = (layoutManager as? LinearLayoutManager) ?: return false if (layoutManager.childCount == 0) return true return (layoutManager.findFirstVisibleItemPosition() == 0 && layoutManager.findViewByPosition(0)?.top == 0) } -internal fun View.visible() { +fun View.visible() { this.visibility = View.VISIBLE } -internal fun View.invisible() { +fun View.invisible() { this.visibility = View.INVISIBLE } -internal fun View.gone() { +fun View.gone() { this.visibility = View.GONE } -internal fun View.setVisible(visible: Boolean, hideState: Int = View.GONE) { +fun View.setVisible(visible: Boolean, hideState: Int = View.GONE) { visibility = if (visible) View.VISIBLE else hideState } /** * Given the context, displays the standard "no internet connection" dialog. */ -internal fun showInternetConnectionErrorDialog(context: Context) { - val args = ModularDialogArgs(DialogArgs(), listOf( - HeadModule(context.string(R.string.internet_connection_error_dialog_title)), - BodyModule(context.string(R.string.internet_connection_error_dialog_description)), - ButtonModule(context.string(R.string.common_close), ButtonStyle.Close) - )) +fun showInternetConnectionErrorDialog(context: Context) { + val args = ModularDialogArgs( + DialogArgs(), listOf( + HeadModule(context.string(R.string.internet_connection_error_dialog_title)), + BodyModule(context.string(R.string.internet_connection_error_dialog_description)), + ButtonModule(context.string(R.string.common_close), ButtonStyle.Close) + ) + ) ModularDialog(context, args).show() } @@ -106,7 +107,7 @@ internal fun showInternetConnectionErrorDialog(context: Context) { * Sets the width of a TextView to the measured width of its contents * taking into account the text size and the typeface. */ -internal fun TextView.setWidthToMeasured() { +fun TextView.setWidthToMeasured() { measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) setLayoutWidth(measuredWidth) } @@ -115,7 +116,7 @@ internal fun TextView.setWidthToMeasured() { * Sets the size of a TextView to the measured size of its contents * taking into account the text size and the typeface. */ -internal fun TextView.setWidthAndHeightToMeasured() { +fun TextView.setWidthAndHeightToMeasured() { measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) setLayoutWidth(measuredWidth) setLayoutHeight(measuredHeight) @@ -124,34 +125,34 @@ internal fun TextView.setWidthAndHeightToMeasured() { /** * Sets text size in pixel units. */ -internal fun TextView.setTextSizePx(sizePx: Float) = setTextSize(TypedValue.COMPLEX_UNIT_PX, sizePx) +fun TextView.setTextSizePx(sizePx: Float) = setTextSize(TypedValue.COMPLEX_UNIT_PX, sizePx) /** * @return first child of the view group, null if no children */ -internal fun ViewGroup.getFirstChild(): View? = if (childCount > 0) this.getChildAt(0) else null +fun ViewGroup.getFirstChild(): View? = if (childCount > 0) this.getChildAt(0) else null /** * @return last child of the view group, null if no children */ -internal fun ViewGroup.getLastChild(): View? = if (childCount > 0) this.getChildAt(childCount - 1) else null +fun ViewGroup.getLastChild(): View? = if (childCount > 0) this.getChildAt(childCount - 1) else null /** * Scroll to the top of the scroll view. */ -internal fun ScrollView.scrollToTop() = scrollTo(0, 0) +fun ScrollView.scrollToTop() = scrollTo(0, 0) /** * Scroll to the bottom of the scroll view. */ -internal fun ScrollView.scrollToBottom() { +fun ScrollView.scrollToBottom() { val lastChild = getChildAt(childCount - 1) val bottom = lastChild.bottom + paddingBottom val delta = bottom - (scrollY + height) smoothScrollBy(0, delta) } -internal fun LottieAnimationView.addAnimatorListener( +fun LottieAnimationView.addAnimatorListener( onStart: (LegacyAnimator?) -> Unit = {}, onEnd: (LegacyAnimator?) -> Unit = {}, onCancel: (LegacyAnimator?) -> Unit = {}, @@ -165,7 +166,7 @@ internal fun LottieAnimationView.addAnimatorListener( }) } -internal fun View.doOnGlobalLayout(block: () -> Unit) { +fun View.doOnGlobalLayout(block: () -> Unit) { this.viewTreeObserver.addOnGlobalLayoutListener( object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { @@ -175,7 +176,7 @@ internal fun View.doOnGlobalLayout(block: () -> Unit) { }) } -internal fun View.setTopMargin(margin: Int) { +fun View.setTopMargin(margin: Int) { if (layoutParams is ViewGroup.MarginLayoutParams) { val layoutParams = layoutParams as ViewGroup.MarginLayoutParams layoutParams.topMargin = margin @@ -183,7 +184,7 @@ internal fun View.setTopMargin(margin: Int) { } } -internal fun View.setBottomMargin(margin: Int) { +fun View.setBottomMargin(margin: Int) { if (layoutParams is ViewGroup.MarginLayoutParams) { val layoutParams = layoutParams as ViewGroup.MarginLayoutParams layoutParams.bottomMargin = margin @@ -191,23 +192,23 @@ internal fun View.setBottomMargin(margin: Int) { } } -internal fun View.postDelayed(timeMillis: Long, action: () -> Unit) = this.postDelayed(action, timeMillis) +fun View.postDelayed(timeMillis: Long, action: () -> Unit) = this.postDelayed(action, timeMillis) -internal fun View.string(@StringRes id: Int): String = context.string(id) +fun View.string(@StringRes id: Int): String = context.string(id) -internal fun View.string(@StringRes id: Int, vararg formatArgs: Any): String = context.string(id, *formatArgs) +fun View.string(@StringRes id: Int, vararg formatArgs: Any): String = context.string(id, *formatArgs) -internal fun View.color(@ColorRes id: Int): Int = context.color(id) +fun View.color(@ColorRes id: Int): Int = context.color(id) -internal fun View.dimen(@DimenRes id: Int): Float = context.dimen(id) +fun View.dimen(@DimenRes id: Int): Float = context.dimen(id) -internal fun View.dimenPx(@DimenRes id: Int): Int = context.dimenPx(id) +fun View.dimenPx(@DimenRes id: Int): Int = context.dimenPx(id) -internal fun View.drawable(@DrawableRes id: Int): Drawable? = context.drawable(id) +fun View.drawable(@DrawableRes id: Int): Drawable? = context.drawable(id) -internal fun View.setOnThrottledClickListener(action: (View) -> Unit) = this.setOnClickListener(ThrottleClick(action)) +fun View.setOnThrottledClickListener(action: (View) -> Unit) = this.setOnClickListener(ThrottleClick(action)) -internal class ThrottleClick(private val delegate: (View) -> Unit) : View.OnClickListener { +class ThrottleClick(private val delegate: (View) -> Unit) : View.OnClickListener { override fun onClick(v: View?) { v?.temporarilyDisableClick() v?.let(delegate) @@ -267,25 +268,21 @@ fun View.temporarilyDisableClick() { fun AppCompatEditText.setTextSilently(newText: String) { if (text.toString() != newText) { - try { + runCatching { var selectionStartPoint = selectionStart var selectionEndPoint = selectionEnd setText(newText) selectionEndPoint = selectionEnd.coerceAtMost(newText.length) selectionStartPoint = selectionStart.coerceAtMost(selectionEnd) setSelection(selectionStartPoint, selectionEndPoint) - } catch (e: Throwable) { - Logger.i(e.toString()) } } } fun AppCompatEditText.setSelectionToEnd() { - try { + runCatching { val selectionEndPoint = text.toString().length setSelection(selectionEndPoint, selectionEndPoint) - } catch (e: Throwable) { - Logger.i(e.toString()) } } @@ -298,10 +295,8 @@ private class ClickEnablingRunnable(@NonNull view: View) : Runnable { override fun run() { viewWR.get()?.run { - try { + runCatching { isClickable = true - } catch (e: Throwable) { - // no-op } } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/extension/ViewHolderExtensions.kt b/app/src/main/java/com/tari/android/wallet/ui/extension/ViewHolderExtensions.kt index 27d38f46c..e2ed43187 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/extension/ViewHolderExtensions.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/extension/ViewHolderExtensions.kt @@ -39,12 +39,12 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.recyclerview.widget.RecyclerView.ViewHolder -internal fun ViewHolder.dimen(@DimenRes id: Int): Int = itemView.dimenPx(id) +fun ViewHolder.dimen(@DimenRes id: Int): Int = itemView.dimenPx(id) -internal fun ViewHolder.string(@StringRes id: Int): String = itemView.string(id) +fun ViewHolder.string(@StringRes id: Int): String = itemView.string(id) -internal fun ViewHolder.string(@StringRes id: Int, vararg formatArgs: Any): String = itemView.string(id, *formatArgs) +fun ViewHolder.string(@StringRes id: Int, vararg formatArgs: Any): String = itemView.string(id, *formatArgs) -internal fun ViewHolder.color(@ColorRes id: Int): Int = itemView.color(id) +fun ViewHolder.color(@ColorRes id: Int): Int = itemView.color(id) -internal fun ViewHolder.drawable(@DrawableRes id: Int): Drawable? = itemView.drawable(id) +fun ViewHolder.drawable(@DrawableRes id: Int): Drawable? = itemView.drawable(id) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt index b0f6c0148..ec16500ea 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt @@ -40,8 +40,6 @@ import android.os.Bundle import android.view.View import androidx.activity.viewModels import androidx.appcompat.app.AlertDialog -import androidx.biometric.BiometricPrompt.ERROR_CANCELED -import androidx.biometric.BiometricPrompt.ERROR_USER_CANCELED import androidx.core.animation.addListener import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope @@ -55,7 +53,7 @@ import com.tari.android.wallet.databinding.ActivityAuthBinding import com.tari.android.wallet.event.EventBus import com.tari.android.wallet.extension.addTo import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationException -import com.tari.android.wallet.ui.activity.home.HomeActivity +import com.tari.android.wallet.ui.fragment.home.HomeActivity import com.tari.android.wallet.ui.common.CommonActivity import com.tari.android.wallet.ui.extension.* import com.tari.android.wallet.ui.fragment.settings.allSettings.TariVersionModel @@ -78,9 +76,6 @@ class AuthActivity : CommonActivity() { setupUi() viewModel.walletServiceLauncher.start() - if (savedInstanceState == null) { - viewModel.tracker.screen(path = "/local_auth", title = "Local Authentication") - } } private fun setupUi() { @@ -146,8 +141,6 @@ class AuthActivity : CommonActivity() { ) authSuccessful() } catch (e: BiometricAuthenticationException) { - if (e.code != ERROR_USER_CANCELED && e.code != ERROR_CANCELED) - Logger.e("Other biometric error. Code: ${e.code}") authHasFailed() } } @@ -169,7 +162,6 @@ class AuthActivity : CommonActivity() { * Auth has failed. */ private fun authHasFailed() { - Logger.e("Authentication other error.") displayAuthFailedDialog() } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt index d668b566c..8735cf33c 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt @@ -3,7 +3,7 @@ package com.tari.android.wallet.ui.fragment.auth import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationService -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.CommonViewModel import javax.inject.Inject diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/AboutFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/AboutFragment.kt index 2c968fe6b..23ec6f37a 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/AboutFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/AboutFragment.kt @@ -45,7 +45,7 @@ import com.tari.android.wallet.databinding.FragmentAboutBinding * * @author The Tari Development Team */ -internal class AboutFragment : Fragment() { +class AboutFragment : Fragment() { private lateinit var ui: FragmentAboutBinding diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/debug/DebugActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/activity/DebugActivity.kt similarity index 95% rename from app/src/main/java/com/tari/android/wallet/ui/activity/debug/DebugActivity.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/debug/activity/DebugActivity.kt index 2d65cc655..6875b019e 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/debug/DebugActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/activity/DebugActivity.kt @@ -30,7 +30,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.activity.debug +package com.tari.android.wallet.ui.fragment.debug.activity import android.os.Bundle import androidx.appcompat.app.AppCompatActivity @@ -39,7 +39,6 @@ import com.google.android.material.tabs.TabLayoutMediator import com.tari.android.wallet.R import com.tari.android.wallet.databinding.ActivityDebugBinding import com.tari.android.wallet.di.DiContainer.appComponent -import com.tari.android.wallet.ui.activity.debug.adapter.DebugViewPagerAdapter import com.tari.android.wallet.ui.extension.addEnterLeftAnimation import com.tari.android.wallet.ui.extension.string import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.BaseNodeConfigRouter @@ -51,7 +50,7 @@ import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.changeBaseNode.C * * @author The Tari Development Team */ -internal class DebugActivity : AppCompatActivity(), BaseNodeConfigRouter { +class DebugActivity : AppCompatActivity(), BaseNodeConfigRouter { private lateinit var pagerAdapter: DebugViewPagerAdapter @@ -93,4 +92,4 @@ internal class DebugActivity : AppCompatActivity(), BaseNodeConfigRouter { .addToBackStack(null) .commit() } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/debug/adapter/DebugViewPagerAdapter.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/activity/DebugViewPagerAdapter.kt similarity index 85% rename from app/src/main/java/com/tari/android/wallet/ui/activity/debug/adapter/DebugViewPagerAdapter.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/debug/activity/DebugViewPagerAdapter.kt index d36872045..ccebf5557 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/debug/adapter/DebugViewPagerAdapter.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/activity/DebugViewPagerAdapter.kt @@ -30,30 +30,23 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.activity.debug.adapter +package com.tari.android.wallet.ui.fragment.debug.activity import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter import com.tari.android.wallet.ui.fragment.debug.AboutFragment import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.BaseNodeConfigFragment -import com.tari.android.wallet.ui.fragment.debug.DebugLogFragment +import com.tari.android.wallet.ui.fragment.debug.debugLog.DebugLogFragment /** * Fragment pager adapter for debug activity. * * @author The Tari Development Team */ -internal class DebugViewPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) { +class DebugViewPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) { - /** - * Logs and base node configuration. - */ - private val numberOfItems = 3 - - override fun getItemCount(): Int { - return numberOfItems - } + override fun getItemCount(): Int = 3 override fun createFragment(position: Int): Fragment { return when (position) { @@ -63,5 +56,4 @@ internal class DebugViewPagerAdapter(activity: FragmentActivity) : FragmentState else -> throw RuntimeException("Unexpected page position: $position") } } - } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigFragment.kt index 09a0af9ea..2cb65c00c 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigFragment.kt @@ -50,7 +50,7 @@ import com.tari.android.wallet.ui.extension.setOnThrottledClickListener * * @author The Tari Development Team */ -internal class BaseNodeConfigFragment : CommonFragment() { +class BaseNodeConfigFragment : CommonFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = FragmentBaseNodeConfigBinding.inflate(inflater, container, false).also { ui = it }.root diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigViewModel.kt index c50b42961..838e334a1 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/BaseNodeConfigViewModel.kt @@ -12,7 +12,7 @@ import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.common.SingleLiveEvent import javax.inject.Inject -internal class BaseNodeConfigViewModel : CommonViewModel() { +class BaseNodeConfigViewModel : CommonViewModel() { @Inject lateinit var baseNodeSharedRepository: BaseNodeSharedRepository diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeFragment.kt index 65511bc5a..e11e5cb49 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeFragment.kt @@ -58,7 +58,7 @@ import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.validator.Valida * * @author The Tari Development Team */ -internal class AddCustomBaseNodeFragment : CommonFragment() { +class AddCustomBaseNodeFragment : CommonFragment() { override fun onCreateView( inflater: LayoutInflater, diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt index 57411a3b1..fd579485e 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt @@ -13,7 +13,7 @@ import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.validator.Public import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.validator.Validator import javax.inject.Inject -internal class AddCustomBaseNodeViewModel : CommonViewModel() { +class AddCustomBaseNodeViewModel : CommonViewModel() { @Inject lateinit var baseNodeSharedRepository: BaseNodeSharedRepository diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeFragment.kt index b79b06573..1f25461df 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeFragment.kt @@ -46,7 +46,7 @@ import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.BaseNodeConfigRo import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.changeBaseNode.adapter.BaseNodeViewHolderItem import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.changeBaseNode.adapter.ChangeBaseNodeAdapter -internal class ChangeBaseNodeFragment : CommonFragment() { +class ChangeBaseNodeFragment : CommonFragment() { private val adapter = ChangeBaseNodeAdapter() diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt index 394dd031b..ca0a31a48 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt @@ -11,7 +11,7 @@ import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.changeBaseNode.adapter.BaseNodeViewHolderItem import javax.inject.Inject -internal class ChangeBaseNodeViewModel : CommonViewModel() { +class ChangeBaseNodeViewModel : CommonViewModel() { @Inject lateinit var baseNodeSharedRepository: BaseNodeSharedRepository diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/DebugLogFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/DebugLogFragment.kt similarity index 53% rename from app/src/main/java/com/tari/android/wallet/ui/fragment/debug/DebugLogFragment.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/DebugLogFragment.kt index cd2f30e84..9a936967b 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/DebugLogFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/DebugLogFragment.kt @@ -30,7 +30,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.fragment.debug +package com.tari.android.wallet.ui.fragment.debug.debugLog import android.animation.ObjectAnimator import android.os.Bundle @@ -39,89 +39,65 @@ import android.view.View import android.view.ViewGroup import android.widget.AdapterView import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.tari.android.wallet.R.string.* -import com.tari.android.wallet.data.WalletConfig -import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.databinding.FragmentDebugLogBinding -import com.tari.android.wallet.di.DiContainer.appComponent -import com.tari.android.wallet.infrastructure.BugReportingService +import com.tari.android.wallet.extension.observe +import com.tari.android.wallet.infrastructure.logging.BugReportingService +import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.extension.string import com.tari.android.wallet.ui.extension.temporarilyDisableClick -import com.tari.android.wallet.ui.fragment.debug.adapter.LogFileSpinnerAdapter -import com.tari.android.wallet.ui.fragment.debug.adapter.LogListAdapter +import com.tari.android.wallet.ui.fragment.debug.debugLog.adapter.LogFileSpinnerAdapter +import com.tari.android.wallet.ui.fragment.debug.debugLog.adapter.LogListAdapter import com.tari.android.wallet.util.Constants -import com.tari.android.wallet.util.WalletUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.io.File -import java.io.InputStream -import javax.inject.Inject -/** - * Debug: show logs from file. - * - * @author The Tari Development Team - */ -internal class DebugLogFragment : Fragment(), AdapterView.OnItemSelectedListener { +class DebugLogFragment : CommonFragment(), AdapterView.OnItemSelectedListener { - @Inject - lateinit var walletConfig: WalletConfig + private lateinit var recyclerViewAdapter: LogListAdapter - @Inject - lateinit var sharedPrefsWrapper: SharedPrefsRepository + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + FragmentDebugLogBinding.inflate(inflater, container, false).also { ui = it }.root - @Inject - lateinit var bugReportingService: BugReportingService + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) - /** - * Log file related vars. - */ - private lateinit var logFiles: List - private lateinit var selectedLogFile: File - private val selectedLogFileLines = mutableListOf() + val viewModel: DebugLogViewModel by viewModels() + bindViewModel(viewModel) - /** - * List, adapter & layout manager. - */ - private lateinit var spinnerAdapter: LogFileSpinnerAdapter - private lateinit var recyclerViewAdapter: LogListAdapter - private lateinit var recyclerViewLayoutManager: RecyclerView.LayoutManager + setupUI() + observeUI() + } - private lateinit var ui: FragmentDebugLogBinding + private fun setupUI() = with(ui) { + recyclerViewAdapter = LogListAdapter() + recyclerView.layoutManager = LinearLayoutManager(requireContext()) + recyclerView.adapter = recyclerViewAdapter + fileSpinner.onItemSelectedListener = this@DebugLogFragment + scrollToTopButton.setOnClickListener { onScrollToTopButtonClicked() } + scrollToBottomButton.setOnClickListener { onScrollToBottomButtonClicked() } + shareButton.setOnClickListener { showShareLogFilesDialog() } + } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View = FragmentDebugLogBinding.inflate(inflater, container, false).also { ui = it }.root + private fun observeUI() = with(viewModel) { + observe(selectedLogFileLines) { updateLogFileLines(it) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - appComponent.inject(this) - setupUI() + observe(logFiles) { ui.fileSpinner.adapter = LogFileSpinnerAdapter(requireContext(), it) } } - private fun setupUI() { - // read log files - logFiles = WalletUtil.getLogFilesFromDirectory(walletConfig.getWalletLogFilesDirPath()) - - // initialize recycler view - recyclerViewLayoutManager = LinearLayoutManager(activity) - recyclerViewAdapter = LogListAdapter(selectedLogFileLines) - spinnerAdapter = LogFileSpinnerAdapter(requireContext(), logFiles) - ui.apply { - recyclerView.layoutManager = recyclerViewLayoutManager - recyclerView.adapter = recyclerViewAdapter - fileSpinner.onItemSelectedListener = this@DebugLogFragment - fileSpinner.adapter = spinnerAdapter - scrollToTopButton.setOnClickListener { onScrollToTopButtonClicked() } - scrollToBottomButton.setOnClickListener { onScrollToBottomButtonClicked() } - shareButton.setOnClickListener { showShareLogFilesDialog() } + private fun updateLogFileLines(lines: MutableList) { + ui.recyclerView.alpha = 0f + recyclerViewAdapter.logLines.clear() + recyclerViewAdapter.logLines.addAll(lines) + recyclerViewAdapter.notifyDataSetChanged() + ObjectAnimator.ofFloat(ui.recyclerView, "alpha", 0f, 1f).apply { + duration = Constants.UI.mediumDurationMs + startDelay = Constants.UI.shortDurationMs + start() } } @@ -132,7 +108,7 @@ internal class DebugLogFragment : Fragment(), AdapterView.OnItemSelectedListener private fun onScrollToBottomButtonClicked() { ui.scrollToBottomButton.temporarilyDisableClick() - ui.recyclerView.scrollToPosition(selectedLogFileLines.lastIndex) + ui.recyclerView.scrollToPosition(recyclerViewAdapter.logLines.lastIndex) } private fun showShareLogFilesDialog() { @@ -152,10 +128,10 @@ internal class DebugLogFragment : Fragment(), AdapterView.OnItemSelectedListener } private fun shareBugReport() { - val mContext = context ?: return + val mContext = requireContext() lifecycleScope.launch(Dispatchers.IO) { try { - bugReportingService.shareBugReport(mContext) + viewModel.bugReportingService.shareBugReport(mContext) } catch (e: BugReportingService.BugReportFileSizeLimitExceededException) { withContext(Dispatchers.Main) { showBugReportFileSizeExceededDialog() @@ -164,41 +140,20 @@ internal class DebugLogFragment : Fragment(), AdapterView.OnItemSelectedListener } } - override fun onNothingSelected(parent: AdapterView<*>?) { - // no-op - } + override fun onNothingSelected(parent: AdapterView<*>?) = Unit override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { ui.recyclerView.scrollToPosition(0) - selectedLogFile = logFiles[position] - updateLogLines() - } - - private fun updateLogLines() { - ui.recyclerView.alpha = 0f - selectedLogFileLines.clear() - val inputStream: InputStream = selectedLogFile.inputStream() - inputStream.bufferedReader() - .useLines { lines -> lines.forEach { selectedLogFileLines.add(it) } } - recyclerViewAdapter.notifyDataSetChanged() - val anim = ObjectAnimator.ofFloat(ui.recyclerView, "alpha", 0f, 1f) - anim.duration = Constants.UI.mediumDurationMs - anim.startDelay = Constants.UI.shortDurationMs - anim.start() + viewModel.selectFile(position) } private fun showBugReportFileSizeExceededDialog() { - val dialogBuilder = AlertDialog.Builder(context ?: return) - val dialog = dialogBuilder.setMessage( - string(debug_log_file_size_limit_exceeded_dialog_content) - ) + AlertDialog.Builder(requireContext()) + .setMessage(string(debug_log_file_size_limit_exceeded_dialog_content)) .setCancelable(false) - .setPositiveButton(string(common_ok)) { dialog, _ -> - dialog.cancel() - } + .setPositiveButton(string(common_ok)) { dialog, _ -> dialog.cancel() } .setTitle(string(debug_log_file_size_limit_exceeded_dialog_title)) .create() - dialog.show() + .show() } - -} +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/DebugLogViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/DebugLogViewModel.kt new file mode 100644 index 000000000..c585e3405 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/DebugLogViewModel.kt @@ -0,0 +1,38 @@ +package com.tari.android.wallet.ui.fragment.debug.debugLog + +import androidx.lifecycle.MutableLiveData +import com.tari.android.wallet.data.WalletConfig +import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository +import com.tari.android.wallet.infrastructure.logging.BugReportingService +import com.tari.android.wallet.ui.common.CommonViewModel +import com.tari.android.wallet.util.WalletUtil +import java.io.File +import javax.inject.Inject + +class DebugLogViewModel : CommonViewModel() { + + @Inject + lateinit var walletConfig: WalletConfig + + @Inject + lateinit var sharedPrefsWrapper: SharedPrefsRepository + + @Inject + lateinit var bugReportingService: BugReportingService + + val logFiles = MutableLiveData>() + val selectedLogFileLines = MutableLiveData>() + + init { + component.inject(this) + + val files = WalletUtil.getLogFilesFromDirectory(walletConfig.getWalletLogFilesDirPath()).toMutableList() + files.add(File(walletConfig.getApplicationLogsFilePath())) + logFiles.postValue(files) + } + + fun selectFile(position: Int) { + val lines = logFiles.value?.get(position)?.inputStream()?.bufferedReader()?.readLines()?.toMutableList() ?: return + selectedLogFileLines.postValue(lines) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogFileSpinnerAdapter.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogFileSpinnerAdapter.kt similarity index 75% rename from app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogFileSpinnerAdapter.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogFileSpinnerAdapter.kt index 241cfc3b2..ffb1da792 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogFileSpinnerAdapter.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogFileSpinnerAdapter.kt @@ -30,9 +30,8 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.fragment.debug.adapter +package com.tari.android.wallet.ui.fragment.debug.debugLog.adapter -import android.annotation.SuppressLint import android.content.Context import android.view.LayoutInflater import android.view.View @@ -44,34 +43,20 @@ import com.tari.android.wallet.R import com.tari.android.wallet.ui.extension.gone import java.io.File -/** - * Log file selector adapter - used in the debug log fragment. - * - * @author The Tari Development Team - */ -internal class LogFileSpinnerAdapter(context: Context, files: List) : - BaseAdapter(), SpinnerAdapter { +class LogFileSpinnerAdapter(context: Context, files: List) : BaseAdapter(), SpinnerAdapter { private val inflater: LayoutInflater = LayoutInflater.from(context) private val fileNames = files.map { it.name } - override fun getCount(): Int { - return fileNames.size - } + override fun getCount(): Int = fileNames.size - override fun getItem(position: Int): Any { - return fileNames[position] - } + override fun getItem(position: Int): Any = fileNames[position] - override fun getItemId(position: Int): Long { - return position.toLong() - } + override fun getItemId(position: Int): Long = position.toLong() - @SuppressLint("InflateParams") override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { - val view: View = convertView ?: inflater.inflate(R.layout.item_log_file_spinner, null) - val textView = view.findViewById(R.id.log_file_spinner_item_txt_file_name) - textView.text = fileNames[position] + val view = convertView ?: inflater.inflate(R.layout.item_log_file_spinner, null) + view.findViewById(R.id.log_file_spinner_item_txt_file_name).text = fileNames[position] view.findViewById(R.id.log_file_spinner_item_vw_gray_bg).gone() return view } @@ -85,5 +70,4 @@ internal class LogFileSpinnerAdapter(context: Context, files: List) : } return view } - } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogListAdapter.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogListAdapter.kt similarity index 63% rename from app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogListAdapter.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogListAdapter.kt index 824c509e4..721189639 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogListAdapter.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogListAdapter.kt @@ -30,61 +30,29 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.fragment.debug.adapter +package com.tari.android.wallet.ui.fragment.debug.debugLog.adapter import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.tari.android.wallet.R -/** - * Log view list recycler view adapter. - * - * @author The Tari Development Team - */ -internal class LogListAdapter(private val logLines: List) : - RecyclerView.Adapter() { +class LogListAdapter(val logLines: MutableList = mutableListOf()) : RecyclerView.Adapter() { - private val regex = - Regex("(\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}\\.\\d+)\\s(\\[[^]]+])\\s(\\[[^]]+]\\s)?([A-Z]+)\\s(.+)") + private val regex = Regex("(\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}\\.\\d+)\\s(\\[[^]]+])\\s(\\[[^]]+]\\s)?([A-Z]+)\\s(.+)") - /** - * Item count. - */ override fun getItemCount() = logLines.size - /** - * Create the view holder instance. - */ - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int - ): RecyclerView.ViewHolder { - val view = LayoutInflater.from(parent.context).inflate(R.layout.item_log, parent, false) - return LogViewHolder(view) - } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = + LogViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_log, parent, false)) - /** - * Bind & display header or transaction. - */ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { if (regex.matches(logLines[position])) { val matchResult = regex.find(logLines[position]) val (timestamp, source1, source2, level, log) = matchResult!!.destructured - (holder as LogViewHolder).bind( - timestamp, - source1, - source2, - level, - log, - position == (logLines.size - 1) - ) + (holder as LogViewHolder).bind(timestamp, source1, source2, level, log) } else { - (holder as LogViewHolder).bind( - logLines[position], - position == (logLines.size - 1) - ) + (holder as LogViewHolder).bind(logLines[position]) } } - } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogViewHolder.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogViewHolder.kt similarity index 54% rename from app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogViewHolder.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogViewHolder.kt index 371cbd0ac..9fc0ba210 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/adapter/LogViewHolder.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/debug/debugLog/adapter/LogViewHolder.kt @@ -30,92 +30,47 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.fragment.debug.adapter +package com.tari.android.wallet.ui.fragment.debug.debugLog.adapter import android.view.View +import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.tari.android.wallet.databinding.ItemLogBinding import com.tari.android.wallet.ffi.LogLevel import com.tari.android.wallet.ui.extension.gone import com.tari.android.wallet.ui.extension.visible -/** - * Displays individual logs. - * - * @author The Tari Development Team - */ class LogViewHolder(view: View) : RecyclerView.ViewHolder(view) { private val ui = ItemLogBinding.bind(view) - fun bind( - log: String, - isLast: Boolean = false - ) { + fun bind(log: String) { ui.timestampTextView.gone() ui.source1TextView.gone() ui.source2TextView.gone() ui.levelTextView.gone() ui.logTextView.text = log.trim() - // bottom spacer - ui.bottomSpacerView.visibility = when (isLast) { - true -> View.VISIBLE - else -> View.GONE - } } - fun bind( - timestamp: String?, - source1: String?, - source2: String?, - level: String?, - log: String?, - isLast: Boolean = false - ) { - // timestamp - if (timestamp != null && timestamp.isNotEmpty()) { - ui.timestampTextView.visible() - ui.timestampTextView.text = timestamp.trim() - } else { - ui.timestampTextView.gone() - } - // source#1 - if (source1 != null && source1.isNotEmpty()) { - ui.source1TextView.visible() - ui.source1TextView.text = source1.trim() - } else { - ui.source1TextView.gone() - } - // source#2 - if (source2 != null && source2.isNotEmpty()) { - ui.source2TextView.visible() - ui.source2TextView.text = source2.trim() - } else { - ui.source2TextView.gone() - } - // level + fun bind(timestamp: String?, source1: String?, source2: String?, level: String?, log: String?) { + putTextInView(timestamp, ui.timestampTextView) + putTextInView(source1, ui.source1TextView) + putTextInView(source2, ui.source2TextView) + + putTextInView(level, ui.levelTextView) if (level != null && level.isNotEmpty()) { - val logLevel = level.trim() - ui.levelTextView.visible() - ui.levelTextView.text = logLevel - ui.levelTextView.setTextColor( - LogLevel.from(logLevel).color - ) - } else { - ui.levelTextView.gone() + ui.levelTextView.setTextColor(LogLevel.from(level.trim()).color) } - // log - if (log != null && log.isNotEmpty()) { - ui.logTextView.visible() - ui.logTextView.text = log.trim() + + putTextInView(log, ui.logTextView) + } + + private fun putTextInView(text: String?, view: TextView) { + if (!text.isNullOrEmpty()) { + view.visible() + view.text = text.trim() } else { - ui.logTextView.gone() - } - // bottom spacer - ui.bottomSpacerView.visibility = when (isLast) { - true -> View.VISIBLE - else -> View.GONE + view.gone() } } - } diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeActivity.kt similarity index 91% rename from app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeActivity.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeActivity.kt index 3ca71bad2..b247ffbe3 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeActivity.kt @@ -30,7 +30,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.activity.home +package com.tari.android.wallet.ui.fragment.home import android.content.Intent import android.os.Bundle @@ -41,9 +41,10 @@ import android.widget.ImageView import androidx.activity.viewModels import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentStatePagerAdapter +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope +import androidx.viewpager2.adapter.FragmentStateAdapter import com.tari.android.wallet.R import com.tari.android.wallet.R.color.home_selected_nav_item import com.tari.android.wallet.application.deeplinks.DeepLink @@ -62,15 +63,11 @@ import com.tari.android.wallet.model.User import com.tari.android.wallet.model.WalletError import com.tari.android.wallet.network.NetworkConnectionState import com.tari.android.wallet.service.TariWalletService -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.connection.ServiceConnectionStatus import com.tari.android.wallet.service.connection.TariWalletServiceConnection -import com.tari.android.wallet.service.connection.TariWalletServiceConnection.ServiceConnectionStatus.CONNECTED -import com.tari.android.wallet.ui.activity.SplashActivity -import com.tari.android.wallet.ui.activity.settings.BackupSettingsActivity -import com.tari.android.wallet.ui.activity.settings.DeleteWalletActivity +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.CommonActivity import com.tari.android.wallet.ui.common.domain.ResourceManager -import com.tari.android.wallet.ui.common.gyphy.GiphyEcosystem import com.tari.android.wallet.ui.component.CustomFont import com.tari.android.wallet.ui.dialog.modular.DialogArgs import com.tari.android.wallet.ui.dialog.modular.ModularDialog @@ -92,9 +89,12 @@ import com.tari.android.wallet.ui.fragment.settings.allSettings.AllSettingsFragm import com.tari.android.wallet.ui.fragment.settings.allSettings.AllSettingsRouter import com.tari.android.wallet.ui.fragment.settings.allSettings.about.TariAboutFragment import com.tari.android.wallet.ui.fragment.settings.backgroundService.BackgroundServiceSettingsActivity +import com.tari.android.wallet.ui.fragment.settings.backup.activity.BackupSettingsActivity +import com.tari.android.wallet.ui.fragment.settings.deleteWallet.DeleteWalletActivity import com.tari.android.wallet.ui.fragment.settings.networkSelection.NetworkSelectionFragment import com.tari.android.wallet.ui.fragment.settings.torBridges.TorBridgesSelectionFragment import com.tari.android.wallet.ui.fragment.settings.torBridges.customBridges.CustomTorBridgesFragment +import com.tari.android.wallet.ui.fragment.splash.SplashActivity import com.tari.android.wallet.ui.fragment.store.StoreFragment import com.tari.android.wallet.ui.fragment.tx.TxListFragment import com.tari.android.wallet.ui.fragment.tx.TxListRouter @@ -106,9 +106,10 @@ import com.tari.android.wallet.util.Constants import io.reactivex.disposables.CompositeDisposable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.lang.ref.WeakReference import javax.inject.Inject -internal class HomeActivity : CommonActivity(), AllSettingsRouter, TxListRouter, BaseNodeConfigRouter { +class HomeActivity : CommonActivity(), AllSettingsRouter, TxListRouter, BaseNodeConfigRouter { @Inject lateinit var sharedPrefsWrapper: SharedPrefsRepository @@ -125,9 +126,6 @@ internal class HomeActivity : CommonActivity @Inject lateinit var resourceManager: ResourceManager - @Inject - lateinit var giphy: GiphyEcosystem - private val deeplinkViewModel: DeeplinkViewModel by viewModels() private lateinit var serviceConnection: TariWalletServiceConnection @@ -135,6 +133,7 @@ internal class HomeActivity : CommonActivity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + instance = WeakReference(this) val viewModel: HomeViewModel by viewModels() bindViewModel(viewModel) @@ -152,10 +151,9 @@ internal class HomeActivity : CommonActivity serviceConnection = ViewModelProvider(this)[TariWalletServiceConnection::class.java] ui = ActivityHomeBinding.inflate(layoutInflater).also { setContentView(it.root) } if (savedInstanceState == null) { - giphy.enable() enableNavigationView(ui.homeImageView) serviceConnection.connection.subscribe { - if (it.status == CONNECTED) { + if (it.status == ServiceConnectionStatus.CONNECTED) { ui.root.postDelayed({ processIntentDeepLink(it.service!!, intent) }, Constants.UI.mediumDurationMs) @@ -177,7 +175,7 @@ internal class HomeActivity : CommonActivity super.onNewIntent(intent) // onNewIntent might get called before onCreate, so we anticipate that here checkScreensDeeplink(intent) - if (::serviceConnection.isInitialized && serviceConnection.currentState.status == CONNECTED) { + if (::serviceConnection.isInitialized && serviceConnection.currentState.status == ServiceConnectionStatus.CONNECTED) { processIntentDeepLink(serviceConnection.currentState.service!!, intent) } else { setIntent(intent) @@ -223,7 +221,8 @@ internal class HomeActivity : CommonActivity private fun setupBottomNavigation() { enableNavigationView(ui.homeImageView) - ui.viewPager.adapter = HomeAdapter(supportFragmentManager) + ui.viewPager.adapter = HomeAdapter(supportFragmentManager, this.lifecycle) + ui.viewPager.isUserInputEnabled = false ui.viewPager.offscreenPageLimit = 3 ui.homeView.setOnClickListener { ui.viewPager.setCurrentItem(INDEX_HOME, NO_SMOOTH_SCROLL) @@ -319,7 +318,7 @@ internal class HomeActivity : CommonActivity HomeDeeplinkScreens.TxDetails -> { (intent.getParcelableExtra(HomeDeeplinkScreens.KeyTxDetailsArgs))?.let { toTxDetails(null, it) } } - else -> { } + else -> {} } } } @@ -398,22 +397,22 @@ internal class HomeActivity : CommonActivity override fun onDestroy() { super.onDestroy() + instance = WeakReference(null) viewModelStore.clear() compositeDisposable.dispose() } - private class HomeAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - override fun getItem(position: Int): Fragment = - when (position) { - INDEX_HOME -> TxListFragment() - INDEX_STORE -> StoreFragment.newInstance() - INDEX_PROFILE -> WalletInfoFragment() - INDEX_SETTINGS -> AllSettingsFragment.newInstance() - else -> error("Unexpected position: $position") - } + class HomeAdapter(fm: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fm, lifecycle) { - override fun getCount(): Int = 4 + override fun createFragment(position: Int): Fragment = when (position) { + INDEX_HOME -> TxListFragment() + INDEX_STORE -> StoreFragment.newInstance() + INDEX_PROFILE -> WalletInfoFragment() + INDEX_SETTINGS -> AllSettingsFragment.newInstance() + else -> error("Unexpected position: $position") + } + override fun getItemCount(): Int = 4 } companion object { @@ -423,5 +422,9 @@ internal class HomeActivity : CommonActivity private const val INDEX_PROFILE = 2 private const val INDEX_SETTINGS = 3 private const val NO_SMOOTH_SCROLL = false + + @Volatile + var instance: WeakReference = WeakReference(null) + private set } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeDeeplinkScreens.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeDeeplinkScreens.kt similarity index 86% rename from app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeDeeplinkScreens.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeDeeplinkScreens.kt index 13a90d85d..805e36302 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/home/HomeDeeplinkScreens.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeDeeplinkScreens.kt @@ -1,4 +1,4 @@ -package com.tari.android.wallet.ui.activity.home +package com.tari.android.wallet.ui.fragment.home enum class HomeDeeplinkScreens { TxDetails; diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeViewModel.kt new file mode 100644 index 000000000..f5dea99ab --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeViewModel.kt @@ -0,0 +1,5 @@ +package com.tari.android.wallet.ui.fragment.home + +import com.tari.android.wallet.ui.common.CommonViewModel + +class HomeViewModel: CommonViewModel() \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt index eaff76250..20e9a22be 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt @@ -34,15 +34,18 @@ package com.tari.android.wallet.ui.fragment.onboarding.activity import android.content.Intent import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity +import androidx.activity.viewModels import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.tari.android.wallet.R import com.tari.android.wallet.data.WalletConfig import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository +import com.tari.android.wallet.databinding.ActivityOnboardingFlowBinding import com.tari.android.wallet.di.DiContainer.appComponent -import com.tari.android.wallet.service.WalletServiceLauncher -import com.tari.android.wallet.ui.activity.home.HomeActivity +import com.tari.android.wallet.service.service.WalletServiceLauncher +import com.tari.android.wallet.ui.fragment.home.HomeActivity +import com.tari.android.wallet.ui.common.CommonActivity +import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.fragment.onboarding.createWallet.CreateWalletFragment import com.tari.android.wallet.ui.fragment.onboarding.createWallet.CreateWalletListener import com.tari.android.wallet.ui.fragment.onboarding.inroduction.IntroductionFragment @@ -63,7 +66,7 @@ import javax.inject.Inject * * @author The Tari Development Team */ -class OnboardingFlowActivity : AppCompatActivity(), IntroductionListener, CreateWalletListener, LocalAuthListener { +class OnboardingFlowActivity : CommonActivity(), IntroductionListener, CreateWalletListener, LocalAuthListener { @Inject lateinit var walletConfig: WalletConfig @@ -77,7 +80,11 @@ class OnboardingFlowActivity : AppCompatActivity(), IntroductionListener, Create override fun onCreate(savedInstanceState: Bundle?) { appComponent.inject(this) super.onCreate(savedInstanceState) - setContentView(R.layout.activity_onboarding_flow) + ui = ActivityOnboardingFlowBinding.inflate(layoutInflater).apply { setContentView(root) } + + val viewModel: OnboardingFlowViewModel by viewModels() + bindViewModel(viewModel) + when { sharedPrefsWrapper.onboardingAuthWasInterrupted -> { walletServiceLauncher.start() diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowViewModel.kt new file mode 100644 index 000000000..278fd0b3a --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowViewModel.kt @@ -0,0 +1,5 @@ +package com.tari.android.wallet.ui.fragment.onboarding.activity + +import com.tari.android.wallet.ui.common.CommonViewModel + +class OnboardingFlowViewModel: CommonViewModel() \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/createWallet/CreateWalletFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/createWallet/CreateWalletFragment.kt index 37cfcc686..f0f44c400 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/createWallet/CreateWalletFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/createWallet/CreateWalletFragment.kt @@ -87,9 +87,6 @@ class CreateWalletFragment : CommonFragment, - grantResults: IntArray - ) { + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_CAMERA_PERMISSION) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionFragment.kt index 5ea285eb3..93db3b58a 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionFragment.kt @@ -45,7 +45,7 @@ import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.extension.* import com.tari.android.wallet.ui.fragment.restore.restore.WalletRestoreRouter -internal class ChooseRestoreOptionFragment : CommonFragment() { +class ChooseRestoreOptionFragment : CommonFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = FragmentChooseRestoreOptionBinding.inflate(inflater, container, false).also { ui = it }.root diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionViewModel.kt index 76b54db31..14989c262 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/chooseRestoreOption/ChooseRestoreOptionViewModel.kt @@ -3,28 +3,31 @@ package com.tari.android.wallet.ui.fragment.restore.chooseRestoreOption import android.content.Intent import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope -import com.orhanobut.logger.Logger import com.tari.android.wallet.R import com.tari.android.wallet.application.WalletManager import com.tari.android.wallet.application.WalletState import com.tari.android.wallet.event.EventBus import com.tari.android.wallet.infrastructure.backup.* import com.tari.android.wallet.model.WalletError -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.common.SingleLiveEvent import com.tari.android.wallet.ui.dialog.error.ErrorDialogArgs import com.tari.android.wallet.ui.dialog.error.WalletErrorArgs +import com.tari.android.wallet.ui.fragment.settings.backup.BackupSettingsRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.io.IOException import javax.inject.Inject -internal class ChooseRestoreOptionViewModel : CommonViewModel() { +class ChooseRestoreOptionViewModel : CommonViewModel() { @Inject lateinit var backupStorage: BackupStorage + @Inject + lateinit var backupSettingsRepository: BackupSettingsRepository + @Inject lateinit var walletManager: WalletManager @@ -50,7 +53,7 @@ internal class ChooseRestoreOptionViewModel : CommonViewModel() { backupStorage.onSetupActivityResult(requestCode, resultCode, data) restoreFromBackup() } catch (exception: Exception) { - Logger.e("Backup storage setup failed: $exception") + logger.e(exception, "Backup storage setup failed") backupStorage.signOut() _state.postValue(ChooseRestoreOptionState.EndProgress) showAuthFailedDialog() @@ -84,12 +87,12 @@ internal class ChooseRestoreOptionViewModel : CommonViewModel() { private suspend fun handleException(exception: java.lang.Exception) { when (exception) { is BackupStorageAuthRevokedException -> { - Logger.e(exception, "Auth revoked.") + logger.e(exception, "Auth revoked") backupStorage.signOut() showAuthFailedDialog() } is BackupStorageTamperedException -> { // backup file not found - Logger.e(exception, "Backup file not found.") + logger.e(exception, "Backup file not found") backupStorage.signOut() showBackupFileNotFoundDialog() } @@ -97,7 +100,7 @@ internal class ChooseRestoreOptionViewModel : CommonViewModel() { _navigation.postValue(ChooseRestoreOptionNavigation.ToEnterRestorePassword) } is WalletStartFailedException -> { - Logger.e(exception, "Restore failed: wallet start failed") + logger.e(exception, "Restore failed: wallet start failed") viewModelScope.launch(Dispatchers.Main) { walletServiceLauncher.stopAndDelete() } @@ -111,12 +114,12 @@ internal class ChooseRestoreOptionViewModel : CommonViewModel() { } } is IOException -> { - Logger.e(exception, "Restore failed: network connection.") + logger.e(exception, "Restore failed: network connection") backupStorage.signOut() showRestoreFailedDialog(resourceManager.getString(R.string.error_no_connection_title)) } else -> { - Logger.e(exception, "Restore failed: $exception") + logger.e(exception, "Restore failed") backupStorage.signOut() showRestoreFailedDialog(exception.message) } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsFragment.kt index 0fe9592cc..f43452f05 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsFragment.kt @@ -22,10 +22,12 @@ import com.tari.android.wallet.ui.fragment.restore.inputSeedWords.suggestions.Su import com.tari.android.wallet.ui.fragment.restore.inputSeedWords.suggestions.SuggestionsAdapter import com.tari.android.wallet.ui.fragment.restore.restore.WalletRestoreRouter import net.yslibrary.android.keyboardvisibilityevent.KeyboardVisibilityEvent +import net.yslibrary.android.keyboardvisibilityevent.Unregistrar -internal class InputSeedWordsFragment : CommonFragment() { +class InputSeedWordsFragment : CommonFragment() { private val suggestionsAdapter = SuggestionsAdapter() + private var keyboardRegistrar: Unregistrar? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = FragmentWalletInputSeedWordsBinding.inflate(inflater, container, false).also { ui = it }.root @@ -43,6 +45,16 @@ internal class InputSeedWordsFragment : CommonFragment addWord(word) } + } + } observe(addedWord) { addWord(it) } @@ -145,6 +159,7 @@ internal class InputSeedWordsFragment : CommonFragment if (actionId == EditorInfo.IME_ACTION_NEXT) { viewModel.finishEntering(word.index.value!!, ui.text.text?.toString().orEmpty()) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsViewModel.kt index f46a42aa3..5137a8a99 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/inputSeedWords/InputSeedWordsViewModel.kt @@ -8,7 +8,7 @@ import com.tari.android.wallet.extension.addTo import com.tari.android.wallet.ffi.FFISeedWords import com.tari.android.wallet.model.WalletError import com.tari.android.wallet.model.seedPhrase.SeedPhrase -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.service.seedPhrase.SeedPhraseRepository import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.common.SingleLiveEvent @@ -25,7 +25,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import javax.inject.Inject -internal class InputSeedWordsViewModel : CommonViewModel() { +class InputSeedWordsViewModel : CommonViewModel() { private var mnemonicList = mutableListOf() diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/restore/WalletRestoreActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/restore/WalletRestoreActivity.kt index 2c8f4f843..1472a229b 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/restore/WalletRestoreActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/restore/WalletRestoreActivity.kt @@ -35,12 +35,15 @@ package com.tari.android.wallet.ui.fragment.restore.restore import android.content.Context import android.content.Intent import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity +import androidx.activity.viewModels import androidx.fragment.app.Fragment import com.tari.android.wallet.R import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository +import com.tari.android.wallet.databinding.ActivityWalletBackupBinding import com.tari.android.wallet.di.DiContainer.appComponent +import com.tari.android.wallet.service.service.WalletServiceLauncher +import com.tari.android.wallet.ui.common.CommonActivity import com.tari.android.wallet.ui.fragment.auth.AuthActivity import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.BaseNodeConfigRouter import com.tari.android.wallet.ui.fragment.debug.baseNodeConfig.addBaseNode.AddCustomBaseNodeFragment @@ -51,7 +54,7 @@ import com.tari.android.wallet.ui.fragment.restore.inputSeedWords.InputSeedWords import com.tari.android.wallet.ui.fragment.restore.walletRestoringFromSeedWords.WalletRestoringFromSeedWordsFragment import javax.inject.Inject -class WalletRestoreActivity : AppCompatActivity(), WalletRestoreRouter, BaseNodeConfigRouter { +class WalletRestoreActivity : CommonActivity(), WalletRestoreRouter, BaseNodeConfigRouter { @Inject lateinit var prefs: SharedPrefsRepository @@ -59,10 +62,17 @@ class WalletRestoreActivity : AppCompatActivity(), WalletRestoreRouter, BaseNode @Inject lateinit var tariSettingsSharedRepository: TariSettingsSharedRepository + @Inject + lateinit var walletServiceLauncher: WalletServiceLauncher + override fun onCreate(savedInstanceState: Bundle?) { appComponent.inject(this) super.onCreate(savedInstanceState) - setContentView(R.layout.activity_wallet_backup) + ui = ActivityWalletBackupBinding.inflate(layoutInflater).apply { setContentView(root) } + + val viewModel : WalletRestoreViewModel by viewModels() + bindViewModel(viewModel) + if (savedInstanceState == null) { loadChooseBackupOptionFragment() } @@ -79,21 +89,13 @@ class WalletRestoreActivity : AppCompatActivity(), WalletRestoreRouter, BaseNode .commit() } - override fun toEnterRestorePassword() { - loadFragment(EnterRestorationPasswordFragment.newInstance()) - } + override fun toEnterRestorePassword() = loadFragment(EnterRestorationPasswordFragment.newInstance()) - override fun toRestoreWithRecoveryPhrase() { - loadFragment(InputSeedWordsFragment.newInstance()) - } + override fun toRestoreWithRecoveryPhrase() = loadFragment(InputSeedWordsFragment.newInstance()) - override fun toRestoreFromSeedWordsInProgress() { - loadFragment(WalletRestoringFromSeedWordsFragment.newInstance()) - } + override fun toRestoreFromSeedWordsInProgress() = loadFragment(WalletRestoringFromSeedWordsFragment.newInstance()) - override fun toBaseNodeSelection() { - loadFragment(ChangeBaseNodeFragment()) - } + override fun toBaseNodeSelection() = loadFragment(ChangeBaseNodeFragment()) override fun onRestoreCompleted() { // wallet restored, setup shared prefs accordingly @@ -102,6 +104,7 @@ class WalletRestoreActivity : AppCompatActivity(), WalletRestoreRouter, BaseNode prefs.onboardingDisplayedAtHome = true tariSettingsSharedRepository.isRestoredWallet = true + finish() startActivity(Intent(this, AuthActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK }) @@ -120,6 +123,13 @@ class WalletRestoreActivity : AppCompatActivity(), WalletRestoreRouter, BaseNode .commit() } + override fun onDestroy() { + if (!tariSettingsSharedRepository.isRestoredWallet) { + walletServiceLauncher.stop() + } + super.onDestroy() + } + companion object { fun navigationIntent(context: Context) = Intent(context, WalletRestoreActivity::class.java) } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/restore/WalletRestoreViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/restore/WalletRestoreViewModel.kt new file mode 100644 index 000000000..e42d4e967 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/restore/WalletRestoreViewModel.kt @@ -0,0 +1,5 @@ +package com.tari.android.wallet.ui.fragment.restore.restore + +import com.tari.android.wallet.ui.common.CommonViewModel + +class WalletRestoreViewModel() : CommonViewModel() \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsFragment.kt index 1b5dd59a2..ea2498ffd 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsFragment.kt @@ -42,7 +42,7 @@ import com.tari.android.wallet.extension.observe import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.fragment.restore.restore.WalletRestoreRouter -internal class WalletRestoringFromSeedWordsFragment : +class WalletRestoringFromSeedWordsFragment : CommonFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt index 4f5f6d4ef..a332b40b9 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt @@ -14,7 +14,7 @@ import com.tari.android.wallet.ffi.FFIPublicKey import com.tari.android.wallet.ffi.FFIWallet import com.tari.android.wallet.ffi.HexString import com.tari.android.wallet.model.recovery.WalletRestorationResult -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.service.seedPhrase.SeedPhraseRepository import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.common.SingleLiveEvent @@ -26,7 +26,7 @@ import kotlinx.coroutines.launch import java.text.DecimalFormat import javax.inject.Inject -internal class WalletRestoringFromSeedWordsViewModel : CommonViewModel() { +class WalletRestoringFromSeedWordsViewModel : CommonViewModel() { @Inject diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/activity/SendTariActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/activity/SendTariActivity.kt index c9c4cfc13..7462c4888 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/activity/SendTariActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/activity/SendTariActivity.kt @@ -40,6 +40,7 @@ import com.tari.android.wallet.databinding.ActivitySendTariBinding import com.tari.android.wallet.di.DiContainer.appComponent import com.tari.android.wallet.event.Event import com.tari.android.wallet.event.EventBus +import com.tari.android.wallet.model.MicroTari import com.tari.android.wallet.model.TxId import com.tari.android.wallet.model.User import com.tari.android.wallet.network.NetworkConnectionState @@ -74,7 +75,7 @@ import javax.inject.Inject * * @author The Tari Development Team */ -internal class SendTariActivity : CommonActivity(), +class SendTariActivity : CommonActivity(), AddRecipientListener, AddAmountListener, AddNodeListener, @@ -114,13 +115,16 @@ internal class SendTariActivity : CommonActivity = WeakReference(null) private set diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt index 2bfe4af8b..89c1b01c7 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt @@ -105,9 +105,6 @@ class AddAmountFragment : CommonFragment(SendTariActivity.PARAMETER_AMOUNT) + keyboardController.setup(requireContext(), AmountCheckRunnable(), ui.numpad, ui.amount, amount?.tariValue?.toDouble() ?: Double.MIN_VALUE) + recipientUser = arguments?.getParcelable(SendTariActivity.PARAMETER_USER) // hide tx fee ui.txFeeContainerView.invisible() // hide/disable continue button diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountViewModel.kt index 823362984..06d0f2bc3 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountViewModel.kt @@ -11,6 +11,7 @@ import com.tari.android.wallet.ffi.FFIWallet import com.tari.android.wallet.model.MicroTari import com.tari.android.wallet.model.WalletError import com.tari.android.wallet.service.TariWalletService +import com.tari.android.wallet.service.connection.ServiceConnectionStatus import com.tari.android.wallet.service.connection.TariWalletServiceConnection import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.dialog.modular.DialogArgs @@ -22,7 +23,6 @@ import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule import com.tari.android.wallet.ui.fragment.send.addAmount.feeModule.FeeModule import com.tari.android.wallet.ui.fragment.send.addAmount.feeModule.NetworkSpeed import com.tari.android.wallet.util.Constants -import io.sentry.Sentry import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.math.BigInteger @@ -55,7 +55,7 @@ class AddAmountViewModel : CommonViewModel() { init { component.inject(this) - connectionService.connection.filter { it.status == TariWalletServiceConnection.ServiceConnectionStatus.CONNECTED }.subscribe { + connectionService.connection.filter { it.status == ServiceConnectionStatus.CONNECTED }.subscribe { _serviceConnected.postValue(Unit) }.addTo(compositeDisposable) loadFees() @@ -96,7 +96,7 @@ class AddAmountViewModel : CommonViewModel() { } _feePerGrams.postValue(FeePerGramOptions(networkSpeed, MicroTari(slowOption), MicroTari(mediumOption), MicroTari(fastOption))) } catch (e: Throwable) { - Sentry.captureException(e) + logger.e(e, "load fees") } } @@ -144,7 +144,7 @@ class AddAmountViewModel : CommonViewModel() { feeData = listOf(FeeData(grams.slow, slowFee), FeeData(grams.medium, mediumFee), FeeData(grams.fast, fastFee)) selectedFeeData = feeData[1] } catch (e: Throwable) { - Sentry.captureException(e) + logger.e(e, "calculate fees") } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt index f828a20a8..a3c776cc3 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt @@ -20,7 +20,7 @@ import com.tari.android.wallet.util.WalletUtil import java.math.BigInteger import kotlin.math.min -internal class KeyboardController { +class KeyboardController { /** * Maps all the elements (digits & separators) displayed in the amount text to their diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt index b5ac5b523..a20552998 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt @@ -58,7 +58,6 @@ import com.bumptech.glide.Glide import com.daasuu.ei.Ease import com.daasuu.ei.EasingInterpolator import com.giphy.sdk.core.models.Media -import com.orhanobut.logger.Logger import com.tari.android.wallet.R import com.tari.android.wallet.R.color.* import com.tari.android.wallet.R.dimen.* @@ -66,7 +65,6 @@ import com.tari.android.wallet.databinding.FragmentAddNoteBinding import com.tari.android.wallet.di.DiContainer.appComponent import com.tari.android.wallet.event.EventBus import com.tari.android.wallet.extension.observe -import com.tari.android.wallet.infrastructure.Tracker import com.tari.android.wallet.model.Contact import com.tari.android.wallet.model.MicroTari import com.tari.android.wallet.model.User @@ -79,10 +77,9 @@ import com.tari.android.wallet.ui.fragment.send.activity.SendTariActivity import com.tari.android.wallet.ui.fragment.send.addNote.gif.* import com.tari.android.wallet.ui.fragment.send.addNote.gif.ThumbnailGIFsViewModel.Companion.REQUEST_CODE_GIF import com.tari.android.wallet.ui.fragment.send.common.TransactionData -import com.tari.android.wallet.ui.presentation.TxNote +import com.tari.android.wallet.model.TxNote import com.tari.android.wallet.util.Constants import java.lang.ref.WeakReference -import javax.inject.Inject /** * Add a note to the transaction & send it through this fragment. @@ -91,9 +88,6 @@ import javax.inject.Inject */ class AddNoteFragment : Fragment(), View.OnTouchListener { - @Inject - lateinit var tracker: Tracker - private lateinit var addNodeListenerWR: WeakReference // slide button animation related variables @@ -130,9 +124,6 @@ class AddNoteFragment : Fragment(), View.OnTouchListener { @SuppressLint("ClickableViewAccessibility") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (savedInstanceState == null) { - tracker.screen(path = "/home/send_tari/add_note", title = "Send Tari - Add Note") - } initializeGIFsViewModel() retrievePageArguments(savedInstanceState) setupUI(savedInstanceState) @@ -142,9 +133,8 @@ class AddNoteFragment : Fragment(), View.OnTouchListener { private fun initializeGIFsViewModel() { viewModel = ViewModelProvider(this)[ThumbnailGIFsViewModel::class.java] observe(viewModel.state) { - when { - it.isSuccessful -> adapter.repopulate(it.gifItems!!) - it.isError -> Logger.e("GIFs request had error") + if (it.isSuccessful) { + adapter.repopulate(it.gifItems!!) } } } @@ -307,7 +297,7 @@ class AddNoteFragment : Fragment(), View.OnTouchListener { val mActivity = activity ?: return ui.noteEditText.requestFocus() val imm = mActivity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY) + imm.showSoftInput(ui.noteEditText, InputMethodManager.HIDE_IMPLICIT_ONLY) } @SuppressLint("ClickableViewAccessibility") @@ -458,8 +448,6 @@ class AddNoteFragment : Fragment(), View.OnTouchListener { } private fun continueToFinalizeSendTx() { - // track event - tracker.event(category = "Transaction", action = "Transaction Initiated") // notify listener (i.e. activity) val note = TxNote(ui.noteEditText.editableText.toString(), gifContainer.gifItem?.embedUri?.toString()).compose() val newData = transactionData.copy(note = note) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/gif/ThumbnailGIFsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/gif/ThumbnailGIFsViewModel.kt index 963cb4acb..d2225253f 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/gif/ThumbnailGIFsViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/gif/ThumbnailGIFsViewModel.kt @@ -3,7 +3,6 @@ package com.tari.android.wallet.ui.fragment.send.addNote.gif import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.orhanobut.logger.Logger import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.common.gyphy.GiphyKeywordsRepository import com.tari.android.wallet.ui.common.gyphy.repository.GIFItem @@ -38,14 +37,10 @@ class ThumbnailGIFsViewModel : CommonViewModel() { _state.value = GIFsState() try { val gifs = withContext(Dispatchers.IO) { - gifsRepository.getAll( - giphyKeywordsRepository.getNext(), - THUMBNAIL_REQUEST_LIMIT - ) + gifsRepository.getAll(giphyKeywordsRepository.getNext(), THUMBNAIL_REQUEST_LIMIT) } _state.value = GIFsState(gifs) } catch (e: Exception) { - Logger.e(e, "Error occurred while fetching gifs") _state.value = GIFsState(e) } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/AddRecipientFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/AddRecipientFragment.kt index 1b819a380..1fd62f769 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/AddRecipientFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/AddRecipientFragment.kt @@ -68,7 +68,6 @@ import com.tari.android.wallet.databinding.FragmentAddRecipientBinding import com.tari.android.wallet.di.DiContainer.appComponent import com.tari.android.wallet.extension.observe import com.tari.android.wallet.extension.observeOnLoad -import com.tari.android.wallet.infrastructure.Tracker import com.tari.android.wallet.model.PublicKey import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.common.domain.ResourceManager @@ -95,9 +94,6 @@ class AddRecipientFragment : CommonFragment listener.continueToAmount(navigation.user) + is AddRecipientNavigation.ToAmount -> listener.continueToAmount(navigation.user, navigation.amount) } } @@ -222,7 +212,7 @@ class AddRecipientFragment : CommonFragment (activity as? AddRecipientListener)?.continueToAmount(user) } + (it as? RecipientViewHolderItem)?.user?.let { user -> (activity as? AddRecipientListener)?.continueToAmount(user, null) } }) ui.contactsListRecyclerView.adapter = recyclerViewAdapter ui.contactsListRecyclerView.addOnScrollListener(scrollListener) @@ -392,7 +382,7 @@ class AddRecipientFragment : CommonFragment contacts = wallet.getContacts(error).orEmpty().toMutableList() @@ -157,7 +160,7 @@ class AddRecipientViewModel : CommonViewModel() { val yatUserOptional = _foundYatUser.value val yatUser = if (yatUserOptional?.isPresent == true) yatUserOptional.get() else null val user = yatUser ?: contacts.firstOrNull { it.publicKey == emojiIdPublicKey } ?: User(emojiIdPublicKey!!) - _navigation.postValue(AddRecipientNavigation.ToAmount(user)) + _navigation.postValue(AddRecipientNavigation.ToAmount(user, amountFromDeeplink)) } } @@ -214,8 +217,8 @@ class AddRecipientViewModel : CommonViewModel() { return false } - fun getPublicKeyFromHexString(publicKeyHex: String): PublicKey = walletService.getWithError { _, wallet -> wallet.getPublicKeyFromHexString(publicKeyHex) } + fun getPublicKeyFromHexString(publicKeyHex: String): PublicKey? = walletService.getWithError { _, wallet -> wallet.getPublicKeyFromHexString(publicKeyHex) } - fun getPublicKeyFromEmojiId(emojiId: String): PublicKey = walletService.getWithError { _, wallet -> wallet.getPublicKeyFromEmojiId(emojiId) } + fun getPublicKeyFromEmojiId(emojiId: String): PublicKey? = walletService.getWithError { _, wallet -> wallet.getPublicKeyFromEmojiId(emojiId) } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/list/RecipientListAdapter.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/list/RecipientListAdapter.kt index b1c7b8684..eedb111c1 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/list/RecipientListAdapter.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addRecepient/list/RecipientListAdapter.kt @@ -36,7 +36,7 @@ import com.tari.android.wallet.ui.common.recyclerView.CommonAdapter import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem import com.tari.android.wallet.ui.common.recyclerView.ViewHolderBuilder -internal class RecipientListAdapter : CommonAdapter() { +class RecipientListAdapter : CommonAdapter() { override var viewHolderBuilders: List = listOf( RecipientHeaderViewHolder.getBuilder(), RecipientViewHolder.getBuilder() diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxFragment.kt index 89f40b22e..7d1476398 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxFragment.kt @@ -193,7 +193,6 @@ class FinalizeSendTxFragment : CommonFragment "Transaction Failed - Node Issue" TxFailureReason.SEND_ERROR -> "Transaction Failed - Node Issue" } - viewModel.tracker.event(category = "Transaction", action = trackerEvent) // fade out text and progress ValueAnimator.ofFloat(1f, 0f).apply { diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxViewModel.kt index 30e3682e7..72168d3ab 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/finalize/FinalizeSendTxViewModel.kt @@ -2,7 +2,6 @@ package com.tari.android.wallet.ui.fragment.send.finalize import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.orhanobut.logger.Logger import com.tari.android.wallet.R.string.* import com.tari.android.wallet.event.Event import com.tari.android.wallet.event.EventBus @@ -12,6 +11,7 @@ import com.tari.android.wallet.model.TxId import com.tari.android.wallet.model.WalletError import com.tari.android.wallet.network.NetworkConnectionState import com.tari.android.wallet.service.TariWalletService +import com.tari.android.wallet.service.connection.ServiceConnectionStatus import com.tari.android.wallet.service.connection.TariWalletServiceConnection import com.tari.android.wallet.tor.TorBootstrapStatus import com.tari.android.wallet.tor.TorProxyState @@ -40,8 +40,6 @@ class FinalizeSendTxViewModel : CommonViewModel() { init { component.inject(this) - - tracker.screen(path = "/home/send_tari/finalize", title = "Send Tari - Finalize") } fun start() { @@ -119,7 +117,7 @@ class FinalizeSendTxViewModel : CommonViewModel() { override fun execute() { connectionService.connection.subscribe { - if (it.status == TariWalletServiceConnection.ServiceConnectionStatus.CONNECTED) onServiceConnected() + if (it.status == ServiceConnectionStatus.CONNECTED) onServiceConnected() }.addTo(compositeDisposable) } @@ -143,7 +141,6 @@ class FinalizeSendTxViewModel : CommonViewModel() { val torProxyState = EventBus.torProxyState.publishSubject.value // check internet connection if (networkConnectionState != NetworkConnectionState.CONNECTED) { - Logger.w("Send error: not connected to the internet.") // either not connected or Tor proxy is not running txFailureReason.value = TxFailureReason.NETWORK_CONNECTION_ERROR isCompleted = true @@ -151,7 +148,6 @@ class FinalizeSendTxViewModel : CommonViewModel() { } // check whether Tor proxy is running if (torProxyState !is TorProxyState.Running) { - Logger.w("Send error: Tor proxy is not running.") // either not connected or Tor proxy is not running txFailureReason.value = TxFailureReason.NETWORK_CONNECTION_ERROR isCompleted = true @@ -159,7 +155,6 @@ class FinalizeSendTxViewModel : CommonViewModel() { } // check Tor bootstrap status if (torProxyState.bootstrapStatus.progress < TorBootstrapStatus.maxProgress) { - Logger.d("Tor proxy not ready - start waiting.") // subscribe to Tor proxy state changes - start waiting on it EventBus.torProxyState.publishSubject.subscribe { state -> onTorProxyStateChanged(state) }.addTo(compositeDisposable) } else { @@ -189,7 +184,7 @@ class FinalizeSendTxViewModel : CommonViewModel() { transactionData.recipientUser, transactionData.amount, transactionData.feePerGram ?: Constants.Wallet.defaultFeePerGram, - transactionData.note, + transactionData.note.orEmpty(), transactionData.isOneSidePayment, error ) @@ -224,12 +219,9 @@ class FinalizeSendTxViewModel : CommonViewModel() { private fun onDirectSendResult(txId: TxId, status: TransactionSendStatus) { if (sentTxId.value != txId) { - Logger.d("Response received for another tx with id: ${txId.value}.") return } if (status.isSuccess) { - // track event - tracker.event(category = "Transaction", action = "Transaction Accepted - Synchronous") // progress state finishSendingTx() } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsFragment.kt index 32711e65b..a8aa7a493 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsFragment.kt @@ -43,14 +43,14 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.tari.android.wallet.R.string.* import com.tari.android.wallet.databinding.FragmentAllSettingsBinding import com.tari.android.wallet.extension.observe -import com.tari.android.wallet.infrastructure.BugReportingService +import com.tari.android.wallet.infrastructure.logging.BugReportingService import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.extension.string import com.tari.android.wallet.ui.fragment.settings.userAutorization.BiometricAuthenticationViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -internal class AllSettingsFragment : CommonFragment() { +class AllSettingsFragment : CommonFragment() { private val optionsAdapter = AllSettingsOptionAdapter() diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt index 7ddd34327..b4524a81c 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt @@ -3,16 +3,15 @@ package com.tari.android.wallet.ui.fragment.settings.allSettings import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.orhanobut.logger.Logger import com.tari.android.wallet.R.color.* import com.tari.android.wallet.R.drawable.* import com.tari.android.wallet.R.string.* import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository import com.tari.android.wallet.event.EventBus -import com.tari.android.wallet.infrastructure.BugReportingService import com.tari.android.wallet.infrastructure.backup.BackupManager import com.tari.android.wallet.infrastructure.backup.BackupState import com.tari.android.wallet.infrastructure.backup.BackupStorageAuthRevokedException +import com.tari.android.wallet.infrastructure.logging.BugReportingService import com.tari.android.wallet.ui.common.ClipboardArgs import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.common.SingleLiveEvent @@ -35,7 +34,7 @@ import java.io.IOException import java.util.* import javax.inject.Inject -internal class AllSettingsViewModel : CommonViewModel() { +class AllSettingsViewModel : CommonViewModel() { lateinit var authenticationViewModel: BiometricAuthenticationViewModel @@ -151,14 +150,14 @@ internal class AllSettingsViewModel : CommonViewModel() { try { backupManager.checkStorageStatus() } catch (e: BackupStorageAuthRevokedException) { - Logger.e("Backup storage auth error.") + logger.e(e, "Backup storage auth error") // show access revoked information showBackupStorageCheckFailedDialog(resourceManager.getString(check_backup_storage_status_auth_revoked_error_description)) } catch (e: IOException) { - Logger.e("Backup storage I/O (access) error.") + logger.e(e, "Backup storage I/O (access) error") showBackupStorageCheckFailedDialog(resourceManager.getString(check_backup_storage_status_access_error_description)) } catch (e: Exception) { - Logger.e("Backup storage tampered.") + logger.e(e, "Backup storage tampered") updateLastSuccessfulBackupDate() } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsActivity.kt index acee2bff4..3422cd5ba 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsActivity.kt @@ -38,11 +38,10 @@ import android.os.Bundle import androidx.activity.viewModels import com.tari.android.wallet.databinding.ActivityBackgroundServiceSettingsBinding import com.tari.android.wallet.extension.observe -import com.tari.android.wallet.ui.extension.ThrottleClick import com.tari.android.wallet.ui.common.CommonActivity +import com.tari.android.wallet.ui.extension.ThrottleClick -class BackgroundServiceSettingsActivity : - CommonActivity() { +class BackgroundServiceSettingsActivity : CommonActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsViewModel.kt index 3a7eb5901..3085947f1 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backgroundService/BackgroundServiceSettingsViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.tari.android.wallet.R import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.component.loadingSwitch.LoadingSwitchState import com.tari.android.wallet.ui.dialog.confirm.ConfirmDialogArgs @@ -14,6 +15,9 @@ class BackgroundServiceSettingsViewModel : CommonViewModel() { @Inject lateinit var tariSettingsSharedRepository: TariSettingsSharedRepository + @Inject + lateinit var serviceLauncher: WalletServiceLauncher + private val _switchState = MutableLiveData() val switchState: LiveData = _switchState @@ -42,5 +46,7 @@ class BackgroundServiceSettingsViewModel : CommonViewModel() { private fun turnSwitcher(isTurnedOn: Boolean) { tariSettingsSharedRepository.backgroundServiceTurnedOn = isTurnedOn _switchState.value = LoadingSwitchState(isTurnedOn, false) + _dismissDialog.postValue(Unit) + serviceLauncher.startIfExist() } } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/ChangeSecurePasswordFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/ChangeSecurePasswordFragment.kt index 177465556..4d1b48cb5 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/ChangeSecurePasswordFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/ChangeSecurePasswordFragment.kt @@ -50,7 +50,6 @@ import android.widget.TextView import androidx.core.widget.addTextChangedListener import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope -import com.orhanobut.logger.Logger import com.tari.android.wallet.R.color.* import com.tari.android.wallet.R.string.* import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository @@ -62,7 +61,7 @@ import com.tari.android.wallet.infrastructure.backup.BackupState import com.tari.android.wallet.infrastructure.backup.BackupState.BackupOutOfDate import com.tari.android.wallet.infrastructure.backup.BackupState.BackupUpToDate import com.tari.android.wallet.infrastructure.backup.BackupStorageAuthRevokedException -import com.tari.android.wallet.ui.activity.settings.BackupSettingsRouter +import com.tari.android.wallet.ui.fragment.settings.backup.activity.BackupSettingsRouter import com.tari.android.wallet.ui.common.domain.ResourceManager import com.tari.android.wallet.ui.dialog.error.ErrorDialogArgs import com.tari.android.wallet.ui.dialog.modular.ModularDialog @@ -73,11 +72,7 @@ import kotlinx.coroutines.withContext import java.net.UnknownHostException import javax.inject.Inject -internal class ChangeSecurePasswordFragment @Deprecated( - """Use newInstance() and supply all the -necessary data via arguments instead, as fragment's default no-op constructor is used by the -framework for UI tree rebuild on configuration changes""" -) constructor() : Fragment() { +class ChangeSecurePasswordFragment : Fragment() { @Inject lateinit var sharedPrefs: SharedPrefsRepository @@ -95,17 +90,12 @@ framework for UI tree rebuild on configuration changes""" override fun onAttach(context: Context) { super.onAttach(context) - inputService = - requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + inputService = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager appComponent.inject(this) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View = FragmentChangeSecurePasswordBinding.inflate(inflater, container, false) - .also { ui = it }.root + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = + FragmentChangeSecurePasswordBinding.inflate(inflater, container, false).also { ui = it }.root override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -349,18 +339,15 @@ framework for UI tree rebuild on configuration changes""" private fun onBackupStateChanged(backupState: BackupState?) { if (!subscribedToBackupState) { // ignore first call - Logger.d("Ignore first state: $backupState") subscribedToBackupState = true return } - Logger.d("Backup state changed: $backupState") when (backupState) { is BackupUpToDate -> { // backup successful allowExitAndPasswordEditing() (requireActivity() as BackupSettingsRouter).onPasswordChanged(this) } is BackupOutOfDate -> { // backup failed - Logger.e(backupState.backupException, "Error during encrypted backup: ${backupState.backupException}") showBackupErrorDialog(deductBackupErrorMessage(backupState.backupException)) { allowExitAndPasswordEditing() setSecurePasswordCtaIdleState() diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/EnterCurrentPasswordFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/EnterCurrentPasswordFragment.kt index f9a8f73da..a0441ccdb 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/EnterCurrentPasswordFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/EnterCurrentPasswordFragment.kt @@ -45,7 +45,7 @@ import com.tari.android.wallet.R.color.change_password_cta_disabled import com.tari.android.wallet.R.color.white import com.tari.android.wallet.databinding.FragmentEnterBackupPasswordBinding import com.tari.android.wallet.di.DiContainer.appComponent -import com.tari.android.wallet.ui.activity.settings.BackupSettingsRouter +import com.tari.android.wallet.ui.fragment.settings.backup.activity.BackupSettingsRouter import com.tari.android.wallet.ui.extension.* import javax.inject.Inject diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/settings/BackupSettingsActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsActivity.kt similarity index 73% rename from app/src/main/java/com/tari/android/wallet/ui/activity/settings/BackupSettingsActivity.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsActivity.kt index ae0186b39..35c51656c 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/settings/BackupSettingsActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsActivity.kt @@ -30,26 +30,33 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.activity.settings +package com.tari.android.wallet.ui.fragment.settings.backup.activity import android.content.Context import android.content.Intent import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity +import androidx.activity.viewModels import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import com.tari.android.wallet.R +import com.tari.android.wallet.databinding.ActivityBackupSettingsBinding +import com.tari.android.wallet.ui.common.CommonActivity import com.tari.android.wallet.ui.fragment.settings.backup.ChangeSecurePasswordFragment import com.tari.android.wallet.ui.fragment.settings.backup.EnterCurrentPasswordFragment import com.tari.android.wallet.ui.fragment.settings.backup.backupSettings.BackupSettingsFragment import com.tari.android.wallet.ui.fragment.settings.backup.verifySeedPhrase.VerifySeedPhraseFragment import com.tari.android.wallet.ui.fragment.settings.backup.writeDownSeedWords.WriteDownSeedPhraseFragment -class BackupSettingsActivity : AppCompatActivity(), BackupSettingsRouter { +class BackupSettingsActivity : CommonActivity(), BackupSettingsRouter { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_settings) + ui = ActivityBackupSettingsBinding.inflate(layoutInflater).apply { setContentView(root) } + + val viewModel: BackupSettingsViewModel by viewModels() + bindViewModel(viewModel) + + setContentView(R.layout.activity_backup_settings) overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left) if (savedInstanceState == null) { loadBackupSettingsFragment() @@ -62,35 +69,19 @@ class BackupSettingsActivity : AppCompatActivity(), BackupSettingsRouter { .commit() } + override fun toWalletBackupWithRecoveryPhrase(sourceFragment: Fragment) = addFragment(sourceFragment, WriteDownSeedPhraseFragment.newInstance()) - override fun toWalletBackupWithRecoveryPhrase(sourceFragment: Fragment) { - addFragment(sourceFragment, WriteDownSeedPhraseFragment.newInstance()) - } - - override fun toSeedPhraseVerification(sourceFragment: Fragment, seedWords: List) { + override fun toSeedPhraseVerification(sourceFragment: Fragment, seedWords: List) = addFragment(sourceFragment, VerifySeedPhraseFragment.newInstance(seedWords)) - } - override fun toConfirmPassword(sourceFragment: Fragment) { - addFragment( - sourceFragment, - EnterCurrentPasswordFragment.newInstance(), - allowStateLoss = true - ) - } + override fun toConfirmPassword(sourceFragment: Fragment) = + addFragment(sourceFragment, EnterCurrentPasswordFragment.newInstance(), allowStateLoss = true) - override fun toChangePassword(sourceFragment: Fragment) { - addFragment( - sourceFragment, - ChangeSecurePasswordFragment.newInstance(), - allowStateLoss = true - ) - } + override fun toChangePassword(sourceFragment: Fragment) = + addFragment(sourceFragment, ChangeSecurePasswordFragment.newInstance(), allowStateLoss = true) override fun onPasswordChanged(sourceFragment: Fragment) { - if (supportFragmentManager - .findFragmentByTag(EnterCurrentPasswordFragment::class.java.simpleName) != null - ) { + if (supportFragmentManager.findFragmentByTag(EnterCurrentPasswordFragment::class.java.simpleName) != null) { supportFragmentManager.popBackStackImmediate( EnterCurrentPasswordFragment::class.java.simpleName, FragmentManager.POP_BACK_STACK_INCLUSIVE @@ -101,10 +92,7 @@ class BackupSettingsActivity : AppCompatActivity(), BackupSettingsRouter { } override fun onSeedPhraseVerificationComplete(sourceFragment: Fragment) { - supportFragmentManager.popBackStackImmediate( - WriteDownSeedPhraseFragment::class.java.simpleName, - FragmentManager.POP_BACK_STACK_INCLUSIVE - ) + supportFragmentManager.popBackStackImmediate(WriteDownSeedPhraseFragment::class.java.simpleName, FragmentManager.POP_BACK_STACK_INCLUSIVE) } override fun onBackPressed() { @@ -117,19 +105,11 @@ class BackupSettingsActivity : AppCompatActivity(), BackupSettingsRouter { // for samsung devices with biometrics enabled, as after launching the biometric prompt // onSaveInstanceState is called, and commit()ing any stuff after onSaveInstanceState is called // results into IllegalStateException: Can not perform this action after onSaveInstanceState - private fun addFragment( - sourceFragment: Fragment, - fragment: Fragment, - allowStateLoss: Boolean = false - ) { + private fun addFragment(sourceFragment: Fragment, fragment: Fragment, allowStateLoss: Boolean = false) { supportFragmentManager .beginTransaction() - .setCustomAnimations( - R.anim.enter_from_right, R.anim.exit_to_left, - R.anim.enter_from_left, R.anim.exit_to_right - ) + .setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right) .hide(sourceFragment) - // .apply { supportFragmentManager.fragments.forEach { hide(it) } } .add(R.id.settings_fragment_container, fragment, fragment.javaClass.simpleName) .addToBackStack(fragment.javaClass.simpleName) .apply { if (allowStateLoss) commitAllowingStateLoss() else commit() } diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/settings/BackupSettingsRouter.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsRouter.kt similarity index 96% rename from app/src/main/java/com/tari/android/wallet/ui/activity/settings/BackupSettingsRouter.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsRouter.kt index 4973870a2..52faed863 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/settings/BackupSettingsRouter.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsRouter.kt @@ -30,7 +30,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.activity.settings +package com.tari.android.wallet.ui.fragment.settings.backup.activity import androidx.fragment.app.Fragment diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsViewModel.kt new file mode 100644 index 000000000..4458d0749 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/activity/BackupSettingsViewModel.kt @@ -0,0 +1,5 @@ +package com.tari.android.wallet.ui.fragment.settings.backup.activity + +import com.tari.android.wallet.ui.common.CommonViewModel + +class BackupSettingsViewModel : CommonViewModel() \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt index 179f302ff..53e68e4d9 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt @@ -50,15 +50,15 @@ import com.tari.android.wallet.event.EventBus import com.tari.android.wallet.extension.observe import com.tari.android.wallet.extension.observeOnLoad import com.tari.android.wallet.infrastructure.backup.BackupState.BackupUpToDate -import com.tari.android.wallet.ui.activity.settings.BackupSettingsRouter import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.extension.* +import com.tari.android.wallet.ui.fragment.settings.backup.activity.BackupSettingsRouter import com.tari.android.wallet.ui.fragment.settings.userAutorization.BiometricAuthenticationViewModel import org.joda.time.DateTime import org.joda.time.format.DateTimeFormat import java.util.* -internal class BackupSettingsFragment : CommonFragment() { +class BackupSettingsFragment : CommonFragment() { private var optionsAnimation: Animator? = null diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsViewModel.kt index adfcf4f58..9c7577fab 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsViewModel.kt @@ -4,7 +4,6 @@ import android.content.Intent import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.orhanobut.logger.Logger import com.tari.android.wallet.R import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository import com.tari.android.wallet.event.EventBus @@ -30,7 +29,7 @@ import java.net.UnknownHostException import java.util.* import javax.inject.Inject -internal class BackupSettingsViewModel : CommonViewModel() { +class BackupSettingsViewModel : CommonViewModel() { @Inject lateinit var backupManager: BackupManager @@ -104,7 +103,7 @@ internal class BackupSettingsViewModel : CommonViewModel() { _blockedBackPressed.postValue(true) backupManager.backup(isInitialBackup = true) } catch (exception: Exception) { - Logger.e("Backup storage setup failed: $exception") + logger.e(exception, "Backup storage setup failed") backupManager.turnOff(deleteExistingBackups = true) _inProgress.postValue(false) _backupPermissionSwitchChecked.postValue(false) @@ -158,8 +157,8 @@ internal class BackupSettingsViewModel : CommonViewModel() { try { //todo looks not finished backupManager.turnOff(deleteExistingBackups = true) - } catch (exception: Exception) { - Logger.i(exception.toString()) + } catch (exception: Throwable) { + logger.e(exception, "Turning off was failed") } } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/verifySeedPhrase/VerifySeedPhraseFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/verifySeedPhrase/VerifySeedPhraseFragment.kt index fa481026b..92ba1f0bf 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/verifySeedPhrase/VerifySeedPhraseFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/verifySeedPhrase/VerifySeedPhraseFragment.kt @@ -44,7 +44,7 @@ import androidx.core.view.get import androidx.fragment.app.viewModels import com.tari.android.wallet.databinding.FragmentVerifySeedPhraseBinding import com.tari.android.wallet.extension.observe -import com.tari.android.wallet.ui.activity.settings.BackupSettingsRouter +import com.tari.android.wallet.ui.fragment.settings.backup.activity.BackupSettingsRouter import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.extension.* diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseFragment.kt index 17150ed1c..6420c3cb4 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseFragment.kt @@ -47,7 +47,7 @@ import com.tari.android.wallet.R import com.tari.android.wallet.R.color.seed_phrase_button_disabled_text_color import com.tari.android.wallet.databinding.FragmentWriteDownSeedPhraseBinding import com.tari.android.wallet.extension.observe -import com.tari.android.wallet.ui.activity.settings.BackupSettingsRouter +import com.tari.android.wallet.ui.fragment.settings.backup.activity.BackupSettingsRouter import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.extension.* import com.tari.android.wallet.ui.fragment.settings.backup.writeDownSeedWords.adapter.PhraseWordsAdapter diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseViewModel.kt index b1cc887f3..3c7b3b531 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/writeDownSeedWords/WriteDownSeedPhraseViewModel.kt @@ -6,6 +6,7 @@ import com.tari.android.wallet.R import com.tari.android.wallet.extension.addTo import com.tari.android.wallet.extension.getWithError import com.tari.android.wallet.model.WalletError +import com.tari.android.wallet.service.connection.ServiceConnectionStatus import com.tari.android.wallet.service.connection.TariWalletServiceConnection import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.dialog.error.ErrorDialogArgs @@ -21,7 +22,7 @@ class WriteDownSeedPhraseViewModel : CommonViewModel() { init { serviceConnection.connection.subscribe { - if (it.status == TariWalletServiceConnection.ServiceConnectionStatus.CONNECTED) { + if (it.status == ServiceConnectionStatus.CONNECTED) { getSeedWords() } }.addTo(compositeDisposable) diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/settings/DeleteWalletActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/deleteWallet/DeleteWalletActivity.kt similarity index 83% rename from app/src/main/java/com/tari/android/wallet/ui/activity/settings/DeleteWalletActivity.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/settings/deleteWallet/DeleteWalletActivity.kt index 08c0092b1..768d893e5 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/settings/DeleteWalletActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/deleteWallet/DeleteWalletActivity.kt @@ -30,19 +30,19 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.activity.settings +package com.tari.android.wallet.ui.fragment.settings.deleteWallet import android.content.Intent import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity +import androidx.activity.viewModels import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.tari.android.wallet.R import com.tari.android.wallet.databinding.ActivityDeleteWalletBinding import com.tari.android.wallet.di.DiContainer.appComponent -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.service.connection.TariWalletServiceConnection -import com.tari.android.wallet.ui.fragment.onboarding.activity.OnboardingFlowActivity +import com.tari.android.wallet.ui.common.CommonActivity import com.tari.android.wallet.ui.dialog.modular.DialogArgs import com.tari.android.wallet.ui.dialog.modular.ModularDialog import com.tari.android.wallet.ui.dialog.modular.ModularDialogArgs @@ -51,23 +51,29 @@ import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonModule import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonStyle import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule import com.tari.android.wallet.ui.extension.* +import com.tari.android.wallet.ui.fragment.onboarding.activity.OnboardingFlowActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import javax.inject.Inject -class DeleteWalletActivity : AppCompatActivity() { +// todo refactor to regular fragment +class DeleteWalletActivity : CommonActivity() { @Inject - internal lateinit var walletServiceLauncher: WalletServiceLauncher + lateinit var walletServiceLauncher: WalletServiceLauncher - private var ui: ActivityDeleteWalletBinding? = null private lateinit var serviceConnection: TariWalletServiceConnection override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + ui = ActivityDeleteWalletBinding.inflate(layoutInflater).apply { setContentView(root) } overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left) appComponent.inject(this) + + val viewModel: DeleteWalletViewModel by viewModels() + bindViewModel(viewModel) + serviceConnection = ViewModelProvider(this)[TariWalletServiceConnection::class.java] setupUI() } @@ -78,10 +84,9 @@ class DeleteWalletActivity : AppCompatActivity() { } private fun setupUI() { - ui = ActivityDeleteWalletBinding.inflate(layoutInflater).apply { setContentView(root) } - ui?.deleteWalletProgress?.setColor(color(R.color.common_error)) - ui?.backCtaView?.setOnClickListener(ThrottleClick { onBackPressed() }) - ui?.deleteWalletCtaView?.setOnClickListener(ThrottleClick { confirmDeleteWallet() }) + ui.deleteWalletProgress.setColor(color(R.color.common_error)) + ui.backCtaView.setOnClickListener(ThrottleClick { onBackPressed() }) + ui.deleteWalletCtaView.setOnClickListener(ThrottleClick { confirmDeleteWallet() }) } private fun confirmDeleteWallet() { @@ -102,9 +107,9 @@ class DeleteWalletActivity : AppCompatActivity() { private fun deleteWallet() { // disable CTAs - ui?.backCtaView?.isEnabled = false - ui?.deleteWalletCtaView?.isEnabled = false - ui?.deleteWalletProgress?.visible() + ui.backCtaView.isEnabled = false + ui.deleteWalletCtaView.isEnabled = false + ui.deleteWalletProgress.visible() // delete wallet lifecycleScope.launch(Dispatchers.IO) { walletServiceLauncher.stopAndDelete() @@ -120,5 +125,4 @@ class DeleteWalletActivity : AppCompatActivity() { startActivity(intent) finishAffinity() } - } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/deleteWallet/DeleteWalletViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/deleteWallet/DeleteWalletViewModel.kt new file mode 100644 index 000000000..26dd0d5e5 --- /dev/null +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/deleteWallet/DeleteWalletViewModel.kt @@ -0,0 +1,5 @@ +package com.tari.android.wallet.ui.fragment.settings.deleteWallet + +import com.tari.android.wallet.ui.common.CommonViewModel + +class DeleteWalletViewModel: CommonViewModel() \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionFragment.kt index c084fe2c1..8b8da3fdc 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionFragment.kt @@ -41,7 +41,7 @@ import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager import com.tari.android.wallet.databinding.FragmentNetworkSelectionBinding import com.tari.android.wallet.extension.observe -import com.tari.android.wallet.ui.activity.SplashActivity +import com.tari.android.wallet.ui.fragment.splash.SplashActivity import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.common.recyclerView.CommonAdapter import com.tari.android.wallet.ui.extension.setOnThrottledClickListener diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt index 8677c09c2..96ad06d79 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt @@ -9,7 +9,7 @@ import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository import com.tari.android.wallet.data.sharedPrefs.network.TariNetwork import com.tari.android.wallet.di.DiContainer import com.tari.android.wallet.event.EventBus -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.common.SingleLiveEvent import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionViewModel.kt index 2bc676a27..498b90597 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionViewModel.kt @@ -28,10 +28,10 @@ class TorBridgesSelectionViewModel : CommonViewModel() { lateinit var torSharedRepository: TorSharedRepository @Inject - internal lateinit var torProxyManager: TorProxyManager + lateinit var torProxyManager: TorProxyManager @Inject - internal lateinit var baseNodes: BaseNodes + lateinit var baseNodes: BaseNodes init { component.inject(this) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt index 2110b3197..69f7aa69b 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt @@ -16,7 +16,7 @@ class CustomTorBridgesViewModel : CommonViewModel() { lateinit var torSharedRepository: TorSharedRepository @Inject - internal lateinit var walletManager: WalletManager + lateinit var walletManager: WalletManager init { component.inject(this) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/userAutorization/BiometricAuthenticationViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/userAutorization/BiometricAuthenticationViewModel.kt index b2566b537..cb1d7a340 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/userAutorization/BiometricAuthenticationViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/userAutorization/BiometricAuthenticationViewModel.kt @@ -4,7 +4,6 @@ import androidx.appcompat.app.AlertDialog import androidx.biometric.BiometricPrompt import androidx.fragment.app.Fragment import androidx.lifecycle.viewModelScope -import com.orhanobut.logger.Logger import com.tari.android.wallet.R import com.tari.android.wallet.extension.observe import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationException @@ -48,7 +47,7 @@ class BiometricAuthenticationViewModel : CommonViewModel() { private fun handleError(e: Exception) { if (e is BiometricAuthenticationException) { if (e.code != BiometricPrompt.ERROR_USER_CANCELED && e.code != BiometricPrompt.ERROR_CANCELED) - Logger.e("Other biometric error. Code: ${e.code}") + logger.e(e, "Other biometric error. Code: ${e.code}") val args = AlertDialogArgs( resourceManager.getString(R.string.auth_failed_desc), resourceManager.getString(R.string.auth_failed_title), diff --git a/app/src/main/java/com/tari/android/wallet/ui/activity/SplashActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/splash/SplashActivity.kt similarity index 90% rename from app/src/main/java/com/tari/android/wallet/ui/activity/SplashActivity.kt rename to app/src/main/java/com/tari/android/wallet/ui/fragment/splash/SplashActivity.kt index 721c137b7..102830973 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/activity/SplashActivity.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/splash/SplashActivity.kt @@ -30,7 +30,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.tari.android.wallet.ui.activity +package com.tari.android.wallet.ui.fragment.splash import android.app.Activity import android.content.Intent @@ -39,7 +39,7 @@ import androidx.appcompat.app.AppCompatActivity import com.tari.android.wallet.data.WalletConfig import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository import com.tari.android.wallet.di.DiContainer.appComponent -import com.tari.android.wallet.service.WalletServiceLauncher +import com.tari.android.wallet.service.service.WalletServiceLauncher import com.tari.android.wallet.ui.fragment.auth.AuthActivity import com.tari.android.wallet.ui.fragment.onboarding.activity.OnboardingFlowActivity import com.tari.android.wallet.util.WalletUtil @@ -50,16 +50,16 @@ import javax.inject.Inject * * @author The Tari Development Team */ -internal class SplashActivity : AppCompatActivity() { +class SplashActivity : AppCompatActivity() { @Inject - internal lateinit var walletConfig: WalletConfig + lateinit var walletConfig: WalletConfig @Inject - internal lateinit var sharedPrefsRepository: SharedPrefsRepository + lateinit var sharedPrefsRepository: SharedPrefsRepository @Inject - internal lateinit var walletServiceLauncher: WalletServiceLauncher + lateinit var walletServiceLauncher: WalletServiceLauncher override fun onCreate(savedInstanceState: Bundle?) { appComponent.inject(this) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TxListFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TxListFragment.kt index 83b4434cb..1a9922293 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TxListFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TxListFragment.kt @@ -38,7 +38,6 @@ import android.animation.ValueAnimator import android.annotation.SuppressLint import android.content.Intent import android.graphics.drawable.GradientDrawable -import android.hardware.SensorManager import android.os.Bundle import android.os.Handler import android.os.Looper @@ -47,7 +46,6 @@ import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity import androidx.core.animation.addListener import androidx.core.os.postDelayed import androidx.fragment.app.viewModels @@ -56,7 +54,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.daasuu.ei.Ease import com.daasuu.ei.EasingInterpolator -import com.squareup.seismic.ShakeDetector import com.tari.android.wallet.R import com.tari.android.wallet.databinding.FragmentTxListBinding import com.tari.android.wallet.event.Event @@ -65,7 +62,7 @@ import com.tari.android.wallet.extension.observe import com.tari.android.wallet.extension.observeOnLoad import com.tari.android.wallet.model.BalanceInfo import com.tari.android.wallet.model.User -import com.tari.android.wallet.ui.activity.debug.DebugActivity +import com.tari.android.wallet.ui.common.CommonActivity import com.tari.android.wallet.ui.common.CommonFragment import com.tari.android.wallet.ui.common.recyclerView.CommonAdapter import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem @@ -77,8 +74,6 @@ import com.tari.android.wallet.ui.fragment.tx.questionMark.QuestionMarkViewModel import com.tari.android.wallet.ui.fragment.tx.ui.CustomScrollView import com.tari.android.wallet.ui.fragment.tx.ui.balanceController.BalanceViewController import com.tari.android.wallet.ui.fragment.tx.ui.progressController.UpdateProgressViewController -import com.tari.android.wallet.ui.resource.AnimationResource -import com.tari.android.wallet.ui.resource.ResourceContainer import com.tari.android.wallet.util.Constants import com.tari.android.wallet.util.WalletUtil import kotlinx.coroutines.Dispatchers @@ -87,12 +82,11 @@ import java.lang.ref.WeakReference import kotlin.math.max import kotlin.math.min -internal class TxListFragment : CommonFragment(), +class TxListFragment : CommonFragment(), View.OnScrollChangeListener, View.OnTouchListener, CustomScrollView.Listener, - UpdateProgressViewController.Listener, - ShakeDetector.Listener { + UpdateProgressViewController.Listener { private val networkIndicatorViewModel: ConnectionIndicatorViewModel by viewModels() private val questionMarkViewModel: QuestionMarkViewModel by viewModels() @@ -101,11 +95,9 @@ internal class TxListFragment : CommonFragment).openDebugActivity() } override fun onSwipeRefresh(source: CustomScrollView) { @@ -359,14 +331,7 @@ internal class TxListFragment : CommonFragment viewModel.displayNetworkConnectionErrorDialog() - } - } - + lifecycleScope.launch(Dispatchers.Main) { ui.scrollView.finishUpdate() } viewModel.refreshAllData() } @@ -510,8 +475,7 @@ internal class TxListFragment : CommonFragment() val listUpdateTrigger: LiveData = _listUpdateTrigger - val debouncedList = Transformations.map(listUpdateTrigger.debounce(LIST_UPDATE_DEBOUNCE)) { updateList() } + val debouncedList = Transformations.map(listUpdateTrigger.debounce(LIST_UPDATE_DEBOUNCE)) { + updateList() + refreshBalance() + } private val _txSendSuccessful = SingleLiveEvent() val txSendSuccessful: MutableLiveData = _txSendSuccessful @@ -143,9 +147,7 @@ internal class TxListViewModel : CommonViewModel() { private fun bindToWalletService() { serviceConnection = TariWalletServiceConnection() - serviceConnection.connection.subscribe { - if (it.status == TariWalletServiceConnection.ServiceConnectionStatus.CONNECTED) onServiceConnected() - }.addTo(compositeDisposable) + serviceConnection.connection.subscribe { if (it.status == ServiceConnectionStatus.CONNECTED) onServiceConnected() }.addTo(compositeDisposable) } private fun onServiceConnected() { @@ -188,7 +190,7 @@ internal class TxListViewModel : CommonViewModel() { } } - private fun refreshBalance(isRestarted: Boolean) { + private fun refreshBalance(isRestarted: Boolean = false) { viewModelScope.launch(Dispatchers.IO) { fetchBalanceInfoData() _refreshBalanceInfo.postValue(isRestarted) @@ -224,6 +226,7 @@ internal class TxListViewModel : CommonViewModel() { } private fun subscribeToEventBus() { + EventBus.subscribe(this) { refreshAllData() } EventBus.subscribe(this) { if (progressControllerState.state != UpdateProgressViewController.State.RECEIVING) { onTxReceived(it.tx) @@ -234,7 +237,6 @@ internal class TxListViewModel : CommonViewModel() { EventBus.subscribe(this) { onInboundTxBroadcast(it.tx) } EventBus.subscribe(this) { onOutboundTxBroadcast(it.tx) } EventBus.subscribe(this) { onTxMinedUnconfirmed(it.tx) } - EventBus.subscribe(this) { onTxMinedUnconfirmed(it.tx) } EventBus.subscribe(this) { onTxMined(it.tx) } EventBus.subscribe(this) { onTxFauxMinedUnconfirmed(it.tx) } EventBus.subscribe(this) { onFauxTxMined(it.tx) } @@ -250,6 +252,8 @@ internal class TxListViewModel : CommonViewModel() { EventBus.subscribe(this) { onTxSendSuccessful(it.txId) } EventBus.subscribe(this) { onTxSendFailed(it.failureReason) } + EventBus.balanceState.publishSubject.subscribe { _balanceInfo.postValue(it) }.addTo(compositeDisposable) + EventBus.subscribe(this) { onContactAddedOrUpdated(it.contactPublicKey, it.contactAlias) } EventBus.subscribe(this) { onContactRemoved(it.contactPublicKey) } @@ -413,9 +417,7 @@ internal class TxListViewModel : CommonViewModel() { testnetRepository.faucetTestnetTariRequestCompleted = true testnetRepository.firstTestnetUTXOTxId = importedTx.id - completedTxs.add(importedTx) - refreshBalance(false) - updateList() + refreshAllData() viewModelScope.launch(Dispatchers.IO) { delay(Constants.UI.Home.showTariBotDialogDelayMs) @@ -428,11 +430,9 @@ internal class TxListViewModel : CommonViewModel() { private fun testnetTariRequestError() { testnetTariRequestIsInProgress = false - if (!networkRepository.currentNetwork?.faucetUrl.isNullOrEmpty()) { - val description = resourceManager.getString(faucet_error_common) - val errorDialogArgs = ErrorDialogArgs(resourceManager.getString(faucet_error_title), description) - _modularDialog.postValue(errorDialogArgs.getModular(resourceManager)) - } + val description = resourceManager.getString(faucet_error_common) + val errorDialogArgs = ErrorDialogArgs(resourceManager.getString(faucet_error_title), description) + _modularDialog.postValue(errorDialogArgs.getModular(resourceManager)) } @@ -518,7 +518,8 @@ internal class TxListViewModel : CommonViewModel() { DialogArgs(true, canceledOnTouchOutside = false), listOf( HeadModule(resourceManager.getString(home_tari_bot_you_got_tari_dlg_title)), BodyModule(resourceManager.getString(home_tari_bot_dialog_desc)), - ButtonModule(resourceManager.getString(home_tari_bot_try_later), ButtonStyle.Normal) { + ButtonModule(resourceManager.getString(send_tari_title), ButtonStyle.Normal) { + _dismissDialog.value = Unit sendTariToUser(testnetSenderPublicKey) }, ButtonModule(resourceManager.getString(home_tari_bot_try_later), ButtonStyle.Close) @@ -562,9 +563,7 @@ internal class TxListViewModel : CommonViewModel() { } importedTx ?: return@launch testnetRepository.secondTestnetUTXOTxId = importedTx.id - completedTxs.add(importedTx) - refreshBalance(false) - updateList() + refreshAllData() delay(SECOND_UTXO_STORE_OPEN_DELAY) showTTLStoreDialog() } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt index 7466b4c78..8c1c7ce04 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt @@ -4,5 +4,5 @@ import com.tari.android.wallet.model.Tx import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem import com.tari.android.wallet.ui.common.gyphy.presentation.GIFViewModel -internal class TransactionItem(val tx: Tx, val position: Int, val viewModel: GIFViewModel, val requiredConfirmationCount: Long) : +class TransactionItem(val tx: Tx, val position: Int, val viewModel: GIFViewModel, val requiredConfirmationCount: Long) : CommonViewHolderItem() \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListAdapter.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListAdapter.kt index a0089a7a1..5977a42dd 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListAdapter.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListAdapter.kt @@ -5,6 +5,6 @@ import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem import com.tari.android.wallet.ui.common.recyclerView.ViewHolderBuilder import com.tari.android.wallet.ui.common.recyclerView.viewHolders.TitleViewHolder -internal class TxListAdapter : CommonAdapter() { +class TxListAdapter : CommonAdapter() { override var viewHolderBuilders: List = listOf(TitleViewHolder.getBuilder(), TxListViewHolder.getBuilder()) } \ No newline at end of file diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt index 119fe113d..4c2d64a4c 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt @@ -18,7 +18,7 @@ import com.tari.android.wallet.ui.common.recyclerView.ViewHolderBuilder import com.tari.android.wallet.ui.component.CustomFont import com.tari.android.wallet.ui.component.EmojiIdSummaryViewController import com.tari.android.wallet.ui.extension.* -import com.tari.android.wallet.ui.presentation.TxNote +import com.tari.android.wallet.model.TxNote import com.tari.android.wallet.util.WalletUtil import com.tari.android.wallet.util.extractEmojis import org.joda.time.DateTime @@ -27,7 +27,7 @@ import org.joda.time.LocalDate import org.joda.time.Minutes import java.util.* -internal class TxListViewHolder(view: ItemHomeTxListBinding) : CommonViewHolder(view), GIFStateConsumer { +class TxListViewHolder(view: ItemHomeTxListBinding) : CommonViewHolder(view), GIFStateConsumer { private val glide = Glide.with(itemView.context) private val emojiIdSummaryController = EmojiIdSummaryViewController(ui.participantEmojiIdView) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt index 4612d78ee..39025e617 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt @@ -41,7 +41,6 @@ import android.view.inputmethod.EditorInfo import android.widget.TextView import androidx.fragment.app.viewModels import com.bumptech.glide.Glide -import com.orhanobut.logger.Logger import com.tari.android.wallet.R.color.* import com.tari.android.wallet.R.dimen.add_amount_element_text_size import com.tari.android.wallet.R.dimen.add_amount_gem_size @@ -70,7 +69,6 @@ import com.tari.android.wallet.ui.extension.* import com.tari.android.wallet.ui.fragment.tx.details.gif.GIFView import com.tari.android.wallet.ui.fragment.tx.details.gif.GIFViewModel import com.tari.android.wallet.ui.fragment.tx.details.gif.TxState -import com.tari.android.wallet.ui.presentation.TxNote import com.tari.android.wallet.util.WalletUtil import java.util.* @@ -79,7 +77,7 @@ import java.util.* * * @author The Tari Development Team */ -internal class TxDetailsFragment : CommonFragment() { +class TxDetailsFragment : CommonFragment() { /** * Values below are used for scaling up/down of the text size. @@ -112,10 +110,6 @@ internal class TxDetailsFragment : CommonFragment "" state == TxState(INBOUND, PENDING) -> string(tx_detail_waiting_for_sender_to_complete) state == TxState(OUTBOUND, PENDING) -> string(tx_detail_waiting_for_recipient) - state.status != MINED_CONFIRMED -> string( + state == TxState(INBOUND, FAUX_UNCONFIRMED) -> "" + state.status != MINED_CONFIRMED && state.status != COINBASE -> string( tx_detail_completing_final_processing, if (tx is CompletedTx) tx.confirmationCount.toInt() + 1 else 1, viewModel.requiredConfirmationCount + 1 @@ -327,22 +322,23 @@ internal class TxDetailsFragment : CommonFragment { +class QuestionMarkView : MainListTouchingView { override fun bindingInflate(layoutInflater: LayoutInflater, parent: ViewGroup?, attachToRoot: Boolean): ViewQuestionMarkBinding = ViewQuestionMarkBinding.inflate(layoutInflater, parent, attachToRoot) diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/questionMark/QuestionMarkViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/questionMark/QuestionMarkViewModel.kt index b34ad9bc4..a992ccdc2 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/questionMark/QuestionMarkViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/questionMark/QuestionMarkViewModel.kt @@ -4,7 +4,7 @@ import com.tari.android.wallet.R import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.dialog.confirm.ConfirmDialogArgs -internal class QuestionMarkViewModel : CommonViewModel() { +class QuestionMarkViewModel : CommonViewModel() { fun showUniversityDialog() { val confirmDialogArgs = ConfirmDialogArgs( resourceManager.getString(R.string.home_balance_info_help_title), diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/CustomScrollView.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/CustomScrollView.kt index f21dc7d70..03caee954 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/CustomScrollView.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/CustomScrollView.kt @@ -57,7 +57,7 @@ import kotlin.math.min * * @author The Tari Development Team */ -internal class CustomScrollView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : +class CustomScrollView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ScrollView(context, attrs, defStyleAttr) { var flingIsRunning = false diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/balanceController/BalanceViewController.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/balanceController/BalanceViewController.kt index 115012f75..1f5a723f3 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/balanceController/BalanceViewController.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/balanceController/BalanceViewController.kt @@ -46,7 +46,7 @@ import java.lang.ref.WeakReference * * @author The Tari Development Team */ -internal class BalanceViewController( +class BalanceViewController( private val context: Context, private val digitContainerView: ViewGroup, decimalDigitContainerView: ViewGroup, diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/progressController/UpdateProgressViewController.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/progressController/UpdateProgressViewController.kt index 156784d6c..bc6b57ccf 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/progressController/UpdateProgressViewController.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/ui/progressController/UpdateProgressViewController.kt @@ -40,7 +40,6 @@ import android.widget.TextView import androidx.core.animation.addListener import com.daasuu.ei.Ease import com.daasuu.ei.EasingInterpolator -import com.orhanobut.logger.Logger import com.tari.android.wallet.R import com.tari.android.wallet.event.Event import com.tari.android.wallet.event.EventBus @@ -65,7 +64,7 @@ import kotlin.coroutines.CoroutineContext * * @author The Tari Development Team */ -internal class UpdateProgressViewController(private val view: View, listener: Listener) : CoroutineScope { +class UpdateProgressViewController(private val view: View, listener: Listener) : CoroutineScope { private val mJob = Job() override val coroutineContext: CoroutineContext @@ -153,7 +152,6 @@ internal class UpdateProgressViewController(private val view: View, listener: Li fun start(walletService: TariWalletService) { this.walletService = walletService - Logger.d("Start update.") progressBar.visible() isReset = false state.numberOfReceivedTxs = 0 @@ -198,10 +196,8 @@ internal class UpdateProgressViewController(private val view: View, listener: Li } private fun checkNetworkConnectionStatus() { - Logger.d("Start connection check.") val networkConnectionState = EventBus.networkConnectionState.publishSubject.value if (networkConnectionState != NetworkConnectionState.CONNECTED) { - Logger.e("Update error: not connected to the internet.") view.postDelayed({ fail(FailureReason.NETWORK_CONNECTION_ERROR) }, minStateDisplayPeriodMs) return } @@ -210,7 +206,6 @@ internal class UpdateProgressViewController(private val view: View, listener: Li @SuppressLint("CheckResult") private fun checkTorBootstrapStatus() { - Logger.d("Check bootstrap status.") torBootstrapStatusSubscription?.dispose() // check for expiration if (connectionCheckHasTimedOut()) { @@ -221,13 +216,11 @@ internal class UpdateProgressViewController(private val view: View, listener: Li // check whether Tor proxy is running if (torProxyState !is TorProxyState.Running) { // either not connected or Tor proxy is not running - Logger.e("Update error: Tor proxy is not running.") view.postDelayed({ fail(FailureReason.BASE_NODE_VALIDATION_ERROR) }, minStateDisplayPeriodMs) return } // check Tor bootstrap status if (torProxyState.bootstrapStatus.progress < TorBootstrapStatus.maxProgress) { - Logger.d("Tor bootstrap not complete. Try again in %d seconds.", minStateDisplayPeriodMs) // check again after a wait period torBootstrapStatusSubscription = Observable .timer(minStateDisplayPeriodMs, TimeUnit.MILLISECONDS) @@ -247,13 +240,11 @@ internal class UpdateProgressViewController(private val view: View, listener: Li } baseNodeSyncCurrentRetryCount++ // sync base node - Logger.d("Try to sync with base node - retry count %d.", baseNodeSyncCurrentRetryCount) val walletError = WalletError() // long running call launch(Dispatchers.IO) { val success = walletService.startBaseNodeSync(walletError) if (isActive && (!success || walletError != WalletError.NoError)) { - Logger.e("Base node sync has failed.") fail(FailureReason.BASE_NODE_VALIDATION_ERROR) } } @@ -270,8 +261,6 @@ internal class UpdateProgressViewController(private val view: View, listener: Li when (event) { is BaseNodeSyncState.Online -> { baseNodeSyncTimeoutSubscription?.dispose() - // base node sync successful - start listening for events - Logger.d("Base node sync successful. Start listening for wallet events.") state.state = State.RECEIVING view.postDelayed({ displayReceivingTxs() }, minStateDisplayPeriodMs) } @@ -329,7 +318,6 @@ internal class UpdateProgressViewController(private val view: View, listener: Li } private fun baseNodeSyncTimedOut() { - Logger.e("Base node sync timed out.") fail(FailureReason.BASE_NODE_VALIDATION_ERROR) } diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListViewModel.kt index 55669c316..47b8e914f 100644 --- a/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListViewModel.kt +++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListViewModel.kt @@ -3,9 +3,12 @@ package com.tari.android.wallet.ui.fragment.utxos.list import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import com.tari.android.wallet.R +import com.tari.android.wallet.event.Event +import com.tari.android.wallet.event.EventBus import com.tari.android.wallet.extension.addTo import com.tari.android.wallet.extension.getWithError import com.tari.android.wallet.service.TariWalletService +import com.tari.android.wallet.service.connection.ServiceConnectionStatus import com.tari.android.wallet.service.connection.TariWalletServiceConnection import com.tari.android.wallet.ui.common.CommonViewModel import com.tari.android.wallet.ui.dialog.modular.DialogArgs @@ -56,7 +59,7 @@ class UtxosListViewModel : CommonViewModel() { setSelectionState(false) serviceConnection.connection.subscribe { - if (it.status == TariWalletServiceConnection.ServiceConnectionStatus.CONNECTED) loadUtxosFromFFI() + if (it.status == ServiceConnectionStatus.CONNECTED) loadUtxosFromFFI() }.addTo(compositeDisposable) component.inject(this) @@ -125,6 +128,7 @@ class UtxosListViewModel : CommonViewModel() { wallet.joinUtxos(selectedUtxos, error) _dismissDialog.postValue(Unit) loadUtxosFromFFI() + EventBus.post(Event.Transaction.Updated) showSuccessJoinDialog() } } @@ -150,6 +154,7 @@ class UtxosListViewModel : CommonViewModel() { wallet.splitUtxos(selectedUtxos, splitModule.count, error) _dismissDialog.postValue(Unit) loadUtxosFromFFI() + EventBus.post(Event.Transaction.Updated) showSuccessSplitDialog() } } diff --git a/app/src/main/java/com/tari/android/wallet/ui/resource/AnimationResource.kt b/app/src/main/java/com/tari/android/wallet/ui/resource/AnimationResource.kt deleted file mode 100644 index a4475e1dc..000000000 --- a/app/src/main/java/com/tari/android/wallet/ui/resource/AnimationResource.kt +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.ui.resource - -import android.animation.Animator -import androidx.core.animation.addListener - -class AnimationResource(private val animator: Animator) : Resource { - - fun attachAndCutoffOnFinish(container: ResourceContainer) { - animator.addListener( - onCancel = { container.remove(this) }, - onEnd = { container.remove(this) } - ) - container.add(this) - } - - override fun dispose() = animator.cancel() - -} diff --git a/app/src/main/java/com/tari/android/wallet/ui/resource/ResourceContainer.kt b/app/src/main/java/com/tari/android/wallet/ui/resource/ResourceContainer.kt deleted file mode 100644 index 9b1582e96..000000000 --- a/app/src/main/java/com/tari/android/wallet/ui/resource/ResourceContainer.kt +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.ui.resource - -class ResourceContainer : Resource { - - private val resources = mutableListOf() - - fun add(resource: Resource) = resources.add(resource) - - fun remove(resource: Resource) = resources.remove(resource) - - override fun dispose() = resources.forEach(Resource::dispose) - -} diff --git a/app/src/main/java/com/tari/android/wallet/util/Constants.kt b/app/src/main/java/com/tari/android/wallet/util/Constants.kt index 73cade6e6..2d7438ad9 100644 --- a/app/src/main/java/com/tari/android/wallet/util/Constants.kt +++ b/app/src/main/java/com/tari/android/wallet/util/Constants.kt @@ -40,7 +40,7 @@ import java.math.BigInteger * * @author The Tari Development Team */ -internal object Constants { +object Constants { /** * UI constants. diff --git a/app/src/main/java/com/tari/android/wallet/util/EmojiUtil.kt b/app/src/main/java/com/tari/android/wallet/util/EmojiUtil.kt index 8b429a32d..16aa69ab1 100644 --- a/app/src/main/java/com/tari/android/wallet/util/EmojiUtil.kt +++ b/app/src/main/java/com/tari/android/wallet/util/EmojiUtil.kt @@ -44,7 +44,7 @@ import com.tari.android.wallet.ffi.FFIEmojiSet /** * Number of emojis from the Tari emoji set in a string. */ -internal fun String.numberOfEmojis(emojiSet: Set = EmojiUtil.emojiSet): Int { +fun String.numberOfEmojis(emojiSet: Set = EmojiUtil.emojiSet): Int { val it: BreakIterator = BreakIterator.getCharacterInstance() it.setText(this) var emojiCount = 0 @@ -67,7 +67,7 @@ internal fun String.numberOfEmojis(emojiSet: Set = EmojiUtil.emojiSet): /** * @return true if there is at least 1 character that is not included in the Tari emoji set. */ -internal fun String.containsNonEmoji(emojiSet: Set = EmojiUtil.emojiSet): Boolean { +fun String.containsNonEmoji(emojiSet: Set = EmojiUtil.emojiSet): Boolean { // iterate through the string val it: BreakIterator = BreakIterator.getCharacterInstance() it.setText(this) @@ -91,7 +91,7 @@ internal fun String.containsNonEmoji(emojiSet: Set = EmojiUtil.emojiSet) /** * @return emojis in the string that are from the Tari emoji set */ -internal fun String.extractEmojis(emojiSet: Set = EmojiUtil.emojiSet): List { +fun String.extractEmojis(emojiSet: Set = EmojiUtil.emojiSet): List { // iterate through the codepoints val it: BreakIterator = BreakIterator.getCharacterInstance() it.setText(this) @@ -116,7 +116,7 @@ internal fun String.extractEmojis(emojiSet: Set = EmojiUtil.emojiSet): L * Checks whether a given number of first characters of the string are emojis from the Tari * emoji set. */ -internal fun String.firstNCharactersAreEmojis(n: Int, emojiSet: Set = EmojiUtil.emojiSet): Boolean { +fun String.firstNCharactersAreEmojis(n: Int, emojiSet: Set = EmojiUtil.emojiSet): Boolean { // iterate through the string val it: BreakIterator = BreakIterator.getCharacterInstance() it.setText(this) @@ -147,25 +147,25 @@ internal fun String.firstNCharactersAreEmojis(n: Int, emojiSet: Set = Em * * @author The Tari Development Team */ -internal class EmojiUtil { +class EmojiUtil { companion object { const val smallEmojiIdSize = 6 val emojiSet by lazy { - val emojis = mutableSetOf() - val emojiSetFFI = FFIEmojiSet() - for (i in 0 until emojiSetFFI.getLength()) { - val emojiFFI = emojiSetFFI.getAt(i) - val emojiBytes = emojiFFI.getBytes() - val emoji = String(emojiBytes) - emojis.add(emoji) - emojiFFI.destroy() - } - emojiSetFFI.destroy() - emojis + val emojis = mutableSetOf() + val emojiSetFFI = FFIEmojiSet() + for (i in 0 until emojiSetFFI.getLength()) { + val emojiFFI = emojiSetFFI.getAt(i) + val emojiBytes = emojiFFI.getBytes() + val emoji = String(emojiBytes) + emojis.add(emoji) + emojiFFI.destroy() } + emojiSetFFI.destroy() + emojis + } /** * Masking-related: get the indices of current chunk separators. @@ -173,10 +173,7 @@ internal class EmojiUtil { * @param string possibly chunked string * @param emojiIdChunkSeparator chunk separator sequence */ - fun getExistingChunkSeparatorIndices( - string: String, - emojiIdChunkSeparator: String - ): ArrayList { + fun getExistingChunkSeparatorIndices(string: String, emojiIdChunkSeparator: String): ArrayList { val existingIndices = ArrayList() var currentIndex = 0 // prep the iterator @@ -253,52 +250,23 @@ internal class EmojiUtil { return builder.toString() } - fun getChunkSeparatorSpannable( - separator: String, - color: Int - ): SpannableString { + fun getChunkSeparatorSpannable(separator: String, color: Int): SpannableString { val spannable = SpannableString(separator) - spannable.setSpan( - ForegroundColorSpan(color), - 0, - separator.length, - Spanned.SPAN_INTERMEDIATE - ) - spannable.applyRelativeTextSizeStyle( - separator, - Constants.UI.emojiIdChunkSeparatorRelativeScale - ) - spannable.applyLetterSpacingStyle( - separator, - Constants.UI.emojiIdChunkSeparatorLetterSpacing - ) + spannable.setSpan(ForegroundColorSpan(color), 0, separator.length, Spanned.SPAN_INTERMEDIATE) + spannable.applyRelativeTextSizeStyle(separator, Constants.UI.emojiIdChunkSeparatorRelativeScale) + spannable.applyLetterSpacingStyle(separator, Constants.UI.emojiIdChunkSeparatorLetterSpacing) return spannable } - fun getFullEmojiIdSpannable( - emojiId: String, - separator: String, - darkColor: Int, - lightColor: Int - ): SpannableString { - val spannable = getChunkedEmojiId( - emojiId, - separator - ).applyColorStyle( + fun getFullEmojiIdSpannable(emojiId: String, separator: String, darkColor: Int, lightColor: Int): SpannableString { + val spannable = getChunkedEmojiId(emojiId, separator).applyColorStyle( darkColor, listOf(separator), lightColor, applyToOnlyFirstOccurrence = false ) - spannable.applyLetterSpacingStyle( - separator, - Constants.UI.emojiIdChunkSeparatorLetterSpacing - ) - spannable.applyRelativeTextSizeStyle( - separator, - Constants.UI.emojiIdChunkSeparatorRelativeScale, - applyToOnlyFirstOccurrence = false - ) + spannable.applyLetterSpacingStyle(separator, Constants.UI.emojiIdChunkSeparatorLetterSpacing) + spannable.applyRelativeTextSizeStyle(separator, Constants.UI.emojiIdChunkSeparatorRelativeScale, applyToOnlyFirstOccurrence = false) return spannable } diff --git a/app/src/main/java/com/tari/android/wallet/util/WalletUtil.kt b/app/src/main/java/com/tari/android/wallet/util/WalletUtil.kt index 461a9dfde..5c94f9263 100644 --- a/app/src/main/java/com/tari/android/wallet/util/WalletUtil.kt +++ b/app/src/main/java/com/tari/android/wallet/util/WalletUtil.kt @@ -43,7 +43,7 @@ import java.util.* * * @author The Tari Development Team */ -internal object WalletUtil { +object WalletUtil { val balanceFormatter = DecimalFormat("#,##0.00").apply { roundingMode = RoundingMode.FLOOR diff --git a/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt b/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt index 2ee61f541..1478e7fd1 100644 --- a/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt +++ b/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt @@ -27,6 +27,10 @@ class YatAdapter( private val networkRepository: NetworkRepository, private val commonRepository: SharedPrefsRepository ) : YatIntegration.Delegate { + + private val logger + get() = Logger.t(YatAdapter::class.simpleName) + fun initYat(application: Application) { val config = YatConfiguration(BuildConfig.YAT_ORGANIZATION_RETURN_URL, BuildConfig.YAT_ORGANIZATION_NAME, BuildConfig.YAT_ORGANIZATION_KEY) YatIntegration.setup(application, config, YatIntegration.ColorMode.LIGHT, this) @@ -54,11 +58,11 @@ class YatAdapter( } override fun onYatIntegrationComplete(yat: String) { - Logger.d("Yat integration completed.") + logger.d("Yat integration completed with $yat") yatSharedRepository.saveYat(yat) } override fun onYatIntegrationFailed(failureType: YatIntegration.FailureType) { - Logger.d("Yat integration failed.$failureType") + logger.d("Yat integration failed $failureType") } } \ No newline at end of file diff --git a/app/src/main/res/drawable/debug_log_arrow_button_bg.xml b/app/src/main/res/drawable/debug_log_arrow_button_bg.xml index 1b2420784..27d438a12 100644 --- a/app/src/main/res/drawable/debug_log_arrow_button_bg.xml +++ b/app/src/main/res/drawable/debug_log_arrow_button_bg.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/log_share_button_bg.xml b/app/src/main/res/drawable/log_share_button_bg.xml index 8bb5991e5..13a2f6eb1 100644 --- a/app/src/main/res/drawable/log_share_button_bg.xml +++ b/app/src/main/res/drawable/log_share_button_bg.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_backup_settings.xml similarity index 67% rename from app/src/main/res/layout/activity_settings.xml rename to app/src/main/res/layout/activity_backup_settings.xml index 9d0a2c225..9d3ed9724 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_backup_settings.xml @@ -1,9 +1,8 @@ + + android:background="@color/black" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml index d74cae299..93b5c01ad 100644 --- a/app/src/main/res/layout/activity_home.xml +++ b/app/src/main/res/layout/activity_home.xml @@ -12,7 +12,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + tools:ignore="FragmentTagUsage" /> + android:background="@color/black" /> diff --git a/app/src/main/res/layout/fragment_debug_log.xml b/app/src/main/res/layout/fragment_debug_log.xml index 352952e0a..c3f5befea 100644 --- a/app/src/main/res/layout/fragment_debug_log.xml +++ b/app/src/main/res/layout/fragment_debug_log.xml @@ -10,7 +10,8 @@ android:layout_width="match_parent" android:layout_height="@dimen/log_item_height" android:layout_marginHorizontal="@dimen/common_horizontal_margin" - android:layout_marginTop="@dimen/common_horizontal_margin" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" android:gravity="center_vertical" android:orientation="horizontal"> @@ -18,6 +19,7 @@ android:id="@+id/file_spinner" android:layout_width="0dp" android:layout_height="@dimen/log_item_height" + android:layout_marginEnd="16dp" android:layout_weight="1" /> + - + android:background="@android:color/white"> + + android:layout_marginVertical="4dp" + android:background="@drawable/log_item_bg" + android:orientation="vertical" + android:paddingHorizontal="10dp" + android:paddingVertical="12dp"> - + android:layout_height="wrap_content" + android:ellipsize="middle" + android:singleLine="true" + android:text="@string/dummy_message" + android:textColor="@color/black" + android:textSize="13sp" + app:customFont="@string/font_regular" /> - - - - - - - - - + android:layout_marginTop="8dp" + android:ellipsize="middle" + android:singleLine="true" + android:text="@string/dummy_message" + android:textColor="@color/black" + android:textSize="13sp" + app:customFont="@string/font_regular" /> - + - + - + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:singleLine="false" + android:text="@string/dummy_message" + android:textColor="@color/black" + android:textSize="13sp" + android:typeface="monospace" /> - + \ No newline at end of file diff --git a/app/src/main/res/raw/dibbler_base_nodes.txt b/app/src/main/res/raw/dibbler_base_nodes.txt deleted file mode 100644 index fecfd843b..000000000 --- a/app/src/main/res/raw/dibbler_base_nodes.txt +++ /dev/null @@ -1,6 +0,0 @@ -oregon::50e6aa8f6c50f1b9d9b3d438dfd2a29cfe1f3e3a650bd9e6b1e10f96b6c38f4d::/onion3/7s6y3cz5bnewlj5ypm7sekhgvqjyrq4bpaj5dyvvo7vxydj7hsmyf5ad:18141 -ncal::c2eca9cf32261a1343e21ed718e79f25bfc74386e9305350b06f62047f519347::/onion3/6yxqk2ybo43u73ukfhyc42qn25echn4zegjpod2ccxzr2jd5atipwzqd:18141 -nvir::42fcde82b44af1de95a505d858cb31a422c56c4ac4747fbf3da47d648d4fc346::/onion3/2l3e7ysmihc23zybapdrsbcfg6omtjtfkvwj65dstnfxkwtai2fawtyd:18141 -seoul::36a9df45e1423b5315ffa7a91521924210c8e1d1537ad0968450f20f21e5200d::/onion3/v24qfheti2rztlwzgk6v4kdbes3ra7mo3i2fobacqkbfrk656e3uvnid:18141 -stockholm::be128d570e8ec7b15c101ee1a56d6c56dd7d109199f0bd02f182b71142b8675f::/onion3/ha422qsy743ayblgolui5pg226u42wfcklhc5p7nbhiytlsp4ir2syqd:18141 -sydney::3e0321c0928ca559ab3c0a396272dfaea705efce88440611a38ff3898b097217::/onion3/sl5ledjoaisst6d4fh7kde746dwweuge4m4mf5nkzdhmy57uwgtb7qqd:18141 \ No newline at end of file diff --git a/app/src/main/res/raw/esmeralda_base_nodes.txt b/app/src/main/res/raw/esmeralda_base_nodes.txt new file mode 100644 index 000000000..a9ebfb1a9 --- /dev/null +++ b/app/src/main/res/raw/esmeralda_base_nodes.txt @@ -0,0 +1,8 @@ +london::083ff333ad7e0e9f3678b67378ec339074474342a6357de64a76bdf15e4c955b::/onion3/ldgdytcrwzfbmbpz3dmyi6yzqzqbeamitpb2saxzxmp52qywlmsg4vyd:18141 +ireland::747d45b8416ffe605d17958d36747eab7d3f5fc3d671e1b1b4884b2a44b98365::/onion3/n35n5fikcqqhhhjcdzpqul5v74mu7k6nikpafmlnwgiapphiw45tmryd:18141 +ncal::ea420ae2948739bc35907b8ab5a2d41526ccef22ec92f8f8e2bb398500bf435a::/onion3/uybnlnzve4j4w2lj5bdoe2uurwsbjm73ck2cotlnknhu2l7msn26oeyd:18141 +nvir::f688c69f2397dc0d4ad18168cd6ad13f93241a665acf19ab7f358fd661ac3d1c::/onion3/qejny5yprzidxt4rhstjmhsyfmeq4yb4r6tnn3pqowjr7e7roxcpxsqd:18141 +oregon::8648575c606269b032f43cd0d54728628ddb911e636bd65ea36e867a5ffd3643::/onion3/5d2owx6uoqcsoapprattb4fmektm3rcpfyzmmwmf64dsu55mhcqef2yd:18141 +seoul::78b2c0bda70fd12a9987757ffc2851e197080af804353e8e025d28c785b6b447::/onion3/ysj76foyp7qkl7d5x63hyocmp5ydwcgkb25oalo23kj2vvx7zjvofqad:18141 +area7::ced769f66b4398ea62eb9f74a08b5ebfdc1a51554a695c0aff4b949fea875b61::/onion3/m4koteatwthmozsbg54y6c4io26d4md6ub5l3rnco4s7a4qu2xkvonyd:18141 +area8::40717ea5146cf6183c07469d188792b12a57b9da2e5af5bc50df270ff789257f::/onion3/qhmrwr2h3fnszwc4udhlgfpealm7mvw64enqghullrarc633fzmd6zqd:18141 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a3a8bcca0..f44ea40ef 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,13 +11,12 @@ https://www.tari.com/user_agreement/ https://www.tari.com/privacy_policy/ https://www.tari.com/disclaimer/ - https://explore.tari.com - https://explore.tari.com/kernel/ + https://explore-esme.tari.com/ + https://explore-esme.tari.com/kernel/ https://bridges.torproject.org/bridges bug_reports@tari.com https://tlu.tarilabs.com/ - https://faucet.tari.com - https://dibbler-faucet.tari.com + https://esmeralda-faucet.tari.com 0 @@ -118,9 +117,9 @@ Your phone is either offline or has a poor connection at the moment. We\'ll wait here until you find some stronger signal. - Tari Aurora wallet service is running. - This service carries out wallet operations across applications. - Could not allocate free tXTR. + Tari Aurora wallet service is running + This service carries out wallet operations across applications + Could not allocate free tXTR No internet connection! @@ -519,7 +518,7 @@ Recovery Failed Unable to connect with base node. Please try again later - Unable to recover your wallet due to the internal error + Unable to recover your wallet due to the error Start typing to see suggestions here are no suggestions for the phrase diff --git a/app/src/privacy/AndroidManifest.xml b/app/src/privacy/AndroidManifest.xml deleted file mode 100644 index 8072ee00d..000000000 --- a/app/src/privacy/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/app/src/privacy/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt b/app/src/privacy/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt index 6ee3d6660..0799a38f9 100644 --- a/app/src/privacy/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt +++ b/app/src/privacy/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt @@ -43,7 +43,7 @@ import dagger.Provides import javax.inject.Singleton @Module -internal class BackupAndRestoreModule { +class BackupAndRestoreModule { @Provides @Singleton diff --git a/app/src/privacy/java/com/tari/android/wallet/di/ServiceModule.kt b/app/src/privacy/java/com/tari/android/wallet/di/ServiceModule.kt index 314776b09..783b914d1 100644 --- a/app/src/privacy/java/com/tari/android/wallet/di/ServiceModule.kt +++ b/app/src/privacy/java/com/tari/android/wallet/di/ServiceModule.kt @@ -41,7 +41,7 @@ import dagger.Provides import javax.inject.Singleton @Module -internal class ServiceModule { +class ServiceModule { @Provides @Singleton diff --git a/app/src/privacy/java/com/tari/android/wallet/di/TrackerModule.kt b/app/src/privacy/java/com/tari/android/wallet/di/TrackerModule.kt deleted file mode 100644 index ba372d1e8..000000000 --- a/app/src/privacy/java/com/tari/android/wallet/di/TrackerModule.kt +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.di - -import android.content.Context -import com.tari.android.wallet.infrastructure.ConsoleLogTracker -import com.tari.android.wallet.infrastructure.Tracker -import dagger.Module -import dagger.Provides -import javax.inject.Singleton - -/** - * Console logging tracker - * - * @author The Tari Development Team - */ -@Module -internal class TrackerModule { - @Provides - @Singleton - // Do not delete this parameter - it is used in another flavors - fun provideTracker(@Suppress("UNUSED_PARAMETER") context: Context): Tracker = - ConsoleLogTracker() -} diff --git a/app/src/privacy/java/com/tari/android/wallet/service/faucet/NoOpTestnetFaucetService.kt b/app/src/privacy/java/com/tari/android/wallet/service/faucet/NoOpTestnetFaucetService.kt index f4c44d278..6918cccf0 100644 --- a/app/src/privacy/java/com/tari/android/wallet/service/faucet/NoOpTestnetFaucetService.kt +++ b/app/src/privacy/java/com/tari/android/wallet/service/faucet/NoOpTestnetFaucetService.kt @@ -32,8 +32,6 @@ */ package com.tari.android.wallet.service.faucet -import com.orhanobut.logger.Logger - class NoOpTestnetFaucetService : TestnetFaucetService { override fun requestMaxTestnetTari( publicKey: String, @@ -41,12 +39,5 @@ class NoOpTestnetFaucetService : TestnetFaucetService { publicNonce: String, onSuccess: (TestnetTariMaxAllocationResult) -> Unit, onError: (Throwable) -> Unit - ) { - Logger.i( - "requestMaxTestnetTari called with " + - "\npublicKey = $publicKey" + - "\nsignature = $signature" + - "\npublicNonce = $publicNonce" - ) - } + ) = Unit } diff --git a/app/src/privacy/java/com/tari/android/wallet/service/notification/NoOpNotificationService.kt b/app/src/privacy/java/com/tari/android/wallet/service/notification/NoOpNotificationService.kt index 34fbc9680..44517dc83 100644 --- a/app/src/privacy/java/com/tari/android/wallet/service/notification/NoOpNotificationService.kt +++ b/app/src/privacy/java/com/tari/android/wallet/service/notification/NoOpNotificationService.kt @@ -32,8 +32,6 @@ */ package com.tari.android.wallet.service.notification -import com.orhanobut.logger.Logger - class NoOpNotificationService : NotificationService { override fun notifyRecipient( recipientPublicKeyHex: String, @@ -41,11 +39,5 @@ class NoOpNotificationService : NotificationService { signer: (String) -> String, onSuccess: () -> Unit, onFailure: (Throwable) -> Unit - ) { - Logger.i( - "notifyRecipient called with" + - "\nrecipientPublicKeyHex = $recipientPublicKeyHex" + - "\nsenderPublicKeyHex = $senderPublicKeyHex" - ) - } + ) = Unit } diff --git a/app/src/regular/AndroidManifest.xml b/app/src/regular/AndroidManifest.xml deleted file mode 100644 index e553ffc8b..000000000 --- a/app/src/regular/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/regular/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt b/app/src/regular/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt index 5e1ccffb1..133b63229 100644 --- a/app/src/regular/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt +++ b/app/src/regular/java/com/tari/android/wallet/di/BackupAndRestoreModule.kt @@ -43,7 +43,7 @@ import dagger.Provides import javax.inject.Singleton @Module -internal class BackupAndRestoreModule { +class BackupAndRestoreModule { @Provides @Singleton diff --git a/app/src/regular/java/com/tari/android/wallet/di/RESTModule.kt b/app/src/regular/java/com/tari/android/wallet/di/RESTModule.kt index b573557ef..31ab743fe 100644 --- a/app/src/regular/java/com/tari/android/wallet/di/RESTModule.kt +++ b/app/src/regular/java/com/tari/android/wallet/di/RESTModule.kt @@ -56,7 +56,7 @@ import javax.inject.Singleton * @author The Tari Development Team */ @Module -internal class RESTModule { +class RESTModule { object FieldName { const val faucetHttpClient = "faucet_http_client" diff --git a/app/src/regular/java/com/tari/android/wallet/di/ServiceModule.kt b/app/src/regular/java/com/tari/android/wallet/di/ServiceModule.kt index 22a42bbff..0850c2b31 100644 --- a/app/src/regular/java/com/tari/android/wallet/di/ServiceModule.kt +++ b/app/src/regular/java/com/tari/android/wallet/di/ServiceModule.kt @@ -35,4 +35,4 @@ package com.tari.android.wallet.di import dagger.Module @Module(includes = [RESTModule::class]) -internal class ServiceModule +class ServiceModule diff --git a/app/src/regular/java/com/tari/android/wallet/di/TrackerModule.kt b/app/src/regular/java/com/tari/android/wallet/di/TrackerModule.kt deleted file mode 100644 index 03beed675..000000000 --- a/app/src/regular/java/com/tari/android/wallet/di/TrackerModule.kt +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.di - -import android.content.Context -import com.tari.android.wallet.BuildConfig -import com.tari.android.wallet.infrastructure.ConsoleLogTracker -import com.tari.android.wallet.infrastructure.MatomoTracker -import com.tari.android.wallet.infrastructure.Tracker -import dagger.Module -import dagger.Provides -import org.matomo.sdk.Matomo -import org.matomo.sdk.TrackerBuilder -import javax.inject.Singleton - -/** - * Satisfies tracker dependencies. - * - * @author The Tari Development Team - */ -@Module -internal class TrackerModule { - - companion object { - - private const val matomoUrl = "https://matomo.tari.com/matomo.php" - private const val matomoSiteId = 2 - - } - - @Provides - @Singleton - fun provideTracker(context: Context): Tracker = - if (BuildConfig.DEBUG) ConsoleLogTracker() - else MatomoTracker( - TrackerBuilder.createDefault(matomoUrl, matomoSiteId) - .build(Matomo.getInstance(context)) - .apply { dispatchInterval = 0 } - ) -} diff --git a/app/src/regular/java/com/tari/android/wallet/infrastructure/MatomoTracker.kt b/app/src/regular/java/com/tari/android/wallet/infrastructure/MatomoTracker.kt deleted file mode 100644 index abaceac2e..000000000 --- a/app/src/regular/java/com/tari/android/wallet/infrastructure/MatomoTracker.kt +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright 2020 The Tari Project - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.tari.android.wallet.infrastructure - -import android.content.Context -import org.matomo.sdk.extra.DownloadTracker -import org.matomo.sdk.extra.TrackHelper -import org.matomo.sdk.Tracker as MatomoSdkTracker - -/** - * Mamoto-based tracker implementation. - * - * @author The Tari Development Team - */ -class MatomoTracker(private val tracker: MatomoSdkTracker) : Tracker { - override fun screen(path: String, title: String) = TrackHelper.track() - .screen(path) - .title(title) - .with(this.tracker) - - override fun download(context: Context) = TrackHelper.track() - .download() - .identifier(DownloadTracker.Extra.ApkChecksum(context)) - .with(this.tracker) - - override fun event(category: String, action: String) = TrackHelper.track() - .event(category, action) - .with(this.tracker) -} diff --git a/app/src/regular/java/com/tari/android/wallet/infrastructure/backup/GoogleDriveBackupStorage.kt b/app/src/regular/java/com/tari/android/wallet/infrastructure/backup/GoogleDriveBackupStorage.kt index 4056d4308..cb8780762 100644 --- a/app/src/regular/java/com/tari/android/wallet/infrastructure/backup/GoogleDriveBackupStorage.kt +++ b/app/src/regular/java/com/tari/android/wallet/infrastructure/backup/GoogleDriveBackupStorage.kt @@ -62,7 +62,7 @@ import java.io.FileOutputStream import java.io.IOException import kotlin.coroutines.suspendCoroutine -internal class GoogleDriveBackupStorage( +class GoogleDriveBackupStorage( private val context: Context, private val namingPolicy: BackupNamingPolicy, private val backupSettingsRepository: BackupSettingsRepository, @@ -70,6 +70,9 @@ internal class GoogleDriveBackupStorage( private val backupFileProcessor: BackupFileProcessor ) : BackupStorage { + private val logger + get() = Logger.t(GoogleDriveBackupStorage::class.simpleName) + private val googleClient: GoogleSignInClient = GoogleSignIn.getClient( context, GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) @@ -163,10 +166,7 @@ internal class GoogleDriveBackupStorage( // delete older backups deleteAllBackupFiles(excludeBackupWithDate = backupDate) } catch (e: Exception) { - Logger.e( - e, - "Ignorable backup error while clearing temporary and old files." - ) + logger.e(e, "Cleaning old files") } return@withContext backupDate } @@ -278,10 +278,14 @@ internal class GoogleDriveBackupStorage( override suspend fun signOut() { suspendCoroutine { continuation -> - backupFileProcessor.clearTempFolder() - googleClient.signOut() - .addOnFailureListener { continuation.resumeWith(Result.failure(it)) } - .addOnCompleteListener { continuation.resumeWith(Result.success(Unit)) } + try { + backupFileProcessor.clearTempFolder() + googleClient.signOut() + .addOnFailureListener { continuation.resumeWith(Result.failure(it)) } + .addOnCompleteListener { continuation.resumeWith(Result.success(Unit)) } + } catch (e: Throwable) { + logger.e(e, "Sentry failed with already resumed for no reason") + } } } diff --git a/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTGateway.kt b/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTGateway.kt index e625d5ff9..9c85906bf 100644 --- a/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTGateway.kt +++ b/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTGateway.kt @@ -42,7 +42,7 @@ import retrofit2.http.Path * * @author The Tari Development Team */ -internal interface TestnetFaucetRESTGateway { +interface TestnetFaucetRESTGateway { @POST("/free_tari/allocate/{publicKeyHex}") fun requestTestnetTari( diff --git a/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTService.kt b/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTService.kt index 60c705474..0de32b10e 100644 --- a/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTService.kt +++ b/app/src/regular/java/com/tari/android/wallet/service/faucet/TestnetFaucetRESTService.kt @@ -37,7 +37,7 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response -internal class TestnetFaucetRESTService( +class TestnetFaucetRESTService( private val gateway: TestnetFaucetRESTGateway, private val networkRepository: NetworkRepository ) : TestnetFaucetService { diff --git a/app/src/regular/java/com/tari/android/wallet/service/notification/PushNotificationRESTService.kt b/app/src/regular/java/com/tari/android/wallet/service/notification/PushNotificationRESTService.kt index 87428bac5..de0ab30e0 100644 --- a/app/src/regular/java/com/tari/android/wallet/service/notification/PushNotificationRESTService.kt +++ b/app/src/regular/java/com/tari/android/wallet/service/notification/PushNotificationRESTService.kt @@ -36,11 +36,7 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response -class PushNotificationRESTService( - private val gateway: PushNotificationRESTGateway, - private val apiKey: String -) : - NotificationService { +class PushNotificationRESTService(private val gateway: PushNotificationRESTGateway, private val apiKey: String) : NotificationService { override fun notifyRecipient( recipientPublicKeyHex: String, senderPublicKeyHex: String, @@ -51,22 +47,12 @@ class PushNotificationRESTService( val signing = signer(apiKey + senderPublicKeyHex + recipientPublicKeyHex) val signature = signing.split("|")[0] val nonce = signing.split("|")[1] - val requestBody = - PushNotificationRequestBody( - senderPublicKeyHex, - signature, - nonce - ) + val requestBody = PushNotificationRequestBody(senderPublicKeyHex, signature, nonce) val response = gateway.sendPushNotificationToRecipient(recipientPublicKeyHex, requestBody) response.enqueue(object : Callback { - override fun onFailure(call: Call, t: Throwable) { - onFailure(t) - } + override fun onFailure(call: Call, t: Throwable) = onFailure(t) - override fun onResponse( - call: Call, - response: Response - ) { + override fun onResponse(call: Call, response: Response) { val body = response.body() if (response.isSuccessful && body != null && body.success) { onSuccess() @@ -76,5 +62,4 @@ class PushNotificationRESTService( } }) } - } diff --git a/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/NetworkRepositoryMock.kt b/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/NetworkRepositoryMock.kt index 3a3cb7ea2..6d750d8e5 100644 --- a/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/NetworkRepositoryMock.kt +++ b/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/NetworkRepositoryMock.kt @@ -5,7 +5,7 @@ import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository import com.tari.android.wallet.data.sharedPrefs.network.TariNetwork class NetworkRepositoryMock : NetworkRepository { - private val network: Network = Network.DIBBLER + private val network: Network = Network.ESMERALDA override var supportedNetworks: List = listOf(network) override var currentNetwork: TariNetwork? = TariNetwork(network, "xtr", "") diff --git a/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/TariBackupNameValidationPolicyTest.kt b/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/TariBackupNameValidationPolicyTest.kt index 9506b72a3..3bcad61b9 100644 --- a/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/TariBackupNameValidationPolicyTest.kt +++ b/app/src/test/java/com/tari/android/wallet/infrastructure/backup/storage/TariBackupNameValidationPolicyTest.kt @@ -48,7 +48,7 @@ import org.junit.runners.model.Statement class TariBackupNameValidationPolicyTest { - private val network: Network = Network.DIBBLER + private val network: Network = Network.ESMERALDA @get:Rule val rule = JodaAndroidFixRule() diff --git a/app/src/test/java/com/tari/android/wallet/ui/presentation/TxNoteTest.kt b/app/src/test/java/com/tari/android/wallet/ui/presentation/TxNoteTest.kt index 3d8cf7344..69e07b5b0 100644 --- a/app/src/test/java/com/tari/android/wallet/ui/presentation/TxNoteTest.kt +++ b/app/src/test/java/com/tari/android/wallet/ui/presentation/TxNoteTest.kt @@ -32,6 +32,7 @@ */ package com.tari.android.wallet.ui.presentation +import com.tari.android.wallet.model.TxNote import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Test diff --git a/build.gradle b/build.gradle index 5bebc3c35..70b262b8a 100644 --- a/build.gradle +++ b/build.gradle @@ -4,11 +4,11 @@ buildscript { ext.kotlin_version = "1.6.21" // build & version - ext.buildNumber = 204 - ext.versionNumber = "0.15.2" + ext.buildNumber = 216 + ext.versionNumber = "0.16.0" // JNI libs - ext.libwalletVersion = "0.32.11" + ext.libwalletVersion = "0.38.5" ext.libwalletHostURL = "https://tari-binaries.s3.amazonaws.com/libwallet/" ext.supportedABIs = ["arm64-v8a", "x86_64"] @@ -19,7 +19,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:7.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "io.sentry:sentry-android-gradle-plugin:2.1.5" }