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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/tangemCardano/res/layout/activity_prepare_transaction.xml b/app/src/tangemCardano/res/layout/activity_prepare_transaction.xml
new file mode 100644
index 0000000000..6cf10efd5e
--- /dev/null
+++ b/app/src/tangemCardano/res/layout/activity_prepare_transaction.xml
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/tangemCardano/res/layout/activity_sign_transaction.xml b/app/src/tangemCardano/res/layout/activity_sign_transaction.xml
new file mode 100644
index 0000000000..f16c5de3e5
--- /dev/null
+++ b/app/src/tangemCardano/res/layout/activity_sign_transaction.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/tangemCardano/res/values/strings.xml b/app/src/tangemCardano/res/values/strings.xml
new file mode 100644
index 0000000000..f61b7fca57
--- /dev/null
+++ b/app/src/tangemCardano/res/values/strings.xml
@@ -0,0 +1,10 @@
+
+
+
+ Cardano
+
+ Confirm
+ Checkout
+ Now touch the banknote
+
+
\ No newline at end of file
diff --git a/card-common/src/main/java/com/tangem/card_common/data/Issuer.java b/card-common/src/main/java/com/tangem/card_common/data/Issuer.java
index 6b72f585fd..374eea579b 100644
--- a/card-common/src/main/java/com/tangem/card_common/data/Issuer.java
+++ b/card-common/src/main/java/com/tangem/card_common/data/Issuer.java
@@ -1,6 +1,7 @@
package com.tangem.card_common.data;
import com.tangem.card_common.reader.CardCrypto;
+import com.tangem.card_common.util.PBKDF2;
import com.tangem.card_common.util.Util;
import java.util.ArrayList;
@@ -15,11 +16,25 @@ public class Issuer {
static class KeyPair {
String privateKey;
+ String privateKeyEncrypted;
String publicKey;
+
byte[] getPrivateKey() throws Exception {
if (privateKey != null) {
return Util.hexToBytes(privateKey);
+ } else if (privateKeyEncrypted != null) {
+ byte[] A = PBKDF2.deriveKey(Util.calculateSHA256(Tangem().getPrivateTransactionKey()),Util.calculateSHA256(Tangem().getPrivateDataKey()), 100);
+ //String B = Util.bytesToHex(CardCrypto.Encrypt(A, Util.hexToBytes(""), true));
+ try {
+ return CardCrypto.Decrypt(A, Util.hexToBytes(privateKeyEncrypted), true);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new Exception("No private key!");
+ }
+
} else {
throw new Exception("No private key!");
}
@@ -57,8 +72,7 @@ public class Issuer {
instances.add(unknown);
}
- public static void fillIssuers(List issuers)
- {
+ public static void fillIssuers(List issuers) {
instances.addAll(issuers);
}
@@ -119,4 +133,9 @@ public class Issuer {
public static Issuer Unknown() {
return instances.get(0);
}
+
+ public static Issuer Tangem() {
+ return instances.get(1);
+ }
+
}
diff --git a/card-common/src/main/java/com/tangem/card_common/reader/CardProtocol.java b/card-common/src/main/java/com/tangem/card_common/reader/CardProtocol.java
index 481d9f8456..524cc0ad40 100644
--- a/card-common/src/main/java/com/tangem/card_common/reader/CardProtocol.java
+++ b/card-common/src/main/java/com/tangem/card_common/reader/CardProtocol.java
@@ -821,9 +821,9 @@ public class CardProtocol {
* @throws Exception - if something went wrong
*/
public TLVList run_SignHashes(String PIN2, byte[][] hashes, byte[] issuerTransactionSignature, byte[] issuerData, byte[] issuerDataSignature) throws Exception {
- if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer && mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash) {
- throw new TangemException("Card don't support signing hashes!");
- }
+// if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer && mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash) {
+// throw new TangemException("Card don't support signing hashes!");
+// }
ByteArrayOutputStream bs = new ByteArrayOutputStream();
if (hashes.length > 10) throw new TangemException("To much hashes in one transaction!");
@@ -837,7 +837,7 @@ public class CardProtocol {
rqApdu.addTLV_U8(TLV.Tag.TAG_TrOut_HashSize, hashes[0].length);
rqApdu.addTLV(TLV.Tag.TAG_TrOut_Hash, bs.toByteArray());
if (issuerData != null) {
- if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData)
+ if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData))
throw new TangemException("Card don't support simultaneous sign with write issuer data!");
if (issuerDataSignature == null)
@@ -849,7 +849,7 @@ public class CardProtocol {
if (issuerTransactionSignature != null) {
//byte[] issuerSignature = CardCrypto.Signature(issuer.getPrivateTransactionKey(), bs.toByteArray());
rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerTransactionSignature);
- } else if (mCard.getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer) {
+ } else if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash)) {
throw new TangemException("Card require issuer validation before sign the transaction!");
}
@@ -900,7 +900,7 @@ public class CardProtocol {
bs.write(bTxOutData);
if (issuerData != null) {
- if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData)
+ if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer_And_WriteIssuerData))
throw new TangemException("Card don't support simultaneous sign with write issuer data!");
if (issuerDataSignature == null)
@@ -911,7 +911,7 @@ public class CardProtocol {
}
if (issuerTransactionSignature != null) {
rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerTransactionSignature);
- } else if (mCard.getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer) {
+ } else if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw)) {
throw new TangemException("Card require issuer validation before sign the transaction!");
}
diff --git a/card-common/src/main/java/com/tangem/card_common/tasks/CustomReadCardTask.java b/card-common/src/main/java/com/tangem/card_common/tasks/CustomReadCardTask.java
index e93ac10832..a84eb7187e 100644
--- a/card-common/src/main/java/com/tangem/card_common/tasks/CustomReadCardTask.java
+++ b/card-common/src/main/java/com/tangem/card_common/tasks/CustomReadCardTask.java
@@ -38,7 +38,7 @@ public class CustomReadCardTask extends Thread {
// this fields are static to optimize process when need enter pin and scan card again
private static ArrayList lastRead_UnsuccessfullPINs = new ArrayList<>();
private static TangemCard.EncryptionMode lastRead_Encryption = null;
- private static String lastRead_UID;
+ private static String lastRead_UID = "";
public static void resetLastReadInfo() {
lastRead_UID = "";
@@ -419,6 +419,7 @@ public class CustomReadCardTask extends Thread {
} finally {
Log.i(TAG, String.format("[-- Finish task -- %s --]", getClass().getSimpleName()));
+ mNotifications.onReadWait(0);
mNotifications.onReadFinish(protocol);
}
} finally {
diff --git a/card-common/src/main/java/com/tangem/card_common/tasks/OneTouchSignTask.java b/card-common/src/main/java/com/tangem/card_common/tasks/OneTouchSignTask.java
new file mode 100644
index 0000000000..0a4b651599
--- /dev/null
+++ b/card-common/src/main/java/com/tangem/card_common/tasks/OneTouchSignTask.java
@@ -0,0 +1,100 @@
+package com.tangem.card_common.tasks;
+
+import com.tangem.card_common.data.TangemCard;
+import com.tangem.card_common.data.external.CardDataSubstitutionProvider;
+import com.tangem.card_common.data.external.PINsProvider;
+import com.tangem.card_common.reader.CardProtocol;
+import com.tangem.card_common.reader.NfcReader;
+import com.tangem.card_common.reader.TLV;
+import com.tangem.card_common.reader.TLVList;
+import com.tangem.card_common.util.Log;
+
+import java.io.ByteArrayOutputStream;
+
+public class OneTouchSignTask extends ReadCardInfoTask {
+ public static final String TAG = OneTouchSignTask.class.getSimpleName();
+
+ /**
+ * Transaction Engine request/notifications during sign process
+ */
+ public interface TransactionToSign {
+ boolean isSigningOnCardSupported(TangemCard card);
+
+ boolean isIssuerCanSignData(TangemCard card);
+
+ boolean isIssuerCanSignTransaction(TangemCard card);
+
+ byte[][] getHashesToSign(TangemCard card) throws Exception;
+
+ byte[] getRawDataToSign(TangemCard card) throws Exception;
+
+ String getHashAlgToSign(TangemCard card) throws Exception;
+
+ byte[] getIssuerTransactionSignature(TangemCard card, byte[] dataToSignByIssuer) throws Exception;
+
+ void onSignCompleted(TangemCard card, byte[] signature) throws Exception;
+ }
+
+ private TransactionToSign transactionToSign;
+
+ public OneTouchSignTask(NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications, TransactionToSign transactionToSign) {
+ super(reader, cardDataSubstitutionProvider, pinsProvider, notifications);
+ this.transactionToSign = transactionToSign;
+ }
+
+ @Override
+ public void run_Task() throws Exception {
+ super.run_Task();
+ Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
+
+ mNotifications.onReadProgress(protocol, 30);
+ if (isCancelled) return;
+
+ if (!transactionToSign.isSigningOnCardSupported(mCard)) {
+ throw new CardProtocol.TangemException("Signing method isn't supported!");
+ }
+
+ TLVList signResult;
+
+ if (transactionToSign.isIssuerCanSignTransaction(mCard) &&
+ (
+ mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer) ||
+ (
+ transactionToSign.isIssuerCanSignData(mCard) &&
+ mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData)
+ )
+ )
+ ) {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ byte[][] hashes = transactionToSign.getHashesToSign(mCard);
+ if (hashes.length > 10) throw new CardProtocol.TangemException("To much hashes in one transaction!");
+ for (int i = 0; i < hashes.length; i++) {
+ if (i != 0 && hashes[0].length != hashes[i].length)
+ throw new CardProtocol.TangemException("Hashes length must be identical!");
+ bs.write(hashes[i]);
+ }
+ signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), hashes, transactionToSign.getIssuerTransactionSignature(mCard, bs.toByteArray()), null, null);
+ } else if (
+ transactionToSign.isIssuerCanSignTransaction(mCard) &&
+ (
+ mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer) ||
+ (
+ transactionToSign.isIssuerCanSignData(mCard) &&
+ mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer_And_WriteIssuerData)
+ )
+ )
+ ) {
+ byte[] txOut = transactionToSign.getRawDataToSign(mCard);
+ signResult = protocol.run_SignRaw(pinsProvider.getPIN2(), transactionToSign.getHashAlgToSign(mCard), txOut, transactionToSign.getIssuerTransactionSignature(mCard, txOut), null, null);
+ } else if (mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash)) {
+ signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), transactionToSign.getHashesToSign(mCard), null, null, null);
+ } else if (mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw)) {
+ signResult = protocol.run_SignRaw(pinsProvider.getPIN2(), transactionToSign.getHashAlgToSign(mCard), transactionToSign.getRawDataToSign(mCard), null, null, null);
+ } else {
+ throw new CardProtocol.TangemException("Signing method isn't supported!");
+ }
+
+ transactionToSign.onSignCompleted(mCard, signResult.getTLV(TLV.Tag.TAG_Signature).Value);
+ mNotifications.onReadProgress(protocol, 100);
+ }
+}
diff --git a/card-common/src/main/java/com/tangem/card_common/util/Log.java b/card-common/src/main/java/com/tangem/card_common/util/Log.java
index a99116aff3..937965acc8 100644
--- a/card-common/src/main/java/com/tangem/card_common/util/Log.java
+++ b/card-common/src/main/java/com/tangem/card_common/util/Log.java
@@ -2,12 +2,18 @@ package com.tangem.card_common.util;
public class Log {
public static void i(String logTag, String message) {
-
+ if( loggerInstance!=null ) loggerInstance.i(logTag,message);
}
public static void e(String logTag, String message) {
-
+ if( loggerInstance!=null ) loggerInstance.e(logTag,message);
}
public static void v(String logTag, String message) {
+ if( loggerInstance!=null ) loggerInstance.v(logTag,message);
+ }
+ private static LoggerInterface loggerInstance=null;
+ public static void setLogger(LoggerInterface logger)
+ {
+ loggerInstance=logger;
}
}
diff --git a/card-common/src/main/java/com/tangem/card_common/util/LoggerInterface.java b/card-common/src/main/java/com/tangem/card_common/util/LoggerInterface.java
new file mode 100644
index 0000000000..dd4b45d1f8
--- /dev/null
+++ b/card-common/src/main/java/com/tangem/card_common/util/LoggerInterface.java
@@ -0,0 +1,7 @@
+package com.tangem.card_common.util;
+
+public interface LoggerInterface {
+ void i(String logTag, String message);
+ void e(String logTag, String message);
+ void v(String logTag, String message);
+}
diff --git a/server-android/build.gradle b/server-android/build.gradle
index 4df23bf51b..f79ad5009e 100644
--- a/server-android/build.gradle
+++ b/server-android/build.gradle
@@ -29,7 +29,7 @@ dependencies {
implementation project(':card-common')
// implementation 'com.github.TangemCash.card_android-common:card_android-android:0.1.0'
- implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
+ implementation 'androidx.appcompat:appcompat:1.1.0-alpha03'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'