Updated on 2026-08-14
This commit is contained in:
commit
73c73f12ae
49 changed files with 2047 additions and 74 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
44
app/src/main/java/com/tangem/data/dp/PrefsManager.kt
Normal file
44
app/src/main/java/com/tangem/data/dp/PrefsManager.kt
Normal file
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<CborBuilder> txArray = cborBuilder.addArray();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,298 +0,0 @@
|
|||
package com.tangem.ui.activity
|
||||
|
||||
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.data.Blockchain
|
||||
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 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
|
||||
|
||||
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.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.INVISIBLE
|
||||
}
|
||||
|
||||
// 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.create(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_)
|
||||
} else
|
||||
Toast.makeText(this, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
val coinEngine = CoinEngineFactory.create(ctx)
|
||||
|
||||
progressBar.visibility = View.VISIBLE
|
||||
|
||||
coinEngine!!.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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.*
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,178 +0,0 @@
|
|||
package com.tangem.ui.activity
|
||||
|
||||
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.View
|
||||
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.data.Blockchain
|
||||
import com.tangem.di.Navigator
|
||||
import com.tangem.domain.wallet.CoinEngineFactory
|
||||
import com.tangem.domain.wallet.TangemContext
|
||||
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 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
|
||||
|
||||
private lateinit var ctx: TangemContext
|
||||
private lateinit var nfcManager: NfcManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_prepare_transaction)
|
||||
|
||||
App.navigatorComponent.inject(this)
|
||||
|
||||
nfcManager = NfcManager(this, this)
|
||||
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
|
||||
|
||||
ctx = TangemContext.loadFromBundle(this, intent.extras)
|
||||
|
||||
tvCardID.text = ctx.card?.cidDescription
|
||||
val engine = CoinEngineFactory.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
|
||||
|
||||
if (!engine.allowSelectFeeInclusion()) {
|
||||
rgIncFee.visibility = View.INVISIBLE
|
||||
} else {
|
||||
rgIncFee.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (ctx.card!!.remainingSignatures < 2)
|
||||
etAmount.isEnabled = false
|
||||
|
||||
tvCurrency.text = engine.balance.currency
|
||||
etAmount.setText(engine.balance.toValueString())
|
||||
|
||||
// limit number of symbols after comma
|
||||
etAmount.filters = engine.amountInputFilters
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
val engine1 = CoinEngineFactory.create(ctx)
|
||||
val strAmount: String = etAmount.text.toString().replace(",", ".")
|
||||
val amount = engine1!!.convertToAmount(etAmount.text.toString(), tvCurrency.text.toString())
|
||||
|
||||
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 (!engine1.validateAddress(etWallet.text.toString())) {
|
||||
etWallet.error = getString(R.string.incorrect_destination_wallet_address)
|
||||
return@setOnClickListener
|
||||
} else
|
||||
etWallet.error = null
|
||||
|
||||
if (etWallet.text.toString() == ctx.coinData!!.wallet) {
|
||||
etWallet.error = getString(R.string.destination_wallet_address_equal_source_address)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (!etAmount.error.isNullOrEmpty() || !etWallet.error.isNullOrEmpty()) {
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
val intent = Intent(baseContext, ConfirmTransactionActivity::class.java)
|
||||
ctx.saveToIntent(intent)
|
||||
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__)
|
||||
}
|
||||
|
||||
ivCamera.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR) }
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.*
|
||||
|
|
|
|||
|
|
@ -1,301 +0,0 @@
|
|||
package com.tangem.ui.activity
|
||||
|
||||
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_common.reader.CardProtocol
|
||||
import com.tangem.card_common.tasks.SignTask
|
||||
import com.tangem.card_common.util.Util
|
||||
import com.tangem.domain.wallet.CoinEngine
|
||||
import com.tangem.domain.wallet.CoinEngineFactory
|
||||
import com.tangem.domain.wallet.TangemContext
|
||||
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.activity_sign_transaction.*
|
||||
import kotlinx.android.synthetic.main.layout_progress_horizontal.*
|
||||
import kotlinx.android.synthetic.main.layout_touch_card.*
|
||||
import com.tangem.card_android.data.asBundle
|
||||
import com.tangem.card_android.data.EXTRA_TANGEM_CARD
|
||||
import com.tangem.card_android.data.EXTRA_TANGEM_CARD_UID
|
||||
|
||||
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 signTransactionTask: SignTask? = 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() {
|
||||
signTransactionTask?.cancel(true)
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
public override fun onStop() {
|
||||
signTransactionTask?.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)
|
||||
val uid = tag.id
|
||||
val sUID = Util.byteArrayToHexString(uid)
|
||||
|
||||
if (sUID == ctx.card.uid) {
|
||||
if (lastReadSuccess)
|
||||
isoDep.timeout = ctx.card.pauseBeforePIN2 + 5000
|
||||
else
|
||||
isoDep.timeout = ctx.card.pauseBeforePIN2 + 65000
|
||||
|
||||
val coinEngine = CoinEngineFactory.create(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 transactionToSign = coinEngine?.constructTransaction(amount, fee, isIncludeFee, outAddressStr)
|
||||
|
||||
signTransactionTask = SignTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this, transactionToSign)
|
||||
signTransactionTask?.start()
|
||||
} else
|
||||
nfcManager.ignoreTag(isoDep.tag)
|
||||
|
||||
} 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?) {
|
||||
signTransactionTask = 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() {
|
||||
signTransactionTask = null
|
||||
|
||||
progressBar?.postDelayed({
|
||||
try {
|
||||
progressBar?.progress = 0
|
||||
progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY)
|
||||
progressBar?.visibility = View.INVISIBLE
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
// private val waitSecurityDelayDialogNew = WaitSecurityDelayDialogNew()
|
||||
|
||||
override fun onReadBeforeRequest(timeout: Int) {
|
||||
LOG.i(TAG, "onReadBeforeRequest timeout $timeout")
|
||||
WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout)
|
||||
|
||||
// if (!waitSecurityDelayDialogNew.isAdded)
|
||||
// waitSecurityDelayDialogNew.show(supportFragmentManager, WaitSecurityDelayDialogNew.TAG)
|
||||
|
||||
|
||||
// val readBeforeRequest = ReadBeforeRequest()
|
||||
// readBeforeRequest.timeout = timeout
|
||||
// EventBus.getDefault().post(readBeforeRequest)
|
||||
}
|
||||
|
||||
override fun onReadAfterRequest() {
|
||||
LOG.i(TAG, "onReadAfterRequest")
|
||||
WaitSecurityDelayDialog.onReadAfterRequest(this)
|
||||
|
||||
// val readAfterRequest = ReadAfterRequest()
|
||||
// EventBus.getDefault().post(readAfterRequest)
|
||||
}
|
||||
|
||||
override fun onReadWait(msec: Int) {
|
||||
LOG.i(TAG, "onReadWait msec $msec")
|
||||
WaitSecurityDelayDialog.onReadWait(this, msec)
|
||||
|
||||
// val readWait = ReadWait()
|
||||
// readWait.msec = msec
|
||||
// EventBus.getDefault().post(readWait)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue