8 Commits

Author SHA1 Message Date
TanelOrumaa
c28fc2be48 Merge branch 'main' of https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC 2022-01-18 00:35:16 +02:00
Kevin
7edd8189a4 Update README.md 2021-12-14 22:52:08 +02:00
TanelOrumaa
b565f6846d MOB-55 Demo website 2021-12-07 00:05:06 +02:00
Henrik Lepson
60207319b7 Merge pull request #16 from TanelOrumaa/newapproach
Improved code
2021-12-06 20:27:00 +02:00
Henrik Lepson
e5300dfa5e got rid of git status syntax 2021-12-04 17:21:07 +02:00
Henrik Lepson
d4c2a11521 added more error messages 2021-12-04 17:08:58 +02:00
Henrik Lepson
09c4fa6be3 fixed small issue in testmobileapp 2021-12-04 12:46:40 +02:00
Henrik Lepson
63bc89b0e4 Merge pull request #14 from TanelOrumaa/iter4UI
UI/UX improvements for iteration 4
2021-12-03 16:24:00 +02:00
21 changed files with 195 additions and 134 deletions

View File

@@ -36,7 +36,8 @@ class AuthFragment : Fragment() {
private val paramsModel: ParametersViewModel by activityViewModels() private val paramsModel: ParametersViewModel by activityViewModels()
private var binding: FragmentAuthBinding? = null private var _binding: FragmentAuthBinding? = null
private val binding get() = _binding!!
private val args: CanFragmentArgs by navArgs() private val args: CanFragmentArgs by navArgs()
@@ -49,8 +50,8 @@ class AuthFragment : Fragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentAuthBinding.inflate(inflater, container, false) _binding = FragmentAuthBinding.inflate(inflater, container, false)
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -59,9 +60,9 @@ class AuthFragment : Fragment() {
override fun onTick(p0: Long) { override fun onTick(p0: Long) {
timeRemaining-- timeRemaining--
if (timeRemaining == 0) { if (timeRemaining == 0) {
binding?.timeCounter?.text = getString(R.string.no_time) binding.timeCounter.text = getString(R.string.no_time)
} else { } else {
binding?.timeCounter?.text = getString(R.string.time_left, timeRemaining) binding.timeCounter.text = getString(R.string.time_left, timeRemaining)
} }
} }
@@ -71,9 +72,9 @@ class AuthFragment : Fragment() {
} }
}.start() }.start()
// The button exists in code for testing reasons, but not visible to the user anymore unless visibility is changed in the code. // The button exists in code for testing reasons, but not visible to the user anymore unless visibility is changed in the code.
binding!!.nextButton.visibility = View.GONE binding.nextButton.visibility = View.GONE
binding!!.nextButton.setOnClickListener { goToNextFragment() } binding.nextButton.setOnClickListener { goToNextFragment() }
binding!!.cancelButton.setOnClickListener { cancelAuth() } binding.cancelButton.setOnClickListener { cancelAuth() }
val adapter = NfcAdapter.getDefaultAdapter(activity) val adapter = NfcAdapter.getDefaultAdapter(activity)
if (adapter != null) if (adapter != null)
getInfoFromIdCard(adapter) getInfoFromIdCard(adapter)
@@ -104,7 +105,7 @@ class AuthFragment : Fragment() {
adapter.enableReaderMode(activity, { tag -> adapter.enableReaderMode(activity, { tag ->
timer.cancel() timer.cancel()
requireActivity().runOnUiThread { requireActivity().runOnUiThread {
binding!!.timeCounter.text = getString(R.string.card_detected) binding.timeCounter.text = getString(R.string.card_detected)
} }
val card = IsoDep.get(tag) val card = IsoDep.get(tag)
card.timeout = 32768 card.timeout = 32768
@@ -127,11 +128,11 @@ class AuthFragment : Fragment() {
when ("invalid pin") { when ("invalid pin") {
in e.message.toString().lowercase() -> requireActivity().runOnUiThread { in e.message.toString().lowercase() -> requireActivity().runOnUiThread {
val messagePieces = e.message.toString().split(" ") val messagePieces = e.message.toString().split(" ")
binding!!.timeCounter.text = getString(R.string.wrong_pin, messagePieces[messagePieces.size - 1]) binding.timeCounter.text = getString(R.string.wrong_pin, messagePieces[messagePieces.size - 1])
viewModel.deletePin(requireContext()) viewModel.deletePin(requireContext())
} }
else -> requireActivity().runOnUiThread { else -> requireActivity().runOnUiThread {
binding!!.timeCounter.text = getString(R.string.wrong_can_text) binding.timeCounter.text = getString(R.string.wrong_can_text)
viewModel.deleteCan(requireContext()) viewModel.deleteCan(requireContext())
} }
} }
@@ -149,6 +150,6 @@ class AuthFragment : Fragment() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding = null _binding = null
} }
} }

View File

@@ -29,7 +29,8 @@ class CanFragment : Fragment() {
private val viewModel: SmartCardViewModel by activityViewModels() private val viewModel: SmartCardViewModel by activityViewModels()
private var binding: FragmentCanBinding? = null private var _binding: FragmentCanBinding? = null
private val binding get() = _binding!!
// Navigation arguments: // Navigation arguments:
// saving = true means that we are navigating here from the settings menu and must return to the settings menu. // saving = true means that we are navigating here from the settings menu and must return to the settings menu.
@@ -40,17 +41,17 @@ class CanFragment : Fragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentCanBinding.inflate(inflater, container, false) _binding = FragmentCanBinding.inflate(inflater, container, false)
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
checkIfSkip() checkIfSkip()
binding!!.canTextField.editText?.addTextChangedListener { binding.canTextField.editText?.addTextChangedListener {
checkEnteredCan() checkEnteredCan()
} }
binding!!.buttonCancel.setOnClickListener { goToTheStart() } binding.buttonCancel.setOnClickListener { goToTheStart() }
} }
/** /**
@@ -112,7 +113,7 @@ class CanFragment : Fragment() {
* allowed to modify the entered can. * allowed to modify the entered can.
*/ */
private fun checkEnteredCan() { private fun checkEnteredCan() {
val enteredCan = binding!!.canTextField.editText?.text.toString() val enteredCan = binding.canTextField.editText?.text.toString()
if (enteredCan.length == 6) { if (enteredCan.length == 6) {
viewModel.setUserCan(enteredCan) viewModel.setUserCan(enteredCan)
viewModel.storeCan(requireContext()) //Maybe storeCan should always automatically call setUserCan method as well because these methods usually are used together viewModel.storeCan(requireContext()) //Maybe storeCan should always automatically call setUserCan method as well because these methods usually are used together
@@ -127,6 +128,6 @@ class CanFragment : Fragment() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding = null _binding = null
} }
} }

View File

@@ -39,7 +39,8 @@ class HomeFragment : Fragment() {
private val intentParams: ParametersViewModel by activityViewModels() private val intentParams: ParametersViewModel by activityViewModels()
private var binding: FragmentHomeBinding? = null private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
// The ID card reader mode is enabled on the home fragment when can is saved. // The ID card reader mode is enabled on the home fragment when can is saved.
private var canSaved: Boolean = false private var canSaved: Boolean = false
@@ -54,10 +55,10 @@ class HomeFragment : Fragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentHomeBinding.inflate(inflater, container, false) _binding = FragmentHomeBinding.inflate(inflater, container, false)
// Making settings menu active again // Making settings menu active again
(activity as MainActivity).menuAvailable = true (activity as MainActivity).menuAvailable = true
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -111,15 +112,29 @@ class HomeFragment : Fragment() {
intentParams.setAuthUrl(requireActivity().intent.data!!.getQueryParameter("authUrl")!!) intentParams.setAuthUrl(requireActivity().intent.data!!.getQueryParameter("authUrl")!!)
intentParams.setOrigin(requireActivity().intent.data!!.getQueryParameter("originUrl")!!) intentParams.setOrigin(requireActivity().intent.data!!.getQueryParameter("originUrl")!!)
} }
goToTheNextFragment(mobile)
} catch (e: Exception) { } catch (e: Exception) {
// There was a problem with parameters, which means that authentication is not possible. // There was a problem with parameters, which means that authentication is not possible.
// In that case we will cancel the authentication immediately as it would be waste of the user's time to carry on // In that case we will cancel the authentication immediately as it would be waste of the user's time to carry on
// before getting an inevitable error. // before getting an inevitable error.
val message = MaterialAlertDialogBuilder(requireContext())
message.setTitle(getString(R.string.problem_parameters))
if (intentParams.challenge == "") {
message.setMessage(getString(R.string.problem_challenge))
} else if (intentParams.authUrl == "") {
message.setMessage(getString(R.string.problem_authurl))
} else if (intentParams.origin == "") {
message.setMessage(getString(R.string.problem_originurl))
} else {
message.setMessage(getString(R.string.problem_other))
}
message.setPositiveButton(getString(R.string.continue_button)) {_, _ ->
val resultIntent = Intent() val resultIntent = Intent()
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent) requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
requireActivity().finish() requireActivity().finish()
} }
goToTheNextFragment(mobile) message.show()
}
} }
/** /**
@@ -127,12 +142,12 @@ class HomeFragment : Fragment() {
*/ */
private fun canState() { private fun canState() {
if (viewModel.userCan.length == 6) { if (viewModel.userCan.length == 6) {
binding!!.canStatusText.text = getString(R.string.can_status_saved) binding.canStatusText.text = getString(R.string.can_status_saved)
binding!!.canStatusLogo.setImageResource(R.drawable.ic_check_logo) binding.canStatusLogo.setImageResource(R.drawable.ic_check_logo)
canSaved = true canSaved = true
} else { } else {
binding!!.canStatusText.text = getString(R.string.can_status_negative) binding.canStatusText.text = getString(R.string.can_status_negative)
binding!!.canStatusLogo.setImageResource(R.drawable.ic_info_logo) binding.canStatusLogo.setImageResource(R.drawable.ic_info_logo)
canSaved = false canSaved = false
} }
} }
@@ -142,11 +157,11 @@ class HomeFragment : Fragment() {
*/ */
private fun pinState() { private fun pinState() {
if (viewModel.userPin.length in 4..12) { if (viewModel.userPin.length in 4..12) {
binding!!.pinStatusText.text = getString(R.string.pin_status_saved) binding.pinStatusText.text = getString(R.string.pin_status_saved)
binding!!.pinStatusLogo.setImageResource(R.drawable.ic_check_logo) binding.pinStatusLogo.setImageResource(R.drawable.ic_check_logo)
} else { } else {
binding!!.pinStatusText.text = getString(R.string.pin_status_negative) binding.pinStatusText.text = getString(R.string.pin_status_negative)
binding!!.pinStatusLogo.setImageResource(R.drawable.ic_info_logo) binding.pinStatusLogo.setImageResource(R.drawable.ic_info_logo)
} }
} }
@@ -172,10 +187,10 @@ class HomeFragment : Fragment() {
/** /**
* Displays a help message to the user explaining what the CAN is * Displays a help message to the user explaining what the CAN is
*/ */
private fun displayMessage() { private fun displayMessage(title: String, message: String) {
val dialog = MaterialAlertDialogBuilder(requireContext()) val dialog = MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.can_question)) .setTitle(title)
.setMessage(getString(R.string.can_explanation)) .setMessage(message)
.setPositiveButton(R.string.return_text){_, _ -> } .setPositiveButton(R.string.return_text){_, _ -> }
.show() .show()
val title = dialog.findViewById<TextView>(R.id.alertTitle) val title = dialog.findViewById<TextView>(R.id.alertTitle)
@@ -188,22 +203,22 @@ class HomeFragment : Fragment() {
*/ */
private fun updateAction(canIsSaved: Boolean) { private fun updateAction(canIsSaved: Boolean) {
if (canIsSaved) { if (canIsSaved) {
binding!!.detectionActionText.text = getString(R.string.action_detect) binding.detectionActionText.text = getString(R.string.action_detect)
enableReaderMode() enableReaderMode()
binding!!.homeActionButton.visibility = View.GONE binding.homeActionButton.visibility = View.GONE
binding!!.homeHelpButton.visibility = View.GONE binding.homeHelpButton.visibility = View.GONE
} else { } else {
binding!!.detectionActionText.text = getString(R.string.action_detect_unavailable) binding.detectionActionText.text = getString(R.string.action_detect_unavailable)
binding!!.homeActionButton.text = getString(R.string.add_can_text) binding.homeActionButton.text = getString(R.string.add_can_text)
binding!!.homeActionButton.setOnClickListener { binding.homeActionButton.setOnClickListener {
val action = HomeFragmentDirections.actionHomeFragmentToCanFragment(saving = true, fromhome = true) val action = HomeFragmentDirections.actionHomeFragmentToCanFragment(saving = true, fromhome = true)
findNavController().navigate(action) findNavController().navigate(action)
} }
binding!!.homeHelpButton.setOnClickListener { binding.homeHelpButton.setOnClickListener {
displayMessage() displayMessage(getString(R.string.can_question), getString(R.string.can_explanation))
} }
binding!!.homeActionButton.visibility = View.VISIBLE binding.homeActionButton.visibility = View.VISIBLE
binding!!.homeHelpButton.visibility = View.VISIBLE binding.homeHelpButton.visibility = View.VISIBLE
} }
} }
@@ -211,11 +226,11 @@ class HomeFragment : Fragment() {
* Resets the error message and allows the user to try again * Resets the error message and allows the user to try again
*/ */
private fun reset() { private fun reset() {
binding!!.homeActionButton.text = getString(R.string.try_again_text) binding.homeActionButton.text = getString(R.string.try_again_text)
binding!!.homeActionButton.setOnClickListener { binding.homeActionButton.setOnClickListener {
updateAction(canSaved) updateAction(canSaved)
} }
binding!!.homeActionButton.visibility = View.VISIBLE binding.homeActionButton.visibility = View.VISIBLE
} }
/** /**
@@ -224,11 +239,11 @@ class HomeFragment : Fragment() {
private fun enableReaderMode() { private fun enableReaderMode() {
val adapter = NfcAdapter.getDefaultAdapter(activity) val adapter = NfcAdapter.getDefaultAdapter(activity)
if (adapter == null || !adapter.isEnabled) { if (adapter == null || !adapter.isEnabled) {
binding!!.detectionActionText.text = getString(R.string.nfc_not_available) binding.detectionActionText.text = getString(R.string.nfc_not_available)
} else { } else {
adapter.enableReaderMode(activity, { tag -> adapter.enableReaderMode(activity, { tag ->
requireActivity().runOnUiThread { requireActivity().runOnUiThread {
binding!!.detectionActionText.text = getString(R.string.card_detected) binding.detectionActionText.text = getString(R.string.card_detected)
} }
val card = IsoDep.get(tag) val card = IsoDep.get(tag)
card.timeout = 32768 card.timeout = 32768
@@ -249,11 +264,11 @@ class HomeFragment : Fragment() {
} catch (e: Exception) { } catch (e: Exception) {
when(e) { when(e) {
is TagLostException -> requireActivity().runOnUiThread { is TagLostException -> requireActivity().runOnUiThread {
binding!!.detectionActionText.text = getString(R.string.id_card_removed_early) binding.detectionActionText.text = getString(R.string.id_card_removed_early)
reset() reset()
} }
else -> requireActivity().runOnUiThread { else -> requireActivity().runOnUiThread {
binding!!.detectionActionText.text = getString(R.string.nfc_reading_error) binding.detectionActionText.text = getString(R.string.nfc_reading_error)
viewModel.deleteCan(requireContext()) viewModel.deleteCan(requireContext())
canState() canState()
reset() reset()
@@ -269,7 +284,9 @@ class HomeFragment : Fragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
if (receiver != null) {
requireActivity().unregisterReceiver(receiver) requireActivity().unregisterReceiver(receiver)
binding = null }
_binding = null
} }
} }

View File

@@ -19,23 +19,24 @@ class Pin2Fragment : Fragment() {
private val viewModel: SmartCardViewModel by activityViewModels() private val viewModel: SmartCardViewModel by activityViewModels()
private var binding: FragmentPin2Binding? = null private var _binding: FragmentPin2Binding? = null
private val binding get() = _binding!!
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentPin2Binding.inflate(inflater, container, false) _binding = FragmentPin2Binding.inflate(inflater, container, false)
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding!!.nextButton.setOnClickListener { binding.nextButton.setOnClickListener {
checkPin2Length() checkPin2Length()
} }
binding!!.cancelButton.setOnClickListener { binding.cancelButton.setOnClickListener {
cancel() cancel()
} }
} }
@@ -45,7 +46,7 @@ class Pin2Fragment : Fragment() {
* then it is saved to the viewModel. * then it is saved to the viewModel.
*/ */
private fun checkPin2Length() { private fun checkPin2Length() {
val enteredPin2 = binding!!.pin2EditText.editText?.text.toString() val enteredPin2 = binding.pin2EditText.editText?.text.toString()
if (enteredPin2.length in 5..12) { if (enteredPin2.length in 5..12) {
viewModel.setUserPin2(enteredPin2) viewModel.setUserPin2(enteredPin2)
} else { } else {
@@ -66,7 +67,7 @@ class Pin2Fragment : Fragment() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding = null _binding = null
} }
} }

View File

@@ -29,7 +29,8 @@ class PinFragment : Fragment() {
private val viewModel: SmartCardViewModel by activityViewModels() private val viewModel: SmartCardViewModel by activityViewModels()
private var binding: FragmentPinBinding? = null private var _binding: FragmentPinBinding? = null
private val binding get() = _binding!!
// Navigation arguments: // Navigation arguments:
// saving = true means that the user must be returned to the settings menu // saving = true means that the user must be returned to the settings menu
@@ -42,8 +43,8 @@ class PinFragment : Fragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentPinBinding.inflate(inflater, container, false) _binding = FragmentPinBinding.inflate(inflater, container, false)
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -51,28 +52,27 @@ class PinFragment : Fragment() {
checkIfSkip() checkIfSkip()
// Switch should be not visible when user is in savings mode // Switch should be not visible when user is in savings mode
if (args.saving) { if (args.saving) {
binding!!.savePinQuestion.visibility = View.GONE binding.savePinQuestion.visibility = View.GONE
binding!!.saveLayout.visibility = View.GONE binding.saveLayout.visibility = View.GONE
} else { } else {
saveToggle = saveToggle =
activity?.getPreferences(Context.MODE_PRIVATE)?.getBoolean("saveToggle", true) == true //Android Studio recommendation to get rid of Boolean?. activity?.getPreferences(Context.MODE_PRIVATE)?.getBoolean("saveToggle", true) == true //Android Studio recommendation to get rid of Boolean?.
Log.i("myLogging", activity?.getPreferences(Context.MODE_PRIVATE)?.getBoolean("saveToggle", true).toString())
if (!saveToggle) { if (!saveToggle) {
binding!!.saveSwitch.isChecked = false binding.saveSwitch.isChecked = false
} }
binding!!.saveSwitch.setOnCheckedChangeListener { _, isChecked -> binding.saveSwitch.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) { if (isChecked) {
binding!!.saveStatus.text = getString(R.string.pin_save_on) binding.saveStatus.text = getString(R.string.pin_save_on)
activity?.getPreferences(Context.MODE_PRIVATE)?.edit()?.putBoolean("saveToggle", true)?.apply() activity?.getPreferences(Context.MODE_PRIVATE)?.edit()?.putBoolean("saveToggle", true)?.apply()
} else { } else {
binding!!.saveStatus.text = getString(R.string.pin_save_off) binding.saveStatus.text = getString(R.string.pin_save_off)
activity?.getPreferences(Context.MODE_PRIVATE)?.edit()?.putBoolean("saveToggle", false)?.apply() activity?.getPreferences(Context.MODE_PRIVATE)?.edit()?.putBoolean("saveToggle", false)?.apply()
} }
saveToggle = !saveToggle saveToggle = !saveToggle
} }
} }
binding!!.buttonContinue.setOnClickListener { checkEnteredPin() } binding.buttonContinue.setOnClickListener { checkEnteredPin() }
binding!!.buttonCancel.setOnClickListener { goToTheStart() } binding.buttonCancel.setOnClickListener { goToTheStart() }
} }
/** /**
@@ -130,7 +130,7 @@ class PinFragment : Fragment() {
* allowed to modify the entered PIN 1. * allowed to modify the entered PIN 1.
*/ */
private fun checkEnteredPin() { private fun checkEnteredPin() {
val enteredPin = binding!!.pinTextField.editText?.text.toString() val enteredPin = binding.pinTextField.editText?.text.toString()
if (enteredPin.length in 4..12) { if (enteredPin.length in 4..12) {
viewModel.setUserPin(enteredPin) viewModel.setUserPin(enteredPin)
if (args.saving) { if (args.saving) {
@@ -152,6 +152,6 @@ class PinFragment : Fragment() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding = null _binding = null
} }
} }

View File

@@ -24,7 +24,8 @@ class ResultFragment : Fragment() {
private val paramsModel: ParametersViewModel by activityViewModels() private val paramsModel: ParametersViewModel by activityViewModels()
private var binding: FragmentResultBinding? = null private var _binding: FragmentResultBinding? = null
private val binding get() = _binding!!
private val args: ResultFragmentArgs by navArgs() private val args: ResultFragmentArgs by navArgs()
@@ -33,8 +34,8 @@ class ResultFragment : Fragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentResultBinding.inflate(inflater, container, false) _binding = FragmentResultBinding.inflate(inflater, container, false)
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -86,7 +87,7 @@ class ResultFragment : Fragment() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding = null _binding = null
} }
} }

View File

@@ -20,33 +20,34 @@ class UserFragment : Fragment() {
private val viewModel: SmartCardViewModel by activityViewModels() private val viewModel: SmartCardViewModel by activityViewModels()
private var binding: FragmentUserBinding? = null private var _binding: FragmentUserBinding? = null
private val binding get() = _binding!!
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentUserBinding.inflate(inflater, container, false) _binding = FragmentUserBinding.inflate(inflater, container, false)
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
displayInformation() displayInformation()
binding!!.clearButton.setOnClickListener { goToTheStart() } binding.clearButton.setOnClickListener { goToTheStart() }
} }
/** /**
* Assigns text values to the fields in order to display user information. * Assigns text values to the fields in order to display user information.
*/ */
private fun displayInformation() { private fun displayInformation() {
binding!!.userName.text = binding.userName.text =
getString(R.string.user_name, viewModel.userFirstName, viewModel.userLastName) getString(R.string.user_name, viewModel.userFirstName, viewModel.userLastName)
binding!!.identificationNumber.text = viewModel.userIdentificationNumber binding.identificationNumber.text = viewModel.userIdentificationNumber
binding!!.gender.text = viewModel.gender binding.gender.text = viewModel.gender
binding!!.expiration.text = viewModel.expiration.replace(" ", "/") binding.expiration.text = viewModel.expiration.replace(" ", "/")
binding!!.citizenship.text = viewModel.citizenship binding.citizenship.text = viewModel.citizenship
} }
/** /**
@@ -59,6 +60,6 @@ class UserFragment : Fragment() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding = null _binding = null
} }
} }

View File

@@ -25,7 +25,8 @@ class SettingsFragment : Fragment() {
private val viewModel: SmartCardViewModel by activityViewModels() private val viewModel: SmartCardViewModel by activityViewModels()
private var binding: FragmentSettingsBinding? = null private var _binding: FragmentSettingsBinding? = null
private val binding get() = _binding!!
private var showPin: Boolean = false private var showPin: Boolean = false
@@ -34,8 +35,8 @@ class SettingsFragment : Fragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
binding = FragmentSettingsBinding.inflate(inflater, container, false) _binding = FragmentSettingsBinding.inflate(inflater, container, false)
return binding!!.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -43,10 +44,10 @@ class SettingsFragment : Fragment() {
showCanField() showCanField()
showPinField() showPinField()
togglePinButton() togglePinButton()
binding!!.canMenuAction.setOnClickListener { canAction() } binding.canMenuAction.setOnClickListener { canAction() }
binding!!.pinMenuAction.setOnClickListener { pinAction() } binding.pinMenuAction.setOnClickListener { pinAction() }
binding!!.pinMenuShow.setOnClickListener { togglePin() } binding.pinMenuShow.setOnClickListener { togglePin() }
binding!!.returnButton.setOnClickListener { backToHome() } binding.returnButton.setOnClickListener { backToHome() }
} }
/** /**
@@ -64,11 +65,11 @@ class SettingsFragment : Fragment() {
*/ */
private fun showCanField() { private fun showCanField() {
if (viewModel.userCan.length == 6) { if (viewModel.userCan.length == 6) {
binding!!.canSaved.text = getString(R.string.saved_can, viewModel.userCan) binding.canSaved.text = getString(R.string.saved_can, viewModel.userCan)
binding!!.canMenuAction.text = getString(R.string.can_delete) binding.canMenuAction.text = getString(R.string.can_delete)
} else { } else {
binding!!.canSaved.text = getString(R.string.saved_can, getString(R.string.missing)) binding.canSaved.text = getString(R.string.saved_can, getString(R.string.missing))
binding!!.canMenuAction.text = getString(R.string.add_can_text) binding.canMenuAction.text = getString(R.string.add_can_text)
} }
} }
@@ -95,16 +96,16 @@ class SettingsFragment : Fragment() {
*/ */
private fun showPinField() { private fun showPinField() {
if (viewModel.userPin.length in 4..12) { if (viewModel.userPin.length in 4..12) {
binding!!.pinMenuShow.visibility = Button.VISIBLE binding.pinMenuShow.visibility = Button.VISIBLE
if (showPin) if (showPin)
binding!!.pinSaved.text = getString(R.string.saved_pin, viewModel.userPin) binding.pinSaved.text = getString(R.string.saved_pin, viewModel.userPin)
else else
binding!!.pinSaved.text = getString(R.string.saved_pin, getString(R.string.hidden_pin)) binding.pinSaved.text = getString(R.string.saved_pin, getString(R.string.hidden_pin))
binding!!.pinMenuAction.text = getString(R.string.pin1_delete) binding.pinMenuAction.text = getString(R.string.pin1_delete)
} else { } else {
binding!!.pinMenuShow.visibility = Button.GONE binding.pinMenuShow.visibility = Button.GONE
binding!!.pinSaved.text = getString(R.string.saved_pin, getString(R.string.missing)) binding.pinSaved.text = getString(R.string.saved_pin, getString(R.string.missing))
binding!!.pinMenuAction.text = getString(R.string.pin1_add) binding.pinMenuAction.text = getString(R.string.pin1_add)
} }
} }
@@ -138,9 +139,9 @@ class SettingsFragment : Fragment() {
*/ */
private fun togglePinButton() { private fun togglePinButton() {
if (showPin) { if (showPin) {
binding!!.pinMenuShow.text = getString(R.string.hide) binding.pinMenuShow.text = getString(R.string.hide)
} else { } else {
binding!!.pinMenuShow.text = getString(R.string.show) binding.pinMenuShow.text = getString(R.string.show)
} }
} }
@@ -154,7 +155,7 @@ class SettingsFragment : Fragment() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding = null _binding = null
} }
} }

View File

@@ -29,7 +29,11 @@
<string name="help_text">HELP</string> <string name="help_text">HELP</string>
<string name="can_question">What is CAN?</string> <string name="can_question">What is CAN?</string>
<string name="can_explanation">CAN is a 6 digit code that is needed to communicate with an ID card. It can be found on the ID card under the card holder\'s picture with a title KASUTAJA ALLKIRI/HOLDER\'S SIGNATURE.</string> <string name="can_explanation">CAN is a 6 digit code that is needed to communicate with an ID card. It can be found on the ID card under the card holder\'s picture with a title KASUTAJA ALLKIRI/HOLDER\'S SIGNATURE.</string>
<string name="problem_parameters">Problem with parameters</string>
<string name="problem_challenge">Challenge is missing</string>
<string name="problem_authurl">AuthUrl is missing</string>
<string name="problem_originurl">OriginUrl is missing</string>
<string name="problem_other">Unspecified problem with parameters</string>
<!-- string resources for PinFragment --> <!-- string resources for PinFragment -->
<string name="pin_view">Please enter PIN 1</string> <string name="pin_view">Please enter PIN 1</string>
<string name="hint_pin">PIN 1</string> <string name="hint_pin">PIN 1</string>

View File

@@ -28,7 +28,11 @@
<string name="help_text">INFO</string> <string name="help_text">INFO</string>
<string name="can_question">Mis on CAN?</string> <string name="can_question">Mis on CAN?</string>
<string name="can_explanation">CAN on 6 kohaline numbritest koosnev kood, mida on vaja ID kaardiga suhtlemiseks. CAN-i leiab ID kaardilt omaniku pildi alt pealkirjaga KASUTAJA ALLKIRI/HOLDER\'S SIGNATURE.</string> <string name="can_explanation">CAN on 6 kohaline numbritest koosnev kood, mida on vaja ID kaardiga suhtlemiseks. CAN-i leiab ID kaardilt omaniku pildi alt pealkirjaga KASUTAJA ALLKIRI/HOLDER\'S SIGNATURE.</string>
<string name="problem_parameters">Probleem parameetritega</string>
<string name="problem_challenge">Puudub challenge parameeter</string>
<string name="problem_authurl">Puudub AuthUrl parameeter</string>
<string name="problem_originurl">Puudub OriginUrl parameeter</string>
<string name="problem_other">Täpsustamata probleem parameetritega</string>
<!-- string resources for PinFragment --> <!-- string resources for PinFragment -->
<string name="pin_view">Palun sisesta PIN 1</string> <string name="pin_view">Palun sisesta PIN 1</string>
<string name="hint_pin">PIN 1</string> <string name="hint_pin">PIN 1</string>

View File

@@ -27,7 +27,11 @@
<string name="help_text">HELP</string> <string name="help_text">HELP</string>
<string name="can_question">What is CAN?</string> <string name="can_question">What is CAN?</string>
<string name="can_explanation">CAN is a 6 digit code that is needed to communicate with an ID card. It can be found on the ID card under the card holder\'s picture with a title KASUTAJA ALLKIRI/HOLDER\'S SIGNATURE.</string> <string name="can_explanation">CAN is a 6 digit code that is needed to communicate with an ID card. It can be found on the ID card under the card holder\'s picture with a title KASUTAJA ALLKIRI/HOLDER\'S SIGNATURE.</string>
<string name="problem_parameters">Problem with parameters</string>
<string name="problem_challenge">Challenge is missing</string>
<string name="problem_authurl">AuthUrl is missing</string>
<string name="problem_originurl">OriginUrl is missing</string>
<string name="problem_other">Unspecified problem with parameters</string>
<!-- string resources for PinFragment --> <!-- string resources for PinFragment -->
<string name="pin_view">Please enter PIN 1</string> <string name="pin_view">Please enter PIN 1</string>
<string name="hint_pin">PIN 1</string> <string name="hint_pin">PIN 1</string>

View File

@@ -22,11 +22,4 @@ More info about installing third party applications on the Android phones: https
The project comes with a test mobile application and a test web application that can be used to try the MobileAuthApp authentication feature even if you don't have any web applications or mobile applications that require user authentication. Both projects come with a README file that help with a setup. The project comes with a test mobile application and a test web application that can be used to try the MobileAuthApp authentication feature even if you don't have any web applications or mobile applications that require user authentication. Both projects come with a README file that help with a setup.
The mobile authentication application, when launched by the user not a website or some other application, can also read card holder's information, which can be used to verify whether the application reads the information from the ID card correctly. The mobile authentication application, when launched by the user not a website or some other application, can also read card holder's information, which can be used to verify whether the application reads the information from the ID card correctly.
### Wiki pages relevant for the "Software project" subject ### See the [Wiki](https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki) for pages relevant for the "Software project" subject
* [Project Vision](https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki/Project-Vision)
* [Release Notes](https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki/Release-notes)
* [Project tasks](https://tvp-mobile-authentication.atlassian.net/jira/software/projects/MOB/boards/1/backlog) (Ask Tanel for JIRA permissions if needed).
* [Project plan](https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki/Project-plan)
* [Use Cases](https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki/Use-Cases)
* [User stories](https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki/User-stories)
* [Use Case Tests](https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki/Use-Case-Tests)

View File

@@ -9,7 +9,6 @@ import android.view.View
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import com.example.testmobileapp.databinding.ActivityMainBinding import com.example.testmobileapp.databinding.ActivityMainBinding
import com.google.gson.JsonObject
import com.koushikdutta.ion.Ion import com.koushikdutta.ion.Ion
import org.json.JSONObject import org.json.JSONObject
@@ -35,9 +34,8 @@ class MainActivity : AppCompatActivity() {
authLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { response -> authLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { response ->
if (response.resultCode == Activity.RESULT_OK) { if (response.resultCode == Activity.RESULT_OK) {
// Currently we are not actually checking whether we get a valid token.
// For testing purposes only, to make sure that we are able to get a response at all.
binding.loginTextView.text = getString(R.string.auth_success) binding.loginTextView.text = getString(R.string.auth_success)
// Logs are used to show what information can be retrieved from the mobileauthapp.
Log.i("getResult", response.data?.getStringExtra("token").toString()) Log.i("getResult", response.data?.getStringExtra("token").toString())
Log.i("getResult", response.data?.getStringExtra("result").toString()) Log.i("getResult", response.data?.getStringExtra("result").toString())
var user = "" var user = ""
@@ -48,14 +46,6 @@ class MainActivity : AppCompatActivity() {
Log.i("getResult", "unable to retrieve name from principal") Log.i("getResult", "unable to retrieve name from principal")
} }
showResult(user) showResult(user)
/*
binding.loginOptionNfcButton.text = "Log Out"
binding.loginOptionNfcButton.setOnClickListener {
binding.loginOptionNfcButton.text = "NFC auth"
binding.loginOptionNfcButton.setOnClickListener { getData() }
}
*/
} }
if (response.resultCode == Activity.RESULT_CANCELED) { if (response.resultCode == Activity.RESULT_CANCELED) {
binding.loginTextView.text = getString(R.string.auth_failure) binding.loginTextView.text = getString(R.string.auth_failure)
@@ -114,6 +104,7 @@ class MainActivity : AppCompatActivity() {
binding.resultLayout.visibility = View.VISIBLE binding.resultLayout.visibility = View.VISIBLE
binding.resultObject.text = getString(R.string.hello, user) binding.resultObject.text = getString(R.string.hello, user)
binding.buttonForget.setOnClickListener { binding.buttonForget.setOnClickListener {
binding.loginTextView.text = getString(R.string.login_text)
binding.resultObject.text = "" binding.resultObject.text = ""
binding.resultLayout.visibility = View.GONE binding.resultLayout.visibility = View.GONE
binding.loginOptions.visibility = View.VISIBLE binding.loginOptions.visibility = View.VISIBLE

View File

@@ -0,0 +1 @@
#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50}#nav{padding:30px}#nav a{font-weight:700;color:#2c3e50}#nav a.router-link-exact-active{color:#42b983}.container>div[data-v-2dcb24ca]{margin-top:2vh}.loginButton[data-v-2dcb24ca]{height:4vh;width:20vh;line-height:3vh}.loginButton>p[data-v-2dcb24ca]{font-size:3vh;text-align:center}#canvas[data-v-2dcb24ca]{height:30vh;width:30vh}nav[data-v-21165a6a]{height:5vh}div[data-v-cd8fea1a]{margin-top:2vh}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>demo-website</title><link href="/css/app.eb039c1f.css" rel="preload" as="style"><link href="/css/chunk-vendors.a251e031.css" rel="preload" as="style"><link href="/js/app.c2a68e49.js" rel="preload" as="script"><link href="/js/chunk-vendors.22b03028.js" rel="preload" as="script"><link href="/css/chunk-vendors.a251e031.css" rel="stylesheet"><link href="/css/app.eb039c1f.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but demo-website doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.22b03028.js"></script><script src="/js/app.c2a68e49.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long