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() } }