diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b4113f3..8c7eebd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -11,8 +11,8 @@ android { applicationId = "sh.sar.basedbank" minSdk = 26 targetSdk = 36 - versionCode = 15 - versionName = "1.0.16" + versionCode = 16 + versionName = "1.0.17" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt index 9755cf5..39d5fac 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/DashboardFragment.kt @@ -26,6 +26,7 @@ import sh.sar.basedbank.api.mib.MibCard import sh.sar.basedbank.api.mib.MibFinanceDeal import sh.sar.basedbank.util.bmlapi.BmlCardParser import sh.sar.basedbank.util.CredentialStore +import sh.sar.basedbank.util.NfcPaymentUtil import sh.sar.basedbank.util.PaymvQrParser import kotlin.math.abs import sh.sar.basedbank.databinding.FragmentDashboardBinding @@ -426,11 +427,13 @@ class DashboardFragment : Fragment() { if (isMib) { Toast.makeText(requireContext(), R.string.mib_qr_nfc_not_supported, Toast.LENGTH_SHORT).show() } else { - val accountNumber = (item as CardItem.Bml).account.accountNumber - (requireActivity() as HomeActivity).navigateTo( - R.id.nav_pay_with_card, - CardsFragment.newInstanceWithAutoTapMode(accountNumber) - ) + NfcPaymentUtil.checkAndProceed(requireContext()) { + val accountNumber = (item as CardItem.Bml).account.accountNumber + (requireActivity() as HomeActivity).navigateTo( + R.id.nav_pay_with_card, + CardsFragment.newInstanceWithAutoTapMode(accountNumber) + ) + } } } } diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt index 889b635..0b6b05f 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/PayWithCardFragment.kt @@ -48,6 +48,7 @@ import sh.sar.basedbank.util.CardsCache import sh.sar.basedbank.util.CredentialStore import sh.sar.basedbank.util.Totp import sh.sar.basedbank.util.bmlapi.BmlCardParser +import sh.sar.basedbank.util.NfcPaymentUtil import sh.sar.basedbank.util.PaymvQrParser import kotlin.math.abs @@ -232,11 +233,13 @@ ViewCompat.setOnApplyWindowInsetsListener(binding.contentLayout) { v, insets -> return@setOnClickListener } val bmlItem = item as CardItem.Bml - val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) - if (prefs.getBoolean("biometrics_transfer_confirm", false)) { - showBiometricPromptForTap(bmlItem) - } else { - setTapMode(true, bmlItem) + NfcPaymentUtil.checkAndProceed(requireContext()) { + val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) + if (prefs.getBoolean("biometrics_transfer_confirm", false)) { + showBiometricPromptForTap(bmlItem) + } else { + setTapMode(true, bmlItem) + } } } @@ -742,11 +745,13 @@ ViewCompat.setOnApplyWindowInsetsListener(binding.contentLayout) { v, insets -> currentCardPosition = pos binding.rvCards.scrollToPosition(pos) } - val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) - if (prefs.getBoolean("biometrics_transfer_confirm", false)) { - showBiometricPromptForTap(targetCard) - } else { - setTapMode(true, targetCard) + NfcPaymentUtil.checkAndProceed(requireContext()) { + val prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) + if (prefs.getBoolean("biometrics_transfer_confirm", false)) { + showBiometricPromptForTap(targetCard) + } else { + setTapMode(true, targetCard) + } } } } diff --git a/app/src/main/java/sh/sar/basedbank/util/NfcPaymentUtil.kt b/app/src/main/java/sh/sar/basedbank/util/NfcPaymentUtil.kt new file mode 100644 index 0000000..277f0f1 --- /dev/null +++ b/app/src/main/java/sh/sar/basedbank/util/NfcPaymentUtil.kt @@ -0,0 +1,53 @@ +package sh.sar.basedbank.util + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.nfc.NfcAdapter +import android.nfc.cardemulation.CardEmulation +import android.provider.Settings +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import sh.sar.basedbank.R +import sh.sar.basedbank.nfc.BmlHostCardEmulatorService + +object NfcPaymentUtil { + fun checkAndProceed(context: Context, onReady: () -> Unit) { + val nfcAdapter = NfcAdapter.getDefaultAdapter(context) ?: run { + MaterialAlertDialogBuilder(context) + .setTitle(R.string.nfc_unsupported_title) + .setMessage(R.string.nfc_unsupported_message) + .setPositiveButton(android.R.string.ok, null) + .show() + return + } + + if (!nfcAdapter.isEnabled) { + MaterialAlertDialogBuilder(context) + .setTitle(R.string.nfc_disabled_title) + .setMessage(R.string.nfc_disabled_message) + .setPositiveButton(R.string.nfc_open_settings) { _, _ -> + context.startActivity(Intent(Settings.ACTION_NFC_SETTINGS)) + } + .setNegativeButton(R.string.cancel, null) + .show() + return + } + + val cardEmulation = CardEmulation.getInstance(nfcAdapter) + val componentName = ComponentName(context, BmlHostCardEmulatorService::class.java) + if (!cardEmulation.isDefaultServiceForCategory(componentName, CardEmulation.CATEGORY_PAYMENT)) { + MaterialAlertDialogBuilder(context) + .setTitle(R.string.nfc_not_default_title) + .setMessage(context.getString(R.string.nfc_not_default_message, + context.applicationInfo.loadLabel(context.packageManager))) + .setPositiveButton(R.string.nfc_payment_open_settings) { _, _ -> + context.startActivity(Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS)) + } + .setNegativeButton(R.string.cancel, null) + .show() + return + } + + onReady() + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 86dbd53..ff467f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -334,6 +334,14 @@ Scan to Pay Tap to Pay Skill issue on MIB side, Not supported + Not Supported + Tap to Pay is not supported on this device. + NFC is Off + Turn on NFC to use Tap to Pay. + NFC Settings + Set Default Payment App + Set %1$s as the default contactless payment app to use Tap to Pay. + Payment Settings Manage Card Set as Default Card Hide from Dashboard