diff --git a/app/build.gradle b/app/build.gradle index 5849552715..3ca01aaf09 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,6 +55,10 @@ android { buildToolsVersion '28.0.3' } +configurations { + all*.exclude group: 'com.google.guava', module: 'listenablefuture' +} + dependencies { implementation project(':card-common') implementation project(':card-android') @@ -64,12 +68,12 @@ dependencies { // 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-alpha01' + implementation 'androidx.appcompat:appcompat:1.1.0-alpha03' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 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' @@ -94,5 +98,7 @@ dependencies { implementation 'io.reactivex.rxjava2:rxjava:2.2.0' implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' - + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0" + //implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5" } \ No newline at end of file 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 743b1bbecc..5a7f56b874 100644 --- a/app/src/main/java/com/tangem/ui/activity/MainActivity.kt +++ b/app/src/main/java/com/tangem/ui/activity/MainActivity.kt @@ -1,3 +1,5 @@ +@file:Suppress("ObsoleteExperimentalCoroutines") + package com.tangem.ui.activity import android.Manifest @@ -25,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 @@ -48,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 { @@ -70,7 +81,8 @@ 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 readCardInfoTask: ReadCardInfoTask? = null + private var task: CustomReadCardTask? = null private var onNfcReaderCallback: NfcAdapter.ReaderCallback? = null override fun onNewIntent(intent: Intent?) { @@ -234,8 +246,77 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco lastTag = tag - readCardInfoTask = ReadCardInfoTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this) - readCardInfoTask?.start() +// readCardInfoTask = ReadCardInfoTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this) + //readCardInfoTask?.start() + val tx: OneTouchSignTask.TransactionToSign = object : OneTouchSignTask.TransactionToSign { + var txToSign: SignTask.TransactionToSign?=null + var ctx: TangemContext?=null + var coinEngine: CoinEngine?=null + val amount: CoinEngine.Amount=CoinEngine.Amount(10,"") + val fee: CoinEngine.Amount=CoinEngine.Amount(1,"") + val incFee: Boolean = true + val targetAddress: String = "aaaa" + + 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==null ) ctx= TangemContext(card) + if( coinEngine==null ) { + coinEngine=CoinEngineFactory.createCardano(ctx!!)!! + coinEngine!!.defineWallet() + runBlocking { requestBalanceAndUnspentTransactions() } + Log.e(TAG, "requestBalanceAndUnspentTransactions completed") + } + if( txToSign==null ) txToSign=coinEngine!!.constructTransaction(amount,fee,true, targetAddress) + } + + override fun isSigningOnCardSupported(card: TangemCard?): Boolean { + initData(card!!) + return (card?.blockchainID==Blockchain.Cardano.id)and(txToSign!!.isSigningMethodSupported(card?.signingMethod)) + } + + 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!!) + 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: Exception) { e.printStackTrace() nfcManager.notifyReadResult(false) @@ -249,12 +330,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() } @@ -267,7 +348,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) @@ -333,7 +414,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco } override fun onReadCancel() { - readCardInfoTask = null + task = null ReadCardInfoTask.resetLastReadInfo() rlProgressBar.postDelayed({ try { 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..d43c4a12ff --- /dev/null +++ b/card-common/src/main/java/com/tangem/card_common/tasks/OneTouchSignTask.java @@ -0,0 +1,90 @@ +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); + + 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 (mCard.getPauseBeforePIN2() > 0) { + mNotifications.onReadWait(mCard.getPauseBeforePIN2()); + } + + if (!transactionToSign.isSigningOnCardSupported(mCard)) { + throw new CardProtocol.TangemException("Signing method isn't supported!"); + } + + TLVList signResult; + switch (mCard.getSigningMethod()) { + case Sign_Hash: + signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), transactionToSign.getHashesToSign(mCard), null, null, null); + break; + case Sign_Hash_Validated_By_Issuer: + case 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); + break; + case Sign_Raw: + signResult = protocol.run_SignRaw(pinsProvider.getPIN2(), transactionToSign.getHashAlgToSign(mCard), transactionToSign.getRawDataToSign(mCard), null, null, null); + break; + case Sign_Raw_Validated_By_Issuer: + case 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); + break; + default: + 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/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'