diff --git a/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java b/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java index 87c4cedb6c..a3267d633a 100644 --- a/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java +++ b/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java @@ -42,6 +42,17 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.observers.DefaultObserver; import io.reactivex.schedulers.Schedulers; +/** + * Request processor for Electrum Api + * Every request live cycle: + * 1. In application create request and call {@link ServerApiElectrum}.electrumRequestData(..) + * 2. Try send every request for max 4 times, + * 3. If all 4 times fail call DefaultObserver.onError (defined in .electrumRequestData(..)) and than + * {@link ElectrumRequestDataListener}.onFail(...) callback + * Error can be acquired with {@link ElectrumRequest}.getError() method + * 4. If request network communication finished successfully then call DefaultObserver.onComplete (defined in .electrumRequestData) and than + * {@link ElectrumRequestDataListener}.onSuccess(...) callback + */ public class ServerApiElectrum { private static String TAG = ServerApiElectrum.class.getSimpleName(); @@ -60,16 +71,37 @@ public class ServerApiElectrum { return requestsCount <= 0; } + /** + * Interface for notification every request result + */ public interface ElectrumRequestDataListener { - void onSuccess(ElectrumRequest electrumRequest); + /** + * Notify that request processing was successful + * @param electrumRequest - processed request containing received answer {@see electrumRequest.getAnswer() method} + */ + void onSuccess(ElectrumRequest electrumRequest); + /** + * Notify that request processing was successful + * @param electrumRequest - processed request containing occurred error {@see electrumRequest.getError() method} + */ void onFail(ElectrumRequest electrumRequest); } + /** + * Set notificaion listener + * @param listener + */ public void setElectrumRequestData(ElectrumRequestDataListener listener) { electrumRequestDataListener = listener; } + + /** + * Start process request + * @param ctx + * @param electrumRequest + */ public void electrumRequestData(TangemContext ctx, ElectrumRequest electrumRequest) { requestsCount++; Log.i(TAG, String.format("New request[%d]: %s", requestsCount,electrumRequest.getMethod())); @@ -111,6 +143,9 @@ public class ServerApiElectrum { electrumRequestDataListener.onFail(electrumRequest); } + /** + * Called after completion request processing + */ @Override public void onComplete() { requestsCount--; diff --git a/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java b/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java index f6a104c7ca..83b0f987bf 100644 --- a/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java @@ -295,7 +295,7 @@ public abstract class CoinEngine { /** * Notification that the all requests in sequence completed * Call after a last request completed - * If occurred error return in ctx.error + * If occurred error return in {@link TangemContext} {@see TangemContext.getError()} * * @param success -* */ @@ -319,12 +319,26 @@ public abstract class CoinEngine { /** * Start sequence of request to blockchain nodes needed to get balance and other information (for example unspent transaction) needed to * show current state of wallet and prepare new withdrawal transaction + * Save result in {@link CoinData} + * If occurred error can be get at onComplete callback in {@link TangemContext}.getError() * @param blockchainRequestsCallbacks - notifications - * @throws Exception + * @throws Exception if something goes wrong */ public abstract void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) throws Exception; + /** + * Start sequence of request to blockchain nodes needed to get fee amount for a new transaction + * Save result in {@link CoinData} minFee, maxFee, normalFee + * @param blockchainRequestsCallbacks - notifications + * @throws Exception if something goes wrong + */ public abstract void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception; + /** + * Start sequence of request to blockchain nodes needed to send new transaction + * If occurred error can be get at onComplete callback in {@link TangemContext}.getError() + * @param blockchainRequestsCallbacks - notifications + * @throws Exception if something goes wrong + */ public abstract void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) throws Exception; } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java b/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java index fe687057d6..847603aa23 100644 --- a/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java +++ b/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java @@ -1,6 +1,7 @@ package com.tangem.domain.wallet.token; import android.net.Uri; +import android.os.Bundle; import android.text.InputFilter; import android.util.Log; @@ -13,6 +14,7 @@ import com.tangem.domain.wallet.CoinEngine; import com.tangem.domain.wallet.ECDSASignatureETH; import com.tangem.domain.wallet.EthTransaction; import com.tangem.domain.wallet.Keccak256; +import com.tangem.domain.wallet.eth.EthData; import com.tangem.tangemcard.data.TangemCard; import com.tangem.domain.wallet.TangemContext; import com.tangem.domain.wallet.BTCUtils; @@ -45,6 +47,13 @@ public class TokenEngine extends CoinEngine { ctx.setCoinData(coinData); } else if (ctx.getCoinData() instanceof TokenData) { coinData = (TokenData) ctx.getCoinData(); + } else if (ctx.getCoinData() instanceof EthData) { + // special case with receive card data substitution from server at the moment + Bundle B=new Bundle(); + ctx.getCoinData().saveToBundle(B); + coinData = new TokenData(); + coinData.loadFromBundle(B); + ctx.setCoinData(coinData); } else { throw new Exception("Invalid type of Blockchain data for TokenEngine"); } diff --git a/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt b/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt index 626a410857..96cd64cf83 100644 --- a/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt +++ b/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt @@ -21,25 +21,28 @@ import android.view.ViewGroup import android.widget.Toast import com.tangem.App import com.tangem.Constant +import com.tangem.data.Blockchain import com.tangem.data.network.ServerApiCommon -import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo -import com.tangem.tangemcard.tasks.VerifyCardTask -import com.tangem.tangemcard.reader.CardProtocol -import com.tangem.tangemcard.android.reader.NfcManager -import com.tangem.domain.wallet.* +import com.tangem.domain.wallet.BalanceValidator +import com.tangem.domain.wallet.CoinEngine +import com.tangem.domain.wallet.CoinEngineFactory +import com.tangem.domain.wallet.TangemContext import com.tangem.presentation.activity.* import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog import com.tangem.presentation.dialog.PINSwapWarningDialog import com.tangem.presentation.dialog.ShowQRCodeDialog import com.tangem.presentation.dialog.WaitSecurityDelayDialog -import com.tangem.data.Blockchain +import com.tangem.tangemcard.android.reader.NfcManager import com.tangem.tangemcard.android.reader.NfcReader import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD_UID import com.tangem.tangemcard.data.TangemCard import com.tangem.tangemcard.data.loadFromBundle +import com.tangem.tangemcard.reader.CardProtocol +import com.tangem.tangemcard.tasks.VerifyCardTask import com.tangem.tangemcard.util.Util import com.tangem.tangemserver.android.ServerApiTangem +import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo import com.tangem.util.UtilHelper import com.tangem.wallet.R import kotlinx.android.synthetic.main.fr_loaded_wallet.* @@ -108,10 +111,6 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific btnExtract.isEnabled = false btnExtract.backgroundTintList = inactiveColor - refresh() - - startVerify(lastTag) - tvWallet.text = ctx.coinData.wallet // set listeners @@ -406,6 +405,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific val cardVerifyAndGetInfoListener: ServerApiTangem.CardVerifyAndGetInfoListener = object : ServerApiTangem.CardVerifyAndGetInfoListener { override fun onSuccess(cardVerifyAndGetArtworkResponse: CardVerifyAndGetInfo.Response?) { Log.i(TAG,"cardVerifyAndGetInfoListener onSuccess") + if( activity==null || !UtilHelper.isOnline(activity!!)) return + val result = cardVerifyAndGetArtworkResponse?.results!![0] if (result.error != null) { ctx.card!!.isOnlineVerified = false @@ -413,8 +414,9 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific } ctx.card!!.isOnlineVerified = result.passed -// if (requestCounter == 0) + requestCounter-- +// if (requestCounter == 0) updateViews() if (!result.passed) return @@ -423,13 +425,6 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific Log.w(TAG, "Batch ${result.batch} info changed to '$result'") ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!)) App.localStorage.applySubstitution(ctx.card!!) - //todo - check this is not need after refactoring -// if (ctx.blockchain == Blockchain.Token || ctx.blockchain == Blockchain.Ethereum) { -// ctx.card!!.setBlockchainIDFromCard(Blockchain.Ethereum.id) - - //ctx.blockchain=Blockchain.Ethereum - //engine=engine!!.swithToOtherEngine(Blockchain.Ethereum) -// } refresh() } if (result.artwork != null && App.localStorage.checkNeedUpdateArtwork(result.artwork)) { @@ -443,6 +438,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific override fun onFail(message: String?) { Log.i(TAG,"cardVerifyAndGetInfoListener onFail") + if( activity==null || !UtilHelper.isOnline(activity!!)) return requestCounter-- updateViews() } @@ -453,6 +449,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific val artworkListener: ServerApiTangem.ArtworkListener = object : ServerApiTangem.ArtworkListener { override fun onSuccess(artworkId: String?, inputStream: InputStream?, updateDate: Date?) { Log.i(TAG,"artworkListener onSuccess") + if( activity==null || !UtilHelper.isOnline(activity!!)) return App.localStorage.updateArtwork(artworkId!!, inputStream!!, updateDate!!) requestCounter-- ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!)) @@ -461,6 +458,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific override fun onFail(message: String?) { Log.i(TAG,"artworkListener onFail") + if( activity==null || !UtilHelper.isOnline(activity!!)) return requestCounter-- updateViews() } @@ -469,27 +467,32 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific // request rate info listener serverApiCommon.setRateInfoData { + if( activity==null || !UtilHelper.isOnline(activity!!)) return@setRateInfoData val rate = it.priceUsd.toFloat() ctx.coinData!!.rate = rate ctx.coinData!!.rateAlter = rate } + + refresh() + + startVerify(lastTag) } override fun onResume() { super.onResume() - nfcManager!!.onResume() + nfcManager.onResume() } override fun onPause() { super.onPause() - nfcManager!!.onPause() + nfcManager.onPause() if (timerRepeatRefresh != null) timerRepeatRefresh!!.cancel() } override fun onStop() { super.onStop() - nfcManager!!.onStop() + nfcManager.onStop() } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -722,6 +725,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific } fun updateViews() { + if( activity==null || !UtilHelper.isOnline(activity!!)) return + if (timerHideErrorAndMessage != null) { timerHideErrorAndMessage!!.cancel() timerHideErrorAndMessage = null @@ -780,7 +785,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific } else tvBlockchain.text = ctx.blockchainName - if (engine.hasBalanceInfo()) { + if (requestCounter==0 && engine.hasBalanceInfo()) { btnExtract.isEnabled = true btnExtract.backgroundTintList = activeColor } else { @@ -815,6 +820,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific object : CoinEngine.BlockchainRequestsCallbacks { override fun onComplete(success: Boolean) { Log.i(TAG, "requestBalanceAndUnspentTransactions onComplete: "+success.toString()+", request counter "+requestCounter.toString()) + if( activity==null || !UtilHelper.isOnline(activity!!)) return requestCounter-- if(! success) { @@ -824,6 +830,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific } override fun onProgress() { + if( activity==null || !UtilHelper.isOnline(activity!!)) return Log.i(TAG, "requestBalanceAndUnspentTransactions onProgress") updateViews() } @@ -864,7 +871,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific // Token else if (ctx.blockchain == Blockchain.Token) { - val engine = CoinEngineFactory.create(ctx) +// val engine = CoinEngineFactory.create(ctx) // requestInfura(ServerApiInfura.INFURA_ETH_CALL, (engine as TokenEngine).getContractAddress(ctx.card)) requestRateInfo("ethereum") } @@ -923,7 +930,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific val sUID = Util.byteArrayToHexString(uid) if (ctx.card.uid != sUID) { // Log.d(TAG, "Invalid UID: $sUID") - nfcManager!!.ignoreTag(isoDep.tag) + nfcManager.ignoreTag(isoDep.tag) return } else { // Log.v(TAG, "UID: $sUID") diff --git a/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt b/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt index 08ce72d5ab..6067ad6f26 100644 --- a/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt +++ b/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt @@ -35,7 +35,6 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback { companion object { val TAG: String = VerifyCard::class.java.simpleName - } private var nfcManager: NfcManager? = null diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/CardDataSubstitutionProvider.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/CardDataSubstitutionProvider.java index fd8c23e624..ceaf756749 100644 --- a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/CardDataSubstitutionProvider.java +++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/CardDataSubstitutionProvider.java @@ -2,6 +2,11 @@ package com.tangem.tangemcard.data.external; import com.tangem.tangemcard.data.TangemCard; + +/** + * This interface provide method to make substitution of read card data (token symbol, contract address) + * if they was unknown when the card was produced + */ public interface CardDataSubstitutionProvider { void applySubstitution(TangemCard card); } diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/FirmwaresDigestsProvider.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/FirmwaresDigestsProvider.java index 6ee6a58069..86e8ba4175 100644 --- a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/FirmwaresDigestsProvider.java +++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/FirmwaresDigestsProvider.java @@ -1,5 +1,9 @@ package com.tangem.tangemcard.data.external; +/** + * This interfaces provide function to randomly select parameters to run one VerifyCode command, check answer and + * state that card is genuine or not + */ public interface FirmwaresDigestsProvider { VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion); diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/PINsProvider.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/PINsProvider.java index 0db22fbbfb..05cabc54af 100644 --- a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/PINsProvider.java +++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/PINsProvider.java @@ -2,10 +2,29 @@ package com.tangem.tangemcard.data.external; import java.util.List; +/** + * Interface of PINsProvider - object that know some list of PINs (used when start first time read), PIN2 (used for protected operation) and store last used PIN + * to use it in following operations + */ public interface PINsProvider { + + /** + * @return list of known PINs + * This PINs used when start reading of card + * When start reading a PINs from this list used sequential in search PIN algorithm until right PIN found + */ + List getPINs(); + + /** + * @return PIN2 for protected operations + */ String getPIN2(); + + /** + * Call after successful first time reading of card to store founded PIN (normally this PIN must be returned in next time {@see getPINs} at first position) + * @param pin + */ void setLastUsedPIN(String pin); - List getPINs(); }