1
0
Estonian-ID-card-mobile-aut.../MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/AuthFragment.kt
stargateprovider 73efb00368 Added basic notifications to the user
For when exceptions occur when communicating with the ID-card
2021-11-08 23:51:07 +02:00

173 lines
6.8 KiB
Kotlin

package com.tarkvaraprojekt.mobileauthapp
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.tech.IsoDep
import android.os.Bundle
import android.os.CountDownTimer
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.tarkvaraprojekt.mobileauthapp.NFC.Comms
import com.tarkvaraprojekt.mobileauthapp.auth.AuthAppException
import com.tarkvaraprojekt.mobileauthapp.auth.InvalidCANException
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentAuthBinding
import com.tarkvaraprojekt.mobileauthapp.model.ParametersViewModel
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
import java.io.IOException
import java.lang.Exception
import java.security.GeneralSecurityException
import kotlin.system.exitProcess
/**
* Fragment that asks the user to detect the ID card with mobile NFC chip.
* Currently contains a next button that won't be needed later on.
* This button is just needed to test navigation between fragments so that every step exists.
*/
class AuthFragment : Fragment() {
private val viewModel: SmartCardViewModel by activityViewModels()
private val intentParameters: ParametersViewModel by activityViewModels()
private var binding: FragmentAuthBinding? = null
private val args: CanFragmentArgs by navArgs()
private lateinit var timer: CountDownTimer
private var timeRemaining: Int = 90
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentAuthBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
timer = object : CountDownTimer((timeRemaining * 1000).toLong(), 1000) {
override fun onTick(p0: Long) {
timeRemaining--
if (timeRemaining == 0) {
binding?.timeCounter?.text = getString(R.string.no_time)
} else {
binding?.timeCounter?.text = getString(R.string.time_left, timeRemaining)
}
}
override fun onFinish() {
Thread.sleep(750)
goToTheStart()
}
}.start()
binding!!.nextButton.setOnClickListener { goToNextFragment() }
binding!!.cancelButton.setOnClickListener { goToTheStart() }
val adapter = NfcAdapter.getDefaultAdapter(activity)
if (adapter != null)
getInfoFromIdCard(adapter)
}
private fun getInfoFromIdCard(adapter: NfcAdapter) {
if (args.reading) {
adapter.enableReaderMode(activity, { tag ->
timer.cancel()
requireActivity().runOnUiThread {
binding!!.timeCounter.text = getString(R.string.card_detected)
}
var msgCode = 0
val card = IsoDep.get(tag)
card.timeout = 32768
card.use {
try {
val comms = Comms(it, viewModel.userCan)
val response = comms.readPersonalData(byteArrayOf(1, 2, 6, 3, 4, 8))
viewModel.setUserFirstName(response[1])
viewModel.setUserLastName(response[0])
viewModel.setUserIdentificationNumber(response[2])
viewModel.setGender(response[3])
viewModel.setCitizenship(response[4])
viewModel.setExpiration(response[5])
requireActivity().runOnUiThread {
binding!!.timeCounter.text = getString(R.string.data_read)
}
} catch (e: android.nfc.TagLostException) {
msgCode = R.string.tag_lost
} catch (e: InvalidCANException) {
msgCode = R.string.invalid_can
// If the CAN is wrong we will also delete the saved CAN so that the user won't use it again.
viewModel.deleteCan(requireContext())
} catch (e: AuthAppException) {
msgCode = when (e.code) {
448 -> R.string.err_bad_data
500 -> R.string.err_internal
else -> R.string.err_unknown
}
} catch (e: GeneralSecurityException) {
msgCode = R.string.err_internal
} catch (e: IOException) {
msgCode = R.string.err_reading_card
} catch (e: Exception) {
msgCode = R.string.err_unknown
} finally {
adapter.disableReaderMode(activity)
}
if (msgCode != 0) {
requireActivity().runOnUiThread {
binding!!.timeCounter.text = getString(msgCode)
}
// Gives user some time to read the error message
Thread.sleep(1000)
goToTheStart()
}
}
}, NfcAdapter.FLAG_READER_NFC_A, null)
} else { //We want to create a JWT instead of reading the info from the card.
goToNextFragment()
}
}
private fun goToNextFragment() {
timer.cancel()
if (args.auth) {
val action = AuthFragmentDirections.actionAuthFragmentToResultFragment(mobile = args.mobile)
findNavController().navigate(action)
} else {
findNavController().navigate(R.id.action_authFragment_to_userFragment)
}
}
private fun goToTheStart() {
viewModel.clearUserInfo()
timer.cancel()
if (args.reading) {
findNavController().navigate(R.id.action_authFragment_to_homeFragment)
} else {
if (!args.mobile) {
//Currently for some reason the activity is not killed entirely. Must be looked into further.
requireActivity().finish()
exitProcess(0)
} else {
val resultIntent = Intent()
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
requireActivity().finish()
}
}
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
}