Updated on 2026-08-14

This commit is contained in:
Tangem 2019-02-27 22:54:37 +03:00
parent 449840473a
commit 64ddaa4541
63 changed files with 128 additions and 164 deletions

View file

@ -0,0 +1,296 @@
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.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.cardandroid.data.loadFromBundle
import com.tangem.cardcommon.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.*
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("UID") && data.extras!!.containsKey("Card")) {
val updatedCard = TangemCard(data.getStringExtra("UID"))
updatedCard.loadFromBundle(data.getBundleExtra("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("message", message)
setResult(errorCode, intent)
finish()
}
}

View file

@ -0,0 +1,212 @@
package com.tangem.ui.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.nfc.tech.IsoDep
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.tangem.App
import com.tangem.Constant
import com.tangem.domain.wallet.TangemContext
import com.tangem.ui.dialog.NoExtendedLengthSupportDialog
import com.tangem.ui.dialog.WaitSecurityDelayDialog
import com.tangem.cardandroid.android.nfc.NfcDeviceAntennaLocation
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.cardandroid.android.reader.NfcReader
import com.tangem.cardandroid.data.asBundle
import com.tangem.cardcommon.reader.CardProtocol
import com.tangem.cardcommon.tasks.CreateNewWalletTask
import com.tangem.cardcommon.util.Util
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_create_new_wallet.*
import kotlinx.android.synthetic.main.layout_progress_horizontal.*
import kotlinx.android.synthetic.main.layout_touch_card.*
class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications {
companion object {
fun callingIntent(context: Context, ctx: TangemContext): Intent {
val intent = Intent(context, CreateNewWalletActivity::class.java)
intent.putExtra("UID", ctx.card!!.uid)
intent.putExtra("Card", ctx.card!!.asBundle)
return intent
}
}
private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation
private var createNewWalletTask: CreateNewWalletTask? = null
private var lastReadSuccess = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_new_wallet)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
ctx = TangemContext.loadFromBundle(this, intent.extras)
// init NFC Antenna
nfcDeviceAntenna = NfcDeviceAntennaLocation(this, ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc)
nfcDeviceAntenna.init()
tvCardId.text = ctx.card!!.cidDescription
progressBar.progressTintList = ColorStateList.valueOf(Color.DKGRAY)
progressBar.visibility = View.INVISIBLE
}
override fun onTagDiscovered(tag: Tag) {
try {
// get IsoDep handle and run cardReader thread
val isoDep = IsoDep.get(tag)
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
// Log.v(TAG, "UID: " + sUID);
if (sUID == ctx.card!!.uid) {
if (lastReadSuccess)
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 5000
else
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 65000
createNewWalletTask = CreateNewWalletTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
createNewWalletTask!!.start()
} else {
// Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + mCard.getUID() + ")");
nfcManager.ignoreTag(isoDep.tag)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
public override fun onPause() {
createNewWalletTask?.cancel(true)
super.onPause()
}
override fun onReadStart(cardProtocol: CardProtocol) {
rlProgressBar?.post { rlProgressBar.visibility = View.VISIBLE }
progressBar?.post {
progressBar?.visibility = View.VISIBLE
progressBar?.progress = 5
}
}
override fun onReadFinish(cardProtocol: CardProtocol?) {
createNewWalletTask = 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)
val intent = Intent()
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card.asBundle)
setResult(Activity.RESULT_OK, intent)
finish()
}
} else {
lastReadSuccess = false
if (cardProtocol.error is CardProtocol.TangemException_InvalidPIN) {
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("message", "Cannot create wallet. Make sure you enter correct PIN2!")
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card!!.asBundle)
setResult(Constant.RESULT_INVALID_PIN, intent)
finish()
} catch (e: Exception) {
e.printStackTrace()
}
}, 500)
} else {
progressBar!!.post {
if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) {
if (!NoExtendedLengthSupportDialog.allReadyShowed) {
NoExtendedLengthSupportDialog().show(supportFragmentManager, NoExtendedLengthSupportDialog.TAG)
}
} else {
Toast.makeText(baseContext, R.string.try_to_scan_again, Toast.LENGTH_SHORT).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 onReadProgress(protocol: CardProtocol, progress: Int) {
progressBar?.post { progressBar?.progress = progress }
}
override fun onReadCancel() {
createNewWalletTask = 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 onReadWait(msec: Int) {
WaitSecurityDelayDialog.onReadWait(this, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout)
}
override fun onReadAfterRequest() {
WaitSecurityDelayDialog.onReadAfterRequest(this)
}
}

View file

@ -0,0 +1,257 @@
package com.tangem.ui.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.nfc.tech.IsoDep
import android.os.Build
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.text.Html
import android.view.View
import android.widget.Toast
import com.tangem.App
import com.tangem.Constant
import com.tangem.di.Navigator
import com.tangem.domain.wallet.TangemContext
import com.tangem.ui.dialog.NoExtendedLengthSupportDialog
import com.tangem.ui.dialog.WaitSecurityDelayDialog
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.cardandroid.android.reader.NfcReader
import com.tangem.cardandroid.data.asBundle
import com.tangem.cardandroid.data.loadFromBundle
import com.tangem.cardcommon.data.TangemCard
import com.tangem.cardcommon.reader.CardProtocol
import com.tangem.cardcommon.tasks.VerifyCardTask
import com.tangem.cardcommon.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.*
import kotlinx.android.synthetic.main.layout_tangem_card.*
import javax.inject.Inject
class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications {
companion object {
val TAG: String = EmptyWalletActivity::class.java.simpleName
fun callingIntent(context: Context, ctx: TangemContext): Intent {
val intent = Intent(context, EmptyWalletActivity::class.java)
ctx.saveToIntent(intent)
return intent
}
}
@Inject
internal lateinit var navigator: Navigator
private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
private var lastReadSuccess = true
private var verifyCardTask: VerifyCardTask? = null
private var requestPIN2Count = 0
private var cardProtocol: CardProtocol? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_empty_wallet)
App.navigatorComponent?.inject(this)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
ctx = TangemContext.loadFromBundle(this, intent.extras)
tvIssuer.text = ctx.card!!.issuerDescription
if (ctx.card!!.tokenSymbol.length > 1) {
@Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
Html.fromHtml(ctx.blockchainName, Html.FROM_HTML_MODE_LEGACY)
else
Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
} else
tvBlockchain.text = ctx.blockchainName
tvCardID.text = ctx.card!!.cidDescription
ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card))
// set listeners
btnNewWallet.setOnClickListener {
requestPIN2Count = 0
val intent = Intent(baseContext, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
intent.putExtra("UID", ctx.card!!.uid)
intent.putExtra("Card", ctx.card!!.asBundle)
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2)
}
btnDetails.setOnClickListener {
if (cardProtocol != null)
navigator.showVerifyCard(this, ctx)
else
UtilHelper.showSingleToast(this, getString(R.string.need_attach_card_again))
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == Constant.REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
data.putExtra("modification", "updateAndViewCard")
data.putExtra("updateDelay", 0)
setResult(Activity.RESULT_OK, data)
}
finish()
} else {
if (data != null && data.extras!!.containsKey("UID") && data.extras!!.containsKey("Card")) {
val updatedCard = TangemCard(data.getStringExtra("UID"))
updatedCard.loadFromBundle(data.getBundleExtra("Card"))
ctx.card = updatedCard
}
if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++
val intent = Intent(baseContext, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
intent.putExtra("UID", ctx.card!!.uid)
intent.putExtra("Card", ctx.card!!.asBundle)
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) {
navigator.showCreateNewWallet(this, ctx)
}
}
}
override fun onTagDiscovered(tag: Tag) {
try {
val isoDep = IsoDep.get(tag)
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
if (ctx.card!!.uid != sUID) {
LOG.d(TAG, "Invalid UID: $sUID")
nfcManager.ignoreTag(isoDep.tag)
return
} else {
LOG.d(TAG, "UID: $sUID")
}
if (lastReadSuccess)
isoDep.timeout = 1000
else
isoDep.timeout = 65000
verifyCardTask = VerifyCardTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, App.firmwaresStorage, this)
verifyCardTask?.start()
} 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 onReadFinish(cardProtocol: CardProtocol?) {
verifyCardTask = 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)
this.cardProtocol = cardProtocol
}
} else {
// remove last UIDs because of error and no card read
progressBar?.post {
lastReadSuccess = false
if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) {
if (!NoExtendedLengthSupportDialog.allReadyShowed)
NoExtendedLengthSupportDialog().show(supportFragmentManager, NoExtendedLengthSupportDialog.TAG)
} else
Toast.makeText(this@EmptyWalletActivity, 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 onReadProgress(protocol: CardProtocol, progress: Int) {
progressBar?.post { progressBar!!.progress = progress }
}
override fun onReadCancel() {
verifyCardTask = null
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 onReadWait(msec: Int) {
WaitSecurityDelayDialog.onReadWait(this, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout)
}
override fun onReadAfterRequest() {
WaitSecurityDelayDialog.onReadAfterRequest(this)
}
}

View file

@ -0,0 +1,46 @@
package com.tangem.ui.activity
import android.content.Context
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
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.ui.fragment.LoadedWallet
import com.tangem.wallet.R
import javax.inject.Inject
class LoadedWalletActivity : AppCompatActivity() {
@Inject
lateinit var navigator: Navigator
companion object {
fun callingIntent(context: Context, lastTag: Tag, ctx: TangemContext): Intent {
val intent = Intent(context, LoadedWalletActivity::class.java)
intent.putExtra(Constant.EXTRA_LAST_DISCOVERED_TAG, lastTag)
ctx.saveToIntent(intent)
return intent
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_loaded_wallet)
App.navigatorComponent?.inject(this)
if (intent.extras!!.containsKey(NfcAdapter.EXTRA_TAG)) {
val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
if (tag != null) {
val fragment = supportFragmentManager.findFragmentById(R.id.loaded_wallet_fragment) as LoadedWallet
fragment.onTagDiscovered(tag)
}
}
}
}

View file

@ -0,0 +1,57 @@
package com.tangem.ui.activity
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.tangem.App
import com.tangem.Constant
import com.tangem.di.Navigator
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_logo.*
import javax.inject.Inject
class LogoActivity : AppCompatActivity() {
companion object {
fun callingIntent(context: Context, autoHide: Boolean): Intent {
val intent = Intent(context, LogoActivity::class.java)
intent.putExtra(Constant.EXTRA_AUTO_HIDE, autoHide)
return intent
}
}
@Inject
internal lateinit var navigator: Navigator
private val hideRunnable = Runnable { this.hide() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_logo)
App.navigatorComponent?.inject(this)
ivLogo.setOnClickListener { hide() }
}
@SuppressLint("SetTextI18n")
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
if (BuildConfig.DEBUG)
tvAppVersion.text = "BETA v." + BuildConfig.VERSION_NAME + "\n" + "dev" + "\n" + "build " + BuildConfig.VERSION_CODE
else
tvAppVersion.text = "BETA v." + BuildConfig.VERSION_NAME
if (intent.getBooleanExtra(Constant.EXTRA_AUTO_HIDE, true))
ivLogo.postDelayed(hideRunnable, Constant.MILLIS_AUTO_HIDE.toLong())
}
private fun hide() {
navigator.showMain(this)
finish()
}
}

View file

@ -0,0 +1,375 @@
package com.tangem.ui.activity
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.nfc.tech.IsoDep
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import com.scottyab.rootbeer.RootBeer
import com.tangem.App
import com.tangem.Constant
import com.tangem.data.Logger
import com.tangem.data.network.ServerApiCommon
import com.tangem.di.Navigator
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.ui.dialog.NoExtendedLengthSupportDialog
import com.tangem.ui.dialog.RootFoundDialog
import com.tangem.ui.dialog.WaitSecurityDelayDialog
import com.tangem.cardandroid.android.nfc.NfcDeviceAntennaLocation
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.cardandroid.android.reader.NfcReader
import com.tangem.cardandroid.data.loadFromBundle
import com.tangem.cardandroid.data.saveToBundle
import com.tangem.cardcommon.data.TangemCard
import com.tangem.cardcommon.reader.CardProtocol
import com.tangem.cardcommon.tasks.ReadCardInfoTask
import com.tangem.util.CommonUtil
import com.tangem.util.LOG
import com.tangem.util.PhoneUtility
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.layout_touch_card.*
import java.io.File
import java.util.*
import javax.inject.Inject
class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications, PopupMenu.OnMenuItemClickListener {
companion object {
val TAG: String = MainActivity::class.java.simpleName
fun callingIntent(context: Context) = Intent(context, MainActivity::class.java)
}
@Inject
internal lateinit var navigator: Navigator
private lateinit var nfcManager: NfcManager
private var zipFile: File? = null
private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation
private var unsuccessReadCount = 0
private var lastTag: Tag? = null
private var readCardInfoTask: ReadCardInfoTask? = null
private var onNfcReaderCallback: NfcAdapter.ReaderCallback? = null
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action || NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action)) {
val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
if (tag != null && onNfcReaderCallback != null)
onNfcReaderCallback!!.onTagDiscovered(tag)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
App.navigatorComponent?.inject(this)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
verifyPermissions()
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
setNfcAdapterReaderCallback(this)
rippleBackgroundNfc.startRippleAnimation()
// init NFC Antenna
nfcDeviceAntenna = NfcDeviceAntennaLocation(this, ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc)
nfcDeviceAntenna.init()
// set phone name
if (nfcDeviceAntenna.fullName != "")
tvNFCHint.text = String.format(getString(R.string.scan_banknote), nfcDeviceAntenna.fullName)
else
tvNFCHint.text = String.format(getString(R.string.scan_banknote), getString(R.string.phone))
// NFC
val intent = intent
if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action || NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action)) {
val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
if (tag != null && onNfcReaderCallback != null) {
onNfcReaderCallback?.onTagDiscovered(tag)
}
}
// check if root device
val rootBeer = RootBeer(this)
if (rootBeer.isRootedWithoutBusyBoxCheck && !BuildConfig.DEBUG)
RootFoundDialog().show(supportFragmentManager, RootFoundDialog.TAG)
// set listeners
fab.setOnClickListener { showMenu(it) }
val apiHelper = ServerApiCommon()
apiHelper.setLastVersionListener { response ->
try {
if (response.isNullOrEmpty()) return@setLastVersionListener
val responseVersionName = response.trim(' ', '\n', '\r', '\t')
val responseBuildVersion = responseVersionName.split('.').last()
val appBuildVersion = BuildConfig.VERSION_NAME.split('.').last()
if (responseBuildVersion.toInt() > appBuildVersion.toInt()) Toast.makeText(this, "There is a new application version: $responseVersionName", Toast.LENGTH_LONG).show()
} catch (E: Exception) {
E.printStackTrace()
}
}
apiHelper.requestLastVersion()
}
private fun verifyPermissions() {
NfcManager.verifyPermissions(this)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
Log.e("QRScanActivity", "User hasn't granted permission to use camera")
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), Constant.REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
Constant.REQUEST_CODE_SEND_EMAIL -> {
if (zipFile != null) {
zipFile!!.delete()
zipFile = null
}
}
Constant.REQUEST_CODE_ENTER_PIN_ACTIVITY -> {
if (resultCode == Activity.RESULT_OK && lastTag != null)
onTagDiscovered(lastTag!!)
else
ReadCardInfoTask.resetLastReadInfo()
}
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun onMenuItemClick(item: MenuItem): Boolean {
return onOptionsItemSelected(item)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
if (BuildConfig.DEBUG) {
for (i in 0 until menu.size()) menu.getItem(i).isVisible = true
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
when (id) {
R.id.sendLogs -> {
var f: File? = null
try {
f = Logger.collectLogs(this)
if (f != null) {
LOG.e(TAG, String.format("Collect %d log bytes", f.length()))
CommonUtil.sendEmail(this, zipFile, TAG, "Logs", PhoneUtility.getDeviceInfo(), arrayOf(f))
} else {
LOG.e(TAG, "Can't create temporarily log file")
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
if (f != null && f.exists())
f.delete()
}
return true
}
R.id.managePIN -> {
navigator.showPinSave(this, false)
return true
}
R.id.managePIN2 -> {
navigator.showPinSave(this, true)
return true
}
R.id.about -> {
navigator.showLogo(this, false)
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onTagDiscovered(tag: Tag) {
try {
// get IsoDep handle and run cardReader thread
val isoDep = IsoDep.get(tag)
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
LOG.e(TAG, "setTimeout(" + (1000 + 3000 * unsuccessReadCount) + ")")
if (unsuccessReadCount < 2) {
isoDep.timeout = 2000 + 5000 * unsuccessReadCount
} else {
isoDep.timeout = 90000
}
lastTag = tag
readCardInfoTask = ReadCardInfoTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
readCardInfoTask?.start()
LOG.i(TAG, "onTagDiscovered " + Arrays.toString(tag.id))
} catch (e: Exception) {
e.printStackTrace()
nfcManager.notifyReadResult(false)
}
}
public override fun onResume() {
super.onResume()
nfcDeviceAntenna.animate()
ReadCardInfoTask.resetLastReadInfo()
}
public override fun onPause() {
readCardInfoTask?.cancel(true)
super.onPause()
}
public override fun onStop() {
readCardInfoTask?.cancel(true)
super.onStop()
}
override fun onReadStart(cardProtocol: CardProtocol) {
rlProgressBar.post { rlProgressBar.visibility = View.VISIBLE }
}
override fun onReadProgress(protocol: CardProtocol, progress: Int) {
}
override fun onReadFinish(cardProtocol: CardProtocol?) {
readCardInfoTask = null
if (cardProtocol != null) {
if (cardProtocol.error == null) {
nfcManager.notifyReadResult(true)
rlProgressBar.post {
rlProgressBar.visibility = View.GONE
// TODO - ??? remove save and load???
val cardInfo = Bundle()
cardInfo.putString("UID", cardProtocol.card.uid)
val bCard = Bundle()
cardProtocol.card.saveToBundle(bCard)
cardInfo.putBundle("Card", bCard)
val uid = cardInfo.getString("UID")
val card = TangemCard(uid)
cardInfo.getBundle("Card")?.let { card.loadFromBundle(it) }
val ctx = TangemContext(card)
when {
card.status == TangemCard.Status.Loaded -> lastTag?.let {
val engineCoin = CoinEngineFactory.create(ctx)
?: throw CardProtocol.TangemException("Can't create CoinEngine!")
engineCoin.defineWallet()
navigator.showLoadedWallet(this, it, ctx)
}
card.status == TangemCard.Status.Empty -> navigator.showEmptyWallet(this, ctx)
card.status == TangemCard.Status.Purged -> Toast.makeText(this, R.string.erased_wallet, Toast.LENGTH_SHORT).show()
card.status == TangemCard.Status.NotPersonalized -> Toast.makeText(this, R.string.not_personalized, Toast.LENGTH_SHORT).show()
else -> lastTag?.let { navigator.showLoadedWallet(this, it, ctx) }
}
}
} else {
// remove last UIDs because of error and no card read
rlProgressBar.post {
Toast.makeText(this, R.string.try_to_scan_again, Toast.LENGTH_SHORT).show()
unsuccessReadCount++
if (cardProtocol.error is CardProtocol.TangemException_InvalidPIN)
navigator.showPinRequest(this, PinRequestActivity.Mode.RequestPIN.toString())
else {
if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported)
if (!NoExtendedLengthSupportDialog.allReadyShowed)
NoExtendedLengthSupportDialog().show(supportFragmentManager, NoExtendedLengthSupportDialog.TAG)
lastTag = null
ReadCardInfoTask.resetLastReadInfo()
nfcManager.notifyReadResult(false)
}
}
}
}
rlProgressBar.postDelayed({
try {
rlProgressBar.visibility = View.GONE
} catch (e: Exception) {
e.printStackTrace()
}
}, 500)
}
override fun onReadCancel() {
readCardInfoTask = null
ReadCardInfoTask.resetLastReadInfo()
rlProgressBar.postDelayed({
try {
rlProgressBar.visibility = View.GONE
} catch (e: Exception) {
e.printStackTrace()
}
}, 500)
}
override fun onReadWait(msec: Int) {
WaitSecurityDelayDialog.onReadWait(Objects.requireNonNull(this), msec)
}
override fun onReadBeforeRequest(timeout: Int) {
WaitSecurityDelayDialog.onReadBeforeRequest(Objects.requireNonNull(this), timeout)
}
override fun onReadAfterRequest() {
WaitSecurityDelayDialog.onReadAfterRequest(Objects.requireNonNull(this))
}
private fun setNfcAdapterReaderCallback(callback: NfcAdapter.ReaderCallback) {
onNfcReaderCallback = callback
}
private fun showMenu(v: View) {
val popup = PopupMenu(this, v)
val inflater = popup.menuInflater
inflater.inflate(R.menu.menu_main, popup.menu)
if (BuildConfig.DEBUG) {
popup.menu.findItem(R.id.managePIN).isEnabled = true
popup.menu.findItem(R.id.managePIN2).isEnabled = true
popup.menu.findItem(R.id.sendLogs).isVisible = true
}
popup.setOnMenuItemClickListener(this)
popup.show()
}
}

View file

@ -0,0 +1,350 @@
package com.tangem.ui.activity
import android.Manifest
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Activity
import android.app.KeyguardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Build
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.appcompat.app.AppCompatActivity
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.widget.Button
import com.tangem.Constant
import com.tangem.data.fingerprint.StartFingerprintReaderTask
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.data.fingerprint.FingerprintHelper
import com.tangem.domain.wallet.TangemContext
import com.tangem.cardandroid.android.data.PINStorage
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.data.loadFromBundle
import com.tangem.cardandroid.data.EXTRA_TANGEM_CARD
import com.tangem.cardandroid.data.EXTRA_TANGEM_CARD_UID
import com.tangem.cardcommon.data.TangemCard
import com.tangem.util.LOG
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_request.*
import kotlinx.android.synthetic.main.layout_pin_buttons.*
import java.io.IOException
class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, FingerprintHelper.FingerprintHelperListener {
companion object {
val TAG: String = PinRequestActivity::class.java.simpleName
fun callingIntent(context: Activity, mode: String): Intent {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra(Constant.EXTRA_MODE, mode)
return intent
}
fun callingIntentRequestPin(context: Activity, mode: String, ctx: TangemContext, newPIN: String): Intent {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra(Constant.EXTRA_MODE, mode)
intent.putExtra(Constant.EXTRA_NEW_PIN, newPIN)
ctx.saveToIntent(intent)
return intent
}
fun callingIntentRequestPin2(context: Activity, mode: String, ctx: TangemContext, newPIN2: String): Intent {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra(Constant.EXTRA_MODE, mode)
intent.putExtra(Constant.EXTRA_NEW_PIN_2, newPIN2)
ctx.saveToIntent(intent)
return intent
}
fun callingIntentRequestPin2(context: Activity, mode: String, ctx: TangemContext): Intent {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra(Constant.EXTRA_MODE, mode)
ctx.saveToIntent(intent)
return intent
}
fun callingIntentConfirmPin(context: Activity, mode: String, newPIN: String): Intent {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra(Constant.EXTRA_MODE, mode)
intent.putExtra(Constant.EXTRA_NEW_PIN, newPIN)
return intent
}
fun callingIntentConfirmPin2(context: Activity, mode: String, newPIN2: String): Intent {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra(Constant.EXTRA_MODE, mode)
intent.putExtra(Constant.EXTRA_NEW_PIN_2, newPIN2)
return intent
}
}
private lateinit var nfcManager: NfcManager
lateinit var mode: Mode
private var allowFingerprint = false
var startFingerprintReaderTask: StartFingerprintReaderTask? = null
private var fingerprintManager: FingerprintManager? = null
private var fingerprintHelper: FingerprintHelper? = null
enum class Mode {
RequestPIN, RequestPIN2, RequestNewPIN, RequestNewPIN2, ConfirmNewPIN, ConfirmNewPIN2
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pin_request)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
mode = Mode.valueOf(intent.getStringExtra(Constant.EXTRA_MODE))
if (mode == Mode.RequestNewPIN)
if (PINStorage.haveEncryptedPIN()) {
allowFingerprint = true
tvPinPrompt.setText(R.string.enter_new_pin_or_use_fingerprint_scanner)
} else
tvPinPrompt.setText(R.string.enter_new_pin)
else if (mode == Mode.ConfirmNewPIN)
tvPinPrompt.setText(R.string.confirm_new_pin)
else if (mode == Mode.RequestPIN)
if (PINStorage.haveEncryptedPIN()) {
allowFingerprint = true
tvPinPrompt.setText(R.string.enter_pin_or_use_fingerprint_scanner)
} else
tvPinPrompt.setText(R.string.enter_pin)
else if (mode == Mode.RequestNewPIN2)
if (PINStorage.haveEncryptedPIN2()) {
allowFingerprint = true
tvPinPrompt.setText(R.string.enter_new_pin_2_or_use_fingerprint_scanner)
} else
tvPinPrompt.setText(R.string.enter_new_pin_2)
else if (mode == Mode.ConfirmNewPIN2)
tvPinPrompt.setText(R.string.confirm_new_pin_2)
else if (mode == Mode.RequestPIN2) {
val uid = intent.getStringExtra(EXTRA_TANGEM_CARD_UID)
val card = TangemCard(uid)
card.loadFromBundle(intent.getBundleExtra(EXTRA_TANGEM_CARD))
if (card.PIN2 == TangemCard.PIN2_Mode.DefaultPIN2 || card.PIN2 == TangemCard.PIN2_Mode.Unchecked) {
// if we know PIN2 or not try default previously - use it
PINStorage.setPIN2(PINStorage.getDefaultPIN2())
setResult(Activity.RESULT_OK)
finish()
return
}
if (PINStorage.haveEncryptedPIN2()) {
allowFingerprint = true
tvPinPrompt.setText(R.string.enter_pin_2_or_use_fingerprint_scanner)
} else
tvPinPrompt.setText(R.string.enter_pin_2)
}
if (!allowFingerprint)
tvPinPrompt.visibility = View.GONE
else
tvPinPrompt.visibility = View.VISIBLE
// set listeners
btn0.setOnClickListener { buttonClick(btn0) }
btn1.setOnClickListener { buttonClick(btn1) }
btn2.setOnClickListener { buttonClick(btn2) }
btn3.setOnClickListener { buttonClick(btn3) }
btn4.setOnClickListener { buttonClick(btn4) }
btn5.setOnClickListener { buttonClick(btn5) }
btn6.setOnClickListener { buttonClick(btn6) }
btn7.setOnClickListener { buttonClick(btn7) }
btn8.setOnClickListener { buttonClick(btn8) }
btn9.setOnClickListener { buttonClick(btn9) }
btnBackspace.setOnClickListener {
val s = tvPin!!.text.toString()
if (s.isNotEmpty())
tvPin!!.text = s.substring(0, s.length - 1)
}
btnContinue.setOnClickListener { doContinue() }
}
override fun onPause() {
super.onPause()
fingerprintHelper?.cancel()
if (startFingerprintReaderTask != null) {
startFingerprintReaderTask!!.cancel(true)
startFingerprintReaderTask = null
}
}
override fun onStop() {
super.onStop()
fingerprintHelper?.cancel()
if (startFingerprintReaderTask != null) {
startFingerprintReaderTask!!.cancel(true)
startFingerprintReaderTask = null
}
}
override fun onResume() {
super.onResume()
if (allowFingerprint)
startFingerprintReader()
}
override fun onTagDiscovered(tag: Tag) {
try {
Log.w(javaClass.name, "Ignore discovered tag!")
nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun authenticationFailed(error: String) {
LOG.w(TAG, error)
}
@TargetApi(Build.VERSION_CODES.M)
override fun authenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
LOG.i(TAG, "Authentication succeeded!")
val cipher = result.cryptoObject.cipher
if (mode == Mode.RequestNewPIN || mode == Mode.ConfirmNewPIN) {
val resultData = Intent()
val pin = PINStorage.loadEncryptedPIN(cipher)
resultData.putExtra("newPIN", pin)
resultData.putExtra("confirmPIN", pin)
setResult(Activity.RESULT_OK, resultData)
finish()
} else if (mode == Mode.RequestNewPIN2 || mode == Mode.ConfirmNewPIN2) {
val resultData = Intent()
val pin = PINStorage.loadEncryptedPIN2(cipher)
resultData.putExtra("newPIN2", pin)
resultData.putExtra("confirmPIN2", pin)
setResult(Activity.RESULT_OK, resultData)
finish()
} else if (mode == Mode.RequestPIN) {
PINStorage.loadEncryptedPIN(cipher)
setResult(Activity.RESULT_OK)
} else if (mode == Mode.RequestPIN2) {
PINStorage.loadEncryptedPIN2(cipher)
setResult(Activity.RESULT_OK)
}
finish()
}
private fun buttonClick(button: Button) {
tvPin.text = tvPin.text.toString() + button.text.toString()
}
@SuppressLint("NewApi")
private fun testFingerPrintSettings(): Boolean {
LOG.i(TAG, "Testing Fingerprint Settings")
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
fingerprintManager = getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager
if (!keyguardManager.isKeyguardSecure) {
LOG.i(TAG, "User hasn't enabled Lock Screen")
return false
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
LOG.i(TAG, "User hasn't granted permission to use Fingerprint")
return false
}
if (!fingerprintManager!!.hasEnrolledFingerprints()) {
LOG.i(TAG, "User hasn't registered any fingerprints")
return false
}
LOG.i(TAG, "Fingerprint authentication is set.\n")
return true
}
private fun startFingerprintReader() {
if (!testFingerPrintSettings())
return
if (!allowFingerprint)
return
fingerprintHelper = FingerprintHelper(this@PinRequestActivity)
startFingerprintReaderTask = StartFingerprintReaderTask(this, fingerprintManager, fingerprintHelper)
startFingerprintReaderTask!!.execute(null as Void?)
}
private fun doContinue() {
if (startFingerprintReaderTask != null)
return
// reset errors.
tvPin!!.error = null
// store values at the time of the login attempt.
val pin = tvPin!!.text.toString()
var cancel = false
var focusView: View? = null
if (mode == Mode.ConfirmNewPIN) {
if (pin != intent.getStringExtra("newPIN")) {
tvPin!!.error = getString(R.string.error_pin_confirmation_failed)
focusView = tvPin
cancel = true
}
} else if (mode == Mode.ConfirmNewPIN2) {
if (pin != intent.getStringExtra("newPIN2")) {
tvPin!!.error = getString(R.string.error_pin_confirmation_failed)
focusView = tvPin
cancel = true
}
} else {
if (TextUtils.isEmpty(pin)) {
tvPin!!.error = getString(R.string.error_empty_pin)
focusView = tvPin
cancel = true
}
}
if (cancel)
focusView!!.requestFocus()
else {
if (mode == Mode.RequestNewPIN || mode == Mode.ConfirmNewPIN) {
val resultData = Intent()
resultData.putExtra("newPIN", pin)
if (mode == Mode.ConfirmNewPIN)
resultData.putExtra("confirmPIN", pin)
setResult(Activity.RESULT_OK, resultData)
finish()
} else if (mode == Mode.RequestNewPIN2 || mode == Mode.ConfirmNewPIN2) {
val resultData = Intent()
resultData.putExtra("newPIN2", pin)
if (mode == Mode.ConfirmNewPIN2)
resultData.putExtra("confirmPIN2", pin)
setResult(Activity.RESULT_OK, resultData)
finish()
} else if (mode == Mode.RequestPIN) {
PINStorage.setUserPIN(pin)
setResult(Activity.RESULT_OK)
finish()
} else if (mode == Mode.RequestPIN2) {
PINStorage.setPIN2(pin)
setResult(Activity.RESULT_OK)
finish()
}
}
}
}

View file

@ -0,0 +1,378 @@
package com.tangem.ui.activity
import android.Manifest
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Dialog
import android.app.KeyguardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
import android.os.Build
import android.os.Bundle
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyPermanentlyInvalidatedException
import android.security.keystore.KeyProperties
import androidx.core.app.ActivityCompat
import androidx.appcompat.app.AppCompatActivity
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.Toast
import com.tangem.Constant
import com.tangem.data.fingerprint.ConfirmWithFingerprintTask
import com.tangem.data.fingerprint.FingerprintHelper
import com.tangem.cardandroid.android.data.PINStorage
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_save.*
import kotlinx.android.synthetic.main.layout_pin_buttons.*
import java.io.IOException
import java.security.KeyStore
import java.security.KeyStoreException
import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateException
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.NoSuchPaddingException
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
class PinSaveActivity : AppCompatActivity(), FingerprintHelper.FingerprintHelperListener {
companion object {
val TAG: String = PinSaveActivity::class.java.simpleName
fun callingIntent(context: Context, hasPin2: Boolean): Intent {
val intent = Intent(context, PinSaveActivity::class.java)
intent.putExtra(Constant.EXTRA_PIN2, hasPin2)
return intent
}
}
private var confirmWithFingerprintTask: ConfirmWithFingerprintTask? = null
private var keyStore: KeyStore? = null
private var cipher: Cipher? = null
var fingerprintManager: FingerprintManager? = null
var cryptoObject: FingerprintManager.CryptoObject? = null
var fingerprintHelper: FingerprintHelper? = null
private var usePIN2 = false
private var onConfirmAction: OnConfirmAction? = null
var dFingerPrintConfirmation: Dialog? = null
private enum class OnConfirmAction {
Save, DeleteEncryptedAndSave, Delete
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pin_save)
usePIN2 = intent.getBooleanExtra(Constant.EXTRA_PIN2, false)
if (usePIN2)
tvPinPrompt.text = getString(R.string.enter_pin2_and_use_fingerprint_to_save_it)
else
tvPinPrompt.text = getString(R.string.enter_pin_and_use_fingerprint_to_save_it)
if (usePIN2) {
cbUseFingerprint.isChecked = true
cbUseFingerprint.isEnabled = false
} else {
cbUseFingerprint.isChecked = PINStorage.haveEncryptedPIN()
cbUseFingerprint.isEnabled = true
}
// set listeners
btn0.setOnClickListener { buttonClick(btn0) }
btn1.setOnClickListener { buttonClick(btn1) }
btn2.setOnClickListener { buttonClick(btn2) }
btn3.setOnClickListener { buttonClick(btn3) }
btn4.setOnClickListener { buttonClick(btn4) }
btn5.setOnClickListener { buttonClick(btn5) }
btn6.setOnClickListener { buttonClick(btn6) }
btn7.setOnClickListener { buttonClick(btn7) }
btn8.setOnClickListener { buttonClick(btn8) }
btn9.setOnClickListener { buttonClick(btn9) }
btnBackspace.setOnClickListener {
val s = tvPin.text.toString()
if (s.isNotEmpty())
tvPin.text = s.substring(0, s.length - 1)
}
btnSavePIN.setOnClickListener { doSavePIN() }
btnDeletePIN.setOnClickListener { doDeletePIN() }
}
override fun onPause() {
super.onPause()
if (fingerprintHelper != null)
fingerprintHelper!!.cancel()
if (confirmWithFingerprintTask != null)
confirmWithFingerprintTask!!.cancel(true)
}
override fun onStop() {
super.onStop()
if (fingerprintHelper != null)
fingerprintHelper!!.cancel()
if (confirmWithFingerprintTask != null)
confirmWithFingerprintTask!!.cancel(true)
}
override fun authenticationFailed(error: String) {
}
@TargetApi(Build.VERSION_CODES.M)
override fun authenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
cipher = result.cryptoObject.cipher
when (onConfirmAction) {
PinSaveActivity.OnConfirmAction.Save -> {
val textToEncrypt = tvPin.text.toString()
if (usePIN2) {
PINStorage.saveEncryptedPIN2(cipher, textToEncrypt)
} else {
PINStorage.saveEncryptedPIN(cipher, textToEncrypt)
}
}
PinSaveActivity.OnConfirmAction.Delete -> {
if (usePIN2) {
PINStorage.deleteEncryptedPIN2()
} else {
PINStorage.deleteEncryptedPIN()
PINStorage.deletePIN()
}
tvPin.text = ""
}
PinSaveActivity.OnConfirmAction.DeleteEncryptedAndSave -> if (usePIN2) {
PINStorage.deleteEncryptedPIN2()
PINStorage.saveEncryptedPIN2(cipher, tvPin.text.toString())
} else {
PINStorage.deleteEncryptedPIN()
PINStorage.savePIN(tvPin.text.toString())
}
}
dFingerPrintConfirmation!!.dismiss()
finish()
}
fun getKeyStore(): Boolean {
try {
keyStore = KeyStore.getInstance(Constant.KEYSTORE)
// create empty keystore
keyStore!!.load(null)
return true
} catch (e: KeyStoreException) {
e.printStackTrace()
} catch (e: CertificateException) {
e.printStackTrace()
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
return false
}
@TargetApi(Build.VERSION_CODES.M)
fun createNewKey(forceCreate: Boolean): Boolean {
try {
if (forceCreate)
keyStore!!.deleteEntry(Constant.KEY_ALIAS)
if (!keyStore!!.containsAlias(Constant.KEY_ALIAS)) {
val generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, Constant.KEYSTORE)
generator.init(KeyGenParameterSpec.Builder(Constant.KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.build()
)
generator.generateKey()
}
return true
} catch (e: Exception) {
e.printStackTrace()
}
return false
}
@SuppressLint("InlinedApi")
fun getCipher(): Boolean {
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7)
return true
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
} catch (e: NoSuchPaddingException) {
e.printStackTrace()
}
return false
}
@TargetApi(Build.VERSION_CODES.M)
fun initCipher(mode: Int): Boolean {
try {
keyStore!!.load(null)
val keySpec = keyStore!!.getKey(Constant.KEY_ALIAS, null) as SecretKey
if (mode == Cipher.ENCRYPT_MODE) {
cipher!!.init(mode, keySpec)
} else {
val iv = PINStorage.loadEncryptedIV()
val ivSpec = IvParameterSpec(iv)
cipher!!.init(mode, keySpec, ivSpec)
}
return true
} catch (e: KeyPermanentlyInvalidatedException) {
e.printStackTrace()
// retry after clearing entry
createNewKey(true)
} catch (e: Exception) {
e.printStackTrace()
}
return false
}
@TargetApi(Build.VERSION_CODES.M)
fun initCryptObject(): Boolean {
try {
cryptoObject = FingerprintManager.CryptoObject(cipher!!)
return true
} catch (e: Exception) {
e.printStackTrace()
}
return false
}
@SuppressLint("SetTextI18n")
private fun buttonClick(button: Button) {
tvPin.text = String.format("%s%s", tvPin.text, button.text)
}
private fun doSavePIN() {
if (confirmWithFingerprintTask != null) {
return
}
tvPin.error = null
val pin = tvPin.text.toString()
var cancel = false
var focusView: View? = null
if (TextUtils.isEmpty(pin)) {
tvPin.error = getString(R.string.error_empty_pin)
focusView = tvPin
cancel = true
}
if (cancel) {
focusView!!.requestFocus()
} else {
if (usePIN2) {
if (!testFingerPrintSettings()) {
tvPin.postDelayed({ this.finish() }, 2000)
return
}
onConfirmAction = OnConfirmAction.Save
confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveActivity)
confirmWithFingerprintTask!!.execute(null as Void?)
} else {
if (cbUseFingerprint.isChecked || PINStorage.haveEncryptedPIN()) {
if (!testFingerPrintSettings()) {
tvPin.postDelayed({ this.finish() }, 2000)
return
}
onConfirmAction = if (cbUseFingerprint.isChecked) {
OnConfirmAction.Save
} else {
OnConfirmAction.DeleteEncryptedAndSave
}
// show a progress spinner, and kick off a background task to perform the user login attempt
confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveActivity)
confirmWithFingerprintTask!!.execute(null as Void?)
} else {
PINStorage.savePIN(tvPin.text.toString())
finish()
}
}
}
}
private fun doDeletePIN() {
if (usePIN2) {
if (PINStorage.haveEncryptedPIN2()) {
if (!testFingerPrintSettings()) {
tvPin.postDelayed({ this.finish() }, 2000)
return
}
onConfirmAction = OnConfirmAction.Delete
confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveActivity)
confirmWithFingerprintTask!!.execute(null as Void?)
} else {
tvPin.text = ""
finish()
}
} else {
if (cbUseFingerprint.isChecked || PINStorage.haveEncryptedPIN()) {
if (!testFingerPrintSettings()) {
tvPin.postDelayed({ this.finish() }, 2000)
return
}
onConfirmAction = OnConfirmAction.Delete
confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveActivity)
confirmWithFingerprintTask!!.execute(null as Void?)
} else {
tvPin.text = ""
PINStorage.deletePIN()
finish()
}
}
}
@SuppressLint("NewApi")
private fun testFingerPrintSettings(): Boolean {
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
fingerprintManager = getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager
if (!keyguardManager.isKeyguardSecure) {
Toast.makeText(baseContext, R.string.user_has_not_enabled_lock_screen, Toast.LENGTH_LONG).show()
return false
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(baseContext, R.string.user_has_not_granted_permission_to_use_fingerprint, Toast.LENGTH_LONG).show()
return false
}
if (!fingerprintManager!!.hasEnrolledFingerprints()) {
Toast.makeText(baseContext, R.string.user_has_not_registered_any_fingerprints, Toast.LENGTH_LONG).show()
return false
}
return true
}
}

View file

@ -0,0 +1,205 @@
package com.tangem.ui.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.nfc.tech.IsoDep
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
import com.tangem.App
import com.tangem.Constant
import com.tangem.ui.dialog.NoExtendedLengthSupportDialog
import com.tangem.ui.dialog.WaitSecurityDelayDialog
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.cardandroid.android.reader.NfcReader
import com.tangem.cardandroid.data.*
import com.tangem.cardcommon.data.TangemCard
import com.tangem.cardcommon.reader.CardProtocol
import com.tangem.cardcommon.tasks.SwapPINTask
import com.tangem.cardcommon.util.Util
import com.tangem.util.LOG
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_swap.*
class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications {
companion object {
val TAG: String = PinSwapActivity::class.java.simpleName
fun callingIntent(context: Context, newPIN: String, newPIN2: String): Intent {
val intent = Intent(context, PinSwapActivity::class.java)
intent.putExtra(Constant.EXTRA_NEW_PIN, newPIN)
intent.putExtra(Constant.EXTRA_NEW_PIN_2, newPIN2)
return intent
}
const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
}
private lateinit var nfcManager: NfcManager
private var card: TangemCard? = null
private var newPIN: String? = null
private var newPIN2: String? = null
private var progressBar: ProgressBar? = null
private var swapPinTask: SwapPINTask? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pin_swap)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
card = TangemCard(intent.getStringExtra(EXTRA_TANGEM_CARD_UID))
card!!.loadFromBundle(intent.extras!!.getBundle(EXTRA_TANGEM_CARD))
newPIN = intent.getStringExtra(Constant.EXTRA_NEW_PIN)
newPIN2 = intent.getStringExtra(Constant.EXTRA_NEW_PIN_2)
tvCardID.text = card!!.cidDescription
progressBar = findViewById(R.id.progressBar)
progressBar!!.progressTintList = ColorStateList.valueOf(Color.DKGRAY)
progressBar!!.visibility = View.INVISIBLE
}
override fun onTagDiscovered(tag: Tag) {
try {
// get IsoDep handle and run cardReader thread
val isoDep = IsoDep.get(tag)
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
LOG.d(TAG, "UID: $sUID")
if (sUID == card!!.uid) {
isoDep.timeout = card!!.pauseBeforePIN2 + 65000
swapPinTask = SwapPINTask(card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this, newPIN, newPIN2)
swapPinTask!!.start()
} else {
LOG.d(TAG, "Mismatch card UID (" + sUID + " instead of " + card!!.uid + ")")
nfcManager.ignoreTag(isoDep.tag)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
public override fun onPause() {
swapPinTask?.cancel(true)
super.onPause()
}
public override fun onStop() {
swapPinTask?.cancel(true)
super.onStop()
}
override fun onReadStart(cardProtocol: CardProtocol) {
progressBar?.post {
progressBar?.visibility = View.VISIBLE
progressBar?.progress = 5
}
}
override fun onReadFinish(cardProtocol: CardProtocol?) {
swapPinTask = null
if (cardProtocol != null) {
when {
cardProtocol.error == null -> progressBar!!.post {
progressBar!!.progress = 100
progressBar!!.progressTintList = ColorStateList.valueOf(Color.GREEN)
val intent = Intent()
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card.asBundle)
setResult(Activity.RESULT_OK, intent)
finish()
}
cardProtocol.error is CardProtocol.TangemException_InvalidPIN -> {
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("message", "Cannot change PIN(s). Make sure you enter correct PIN2!")
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card.asBundle)
setResult(RESULT_INVALID_PIN, intent)
finish()
} catch (e: Exception) {
e.printStackTrace()
}
}, 500)
}
else -> progressBar!!.post {
if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) {
if (!NoExtendedLengthSupportDialog.allReadyShowed) {
NoExtendedLengthSupportDialog().show(supportFragmentManager, NoExtendedLengthSupportDialog.TAG)
}
} else {
Toast.makeText(baseContext, R.string.try_to_scan_again, Toast.LENGTH_SHORT).show()
}
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
} catch (e: Exception) {
e.printStackTrace()
}
}, 500)
}
}
override fun onReadProgress(protocol: CardProtocol, progress: Int) {
progressBar!!.post { progressBar!!.progress = progress }
}
override fun onReadCancel() {
swapPinTask = 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 onReadWait(msec: Int) {
WaitSecurityDelayDialog.onReadWait(this, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout)
}
override fun onReadAfterRequest() {
WaitSecurityDelayDialog.onReadAfterRequest(this)
}
}

View file

@ -0,0 +1,176 @@
package com.tangem.ui.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.View
import com.tangem.App
import com.tangem.Constant
import com.tangem.data.Blockchain
import com.tangem.data.network.CryptonitOtherApi
import com.tangem.di.Navigator
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_cryptonit_other_api_withdrawal.*
import java.io.IOException
import javax.inject.Inject
class PrepareCryptonitOtherApiWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareCryptonitOtherApiWithdrawalActivity::class.java.simpleName
}
private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
private var cryptonit: CryptonitOtherApi? = null
@Inject
internal lateinit var navigator: Navigator
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_cryptonit_other_api_withdrawal)
App.navigatorComponent?.inject(this)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
ctx = TangemContext.loadFromBundle(this, intent.extras)
cryptonit = CryptonitOtherApi(this)
tvKey.text = cryptonit!!.key
tvUserID.text = cryptonit!!.userId
tvSecret.text = cryptonit!!.secretDescription
tvCardID.text = ctx.card!!.cidDescription
tvWallet.text = ctx.coinData!!.wallet
val engine = CoinEngineFactory.create(ctx)
tvCurrency.text = engine!!.balanceCurrency
etAmount.setText(engine.convertToAmount(engine.convertToInternalAmount(ctx.card!!.denomination)).toValueString())
etAmount.filters = engine.amountInputFilters
// set listeners
btnLoad.setOnClickListener {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
// if (!engine.checkAmount(card, strAmount))
// etAmount.error = getString(R.string.unknown_amount_format)
val dblAmount: Double = strAmount.toDouble()
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_withdrawal)
cryptonit!!.requestCryptoWithdrawal(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
//Toast.makeText(this, strAmount, Toast.LENGTH_LONG).show()
// val balance = engine.getBalanceLong(card)!! / (card!!.blockchain.multiplier / 1000.0)
// if (etAmount.text.toString().replace(",", ".").toDouble() > balance) {
// etAmount.error = getString(R.string.not_enough_funds_on_your_account)
// return@setOnClickListener
// }
}
ivCameraKey.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR_KEY) }
ivCameraSecret.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR_SECRET) }
ivCameraUserId.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR_USER_ID) }
ivRefreshBalance.setOnClickListener { doRequestBalance() }
cryptonit!!.setBalanceListener { response ->
when (ctx.blockchain) {
Blockchain.Ethereum, Blockchain.EthereumTestNet -> {
tvBalance.text = response.eth_available
}
Blockchain.Bitcoin, Blockchain.BitcoinTestNet, Blockchain.BitcoinCash -> {
tvBalance.text = response.btc_available
}
else -> {
}
}
tvBalanceCurrency.text = ctx.blockchain.currency
tvBalance.setTextColor(Color.BLACK)
rlProgressBar.visibility = View.INVISIBLE
btnLoad.isActivated = true
}
cryptonit!!.setErrorListener { throwable ->
throwable.printStackTrace()
rlProgressBar.visibility = View.INVISIBLE
tvError.visibility = View.VISIBLE
tvError.text = throwable.message
}
cryptonit!!.setWithdrawalListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.success != null && response.success!!) finish()
else {
tvError.visibility = View.VISIBLE
tvError.text = response.reason!!.toString()
}
}
btnLoad.isActivated = false
doRequestBalance()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
when (requestCode) {
Constant.REQUEST_CODE_SCAN_QR_KEY -> {
cryptonit!!.key = data.getStringExtra("QRCode")
tvKey!!.text = cryptonit!!.key
}
Constant.REQUEST_CODE_SCAN_QR_SECRET -> {
cryptonit!!.secret = data.getStringExtra("QRCode")
tvSecret!!.text = cryptonit!!.secretDescription
}
Constant.REQUEST_CODE_SCAN_QR_USER_ID -> {
cryptonit!!.userId = data.getStringExtra("QRCode")
tvUserID!!.text = cryptonit!!.userId
}
}
cryptonit!!.saveAccountInfo()
doRequestBalance()
}
}
override fun onTagDiscovered(tag: Tag) {
try {
nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun doRequestBalance() {
if (cryptonit!!.havaAccountInfo()) {
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_balance)
tvError.visibility = View.INVISIBLE
cryptonit!!.requestBalance(ctx.blockchain.currency, "USD")
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.cryptonit_not_enough_account_data)
}
}
}

View file

@ -0,0 +1,160 @@
package com.tangem.ui.activity
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.text.InputFilter
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import com.tangem.data.network.Cryptonit
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.data.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.util.DecimalDigitsInputFilter
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_cryptonit_withdrawal.*
import java.io.IOException
class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareCryptonitWithdrawalActivity::class.java.simpleName
}
private lateinit var ctx: TangemContext
private lateinit var nfcManager: NfcManager
private var cryptonit: Cryptonit? = null
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_cryptonit_withdrawal)
ctx = TangemContext.loadFromBundle(this, intent.extras)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
cryptonit = Cryptonit(this)
etUsername.setText(cryptonit!!.username)
etPassword.setText(cryptonit!!.password)
etFee.setText(cryptonit!!.fee)
tvCardID.text = ctx.card!!.cidDescription
tvWallet.text = ctx.coinData!!.wallet
val engine = CoinEngineFactory.create(ctx)
tvCurrency.text = engine!!.balanceCurrency
tvFeeCurrency.text = engine.feeCurrency
etAmount.setText(engine.convertToAmount(engine.convertToInternalAmount(ctx.card!!.denomination)).toValueString())
etAmount.filters = engine.amountInputFilters
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)
true
} else
false
}
when (ctx.blockchain) {
Blockchain.Bitcoin -> {
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(5))
etFee.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(5))
}
Blockchain.BitcoinCash -> {
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(8))
etFee.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(8))
}
Blockchain.Ethereum -> {
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(18))
etFee.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(18))
}
else -> {
}
}
// set listeners
btnLoad.setOnClickListener {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
val strFee: String = etFee.text.toString().replace(",", ".")
val dblAmount: Double = strAmount.toDouble()
cryptonit!!.fee = strFee
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_withdrawal)
cryptonit!!.requestWithdrawCoins(ctx.blockchain.currency, dblAmount, ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
}
ivRefreshBalance.setOnClickListener {
cryptonit!!.username = etUsername.text.toString()
cryptonit!!.password = etPassword.text.toString()
cryptonit!!.saveAccountInfo()
doRequestBalance()
}
cryptonit!!.setBalanceListener { response ->
tvBalance.text = response.results[0].balance.toString()
tvBalanceCurrency.text = response.results[0].currency // card!!.blockchain.currency
tvBalance.setTextColor(Color.BLACK)
rlProgressBar.visibility = View.INVISIBLE
btnLoad.visibility = View.VISIBLE
}
cryptonit!!.setErrorListener { throwable ->
throwable.printStackTrace()
rlProgressBar.visibility = View.INVISIBLE
tvError.visibility = View.VISIBLE
tvError.text = throwable.message
}
cryptonit!!.setWithdrawalListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.success != null && response.success!!) {
Toast.makeText(this, R.string.withdrawal_successful, Toast.LENGTH_LONG).show();
finish()
} else {
tvError.visibility = View.VISIBLE
tvError.text = response.errors.toString()
}
}
btnLoad.visibility = View.INVISIBLE
doRequestBalance()
}
override fun onTagDiscovered(tag: Tag) {
try {
nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun doRequestBalance() {
if (cryptonit!!.haveAccountInfo()) {
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_balance)
tvError.visibility = View.INVISIBLE
cryptonit!!.requestBalance(ctx.blockchain.currency)
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.cryptonit_not_enough_account_data)
}
}
}

View file

@ -0,0 +1,258 @@
package com.tangem.ui.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import com.tangem.App
import com.tangem.Constant
import com.tangem.data.network.Kraken
import com.tangem.cardandroid.android.reader.NfcManager
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.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_kraken_withdrawal.*
import java.io.IOException
import java.math.BigDecimal
import java.net.URI
import java.util.*
import javax.inject.Inject
class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareKrakenWithdrawalActivity::class.java.simpleName
}
private lateinit var ctx: TangemContext
private lateinit var nfcManager: NfcManager
private var kraken: Kraken? = null
private var fee: BigDecimal? = null
@Inject
internal lateinit var navigator: Navigator
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_kraken_withdrawal)
App.navigatorComponent?.inject(this)
ctx = TangemContext.loadFromBundle(this, intent.extras)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
kraken = Kraken(this)
tvKey.text = kraken!!.key
tvSecret.text = kraken!!.secretDescription
tvCardID.text = ctx.card!!.cidDescription
tvWallet.text = ctx.coinData!!.wallet
val engine = CoinEngineFactory.create(ctx)
tvCurrency.text = engine!!.balanceCurrency
etAmount.setText(engine.convertToAmount(engine.convertToInternalAmount(ctx.card!!.denomination)).toValueString())
etAmount.filters = engine.amountInputFilters
etAmount.setOnEditorActionListener { lv, actionId, event ->
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
}
}
// set listeners
btnLoad.setOnClickListener {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
var dblAmount: Double = strAmount.toDouble()
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.kraken_request_withdrawal)
kraken!!.requestWithdrawInfo(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
}
ivCamera.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR) }
ivRefreshBalance.setOnClickListener { doRequestBalance() }
kraken!!.setBalanceListener { response ->
if (response.error != null && response.error.isNotEmpty()) {
tvError.visibility = View.VISIBLE
tvError.text = Arrays.toString(response.error)
} else {
when (ctx.blockchain) {
Blockchain.Ethereum -> {
tvBalance.text = response.result.XETH.trimEnd('0')
}
Blockchain.Bitcoin -> {
tvBalance.text = response.result.XXBT.trimEnd('0')
}
Blockchain.BitcoinCash -> {
tvBalance.text = response.result.BCH.trimEnd('0')
}
else -> {
tvBalance.text = "???"
}
}
tvBalanceCurrency.text = ctx.blockchain.currency
tvBalance.setTextColor(Color.BLACK)
btnLoad.visibility = View.VISIBLE
}
rlProgressBar.visibility = View.INVISIBLE
}
kraken!!.setErrorListener { throwable ->
throwable.printStackTrace()
rlProgressBar.visibility = View.INVISIBLE
tvError.visibility = View.VISIBLE
tvError.text = throwable.message
}
kraken!!.setWithdrawalListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.error != null && response.error.isNotEmpty()) {
tvError.visibility = View.VISIBLE
tvError.text = Arrays.toString(response.error)
} else {
Toast.makeText(this, "Withdrawal successful!", Toast.LENGTH_LONG).show()
finish()
}
}
kraken!!.setWithdrawalInfoListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.error != null && response.error.isNotEmpty()) {
tvError.visibility = View.VISIBLE
tvError.text = Arrays.toString(response.error)
} else {
fee = BigDecimal(response.result.fee)
showConfirmDialog()
}
}
btnLoad.visibility = View.INVISIBLE
doRequestBalance()
}
// Method to show an alert dialog with yes, no and cancel button
private fun showConfirmDialog() {
// Late initialize an alert dialog object
lateinit var dialog: AlertDialog
// Initialize a new instance of alert dialog builder object
val builder = AlertDialog.Builder(this)
// Set a title for alert dialog
builder.setTitle(R.string.please_confirm_withdraw)
// Set a message for alert dialog
builder.setMessage(String.format("Continue with fee %s %s?", fee!!.toString().trimEnd('0'), ctx.blockchain.currency))
// On click listener for dialog buttons
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
var dblAmount: Double = strAmount.toDouble()
dblAmount += fee!!.toDouble()
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.kraken_request_withdrawal)
kraken!!.requestWithdraw(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
}
DialogInterface.BUTTON_NEGATIVE -> {
Toast.makeText(this, R.string.operation_canceled, Toast.LENGTH_LONG).show()
}
}
}
// Set the alert dialog positive/yes button
builder.setPositiveButton(R.string.yes, dialogClickListener)
// Set the alert dialog negative/no button
builder.setNegativeButton(R.string.no, dialogClickListener)
// Initialize the AlertDialog using builder object
dialog = builder.create()
// Finally, display the alert dialog
dialog.show()
}
private fun doRequestBalance() {
if (kraken!!.haveAccountInfo()) {
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.kraken_request_balance)
tvError.visibility = View.INVISIBLE
kraken!!.requestBalance()
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.kraken_not_enough_account_data)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
when (requestCode) {
Constant.REQUEST_CODE_SCAN_QR -> {
val uri = URI(data.getStringExtra("QRCode"))
val query = uri.query
val params = query.split("&")
for (param in params) {
if (param.startsWith("key=")) kraken!!.key = param.substring(4)
else if (param.startsWith("secret=")) kraken!!.secret = param.substring(7)
}
tvKey!!.text = kraken!!.key
tvSecret!!.text = kraken!!.secretDescription
}
}
kraken!!.saveAccountInfo()
doRequestBalance()
}
}
override fun onTagDiscovered(tag: Tag) {
try {
nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
}

View file

@ -0,0 +1,178 @@
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.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.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()
}
}
}

View file

@ -0,0 +1,239 @@
package com.tangem.ui.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.res.ColorStateList
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.nfc.tech.IsoDep
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.tangem.App
import com.tangem.domain.wallet.TangemContext
import com.tangem.ui.dialog.NoExtendedLengthSupportDialog
import com.tangem.ui.dialog.WaitSecurityDelayDialog
import com.tangem.ui.dialog.WaitSecurityDelayDialogNew
import com.tangem.ui.event.DeletingWalletFinish
import com.tangem.cardandroid.android.nfc.NfcDeviceAntennaLocation
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.cardandroid.android.reader.NfcReader
import com.tangem.cardandroid.data.asBundle
import com.tangem.cardcommon.reader.CardProtocol
import com.tangem.cardcommon.tasks.PurgeTask
import com.tangem.cardcommon.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.*
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject
class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications {
companion object {
val TAG: String = PurgeActivity::class.java.simpleName
fun callingIntent(context: Context, ctx: TangemContext): Intent {
val intent = Intent(context, PurgeActivity::class.java)
ctx.saveToIntent(intent)
return intent
}
const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
}
@Inject
internal lateinit var waitSecurityDelayDialogNew: WaitSecurityDelayDialogNew
private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation
private var purgeTask: PurgeTask? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_purge)
App.navigatorComponent?.inject(this)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
ctx = TangemContext.loadFromBundle(this, intent.extras)
// init NFC Antenna
nfcDeviceAntenna = NfcDeviceAntennaLocation(this, ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc)
nfcDeviceAntenna.init()
tvCardID.text = ctx.card!!.cidDescription
progressBar.progressTintList = ColorStateList.valueOf(Color.DKGRAY)
progressBar.visibility = View.INVISIBLE
}
public override fun onStop() {
purgeTask?.cancel(true)
super.onStop()
}
override fun onTagDiscovered(tag: Tag) {
try {
// get IsoDep handle and run cardReader thread
val isoDep = IsoDep.get(tag)
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
LOG.d(TAG, "UID: $sUID")
if (sUID == ctx.card!!.uid) {
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 65000
purgeTask = PurgeTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
purgeTask!!.start()
} else {
LOG.d(TAG, "Mismatch card UID (" + sUID + " instead of " + ctx.card.uid + ")")
nfcManager.ignoreTag(isoDep.tag)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun onReadWait(msec: Int) {
WaitSecurityDelayDialog.onReadWait(this, msec)
// val readWait = ReadWait()
// readWait.msec = msec
// EventBus.getDefault().post(readWait)
}
override fun onReadBeforeRequest(timeout: Int) {
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() {
WaitSecurityDelayDialog.onReadAfterRequest(this)
// val readAfterRequest = ReadAfterRequest()
// EventBus.getDefault().post(readAfterRequest)
}
override fun onReadStart(cardProtocol: CardProtocol) {
rlProgressBar.post { rlProgressBar.visibility = View.VISIBLE }
progressBar.post {
progressBar.visibility = View.VISIBLE
progressBar.progress = 5
}
}
override fun onReadFinish(cardProtocol: CardProtocol?) {
purgeTask = 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)
val intent = Intent()
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card.asBundle)
setResult(Activity.RESULT_OK, intent)
EventBus.getDefault().post(DeletingWalletFinish())
finish()
}
} else {
if (cardProtocol.error is CardProtocol.TangemException_InvalidPIN) {
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("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card.asBundle)
intent.putExtra("message", getString(R.string.cannot_erase_wallet))
setResult(RESULT_INVALID_PIN, intent)
finish()
} catch (e: Exception) {
e.printStackTrace()
}
}, 500)
} else {
progressBar!!.post {
if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) {
if (!NoExtendedLengthSupportDialog.allReadyShowed)
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 onReadProgress(protocol: CardProtocol, progress: Int) {
progressBar?.post { progressBar?.progress = progress }
}
override fun onReadCancel() {
purgeTask = null
progressBar?.postDelayed({
try {
progressBar?.progress = 0
progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY)
progressBar?.visibility = View.INVISIBLE
} catch (e: Exception) {
e.printStackTrace()
}
}, 500)
}
}

View file

@ -0,0 +1,72 @@
package com.tangem.ui.activity
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.appcompat.app.AppCompatActivity
import com.google.zxing.Result
import com.tangem.Constant
import me.dm7.barcodescanner.zxing.ZXingScannerView
class QrScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
companion object {
fun callingIntent(context: Context): Intent {
return Intent(context, QrScanActivity::class.java)
}
}
private var scannerView: ZXingScannerView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 1)
else
runScanner()
}
override fun onPause() {
super.onPause()
scannerView?.stopCamera()
}
override fun onResume() {
super.onResume()
scannerView?.startCamera()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
1 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)
runScanner()
else {
setResult(Activity.RESULT_CANCELED)
finish()
}
}
}
}
override fun handleResult(result: Result) {
val data = Intent()
data.putExtra(Constant.EXTRA_QR_CODE, result.text)
setResult(Activity.RESULT_OK, data)
finish()
}
private fun runScanner() {
// programmatically initialize the scanner view
scannerView = ZXingScannerView(this)
setContentView(scannerView)
// register ourselves as a handler for scan results.
scannerView?.setResultHandler(this)
scannerView?.startCamera()
}
}

View file

@ -0,0 +1,102 @@
package com.tangem.ui.activity
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.KeyEvent
import android.widget.Toast
import com.tangem.Constant
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.ui.event.TransactionFinishWithSuccess
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.util.UtilHelper
import com.tangem.wallet.R
import org.greenrobot.eventbus.EventBus
import java.io.IOException
class SendTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
private var tx: ByteArray? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_send_transaction)
nfcManager = NfcManager(this, this)
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
ctx = TangemContext.loadFromBundle(this, intent.extras)
tx = intent.getByteArrayExtra(Constant.EXTRA_TX)
val engine = CoinEngineFactory.create(ctx)
engine!!.requestSendTransaction(
object : CoinEngine.BlockchainRequestsCallbacks {
override fun onComplete(success: Boolean) {
if (success)
finishWithSuccess()
else
finishWithError(ctx.error)
}
override fun onProgress() {
}
override fun allowAdvance(): Boolean {
return UtilHelper.isOnline(this@SendTransactionActivity)
}
},
tx
)
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
Toast.makeText(this, R.string.please_wait, Toast.LENGTH_LONG).show()
return true
}
}
return super.onKeyDown(keyCode, event)
}
override fun onTagDiscovered(tag: Tag) {
try {
nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun finishWithSuccess() {
val transactionFinishWithSuccess = TransactionFinishWithSuccess()
transactionFinishWithSuccess.message = getString(R.string.transaction_has_been_successfully_signed)
EventBus.getDefault().post(transactionFinishWithSuccess)
val intent = Intent()
intent.putExtra(Constant.EXTRA_MESSAGE, getString(R.string.transaction_has_been_successfully_signed))
setResult(RESULT_OK, intent)
finish()
}
private fun finishWithError(message: String) {
val transactionFinishWithError = TransactionFinishWithError()
transactionFinishWithError.message = String.format(getString(R.string.try_again_failed_to_send_transaction), message)
EventBus.getDefault().post(transactionFinishWithError)
val intent = Intent()
intent.putExtra(Constant.EXTRA_MESSAGE, String.format(getString(R.string.try_again_failed_to_send_transaction), message))
setResult(RESULT_CANCELED, intent)
finish()
}
}

View file

@ -0,0 +1,302 @@
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.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.cardandroid.android.nfc.NfcDeviceAntennaLocation
import com.tangem.cardandroid.android.nfc.NfcLifecycleObserver
import com.tangem.cardandroid.android.reader.NfcManager
import com.tangem.cardandroid.android.reader.NfcReader
import com.tangem.cardandroid.data.asBundle
import com.tangem.cardcommon.reader.CardProtocol
import com.tangem.cardcommon.tasks.SignTask
import com.tangem.cardcommon.util.Util
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.*
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)
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
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)
?: throw CardProtocol.TangemException("Can't create CoinEngine!")
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("message", getString(R.string.cannot_sign_transaction_wrong_amount))
intent.putExtra("UID", ctx.card.uid)
intent.putExtra("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("message", getString(R.string.cannot_sign_transaction_make_sure_you_enter_correct_pin_2))
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("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("message", getString(R.string.cannot_sign_transaction_wrong_amount))
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("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)
}
}

View file

@ -0,0 +1,43 @@
package com.tangem.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
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.ui.fragment.VerifyCard
import com.tangem.wallet.R
import javax.inject.Inject
class VerifyCardActivity : AppCompatActivity() {
@Inject
lateinit var navigator: Navigator
companion object {
fun callingIntent(context: Context, ctx: TangemContext): Intent {
val intent = Intent(context, VerifyCardActivity::class.java)
ctx.saveToIntent(intent)
return intent
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_verify_card)
App.navigatorComponent?.inject(this)
}
override fun onBackPressed() {
super.onBackPressed()
val verifyCard = supportFragmentManager.findFragmentById(R.id.verify_card_fragment) as VerifyCard
val data = verifyCard.prepareResultIntent()
data.putExtra(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_UPDATE)
finish()
}
}