diff --git a/app/build.gradle b/app/build.gradle index f368ea6864..122d8c212d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,7 +12,6 @@ static def generateVersionName() { android { compileSdkVersion 28 defaultConfig { - applicationId "com.tangem.wallet" minSdkVersion 21 targetSdkVersion 28 versionCode 107 @@ -33,6 +32,22 @@ android { debuggable true minifyEnabled false applicationIdSuffix ".debug" + versionNameSuffix '-DEBUG' + signingConfig signingConfigs.debug + } + } + flavorDimensions "" + productFlavors { + tangemAccess { + versionName "0.903.2." + generateVersionName() + versionCode 106 + applicationId "com.tangem.wallet" + signingConfig signingConfigs.debug + } + tangemCardano { + versionName "0.1.0" + versionCode 1 + applicationId "com.tangem.cardano" signingConfig signingConfigs.debug } } @@ -43,10 +58,20 @@ android { buildToolsVersion '28.0.3' } +configurations { + all*.exclude group: 'com.google.guava', module: 'listenablefuture' +} + dependencies { implementation project(':card-common') implementation project(':card-android') implementation project(':server-android') + +// implementation 'com.github.TangemCash:card-common:0.1.2' +// implementation 'com.github.TangemCash:card-android:0.1.3' +// implementation 'com.github.TangemCash:server-android:0.1.4' + + implementation 'androidx.appcompat:appcompat:1.1.0-alpha03' // implementation 'com.github.TangemCash:card-common:0.1.2' // implementation 'com.github.TangemCash:card-android:0.1.3' // implementation 'com.github.TangemCash:server-android:0.1.4' @@ -55,7 +80,7 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.biometric:biometric:1.0.0-alpha03' implementation 'co.nstant.in:cbor:0.8' - implementation 'com.google.android.material:material:1.1.0-alpha02' + implementation 'com.google.android.material:material:1.1.0-alpha05' implementation 'com.google.dagger:dagger:2.21' kapt 'com.google.dagger:dagger-compiler:2.21' annotationProcessor 'com.google.dagger:dagger-compiler:2.21' @@ -70,7 +95,10 @@ dependencies { implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0' implementation 'com.skyfishjy.ripplebackground:library:1.0.1' implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' + implementation "com.orhanobut:hawk:2.0.1" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0" implementation 'org.bitcoinj:bitcoinj-parent:0.14.7' implementation 'org.bitcoinj:bitcoinj-core:0.14.7' implementation 'org.greenrobot:eventbus:3.1.1' diff --git a/app/src/debug/java/com/tangem/Test.java b/app/src/debug/java/com/tangem/Test.java new file mode 100644 index 0000000000..df5872e621 --- /dev/null +++ b/app/src/debug/java/com/tangem/Test.java @@ -0,0 +1,4 @@ +package com.tangem; + +public class Test { +} diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml index 700e32affc..ec5cc446df 100644 --- a/app/src/debug/res/values/strings.xml +++ b/app/src/debug/res/values/strings.xml @@ -1,7 +1,6 @@ - DEV - com.tangem.data.LogFileProvider.debug + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0758bd9d3e..ea530e48e4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,12 +29,12 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning"> - + + + + + + diff --git a/app/src/main/assets/issuers.json b/app/src/main/assets/issuers.json index e409506c32..f2e7cb0f8a 100644 --- a/app/src/main/assets/issuers.json +++ b/app/src/main/assets/issuers.json @@ -61,6 +61,17 @@ "transactionKey": { "publicKey": "04ECA685AFD135EF2AB24D07BED71ED82CC1882C282976616DAC655ED3E5B8E75487C131F5D79A87895ECDE89AC58CD1BB220A0C29DD544D8D9AD5156184456F3F" } + }, + { + "id": "CARDANO", + "dataKey": { + "publicKey": "0445C312089E57A6952F96D74FF75C962E1E2C2DDA5FB4195661B92E2744791350FE6C60E1A1D145C6A34D8BEAD57506A90FE4A149A9AA43CFF3C6CAE0748B771E", + "privateKeyEncrypted": "2791FA18DFD4D2AD11509266C4721CE9BB4E9C7C8A06BF5071C6294EAB1F47A153CFDEBAF804425E5ED49AFEB70DD741" + }, + "transactionKey": { + "publicKey": "04969A008E8A61F92EF8D380DB7BB7B8F6F667CA169934371F544F6697D1D2AF97FB87B8D75F550CD782472D46BFCADF354AF17D807C1D2EB82E184C367CACF1FC", + "privateKeyEncrypted": "4707EEB8704D53EB1B6D905604C394D1514C205E3EC16423961BB82A7A47896783F8035BE56D6DAE5DE200E67F2D92E3" + } } diff --git a/app/src/main/java/com/tangem/App.kt b/app/src/main/java/com/tangem/App.kt index f4c1acd03a..64d16a74e3 100644 --- a/app/src/main/java/com/tangem/App.kt +++ b/app/src/main/java/com/tangem/App.kt @@ -8,8 +8,10 @@ import com.tangem.data.local.PendingTransactionsStorage import com.tangem.card_android.android.data.Firmwares import com.tangem.card_android.android.data.PINStorage import com.tangem.card_common.data.Issuer +import com.tangem.data.dp.PrefsManager import com.tangem.di.* import com.tangem.server_android.data.LocalStorage +import com.tangem.wallet.BuildConfig import java.io.InputStreamReader import java.nio.charset.StandardCharsets @@ -42,6 +44,8 @@ class App : Application() { navigatorComponent = buildNavigatorComponent() toastHelperComponent = buildToastHelperComponent() + PrefsManager.getInstance().init(this) + // common init if (PINStorage.needInit()) PINStorage.init(applicationContext) @@ -52,6 +56,24 @@ class App : Application() { localStorage = LocalStorage(applicationContext) pinStorage = PINStorage() pendingTransactionsStorage = PendingTransactionsStorage(applicationContext) + + if (BuildConfig.DEBUG) { + com.tangem.card_common.util.Log.setLogger( + object : com.tangem.card_common.util.LoggerInterface { + override fun i(logTag: String, message: String) { + android.util.Log.i(logTag, message) + } + + override fun e(logTag: String, message: String) { + android.util.Log.e(logTag, message) + } + + override fun v(logTag: String, message: String) { + android.util.Log.v(logTag, message) + } + } + ) + } } private fun buildNavigatorComponent(): NavigatorComponent { diff --git a/app/src/main/java/com/tangem/Constant.kt b/app/src/main/java/com/tangem/Constant.kt index 6283ce6435..c04a892b40 100644 --- a/app/src/main/java/com/tangem/Constant.kt +++ b/app/src/main/java/com/tangem/Constant.kt @@ -4,6 +4,12 @@ import android.app.Activity object Constant { + const val FLAVOR_TANGEM_ACCESS = "tangemAccess" + const val FLAVOR_TANGEM_CARDANO = "tangemCardano" + + + const val PREF_LAST_WALLET_ADDRESS = "last_wallet_address" + const val URL_TANGEM = "https://play.google.com/store/apps/details?id=com.tangem.wallet" const val EXTRA_BLOCKCHAIN_DATA = "BLOCKCHAIN_DATA" diff --git a/app/src/main/java/com/tangem/data/LogFileProvider.java b/app/src/main/java/com/tangem/data/LogFileProvider.java index 48c9b1ff56..268d3f4884 100644 --- a/app/src/main/java/com/tangem/data/LogFileProvider.java +++ b/app/src/main/java/com/tangem/data/LogFileProvider.java @@ -37,7 +37,8 @@ public class LogFileProvider extends ContentProvider { // 'content://it.my.app.LogFileProvider/*' // and return 1 in the case that the incoming Uri matches this pattern - uriMatcher.addURI(Objects.requireNonNull(getContext()).getString(R.string.log_file_provider_authorities), "*", 1); +// uriMatcher.addURI(Objects.requireNonNull(getContext()).getString(R.string.log_file_provider_authorities), "*", 1); +// uriMatcher.addURI(Objects.requireNonNull("com.tangem.data.LogFileProvider"), "*", 1); return true; } @@ -60,7 +61,7 @@ public class LogFileProvider extends ContentProvider { // The desired file name is specified by the last segment of the // path // E.g. - // 'content://it.my.app.LogFileProvider/Test.txt' + // 'content://it.my.app.LogFileProvider/Test1.txt' // Take this and build the path to the file String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment(); diff --git a/app/src/main/java/com/tangem/data/dp/PrefsManager.kt b/app/src/main/java/com/tangem/data/dp/PrefsManager.kt new file mode 100644 index 0000000000..29bc85c94d --- /dev/null +++ b/app/src/main/java/com/tangem/data/dp/PrefsManager.kt @@ -0,0 +1,44 @@ +package com.tangem.data.dp + +import android.annotation.SuppressLint +import android.content.Context +import android.content.SharedPreferences + +import com.orhanobut.hawk.Hawk +import com.tangem.Constant + +class PrefsManager { + companion object { + const val PREF_NAME = "tangem_access" + @SuppressLint("StaticFieldLeak") + private var instance: PrefsManager? = null + + fun getInstance(): PrefsManager { + if (instance == null) { + instance = PrefsManager() + } + return instance as PrefsManager + } + } + + private lateinit var context: Context + private lateinit var preferences: SharedPreferences + + fun init(context: Context) { + this.context = context + preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + Hawk.init(context).build() + } + + val lastWalletAddress: String + get() = Hawk.get(Constant.PREF_LAST_WALLET_ADDRESS, "") + + fun saveLastWalletAddress(value: String) { + Hawk.put(Constant.PREF_LAST_WALLET_ADDRESS, value) + } + + fun clearLastWalletAddress() { + Hawk.delete(Constant.PREF_LAST_WALLET_ADDRESS) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/Navigator.kt b/app/src/main/java/com/tangem/di/Navigator.kt index 07ba69f100..233e89fa3e 100644 --- a/app/src/main/java/com/tangem/di/Navigator.kt +++ b/app/src/main/java/com/tangem/di/Navigator.kt @@ -4,7 +4,9 @@ import android.app.Activity import android.nfc.Tag import com.tangem.Constant import com.tangem.domain.wallet.TangemContext +import com.tangem.ui.PrepareTransactionActivity import com.tangem.ui.activity.* +import com.tangem.wallet.BuildConfig class Navigator { @@ -69,7 +71,14 @@ class Navigator { } fun showPrepareTransaction(context: Activity, ctx: TangemContext) { - context.startActivityForResult(PrepareTransactionActivity.callingIntent(context, ctx), Constant.REQUEST_CODE_SEND_TRANSACTION) + when (BuildConfig.FLAVOR) { + Constant.FLAVOR_TANGEM_CARDANO -> { + context.startActivity(PrepareTransactionActivity.callingIntent(context, ctx)) + } + else -> { + context.startActivityForResult(PrepareTransactionActivity.callingIntent(context, ctx), Constant.REQUEST_CODE_SEND_TRANSACTION) + } + } } fun showCreateNewWallet(context: Activity, ctx: TangemContext) { diff --git a/app/src/main/java/com/tangem/di/NavigatorComponent.kt b/app/src/main/java/com/tangem/di/NavigatorComponent.kt index f3cef57221..25990b46a1 100644 --- a/app/src/main/java/com/tangem/di/NavigatorComponent.kt +++ b/app/src/main/java/com/tangem/di/NavigatorComponent.kt @@ -6,7 +6,7 @@ import com.tangem.ui.activity.LogoActivity import com.tangem.ui.activity.MainActivity import com.tangem.ui.activity.PrepareCryptonitOtherApiWithdrawalActivity import com.tangem.ui.activity.PrepareKrakenWithdrawalActivity -import com.tangem.ui.activity.PrepareTransactionActivity +import com.tangem.ui.PrepareTransactionActivity import com.tangem.ui.activity.PurgeActivity import com.tangem.ui.activity.VerifyCardActivity diff --git a/app/src/main/java/com/tangem/di/ToastHelper.kt b/app/src/main/java/com/tangem/di/ToastHelper.kt index 18a8fbfe64..43490460ba 100644 --- a/app/src/main/java/com/tangem/di/ToastHelper.kt +++ b/app/src/main/java/com/tangem/di/ToastHelper.kt @@ -9,6 +9,7 @@ import com.google.android.material.snackbar.Snackbar import com.tangem.Constant import com.tangem.wallet.R + class ToastHelper { fun showSnackbarUpdateVersion(context: Context, vg: ViewGroup, versionName: String) { @@ -24,6 +25,24 @@ class ToastHelper { }.show() } + fun showSnackbarSuccess(context: Context, vg: ViewGroup, message: String) { + val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_INDEFINITE) + val snackView = snackbar.view + snackView.setBackgroundColor(context.resources.getColor(R.color.msg_okay)) + snackbar.setAction(R.string.ok) { + snackbar.dismiss() + } + snackbar.show() + } + fun showSnackbarError(context: Context, vg: ViewGroup, message: String) { + val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_INDEFINITE) + val snackView = snackbar.view + snackView.setBackgroundColor(context.resources.getColor(R.color.msg_err)) + snackbar.setAction(R.string.ok) { + snackbar.dismiss() + } + snackbar.show() + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/ToastHelperComponent.kt b/app/src/main/java/com/tangem/di/ToastHelperComponent.kt index b98d944333..39907760eb 100644 --- a/app/src/main/java/com/tangem/di/ToastHelperComponent.kt +++ b/app/src/main/java/com/tangem/di/ToastHelperComponent.kt @@ -1,5 +1,6 @@ package com.tangem.di +import com.tangem.ui.PrepareTransactionActivity import com.tangem.ui.activity.MainActivity import dagger.Component import javax.inject.Singleton @@ -10,4 +11,6 @@ interface ToastHelperComponent { fun inject(activity: MainActivity) + fun inject(activity: PrepareTransactionActivity) + } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt b/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt index 15c56cef45..2619f76b4a 100644 --- a/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt +++ b/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt @@ -7,7 +7,9 @@ import com.tangem.domain.wallet.eth.EthEngine import com.tangem.domain.wallet.token.TokenEngine import com.tangem.domain.wallet.bch.BtcCashEngine import com.tangem.data.Blockchain +import com.tangem.domain.wallet.cardano.CardanoData import com.tangem.domain.wallet.cardano.CardanoEngine +import com.tangem.domain.wallet.eth.EthData import com.tangem.domain.wallet.ltc.LtcEngine import com.tangem.domain.wallet.nftToken.NftTokenEngine import com.tangem.domain.wallet.rsk.RskEngine @@ -43,7 +45,6 @@ object CoinEngineFactory { } fun create(context: TangemContext): CoinEngine? { - var result: CoinEngine? try { result = if (Blockchain.BitcoinCash == context.blockchain) @@ -76,4 +77,24 @@ object CoinEngineFactory { return result } + fun createCardano(context: TangemContext): CoinEngine? { + var result: CoinEngine? + try { + result = CardanoEngine(context)//EthEngine(context)// + + } catch (e: Exception) { + e.printStackTrace() + result = null + Log.e(TAG, "Can't create Cardano CoinEngine!") + } + return result + } + + fun createCardanoData(): CoinData? { + return CardanoData()//EthData()// CardanoData() + } + + fun isCardano(blockchainID: String): Boolean { + return blockchainID==Blockchain.Cardano.id//Ethereum.id + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java b/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java index 3e248c2bef..af4e04ece6 100644 --- a/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java @@ -12,7 +12,6 @@ import com.tangem.card_common.util.Util; import com.tangem.data.Blockchain; import com.tangem.data.local.PendingTransactionsStorage; import com.tangem.data.network.ElectrumRequest; -import com.tangem.data.network.ServerApiCommon; import com.tangem.data.network.ServerApiElectrum; import com.tangem.domain.wallet.BTCUtils; import com.tangem.domain.wallet.BalanceValidator; diff --git a/app/src/main/java/com/tangem/domain/wallet/cardano/CardanoEngine.java b/app/src/main/java/com/tangem/domain/wallet/cardano/CardanoEngine.java index 9a12b2ab4e..9b5b085666 100644 --- a/app/src/main/java/com/tangem/domain/wallet/cardano/CardanoEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/cardano/CardanoEngine.java @@ -6,6 +6,7 @@ import android.util.Base64; import android.util.Log; import com.tangem.App; +import com.tangem.Constant; import com.tangem.data.local.PendingTransactionsStorage; import com.tangem.data.network.ServerApiAdalite; import com.tangem.data.network.model.AdaliteResponse; @@ -23,6 +24,7 @@ import com.tangem.card_common.reader.CardProtocol; import com.tangem.card_common.tasks.SignTask; import com.tangem.card_common.util.Util; import com.tangem.util.DecimalDigitsInputFilter; +import com.tangem.wallet.BuildConfig; import com.tangem.wallet.R; import org.spongycastle.crypto.Digest; @@ -198,6 +200,9 @@ public class CardanoEngine extends CoinEngine { @Override public boolean checkNewTransactionAmount(Amount amount) { + if( BuildConfig.FLAVOR==Constant.FLAVOR_TANGEM_CARDANO ) { + return true; + } if (coinData == null) return false; if (amount.compareTo(convertToAmount(coinData.getBalanceInInternalUnits())) > 0) { return false; @@ -424,9 +429,10 @@ public class CardanoEngine extends CoinEngine { final long amountFinal = amount; final long changeFinal = change; - if (amount + fees > fullAmount) { - throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < change (%d) + amount (%d)", fullAmount, change, amount)); - } + //TODO - uncomment +// if (amount + fees > fullAmount) { +// throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < change (%d) + amount (%d)", fullAmount, change, amount)); +// } CborBuilder cborBuilder = new CborBuilder(); ArrayBuilder txArray = cborBuilder.addArray(); diff --git a/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java b/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java index 8a7123527b..79f97153da 100644 --- a/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java @@ -4,6 +4,7 @@ import android.net.Uri; import android.text.InputFilter; import android.util.Log; +import com.tangem.Constant; import com.tangem.data.Blockchain; import com.tangem.data.network.ServerApiInfura; import com.tangem.data.network.model.InfuraResponse; @@ -19,6 +20,7 @@ import com.tangem.card_common.data.TangemCard; import com.tangem.card_common.tasks.SignTask; import com.tangem.util.CryptoUtil; import com.tangem.util.DecimalDigitsInputFilter; +import com.tangem.wallet.BuildConfig; import com.tangem.wallet.R; import org.bitcoinj.core.ECKey; @@ -264,7 +266,9 @@ public class EthEngine extends CoinEngine { @Override public boolean checkNewTransactionAmount(Amount amount) { - if (coinData == null) return false; + if( BuildConfig.FLAVOR== Constant.FLAVOR_TANGEM_CARDANO ) { + return true; + } Amount balance = getBalance(); if (balance == null || amount.compareTo(balance) > 0) { return false; diff --git a/app/src/main/java/com/tangem/ui/activity/EmptyWalletActivity.kt b/app/src/main/java/com/tangem/ui/activity/EmptyWalletActivity.kt index ce1adb51fd..2b77a85ec3 100644 --- a/app/src/main/java/com/tangem/ui/activity/EmptyWalletActivity.kt +++ b/app/src/main/java/com/tangem/ui/activity/EmptyWalletActivity.kt @@ -29,7 +29,6 @@ import com.tangem.card_common.data.TangemCard import com.tangem.card_common.reader.CardProtocol import com.tangem.card_common.tasks.VerifyCardTask import com.tangem.card_common.util.Util -import com.tangem.util.LOG import com.tangem.util.UtilHelper import com.tangem.wallet.R import kotlinx.android.synthetic.main.activity_empty_wallet.* diff --git a/app/src/main/java/com/tangem/ui/activity/LogoActivity.kt b/app/src/main/java/com/tangem/ui/activity/LogoActivity.kt index 93e2452276..88bff775fc 100644 --- a/app/src/main/java/com/tangem/ui/activity/LogoActivity.kt +++ b/app/src/main/java/com/tangem/ui/activity/LogoActivity.kt @@ -1,13 +1,14 @@ package com.tangem.ui.activity -import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.appcompat.app.AppCompatActivity import com.tangem.App import com.tangem.Constant import com.tangem.di.Navigator +import com.tangem.domain.wallet.TangemContext import com.tangem.wallet.BuildConfig import com.tangem.wallet.R import kotlinx.android.synthetic.main.activity_logo.* @@ -36,21 +37,40 @@ class LogoActivity : AppCompatActivity() { ivLogo.setOnClickListener { hide() } } - @SuppressLint("SetTextI18n") override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) + // set beta version name if (BuildConfig.DEBUG) - tvAppVersion.text = "BETA v." + BuildConfig.VERSION_NAME + "\n" + "dev" + "\n" + "build " + BuildConfig.VERSION_CODE + tvAppVersion.text = String.format(getString(R.string.version_name_debug), BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) else - tvAppVersion.text = "BETA v." + BuildConfig.VERSION_NAME + tvAppVersion.text = String.format(getString(R.string.version_name_release), BuildConfig.VERSION_NAME) + + // set flavor app name + when (BuildConfig.FLAVOR) { + Constant.FLAVOR_TANGEM_CARDANO -> { + tvExtension.visibility = View.VISIBLE + tvExtension.text = getString(R.string.cardano) + } + else -> { + tvExtension.visibility = View.GONE + } + } if (intent.getBooleanExtra(Constant.EXTRA_AUTO_HIDE, true)) ivLogo.postDelayed(hideRunnable, Constant.MILLIS_AUTO_HIDE.toLong()) } private fun hide() { - navigator.showMain(this) + when (BuildConfig.FLAVOR) { + Constant.FLAVOR_TANGEM_CARDANO -> { + navigator.showPrepareTransaction(this, TangemContext()) + } + else -> { + navigator.showMain(this) + } + } + finish() } diff --git a/app/src/main/java/com/tangem/ui/activity/MainActivity.kt b/app/src/main/java/com/tangem/ui/activity/MainActivity.kt index 4ee6e16658..318847f23f 100644 --- a/app/src/main/java/com/tangem/ui/activity/MainActivity.kt +++ b/app/src/main/java/com/tangem/ui/activity/MainActivity.kt @@ -1,14 +1,13 @@ +@file:Suppress("ObsoleteExperimentalCoroutines") + package com.tangem.ui.activity import android.Manifest import android.app.Activity -import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.PackageManager -import android.graphics.Color -import android.net.Uri import android.nfc.NfcAdapter import android.nfc.Tag import android.nfc.tech.IsoDep @@ -21,7 +20,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.PopupMenu import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import com.google.android.material.snackbar.Snackbar import com.scottyab.rootbeer.RootBeer import com.tangem.App import com.tangem.Constant @@ -29,14 +27,23 @@ import com.tangem.card_android.android.nfc.NfcDeviceAntennaLocation import com.tangem.card_android.android.nfc.NfcLifecycleObserver import com.tangem.card_android.android.reader.NfcManager import com.tangem.card_android.android.reader.NfcReader +import com.tangem.card_android.data.EXTRA_TANGEM_CARD +import com.tangem.card_android.data.EXTRA_TANGEM_CARD_UID import com.tangem.card_android.data.loadFromBundle import com.tangem.card_android.data.saveToBundle import com.tangem.card_common.data.TangemCard import com.tangem.card_common.reader.CardProtocol +import com.tangem.card_common.tasks.CustomReadCardTask +import com.tangem.card_common.tasks.OneTouchSignTask import com.tangem.card_common.tasks.ReadCardInfoTask +import com.tangem.card_common.tasks.SignTask +import com.tangem.card_common.util.Log +import com.tangem.data.Blockchain import com.tangem.data.Logger import com.tangem.data.network.ServerApiCommon import com.tangem.di.Navigator +import com.tangem.di.ToastHelper +import com.tangem.domain.wallet.CoinEngine import com.tangem.domain.wallet.CoinEngineFactory import com.tangem.domain.wallet.TangemContext import com.tangem.ui.dialog.NoExtendedLengthSupportDialog @@ -52,9 +59,9 @@ import kotlinx.android.synthetic.main.layout_touch_card.* import java.io.File import java.util.* import javax.inject.Inject -import com.tangem.card_android.data.EXTRA_TANGEM_CARD -import com.tangem.card_android.data.EXTRA_TANGEM_CARD_UID -import com.tangem.di.ToastHelper +import kotlinx.coroutines.runBlocking +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications, PopupMenu.OnMenuItemClickListener { @@ -74,7 +81,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation private var unsuccessReadCount = 0 private var lastTag: Tag? = null - private var readCardInfoTask: ReadCardInfoTask? = null + private var task: CustomReadCardTask? = null private var onNfcReaderCallback: NfcAdapter.ReaderCallback? = null override fun onNewIntent(intent: Intent?) { @@ -142,7 +149,8 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco val responseBuildVersion = responseVersionName.split('.').last() val appBuildVersion = BuildConfig.VERSION_NAME.split('.').last() if (responseBuildVersion.toInt() > appBuildVersion.toInt()) - toastHelper.showSnackbarUpdateVersion(this, cl, responseVersionName) + if (BuildConfig.FLAVOR.equals(Constant.FLAVOR_TANGEM_ACCESS)) + toastHelper.showSnackbarUpdateVersion(this, cl, responseVersionName) } catch (E: Exception) { E.printStackTrace() } @@ -237,8 +245,8 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco lastTag = tag - readCardInfoTask = ReadCardInfoTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this) - readCardInfoTask?.start() + task = ReadCardInfoTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this) + task?.start() } catch (e: Exception) { e.printStackTrace() nfcManager.notifyReadResult(false) @@ -252,12 +260,12 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco } public override fun onPause() { - readCardInfoTask?.cancel(true) + task?.cancel(true) super.onPause() } public override fun onStop() { - readCardInfoTask?.cancel(true) + task?.cancel(true) super.onStop() } @@ -270,7 +278,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco } override fun onReadFinish(cardProtocol: CardProtocol?) { - readCardInfoTask = null + task = null if (cardProtocol != null) { if (cardProtocol.error == null) { nfcManager.notifyReadResult(true) @@ -336,7 +344,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco } override fun onReadCancel() { - readCardInfoTask = null + task = null ReadCardInfoTask.resetLastReadInfo() rlProgressBar.postDelayed({ try { diff --git a/app/src/main/java/com/tangem/ui/activity/PurgeActivity.kt b/app/src/main/java/com/tangem/ui/activity/PurgeActivity.kt index 1dc1095f33..efd992346a 100644 --- a/app/src/main/java/com/tangem/ui/activity/PurgeActivity.kt +++ b/app/src/main/java/com/tangem/ui/activity/PurgeActivity.kt @@ -28,7 +28,6 @@ import com.tangem.card_android.data.asBundle import com.tangem.card_common.reader.CardProtocol import com.tangem.card_common.tasks.PurgeTask import com.tangem.card_common.util.Util -import com.tangem.util.LOG import com.tangem.wallet.R import kotlinx.android.synthetic.main.activity_purge.* import kotlinx.android.synthetic.main.layout_touch_card.* diff --git a/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialog.java b/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialog.java index 5a07459eb3..3186affc30 100644 --- a/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialog.java +++ b/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialog.java @@ -10,6 +10,7 @@ import android.view.View; import android.view.WindowManager; import android.widget.ProgressBar; +import com.tangem.card_common.util.Log; import com.tangem.wallet.R; import java.util.Timer; @@ -104,22 +105,39 @@ public class WaitSecurityDelayDialog extends DialogFragment { } public static void onReadWait(final AppCompatActivity activity, final int msec) { + Log.e(TAG, "onReadWait callback(" + msec + ")"); activity.runOnUiThread(() -> { + Log.e(TAG, "onReadWait on ui thread(" + msec + ")"); if (timerToShowDelayDialog != null) { timerToShowDelayDialog.cancel(); timerToShowDelayDialog = null; } if (msec == 0) { - if (instance != null && instance.isAdded()) { - instance.dismiss(); - instance = null; + if (instance != null) { + if (instance.isAdded()) { + instance.dismiss(); + instance = null; + } else { + Log.e(TAG, "onReadWait(0) with not added dialog"); +// instance.progressBar.postDelayed(() -> { +// Log.e(TAG, "onReadWait(0) dismiss delayed"); + try { + instance.dismiss(); + instance = null; + } + catch (Exception e) + { + e.printStackTrace(); + } +// }, 10000); + } } return; } if (instance == null) { - if (msec > minRemainingDelayToShowDialog) { + if (msec > delayBeforeShowDialog + minRemainingDelayToShowDialog) { instance = new WaitSecurityDelayDialog(); // 1000ms - card delay notification interval instance.setup(msec + 1000, 1000); diff --git a/app/src/main/res/layout/activity_logo.xml b/app/src/main/res/layout/activity_logo.xml index 97397e9d4d..cf3bb0afc9 100644 --- a/app/src/main/res/layout/activity_logo.xml +++ b/app/src/main/res/layout/activity_logo.xml @@ -7,6 +7,25 @@ tools:context="com.tangem.ui.activity.LogoActivity" tools:ignore="contentDescription"> + + + app:layout_constraintTop_toBottomOf="@+id/tvExtension" /> #FF505050 @color/black #4a763d - #BF7FF27F - #BFFF4444 + #F27FF27F + #F2FF4444 #4a086e #0c15c1 #e3e3e3 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 815f8e5599..572c502794 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,7 +7,6 @@ No connection with blockchain nodes Continue Not found - Card must be loaded first! Tag lost! command @@ -56,6 +55,7 @@ Show QR-code LOAD BETA + Cardano Your Android device is rooted. Security at risk! @@ -84,6 +84,12 @@ Reset PINs to default Erase wallet + + BETA v.%1$s \n dev \n build %2$s + BETA v.%1$s + + Hello, %1$s! You have %2$d new messages. + Tap Tangem card with your smartphone Scan a banknote with your \n %1$s \n as shown above @@ -143,6 +149,8 @@ enter wallet address enter amount Verify + Wallet address is empty + Amount is empty Enter new PIN or use fingerprint scanner diff --git a/app/src/main/res/values/strings_untranslatable.xml b/app/src/main/res/values/strings_untranslatable.xml index 78b9c55461..13279d3f9c 100644 --- a/app/src/main/res/values/strings_untranslatable.xml +++ b/app/src/main/res/values/strings_untranslatable.xml @@ -20,6 +20,7 @@ 9 0 + com.tangem.data.LogFileProvider Can\'t create CoinEngine! diff --git a/app/src/tangemAccess/java/com/tangem/Test2.java b/app/src/tangemAccess/java/com/tangem/Test2.java new file mode 100644 index 0000000000..c4c336af47 --- /dev/null +++ b/app/src/tangemAccess/java/com/tangem/Test2.java @@ -0,0 +1,4 @@ +package com.tangem; + +public class Test2 { +} diff --git a/app/src/main/java/com/tangem/ui/activity/ConfirmTransactionActivity.kt b/app/src/tangemAccess/java/com/tangem/ui/ConfirmTransactionActivity.kt similarity index 98% rename from app/src/main/java/com/tangem/ui/activity/ConfirmTransactionActivity.kt rename to app/src/tangemAccess/java/com/tangem/ui/ConfirmTransactionActivity.kt index ed4d1d7a5f..30f1693e35 100644 --- a/app/src/main/java/com/tangem/ui/activity/ConfirmTransactionActivity.kt +++ b/app/src/tangemAccess/java/com/tangem/ui/ConfirmTransactionActivity.kt @@ -1,4 +1,4 @@ -package com.tangem.ui.activity +package com.tangem.ui import android.app.Activity import android.content.Intent @@ -25,12 +25,14 @@ import com.tangem.card_android.data.loadFromBundle import com.tangem.card_common.data.TangemCard import com.tangem.util.UtilHelper import com.tangem.wallet.R -import kotlinx.android.synthetic.main.activity_confirm_transaction.* import org.greenrobot.eventbus.EventBus import java.io.IOException import java.util.* import com.tangem.card_android.data.EXTRA_TANGEM_CARD import com.tangem.card_android.data.EXTRA_TANGEM_CARD_UID +import com.tangem.ui.activity.PinRequestActivity +import com.tangem.ui.activity.SignTransactionActivity +import kotlinx.android.synthetic.tangemAccess.activity_confirm_transaction.* class ConfirmTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback { diff --git a/app/src/main/java/com/tangem/ui/activity/PrepareTransactionActivity.kt b/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionActivity.kt similarity index 98% rename from app/src/main/java/com/tangem/ui/activity/PrepareTransactionActivity.kt rename to app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionActivity.kt index 9789a22815..c6edc34fb4 100644 --- a/app/src/main/java/com/tangem/ui/activity/PrepareTransactionActivity.kt +++ b/app/src/tangemAccess/java/com/tangem/ui/PrepareTransactionActivity.kt @@ -1,4 +1,4 @@ -package com.tangem.ui.activity +package com.tangem.ui import android.app.Activity import android.content.Context @@ -23,7 +23,7 @@ import com.tangem.card_android.android.nfc.NfcLifecycleObserver import com.tangem.card_android.android.reader.NfcManager import com.tangem.util.UtilHelper import com.tangem.wallet.R -import kotlinx.android.synthetic.main.activity_prepare_transaction.* +import kotlinx.android.synthetic.tangemAccess.activity_prepare_transaction.* import java.io.IOException import javax.inject.Inject diff --git a/app/src/main/java/com/tangem/ui/activity/SignTransactionActivity.kt b/app/src/tangemAccess/java/com/tangem/ui/SignTransactionActivity.kt similarity index 100% rename from app/src/main/java/com/tangem/ui/activity/SignTransactionActivity.kt rename to app/src/tangemAccess/java/com/tangem/ui/SignTransactionActivity.kt diff --git a/app/src/main/res/layout/activity_confirm_transaction.xml b/app/src/tangemAccess/res/layout/activity_confirm_transaction.xml similarity index 99% rename from app/src/main/res/layout/activity_confirm_transaction.xml rename to app/src/tangemAccess/res/layout/activity_confirm_transaction.xml index 5a48672aa3..c94c3a66f6 100644 --- a/app/src/main/res/layout/activity_confirm_transaction.xml +++ b/app/src/tangemAccess/res/layout/activity_confirm_transaction.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="com.tangem.ui.activity.ConfirmTransactionActivity" + tools:context="com.tangem.ui.ConfirmTransactionActivity" tools:ignore="Autofill"> + tools:context="com.tangem.ui.SignTransactionActivity"> Tangem Access - com.tangem.data.LogFileProvider \ No newline at end of file diff --git a/app/src/tangemCardano/java/com/tangem/Test1.java b/app/src/tangemCardano/java/com/tangem/Test1.java new file mode 100644 index 0000000000..fa30c973e7 --- /dev/null +++ b/app/src/tangemCardano/java/com/tangem/Test1.java @@ -0,0 +1,4 @@ +package com.tangem; + +public class Test1 { +} diff --git a/app/src/tangemCardano/java/com/tangem/ui/ConfirmTransactionActivity.kt b/app/src/tangemCardano/java/com/tangem/ui/ConfirmTransactionActivity.kt new file mode 100644 index 0000000000..c325101aa8 --- /dev/null +++ b/app/src/tangemCardano/java/com/tangem/ui/ConfirmTransactionActivity.kt @@ -0,0 +1,310 @@ +package com.tangem.ui + +import android.app.Activity +import android.content.Intent +import android.nfc.NfcAdapter +import android.nfc.Tag +import android.os.Build +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import android.text.Editable +import android.text.Html +import android.text.TextWatcher +import android.view.KeyEvent +import android.view.View +import android.widget.Toast +import com.tangem.Constant +import com.tangem.card_android.android.data.PINStorage +import com.tangem.domain.wallet.CoinEngine +import com.tangem.domain.wallet.CoinEngineFactory +import com.tangem.domain.wallet.TangemContext +import com.tangem.ui.event.TransactionFinishWithError +import com.tangem.card_android.android.nfc.NfcLifecycleObserver +import com.tangem.card_android.android.reader.NfcManager +import com.tangem.card_android.data.loadFromBundle +import com.tangem.card_common.data.TangemCard +import com.tangem.util.UtilHelper +import com.tangem.wallet.R +import org.greenrobot.eventbus.EventBus +import java.io.IOException +import java.util.* +import com.tangem.card_android.data.EXTRA_TANGEM_CARD +import com.tangem.card_android.data.EXTRA_TANGEM_CARD_UID +import com.tangem.ui.activity.PinRequestActivity +import kotlinx.android.synthetic.tangemCardano.activity_confirm_transaction.* + +class ConfirmTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback { + + private lateinit var nfcManager: NfcManager + private lateinit var ctx: TangemContext + private lateinit var amount: CoinEngine.Amount + + private var isIncludeFee: Boolean = true + private var requestPIN2Count = 0 + private var nodeCheck = true + private var dtVerified: Date? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_confirm_transaction) + + nfcManager = NfcManager(this, this) + lifecycle.addObserver(NfcLifecycleObserver(nfcManager)) + + ctx = TangemContext();//.loadFromBundle(this, intent.extras) + + val engine = CoinEngineFactory.createCardano(ctx) //create(ctx) + + @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + Html.fromHtml(engine!!.balanceHTML, Html.FROM_HTML_MODE_LEGACY) + else + Html.fromHtml(engine!!.balanceHTML) + tvBalance.text = html + + isIncludeFee = intent.getBooleanExtra(Constant.EXTRA_FEE_INCLUDED, true) + + if (isIncludeFee) + tvIncFee.setText(R.string.including_fee) + else + tvIncFee.setText(R.string.not_including_fee) + + amount = CoinEngine.Amount(intent.getStringExtra(Constant.EXTRA_AMOUNT), intent.getStringExtra(Constant.EXTRA_AMOUNT_CURRENCY)) + + if (engine.allowSelectFeeInclusion()) + tvIncFee.visibility = View.VISIBLE + else + tvIncFee.visibility = View.INVISIBLE + +// if (ctx.card.blockchainID == Blockchain.Token.id) { +// // for Blockchain.Token limit decimals +// etAmount.setText(amount.toValueString(ctx.card.tokensDecimal)) +// } else { + // for others + etAmount.setText(amount.toValueString()) +// } + + tvCurrency.text = engine.balanceCurrency + tvCurrency2.text = engine.feeCurrency +// tvCardID.text = ctx.card.cidDescription + etWallet.setText(intent.getStringExtra(Constant.EXTRA_TARGET_ADDRESS)) + + btnSend.visibility = View.INVISIBLE + + if (!engine.allowSelectFeeLevel()) { + rgFee.visibility = View.GONE + } + + // set listeners + rgFee.setOnCheckedChangeListener { _, checkedId -> doSetFee(checkedId) } + etFee.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + try { + val eqFee = engine.evaluateFeeEquivalent(etFee!!.text.toString()) + tvFeeEquivalent.text = eqFee + + if (!ctx.coinData!!.amountEquivalentDescriptionAvailable) { + tvFeeEquivalent.error = getString(R.string.service_unavailable) + tvCurrency2.visibility = View.GONE + tvFeeEquivalent.visibility = View.GONE + } else + tvFeeEquivalent.error = null + + } catch (e: Exception) { + e.printStackTrace() + tvFeeEquivalent.text = "" + } + } + + override fun afterTextChanged(s: Editable) { + + } + }) + btnSend.setOnClickListener { + if (UtilHelper.isOnline(this)) { + val calendar = Calendar.getInstance() + calendar.add(Calendar.MINUTE, -1) + + if (dtVerified == null || dtVerified!!.before(calendar.time)) { + finishWithError(Activity.RESULT_CANCELED, getString(R.string.the_obtained_data_is_outdated_try_again)) + return@setOnClickListener + } + + val engineCoin = CoinEngineFactory.createCardano(ctx) + + if (engineCoin!!.isNeedCheckNode && !nodeCheck) { + Toast.makeText(baseContext, getString(R.string.cannot_reach_current_active_blockchain_node_try_again), Toast.LENGTH_LONG).show() + return@setOnClickListener + } + + val txFee = engineCoin.convertToAmount(etFee.text.toString(), tvCurrency2.text.toString()) + val txAmount = engineCoin.convertToAmount(etAmount.text.toString(), tvCurrency.text.toString()) + +// if (!engineCoin.hasBalanceInfo()) { +// finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_check_balance_no_connection_with_blockchain_nodes)) +// return@setOnClickListener +// +// } else if (!engineCoin.isBalanceNotZero) { +// finishWithError(Activity.RESULT_CANCELED, getString(R.string.the_wallet_is_empty)) +// return@setOnClickListener +// +// } else if (!engineCoin.isExtractPossible) { +// finishWithError(Activity.RESULT_CANCELED, getString(R.string.please_wait_for_confirmation_of_incoming_transaction)) +// return@setOnClickListener +// } +// +// if (!engineCoin.checkNewTransactionAmountAndFee(txAmount, txFee, isIncludeFee)) { +// finishWithError(Activity.RESULT_CANCELED, getString(R.string.not_enough_funds_on_your_card)) +// return@setOnClickListener +// } + + requestPIN2Count = 0 +// val intent = Intent(baseContext, PinRequestActivity::class.java) +// intent.putExtra(Constant.EXTRA_MODE, PinRequestActivity.Mode.RequestPIN2.toString()) +// ctx.saveToIntent(intent) +// intent.putExtra(Constant.EXTRA_FEE_INCLUDED, isIncludeFee) +// startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_) + + //TODO - PIN2 workaround + PINStorage.setPIN2(PINStorage.getDefaultPIN2()) + val intent = Intent(baseContext, SignTransactionActivity::class.java) + ctx.saveToIntent(intent) + intent.putExtra(Constant.EXTRA_TARGET_ADDRESS, etWallet!!.text.toString()) + intent.putExtra(Constant.EXTRA_AMOUNT, etAmount.text.toString()) + intent.putExtra(Constant.EXTRA_AMOUNT_CURRENCY, tvCurrency.text.toString()) + intent.putExtra(Constant.EXTRA_FEE, etFee.text.toString()) + intent.putExtra(Constant.EXTRA_FEE_CURRENCY, tvCurrency2.text.toString()) + intent.putExtra(Constant.EXTRA_FEE_INCLUDED, isIncludeFee) + startActivityForResult(intent, Constant.REQUEST_CODE_SIGN_TRANSACTION) + + } else + Toast.makeText(this, getString(R.string.no_connection), Toast.LENGTH_SHORT).show() + } + + progressBar.visibility = View.VISIBLE + + engine!!.requestFee( + object : CoinEngine.BlockchainRequestsCallbacks { + override fun onComplete(success: Boolean) { + if (success) { + onProgress() + progressBar.visibility = View.INVISIBLE + dtVerified = Date() + } else { + finishWithError(Activity.RESULT_CANCELED, ctx.error) + } + } + + override fun onProgress() { + doSetFee(rgFee.checkedRadioButtonId) + } + + override fun allowAdvance(): Boolean { + return UtilHelper.isOnline(this@ConfirmTransactionActivity) + } + }, + etWallet.text.toString(), + amount) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == Constant.REQUEST_CODE_SIGN_TRANSACTION) { + if (data != null && data.extras != null) { + if (data.extras!!.containsKey(EXTRA_TANGEM_CARD_UID) && data.extras!!.containsKey(EXTRA_TANGEM_CARD)) { + val updatedCard = TangemCard(data.getStringExtra(EXTRA_TANGEM_CARD_UID)) + updatedCard.loadFromBundle(data.getBundleExtra(EXTRA_TANGEM_CARD)) + ctx.card = updatedCard + } + } + if (resultCode == Constant.RESULT_INVALID_PIN_ && requestPIN2Count < 2) { + requestPIN2Count++ + + val intent = Intent(baseContext, PinRequestActivity::class.java) + intent.putExtra(Constant.EXTRA_MODE, PinRequestActivity.Mode.RequestPIN2.toString()) + ctx.saveToIntent(intent) + intent.putExtra(Constant.EXTRA_FEE_INCLUDED, isIncludeFee) + startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_) + + return + } + setResult(resultCode, data) + finish() + } else if (requestCode == Constant.REQUEST_CODE_REQUEST_PIN2_) { + if (resultCode == Activity.RESULT_OK) { + val intent = Intent(baseContext, SignTransactionActivity::class.java) + ctx.saveToIntent(intent) + intent.putExtra(Constant.EXTRA_TARGET_ADDRESS, etWallet!!.text.toString()) + intent.putExtra(Constant.EXTRA_AMOUNT, etAmount.text.toString()) + intent.putExtra(Constant.EXTRA_AMOUNT_CURRENCY, tvCurrency.text.toString()) + intent.putExtra(Constant.EXTRA_FEE, etFee.text.toString()) + intent.putExtra(Constant.EXTRA_FEE_CURRENCY, tvCurrency2.text.toString()) + intent.putExtra(Constant.EXTRA_FEE_INCLUDED, isIncludeFee) + startActivityForResult(intent, Constant.REQUEST_CODE_SIGN_TRANSACTION) + } else + Toast.makeText(baseContext, R.string.pin_2_is_required_to_sign_the_transaction, Toast.LENGTH_LONG).show() + } + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_BACK -> { + val intent = Intent() + setResult(Activity.RESULT_CANCELED, intent) + finish() + return true + } + } + return super.onKeyDown(keyCode, event) + } + + override fun onTagDiscovered(tag: Tag) { + try { + nfcManager.ignoreTag(tag) + } catch (e: IOException) { + e.printStackTrace() + } + } + + private fun doSetFee(checkedRadioButtonId: Int) { + var txtFee = "" + when (checkedRadioButtonId) { + R.id.rbMinimalFee -> + if (ctx.coinData.minFee != null) { + txtFee = ctx.coinData.minFee!!.toValueString() + btnSend.visibility = View.VISIBLE + } else + btnSend.visibility = View.INVISIBLE + + R.id.rbNormalFee -> + if (ctx.coinData.normalFee != null) { + txtFee = ctx.coinData.normalFee!!.toValueString() + btnSend.visibility = View.VISIBLE + } else + btnSend.visibility = View.INVISIBLE + + R.id.rbMaximumFee -> + if (ctx.coinData.maxFee != null) { + txtFee = ctx.coinData.maxFee!!.toValueString() + btnSend.visibility = View.VISIBLE + } else + btnSend.visibility = View.INVISIBLE + } + etFee.setText(txtFee.replace(',', '.')) + } + + private fun finishWithError(errorCode: Int, message: String) { + val transactionFinishWithError = TransactionFinishWithError() + transactionFinishWithError.message = message + EventBus.getDefault().post(transactionFinishWithError) + + val intent = Intent() + intent.putExtra(Constant.EXTRA_MESSAGE, message) + setResult(errorCode, intent) + finish() + } + +} \ No newline at end of file diff --git a/app/src/tangemCardano/java/com/tangem/ui/PrepareTransactionActivity.kt b/app/src/tangemCardano/java/com/tangem/ui/PrepareTransactionActivity.kt new file mode 100644 index 0000000000..0a13127068 --- /dev/null +++ b/app/src/tangemCardano/java/com/tangem/ui/PrepareTransactionActivity.kt @@ -0,0 +1,225 @@ +package com.tangem.ui + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.nfc.NfcAdapter +import android.nfc.Tag +import android.os.Build +import android.os.Bundle +import android.text.Html +import android.view.MotionEvent +import android.view.View +import android.view.View.OnTouchListener +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import com.tangem.App +import com.tangem.Constant +import com.tangem.card_android.android.nfc.NfcLifecycleObserver +import com.tangem.card_android.android.reader.NfcManager +import com.tangem.data.dp.PrefsManager +import com.tangem.di.Navigator +import com.tangem.di.ToastHelper +import com.tangem.domain.wallet.CoinEngineFactory +import com.tangem.domain.wallet.TangemContext +import com.tangem.ui.event.TransactionFinishWithError +import com.tangem.ui.event.TransactionFinishWithSuccess +import com.tangem.util.UtilHelper +import com.tangem.wallet.R +import kotlinx.android.synthetic.tangemCardano.activity_prepare_transaction.* +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import java.io.IOException +import javax.inject.Inject + +class PrepareTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback { + companion object { + val TAG: String = PrepareTransactionActivity::class.java.simpleName + fun callingIntent(context: Context, ctx: TangemContext): Intent { + val intent = Intent(context, PrepareTransactionActivity::class.java) + ctx.saveToIntent(intent) + return intent + } + } + + @Inject + internal lateinit var navigator: Navigator + @Inject + internal lateinit var toastHelper: ToastHelper + + private lateinit var nfcManager: NfcManager + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_prepare_transaction) + + App.navigatorComponent.inject(this) + App.toastHelperComponent.inject(this) + + nfcManager = NfcManager(this, this) + lifecycle.addObserver(NfcLifecycleObserver(nfcManager)) + + val engine = CoinEngineFactory.createCardano(TangemContext()) + + @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + Html.fromHtml(engine?.balanceHTML, Html.FROM_HTML_MODE_LEGACY) + else + Html.fromHtml(engine?.balanceHTML) + tvBalance.text = html + + if (!engine!!.allowSelectFeeInclusion()) { + rgIncFee.visibility = View.INVISIBLE + } else { + rgIncFee.visibility = View.VISIBLE + } + + tvCurrency.text = engine.balance?.currency + etAmount.setText(engine.balance?.toValueString()) + + // limit number of symbols after comma + etAmount.filters = engine.amountInputFilters + + etWallet.setText(PrefsManager.getInstance().lastWalletAddress) + + // set listeners + etAmount.setOnEditorActionListener { lv, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + val imm = lv.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(lv.windowToken, 0) + lv.clearFocus() + true + } else { + false + } + } + + btnVerify.setOnClickListener { + if (!UtilHelper.isOnline(this)) { + Toast.makeText(this, R.string.no_connection, Toast.LENGTH_LONG).show() + return@setOnClickListener + } + + // check on empty wallet address + if (etWallet.text.toString() == "") { + etWallet.error = getString(R.string.wallet_address_empty) + return@setOnClickListener + } + + // check on empty amount + if (etAmount.text.toString() == "") { + etAmount.error = getString(R.string.amount_empty) + return@setOnClickListener + } + + val strAmount: String = etAmount.text.toString().replace(",", ".") + val amount = engine.convertToAmount(etAmount.text.toString(), tvCurrency.text.toString()) + + // check amount + try { + if (!engine.checkNewTransactionAmount(amount)) + etAmount.error = getString(R.string.not_enough_funds_on_your_card) + else + etAmount.error = null + } catch (e: Exception) { + etAmount.error = getString(R.string.unknown_amount_format) + } + + // check wallet address + if (!engine.validateAddress(etWallet.text.toString())) { + etWallet.error = getString(R.string.incorrect_destination_wallet_address) + return@setOnClickListener + } else + etWallet.error = null + + if (!etAmount.error.isNullOrEmpty() || !etWallet.error.isNullOrEmpty()) { + return@setOnClickListener + } + + val intent = Intent(baseContext, ConfirmTransactionActivity::class.java) + intent.putExtra(Constant.EXTRA_TARGET_ADDRESS, etWallet!!.text.toString()) + intent.putExtra(Constant.EXTRA_FEE_INCLUDED, (rgIncFee!!.checkedRadioButtonId == R.id.rbFeeIn)) + intent.putExtra(Constant.EXTRA_AMOUNT, strAmount) + intent.putExtra(Constant.EXTRA_AMOUNT_CURRENCY, tvCurrency.text.toString()) + startActivityForResult(intent, Constant.REQUEST_CODE_SEND_TRANSACTION__) + + PrefsManager.getInstance().saveLastWalletAddress(etWallet.text.toString()) + } + + ivCamera.setOnClickListener { + navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR) + etWallet.text.clear() + } + + etWallet.setOnTouchListener(OnTouchListener { _, event -> + if (event.action == MotionEvent.ACTION_UP) { + if (event.rawX >= etWallet.right - etWallet.compoundDrawables[2].bounds.width()) { + etWallet.text.clear() + return@OnTouchListener true + } + } + false + }) + } + + override fun onStart() { + super.onStart() + if (!EventBus.getDefault().isRegistered(this)) + EventBus.getDefault().register(this) + } + + override fun onDestroy() { + EventBus.getDefault().unregister(this) + super.onDestroy() + } + + @Subscribe + fun onTransactionFinishWithSuccess(transactionFinishWithSuccess: TransactionFinishWithSuccess) { + transactionFinishWithSuccess.message?.let { toastHelper.showSnackbarSuccess(this, cl, it) } + } + + @Subscribe + fun onTransactionFinishWithError(transactionFinishWithError: TransactionFinishWithError) { + transactionFinishWithError.message?.let { toastHelper.showSnackbarError(this, cl, it) } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == Constant.REQUEST_CODE_SCAN_QR && resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) { + var code = data.getStringExtra("QRCode") +// when (ctx.blockchain) { +// Blockchain.Bitcoin -> { +// if (code.contains("bitcoin:")) { +// val tmp = code.split("bitcoin:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() +// code = tmp[1] +// } +// } +// Blockchain.Ethereum, Blockchain.Token -> { +// if (code.contains("ethereum:")) { +// val tmp = code.split("ethereum:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() +// code = tmp[1] +// } else if (code.contains("blockchain:")) { +// val tmp = code.split("blockchain:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() +// code = tmp[1] +// } +// } +// else -> { +// } +// } + etWallet?.setText(code) +// } else if (requestCode == Constant.REQUEST_CODE_SEND_TRANSACTION__) { +// setResult(resultCode, data) +// finish() + } + } + + override fun onTagDiscovered(tag: Tag) { + try { + nfcManager.ignoreTag(tag) + } catch (e: IOException) { + e.printStackTrace() + } + } + +} \ No newline at end of file diff --git a/app/src/tangemCardano/java/com/tangem/ui/SignTransactionActivity.kt b/app/src/tangemCardano/java/com/tangem/ui/SignTransactionActivity.kt new file mode 100644 index 0000000000..5315335d51 --- /dev/null +++ b/app/src/tangemCardano/java/com/tangem/ui/SignTransactionActivity.kt @@ -0,0 +1,366 @@ +package com.tangem.ui + +import android.app.Activity +import android.content.Intent +import android.content.res.ColorStateList +import android.graphics.Color +import android.media.MediaPlayer +import android.nfc.NfcAdapter +import android.nfc.Tag +import android.nfc.tech.IsoDep +import android.os.Bundle +import android.view.KeyEvent +import android.view.View +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import com.tangem.App +import com.tangem.Constant +import com.tangem.card_android.android.nfc.NfcDeviceAntennaLocation +import com.tangem.card_android.android.nfc.NfcLifecycleObserver +import com.tangem.card_android.android.reader.NfcManager +import com.tangem.card_android.android.reader.NfcReader +import com.tangem.card_android.data.EXTRA_TANGEM_CARD +import com.tangem.card_android.data.EXTRA_TANGEM_CARD_UID +import com.tangem.card_android.data.asBundle +import com.tangem.card_common.data.TangemCard +import com.tangem.card_common.reader.CardCrypto +import com.tangem.card_common.reader.CardProtocol +import com.tangem.card_common.tasks.CustomReadCardTask +import com.tangem.card_common.tasks.OneTouchSignTask +import com.tangem.card_common.tasks.SignTask +import com.tangem.card_common.util.Log +import com.tangem.domain.wallet.CoinEngine +import com.tangem.domain.wallet.CoinEngineFactory +import com.tangem.domain.wallet.TangemContext +import com.tangem.ui.activity.MainActivity +import com.tangem.ui.activity.SendTransactionActivity +import com.tangem.ui.dialog.NoExtendedLengthSupportDialog +import com.tangem.ui.dialog.WaitSecurityDelayDialog +import com.tangem.util.LOG +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.layout_progress_horizontal.* +import kotlinx.android.synthetic.main.layout_touch_card.* +import kotlinx.coroutines.runBlocking +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +class SignTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications { + + companion object { + val TAG: String = SignTransactionActivity::class.java.simpleName + } + + private lateinit var nfcManager: NfcManager + private lateinit var ctx: TangemContext + private lateinit var mpFinishSignSound: MediaPlayer + + private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation + + private var task: CustomReadCardTask? = null + + private lateinit var amount: CoinEngine.Amount + private lateinit var fee: CoinEngine.Amount + private var isIncludeFee = true + private var outAddressStr: String? = null + private var lastReadSuccess = true + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_sign_transaction) + + nfcManager = NfcManager(this, this) + lifecycle.addObserver(NfcLifecycleObserver(nfcManager)) + + ctx = TangemContext.loadFromBundle(this, intent.extras) + + mpFinishSignSound = MediaPlayer.create(this, R.raw.scan_card_sound) + + // init NFC Antenna + nfcDeviceAntenna = NfcDeviceAntennaLocation(this, ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc) + nfcDeviceAntenna.init() + + amount = CoinEngine.Amount(intent.getStringExtra(Constant.EXTRA_AMOUNT), intent.getStringExtra(Constant.EXTRA_AMOUNT_CURRENCY)) + fee = CoinEngine.Amount(intent.getStringExtra(Constant.EXTRA_FEE), intent.getStringExtra(Constant.EXTRA_FEE_CURRENCY)) + isIncludeFee = intent.getBooleanExtra(Constant.EXTRA_FEE_INCLUDED, true) + outAddressStr = intent.getStringExtra(Constant.EXTRA_TARGET_ADDRESS) + + // tvCardID.text = ctx.card!!.cidDescription + progressBar.progressTintList = ColorStateList.valueOf(Color.DKGRAY) + progressBar.visibility = View.INVISIBLE + } + + public override fun onPause() { + task?.cancel(true) + super.onPause() + } + + public override fun onStop() { + task?.cancel(true) + super.onStop() + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (requestCode == Constant.REQUEST_CODE_SEND_TRANSACTION_) { + setResult(resultCode, data) + finish() + return + } + super.onActivityResult(requestCode, resultCode, data) + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_BACK -> { + val intent = Intent() + setResult(Activity.RESULT_CANCELED, intent) + finish() + return true + } + } + return super.onKeyDown(keyCode, event) + } + + override fun onTagDiscovered(tag: Tag) { + try { + // get IsoDep handle and run cardReader thread + val isoDep = IsoDep.get(tag) + + isoDep.timeout = 65000 + + val coinEngine = CoinEngineFactory.createCardano(ctx!!)!! + coinEngine.setOnNeedSendTransaction { tx -> + if (tx != null) { + val intent = Intent(this, SendTransactionActivity::class.java) + ctx.saveToIntent(intent) + intent.putExtra(Constant.EXTRA_TX, tx) + startActivityForResult(intent, Constant.REQUEST_CODE_SEND_TRANSACTION_) + } + } + + val tx: OneTouchSignTask.TransactionToSign = object : OneTouchSignTask.TransactionToSign { + var txToSign: SignTask.TransactionToSign? = null + suspend fun requestBalanceAndUnspentTransactions(): Boolean = suspendCoroutine { cont -> + coinEngine!!.requestBalanceAndUnspentTransactions(object : CoinEngine.BlockchainRequestsCallbacks { + override fun onComplete(success: Boolean?) { + cont.resume(success!!) + } + + override fun onProgress() { + } + + override fun allowAdvance(): Boolean { + return true + } + }) + } + + fun initData(card: TangemCard) { + if (ctx.card == null) { + ctx.card = card + } + if (ctx.coinData == null) { + ctx.coinData = CoinEngineFactory.createCardanoData() + } + if (ctx.coinData.wallet.isNullOrEmpty()) { + coinEngine.defineWallet() + runBlocking { requestBalanceAndUnspentTransactions() } + Log.e(MainActivity.TAG, "requestBalanceAndUnspentTransactions completed") + } + if (txToSign == null) txToSign = coinEngine!!.constructTransaction(amount, fee, isIncludeFee, outAddressStr) + } + + override fun isSigningOnCardSupported(card: TangemCard?): Boolean { + initData(card!!) + return CoinEngineFactory.isCardano(card?.blockchainID) and (txToSign!!.isSigningMethodSupported(card?.signingMethod)) + } + + override fun isIssuerCanSignData(card: TangemCard?): Boolean { + return try { + card?.issuer?.privateDataKey!=null + } catch (e: java.lang.Exception) { + false + } + } + + override fun isIssuerCanSignTransaction(card: TangemCard?): Boolean { + return try { + card?.issuer?.privateTransactionKey!=null + } catch (e: java.lang.Exception) { + false + } + } + + override fun getHashesToSign(card: TangemCard?): Array { + initData(card!!) + return txToSign!!.hashesToSign + } + + override fun getRawDataToSign(card: TangemCard?): ByteArray { + initData(card!!) + return txToSign!!.rawDataToSign + } + + override fun getHashAlgToSign(card: TangemCard?): String { + initData(card!!) + return txToSign!!.hashAlgToSign + } + + override fun getIssuerTransactionSignature(card: TangemCard?, dataToSignByIssuer: ByteArray?): ByteArray { + initData(card!!) + if( card.issuer!=null && card.issuer.privateTransactionKey!=null) + { + return CardCrypto.Signature(card.issuer.privateTransactionKey, dataToSignByIssuer) + } + return txToSign!!.getIssuerTransactionSignature(dataToSignByIssuer) + } + + override fun onSignCompleted(card: TangemCard?, signature: ByteArray?) { + initData(card!!) + txToSign!!.onSignCompleted(signature) + } + + } + task = OneTouchSignTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this, tx) + task!!.start() + + } catch (e: CardProtocol.TangemException_WrongAmount) { + try { + val intent = Intent() + intent.putExtra(Constant.EXTRA_MESSAGE, getString(R.string.cannot_sign_transaction_wrong_amount)) + intent.putExtra(EXTRA_TANGEM_CARD_UID, ctx.card.uid) + intent.putExtra(EXTRA_TANGEM_CARD, ctx.card.asBundle) + setResult(Activity.RESULT_CANCELED, intent) + finish() + } catch (e: Exception) { + e.printStackTrace() + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun onReadStart(cardProtocol: CardProtocol) { + rlProgressBar.post { rlProgressBar.visibility = View.VISIBLE } + + progressBar?.post { + progressBar?.visibility = View.VISIBLE + progressBar?.progress = 5 + } + } + + override fun onReadProgress(protocol: CardProtocol, progress: Int) { + progressBar?.post { progressBar!!.progress = progress } + } + + override fun onReadFinish(cardProtocol: CardProtocol?) { + task = null + if (cardProtocol != null) { + if (cardProtocol.error == null) { + rlProgressBar.post { rlProgressBar.visibility = View.GONE } + + progressBar?.post { + progressBar?.progress = 100 + progressBar?.progressTintList = ColorStateList.valueOf(Color.GREEN) + } + + mpFinishSignSound.start() + } else { + lastReadSuccess = false + if (cardProtocol.error.javaClass == CardProtocol.TangemException_InvalidPIN::class.java) { + progressBar?.post { + progressBar?.progress = 100 + progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) + } + progressBar?.postDelayed({ + try { + progressBar?.progress = 0 + progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) + progressBar?.visibility = View.INVISIBLE + val intent = Intent() + intent.putExtra(Constant.EXTRA_MESSAGE, getString(R.string.cannot_sign_transaction_make_sure_you_enter_correct_pin_2)) + intent.putExtra(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) + intent.putExtra(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) + setResult(Constant.RESULT_INVALID_PIN_, intent) + finish() + } catch (e: Exception) { + e.printStackTrace() + } + }, 500) + } else { + if (cardProtocol.error is CardProtocol.TangemException_WrongAmount) { + try { + val intent = Intent() + intent.putExtra(Constant.EXTRA_MESSAGE, getString(R.string.cannot_sign_transaction_wrong_amount)) + intent.putExtra(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) + intent.putExtra(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) + setResult(Activity.RESULT_CANCELED, intent) + finish() + } catch (e: Exception) { + e.printStackTrace() + } + } + progressBar?.post { + if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) { + if (!NoExtendedLengthSupportDialog.allReadyShowed) { + NoExtendedLengthSupportDialog.message = getText(R.string.the_nfc_adapter_length_apdu).toString() + "\n" + getText(R.string.the_nfc_adapter_length_apdu_advice).toString() + NoExtendedLengthSupportDialog().show(supportFragmentManager, NoExtendedLengthSupportDialog.TAG) + } + } else { + Toast.makeText(baseContext, R.string.try_to_scan_again, Toast.LENGTH_LONG).show() + } + progressBar?.progress = 100 + progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) + } + } + } + } + + rlProgressBar.postDelayed({ + try { + rlProgressBar.visibility = View.GONE + } catch (e: Exception) { + e.printStackTrace() + } + }, 500) + + progressBar?.postDelayed({ + try { + progressBar?.progress = 0 + progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) + progressBar?.visibility = View.INVISIBLE + } catch (e: Exception) { + e.printStackTrace() + } + }, 500) + } + + override fun onReadCancel() { + task = null + + progressBar?.postDelayed({ + try { + progressBar?.progress = 0 + progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) + progressBar?.visibility = View.INVISIBLE + } catch (e: Exception) { + e.printStackTrace() + } + }, 500) + } + + override fun onReadBeforeRequest(timeout: Int) { + LOG.i(TAG, "onReadBeforeRequest timeout $timeout") + WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout) + } + + override fun onReadAfterRequest() { + LOG.i(TAG, "onReadAfterRequest") + WaitSecurityDelayDialog.onReadAfterRequest(this) + } + + override fun onReadWait(msec: Int) { + LOG.i(TAG, "onReadWait msec $msec") + WaitSecurityDelayDialog.onReadWait(this, msec) + } + +} \ No newline at end of file diff --git a/app/src/tangemCardano/res/layout/activity_confirm_transaction.xml b/app/src/tangemCardano/res/layout/activity_confirm_transaction.xml new file mode 100644 index 0000000000..6f9e6375a1 --- /dev/null +++ b/app/src/tangemCardano/res/layout/activity_confirm_transaction.xml @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +