tangem-app-android-audited/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt
2019-01-18 13:51:20 +03:00

454 lines
No EOL
20 KiB
Kotlin

package com.tangem.presentation.fragment
import android.app.Activity
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.text.Html
import android.text.format.DateUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import android.widget.Toast
import com.tangem.App
import com.tangem.Constant
import com.tangem.data.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.activity.*
import com.tangem.presentation.dialog.PINSwapWarningDialog
import com.tangem.tangemcard.android.data.PINStorage
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fr_verify_card.*
import java.io.IOException
import java.util.*
class VerifyCard : Fragment() {
companion object {
val TAG: String = VerifyCard::class.java.simpleName
}
private lateinit var ctx: TangemContext
private var requestPIN2Count = 0
private var timerHideErrorAndMessage: Timer? = null
private var newPIN = ""
private var newPIN2 = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ctx = TangemContext.loadFromBundle(activity, activity?.intent?.extras)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fr_verify_card, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
updateViews()
srlVerifyCard.setOnRefreshListener { srlVerifyCard.isRefreshing = false }
// set listeners
fabMenu.setOnClickListener { showMenu(fabMenu) }
btnOk.setOnClickListener {
val data = prepareResultIntent()
data.putExtra(Constant.EXTRA_MODIFICATION, "update")
activity?.finish()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
Constant.REQUEST_CODE_ENTER_NEW_PIN -> if (resultCode == Activity.RESULT_OK) {
if (data != null) {
if (data.extras!!.containsKey("confirmPIN")) {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
newPIN = data.getStringExtra("newPIN")
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
} else {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("newPIN", data.getStringExtra("newPIN"))
intent.putExtra("mode", PinRequestActivity.Mode.ConfirmNewPIN.toString())
startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN)
}
}
}
Constant.REQUEST_CODE_ENTER_NEW_PIN2 -> if (resultCode == Activity.RESULT_OK) {
if (data != null) {
if (data.extras!!.containsKey("confirmPIN2")) {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
newPIN2 = data.getStringExtra("newPIN2")
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
} else {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("newPIN2", data.getStringExtra("newPIN2"))
intent.putExtra("mode", PinRequestActivity.Mode.ConfirmNewPIN2.toString())
startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN2)
}
}
}
Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
if (newPIN == "") newPIN = ctx.card!!.pin
if (newPIN2 == "") newPIN2 = App.pinStorage.piN2
val pinSwapWarningDialog = PINSwapWarningDialog()
pinSwapWarningDialog.setOnRefreshPage { (activity as VerifyCardActivity).navigator.showPinSwap(context as Activity, newPIN, newPIN2) }
val bundle = Bundle()
if (!CardProtocol.isDefaultPIN(newPIN) || !CardProtocol.isDefaultPIN2(newPIN2))
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_forget))
else
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_use_default))
pinSwapWarningDialog.arguments = bundle
pinSwapWarningDialog.show(activity?.supportFragmentManager, PINSwapWarningDialog.TAG)
}
Constant.REQUEST_CODE_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
if (data == null) {
ctx.saveToIntent(data)
data?.putExtra("modification", "delete")
} else
data.putExtra("modification", "update")
activity!!.setResult(Activity.RESULT_OK, data)
activity!!.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(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
return
} else {
if (data != null && data.extras!!.containsKey("message")) {
ctx.error = data.getStringExtra("message")
}
}
}
Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE -> if (resultCode == Activity.RESULT_OK)
(activity as VerifyCardActivity).navigator.showPurge(context as Activity, ctx)
Constant.REQUEST_CODE_PURGE -> if (resultCode == Activity.RESULT_OK) {
if (data == null) {
ctx.saveToIntent(data)
data?.putExtra(Constant.EXTRA_MODIFICATION, "delete")
} else
data.putExtra(Constant.EXTRA_MODIFICATION, "update")
activity!!.setResult(Activity.RESULT_OK, data)
activity!!.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(context, PinRequestActivity::class.java)
intent.putExtra(Constant.EXTRA_MODE, PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
return
} else {
if (data != null && data.extras!!.containsKey("message")) {
ctx.error = data.getStringExtra("message")
}
}
updateViews()
}
}
}
private fun updateViews() {
try {
if (timerHideErrorAndMessage != null) {
timerHideErrorAndMessage!!.cancel()
timerHideErrorAndMessage = null
}
tvCardID.text = ctx.card!!.cidDescription
if (ctx.error == null || ctx.error.isEmpty()) {
tvError.visibility = View.GONE
tvError.text = ""
} else {
tvError.visibility = View.VISIBLE
tvError.text = ctx.error
}
if (ctx.message == null || ctx.message.isEmpty()) {
tvMessage.visibility = View.GONE
tvMessage.text = ""
} else {
tvMessage.visibility = View.VISIBLE
tvMessage.text = ctx.message
}
tvManufacturerInfo.text = ctx.card!!.manufacturer.officialName
if (ctx.card!!.isManufacturerConfirmed && ctx.card!!.isCardPublicKeyValid) {
tvCardIdentity.setText(R.string.attested)
tvCardIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed))
} else {
tvCardIdentity.setText(R.string.not_confirmed)
tvCardIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed))
}
tvIssuer.text = ctx.card!!.issuerDescription
tvCardRegistredDate.text = DateUtils.formatDateTime(null, ctx.card!!.personalizationDateTime.time, DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NUMERIC_DATE or DateUtils.FORMAT_SHOW_YEAR)
val html = Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
tvValidationNode.text = ctx.coinData!!.validationNodeDescription
val engine = CoinEngineFactory.create(ctx)
tvInputs.text = engine!!.unspentInputsDescription
ivBlockchain.setImageResource(Blockchain.getLogoImageResource(ctx.card!!.blockchainID, ctx.card!!.tokenSymbol))
if (ctx.card!!.isReusable!!)
tvReusable.setText(R.string.reusable)
else
tvReusable.setText(R.string.one_off_banknote)
tvSigningMethod.text = ctx.card!!.signingMethod.description
if (ctx.card!!.status == TangemCard.Status.Loaded || ctx.card!!.status == TangemCard.Status.Purged) {
when {
ctx.card!!.remainingSignatures == 0 -> {
tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed))
tvRemainingSignatures.setText(R.string.none)
}
ctx.card!!.remainingSignatures == 1 -> {
tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed))
tvRemainingSignatures.setText(R.string.last_one)
}
ctx.card!!.remainingSignatures > 1000 -> {
tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed))
tvRemainingSignatures.setText(R.string.unlimited)
}
else -> {
tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed))
tvRemainingSignatures.text = ctx.card!!.remainingSignatures.toString()
}
}
tvSignedTx.text = (ctx.card!!.maxSignatures - ctx.card!!.remainingSignatures).toString()
} else {
tvLastSigned.text = ""
tvRemainingSignatures.text = ""
tvSignedTx.text = ""
}
tvFirmware.text = ctx.card!!.firmwareVersion
var features = ""
features += if (ctx.card!!.allowSwapPIN()!! && ctx.card!!.allowSwapPIN2()!!) {
"Allows change PIN1 and PIN2\n"
} else if (ctx.card!!.allowSwapPIN()!!) {
"Allows change PIN1\n"
} else if (ctx.card!!.allowSwapPIN2()!!) {
"Allows change PIN2\n"
} else {
"Fixed PIN1 and PIN2\n"
}
if (ctx.card!!.needCVC()!!)
features += "Requires CVC\n"
if (ctx.card!!.supportDynamicNDEF()!!) {
features += "Dynamic NDEF for iOS\n"
} else if (ctx.card!!.supportNDEF()!!)
features += "NDEF\n"
if (ctx.card!!.supportBlock()!!)
features += "Blockable\n"
if (ctx.card!!.supportOnlyOneCommandAtTime()!!)
features += "Atomic command mode"
if (features.endsWith("\n"))
features = features.substring(0, features.length - 1)
tvFeatures.text = features
if (ctx.card!!.useDefaultPIN1()) {
imgPIN.setImageResource(R.drawable.unlock_pin1)
imgPIN.setOnClickListener { Toast.makeText(context, R.string.this_banknote_protected_default_PIN1_code, Toast.LENGTH_LONG).show() }
} else {
imgPIN.setImageResource(R.drawable.lock_pin1)
imgPIN.setOnClickListener { Toast.makeText(context, R.string.this_banknote_protected_user_PIN1_code, Toast.LENGTH_LONG).show() }
}
if (ctx.card!!.pauseBeforePIN2 > 0 && (ctx.card!!.useDefaultPIN2()!! || !ctx.card!!.useSmartSecurityDelay())) {
imgPIN2orSecurityDelay.setImageResource(R.drawable.timer)
imgPIN2orSecurityDelay.setOnClickListener { Toast.makeText(context, String.format(getString(R.string.this_banknote_will_enforce), ctx.card!!.pauseBeforePIN2 / 1000.0), Toast.LENGTH_LONG).show() }
} else if (ctx.card!!.useDefaultPIN2()!!) {
imgPIN2orSecurityDelay.setImageResource(R.drawable.unlock_pin2)
imgPIN2orSecurityDelay.setOnClickListener { Toast.makeText(context, R.string.this_banknote_protected_default_PIN2_code, Toast.LENGTH_LONG).show() }
} else {
imgPIN2orSecurityDelay.setImageResource(R.drawable.lock_pin2)
imgPIN2orSecurityDelay.setOnClickListener { Toast.makeText(context, R.string.this_banknote_protected_user_PIN2_code, Toast.LENGTH_LONG).show() }
}
if (ctx.card!!.useDevelopersFirmware()!!) {
imgDeveloperVersion.setImageResource(R.drawable.ic_developer_version)
imgDeveloperVersion.visibility = View.VISIBLE
imgDeveloperVersion.setOnClickListener { Toast.makeText(context, R.string.unlocked_banknote_only_development_use, Toast.LENGTH_LONG).show() }
} else
imgDeveloperVersion.visibility = View.INVISIBLE
if (ctx.card!!.status == TangemCard.Status.Loaded) {
tvWallet.text = ctx.coinData!!.shortWalletString
if (ctx.card!!.isWalletPublicKeyValid) {
tvWalletIdentity.setText(R.string.possession_proved)
tvWalletIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed))
} else {
tvWalletIdentity.setText(R.string.possession_not_proved)
tvWalletIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed))
}
} else {
tvWallet!!.setText(R.string.not_available)
tvWalletIdentity.setText(R.string.no_data_string)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun doSetPin() {
requestPIN2Count = 0
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestNewPIN.toString())
newPIN = ""
newPIN2 = ""
startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN)
}
private fun doResetPin() {
requestPIN2Count = 0
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
newPIN = PINStorage.getDefaultPIN()
newPIN2 = ""
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
}
private fun doResetPin2() {
requestPIN2Count = 0
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
newPIN = ""
newPIN2 = PINStorage.getDefaultPIN2()
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
}
private fun doResetPins() {
requestPIN2Count = 0
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
newPIN = PINStorage.getDefaultPIN()
newPIN2 = PINStorage.getDefaultPIN2()
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
}
private fun doSetPin2() {
requestPIN2Count = 0
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestNewPIN2.toString())
newPIN = ""
newPIN2 = ""
startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN2)
}
private fun doPurge() {
requestPIN2Count = 0
val engine = CoinEngineFactory.create(ctx)
if (!engine!!.hasBalanceInfo()) {
return
} else if (engine.isBalanceNotZero) {
Toast.makeText(context, R.string.cannot_erase_wallet_with_non_zero_balance, Toast.LENGTH_LONG).show()
return
}
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
}
fun prepareResultIntent(): Intent {
val data = Intent()
ctx.saveToIntent(data)
return data
}
private fun showMenu(v: View) {
val popup = PopupMenu(activity, v)
val inflater = popup.menuInflater
inflater.inflate(R.menu.menu_loaded_wallet, popup.menu)
popup.menu.findItem(R.id.action_set_PIN1).isVisible = ctx.card!!.allowSwapPIN()!!
popup.menu.findItem(R.id.action_reset_PIN1).isVisible = ctx.card!!.allowSwapPIN()!! && !ctx.card!!.useDefaultPIN1()
popup.menu.findItem(R.id.action_set_PIN2).isVisible = ctx.card!!.allowSwapPIN2()!!
popup.menu.findItem(R.id.action_reset_PIN2).isVisible = ctx.card!!.allowSwapPIN2()!! && !ctx.card!!.useDefaultPIN2()
popup.menu.findItem(R.id.action_reset_PINs).isVisible = ctx.card!!.allowSwapPIN()!! && ctx.card!!.allowSwapPIN2()!! && !ctx.card!!.useDefaultPIN1() && !ctx.card!!.useDefaultPIN2()
if (!ctx.card!!.isReusable || ctx.card!!.status != TangemCard.Status.Loaded)
popup.menu.findItem(R.id.action_purge).isVisible = false
popup.setOnMenuItemClickListener { item ->
val id = item.itemId
when (id) {
R.id.action_set_PIN1 -> doSetPin()
R.id.action_reset_PIN1 -> doResetPin()
R.id.action_set_PIN2 -> doSetPin2()
R.id.action_reset_PIN2 -> doResetPin2()
R.id.action_reset_PINs -> doResetPins()
R.id.action_purge -> doPurge()
}
false
}
if (BuildConfig.DEBUG) {
popup.menu.findItem(R.id.action_set_PIN2).isEnabled = true
popup.menu.findItem(R.id.action_reset_PIN2).isEnabled = true
}
popup.show()
}
}