432 lines
No EOL
15 KiB
Kotlin
432 lines
No EOL
15 KiB
Kotlin
package com.tangem.presentation.activity
|
|
|
|
import android.app.Activity
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.pm.ActivityInfo
|
|
import android.nfc.NfcAdapter
|
|
import android.nfc.Tag
|
|
import android.nfc.tech.IsoDep
|
|
import android.os.Bundle
|
|
import android.support.v7.app.AppCompatActivity
|
|
import android.support.v7.widget.PopupMenu
|
|
import android.view.Menu
|
|
import android.view.MenuItem
|
|
import android.view.View
|
|
import android.view.animation.Animation
|
|
import android.view.animation.DecelerateInterpolator
|
|
import android.view.animation.Transformation
|
|
import android.widget.RelativeLayout
|
|
import android.widget.Toast
|
|
import com.scottyab.rootbeer.RootBeer
|
|
import com.tangem.data.nfc.ReadCardInfoTask
|
|
import com.tangem.domain.cardReader.CardProtocol
|
|
import com.tangem.domain.cardReader.FW
|
|
import com.tangem.domain.cardReader.NfcManager
|
|
import com.tangem.domain.wallet.*
|
|
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
|
|
import com.tangem.presentation.dialog.RootFoundDialog
|
|
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
|
|
import com.tangem.util.CommonUtil
|
|
import com.tangem.util.PhoneUtility
|
|
import com.tangem.wallet.BuildConfig
|
|
import com.tangem.wallet.R
|
|
import kotlinx.android.synthetic.main.activity_main.*
|
|
import java.io.File
|
|
import java.util.*
|
|
|
|
class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications, PopupMenu.OnMenuItemClickListener {
|
|
|
|
companion object {
|
|
val TAG: String = MainActivity::class.java.simpleName
|
|
|
|
private const val REQUEST_CODE_SEND_EMAIL = 3
|
|
private const val REQUEST_CODE_ENTER_PIN_ACTIVITY = 2
|
|
private const val REQUEST_CODE_SHOW_CARD_ACTIVITY = 1
|
|
|
|
const val EXTRA_LAST_DISCOVERED_TAG = "extra_last_tag"
|
|
|
|
fun commonInit(context: Context) {
|
|
if (PINStorage.needInit())
|
|
PINStorage.Init(context)
|
|
|
|
if (LastSignStorage.needInit())
|
|
LastSignStorage.Init(context)
|
|
|
|
if (Issuer.needInit())
|
|
Issuer.Init(context)
|
|
|
|
if (FW.needInit())
|
|
FW.Init(context)
|
|
}
|
|
}
|
|
|
|
private var zipFile: File? = null
|
|
private val onNFCReaderCallback: NfcAdapter.ReaderCallback? = null
|
|
private val onCardsClean: OnCardsClean? = null
|
|
private var antenna: DeviceNFCAntennaLocation? = null
|
|
private var mNfcManager: NfcManager? = null
|
|
private var readCardInfoTask: ReadCardInfoTask? = null
|
|
private var unsuccessReadCount = 0
|
|
private var lastTag: Tag? = 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)
|
|
|
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
|
|
|
mNfcManager = NfcManager(this, this)
|
|
|
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
|
|
|
|
commonInit(applicationContext)
|
|
|
|
rippleBackgroundNfc.startRippleAnimation()
|
|
|
|
antenna = DeviceNFCAntennaLocation()
|
|
antenna!!.getAntennaLocation()
|
|
|
|
// set card orientation
|
|
when (antenna!!.orientation) {
|
|
DeviceNFCAntennaLocation.CARD_ORIENTATION_HORIZONTAL -> {
|
|
ivHandCardHorizontal.visibility = View.VISIBLE
|
|
ivHandCardVertical.visibility = View.GONE
|
|
}
|
|
|
|
DeviceNFCAntennaLocation.CARD_ORIENTATION_VERTICAL -> {
|
|
ivHandCardVertical.visibility = View.VISIBLE
|
|
ivHandCardHorizontal.visibility = View.GONE
|
|
}
|
|
}
|
|
|
|
// set card z position
|
|
when (antenna!!.z) {
|
|
DeviceNFCAntennaLocation.CARD_ON_BACK -> llHand.elevation = 0.0f
|
|
DeviceNFCAntennaLocation.CARD_ON_FRONT -> llHand.elevation = 30.0f
|
|
}
|
|
|
|
// set phone name
|
|
if (antenna!!.fullName != "")
|
|
tvNFCHint.text = String.format(getString(R.string.scan_banknote), antenna!!.fullName)
|
|
else
|
|
tvNFCHint.text = String.format(getString(R.string.scan_banknote), getString(R.string.phone))
|
|
|
|
animate()
|
|
|
|
// 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(fragmentManager, RootFoundDialog.TAG)
|
|
|
|
// set listeners
|
|
fab.setOnClickListener { this.showMenu(it) }
|
|
}
|
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
if (requestCode == REQUEST_CODE_SEND_EMAIL) {
|
|
if (zipFile != null) {
|
|
zipFile!!.delete()
|
|
zipFile = null
|
|
}
|
|
}
|
|
|
|
if (requestCode == 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 temporaly log file");
|
|
}
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
} finally {
|
|
if (f != null && f.exists())
|
|
f.delete()
|
|
}
|
|
return true
|
|
}
|
|
R.id.managePIN -> {
|
|
showSavePinActivity()
|
|
return true
|
|
}
|
|
|
|
R.id.managePIN2 -> {
|
|
showSavePin2Activity()
|
|
return true
|
|
}
|
|
|
|
// R.id.cleanCards -> {
|
|
// onCardsClean!!.doClean()
|
|
// llTapPrompt.visibility = View.VISIBLE
|
|
// return true
|
|
// }
|
|
|
|
R.id.about -> {
|
|
showLogoActivity()
|
|
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(" + String.valueOf(1000 + 3000 * unsuccessReadCount) + ")");
|
|
if (unsuccessReadCount < 2) {
|
|
isoDep.timeout = 2000 + 5000 * unsuccessReadCount
|
|
} else {
|
|
isoDep.timeout = 90000
|
|
}
|
|
lastTag = tag
|
|
|
|
readCardInfoTask = ReadCardInfoTask(this, mNfcManager, isoDep, this)
|
|
readCardInfoTask!!.start()
|
|
|
|
// Log.i(TAG, "onTagDiscovered " + Arrays.toString(tag.getId()));
|
|
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
mNfcManager!!.notifyReadResult(false)
|
|
}
|
|
}
|
|
|
|
public override fun onResume() {
|
|
super.onResume()
|
|
animate()
|
|
ReadCardInfoTask.resetLastReadInfo()
|
|
mNfcManager!!.onResume()
|
|
}
|
|
|
|
public override fun onPause() {
|
|
mNfcManager!!.onPause()
|
|
if (readCardInfoTask != null) {
|
|
readCardInfoTask!!.cancel(true)
|
|
}
|
|
super.onPause()
|
|
}
|
|
|
|
public override fun onStop() {
|
|
// dismiss enable NFC dialog
|
|
mNfcManager!!.onStop()
|
|
if (readCardInfoTask != null) {
|
|
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) {
|
|
mNfcManager!!.notifyReadResult(true)
|
|
rlProgressBar.post {
|
|
rlProgressBar.visibility = View.GONE
|
|
|
|
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)
|
|
card.LoadFromBundle(cardInfo.getBundle("Card"))
|
|
|
|
val intent: Intent
|
|
intent = when {
|
|
card.status == TangemCard.Status.Empty -> Intent(this, EmptyWalletActivity::class.java)
|
|
card.status == TangemCard.Status.Loaded -> Intent(this, LoadedWalletActivity::class.java)
|
|
card.status == TangemCard.Status.Purged -> {
|
|
Toast.makeText(this, R.string.erased_wallet, Toast.LENGTH_SHORT).show()
|
|
return@post
|
|
}
|
|
card.status == TangemCard.Status.NotPersonalized -> {
|
|
Toast.makeText(this, R.string.not_personalized, Toast.LENGTH_SHORT).show()
|
|
return@post
|
|
}
|
|
else -> Intent(this, LoadedWalletActivity::class.java)
|
|
}
|
|
|
|
intent.putExtra(EXTRA_LAST_DISCOVERED_TAG, lastTag)
|
|
intent.putExtras(cardInfo)
|
|
startActivityForResult(intent, REQUEST_CODE_SHOW_CARD_ACTIVITY)
|
|
}
|
|
|
|
} 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)
|
|
doEnterPIN()
|
|
else {
|
|
if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported)
|
|
if (!NoExtendedLengthSupportDialog.allReadyShowed)
|
|
NoExtendedLengthSupportDialog().show(fragmentManager, NoExtendedLengthSupportDialog.TAG)
|
|
|
|
lastTag = null
|
|
ReadCardInfoTask.resetLastReadInfo()
|
|
mNfcManager!!.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))
|
|
}
|
|
|
|
interface OnCardsClean {
|
|
fun doClean()
|
|
}
|
|
|
|
private fun showLogoActivity() {
|
|
val intent = Intent(baseContext, LogoActivity::class.java)
|
|
intent.putExtra(LogoActivity.TAG, true)
|
|
intent.putExtra(LogoActivity.EXTRA_AUTO_HIDE, false)
|
|
startActivity(intent)
|
|
}
|
|
|
|
private fun animate() {
|
|
val lp = llHand.layoutParams as RelativeLayout.LayoutParams
|
|
val lp2 = llNfc.layoutParams as RelativeLayout.LayoutParams
|
|
val dp = resources.displayMetrics.density
|
|
val lm = dp * (69 + antenna!!.x * 75)
|
|
lp.topMargin = (dp * (-100 + antenna!!.y * 250)).toInt()
|
|
lp2.topMargin = (dp * (-125 + antenna!!.y * 250)).toInt()
|
|
llNfc.layoutParams = lp2
|
|
|
|
val a = object : Animation() {
|
|
override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
|
|
lp.leftMargin = (lm * interpolatedTime).toInt()
|
|
llHand.layoutParams = lp
|
|
}
|
|
}
|
|
a.duration = 2000
|
|
a.interpolator = DecelerateInterpolator()
|
|
llHand.startAnimation(a)
|
|
}
|
|
|
|
private fun showSavePinActivity() {
|
|
val intent = Intent(baseContext, PinSaveActivity::class.java)
|
|
intent.putExtra("PIN2", false)
|
|
startActivity(intent)
|
|
}
|
|
|
|
private fun showSavePin2Activity() {
|
|
val intent = Intent(baseContext, PinSaveActivity::class.java)
|
|
intent.putExtra("PIN2", true)
|
|
startActivity(intent)
|
|
}
|
|
|
|
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()
|
|
}
|
|
|
|
private fun doEnterPIN() {
|
|
val intent = Intent(this, PinRequestActivity::class.java)
|
|
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN.toString())
|
|
startActivityForResult(intent, REQUEST_CODE_ENTER_PIN_ACTIVITY)
|
|
}
|
|
|
|
} |