diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt index 3ffc17e7..315d7932 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt @@ -15,10 +15,7 @@ import net.dankito.banking.fints4java.android.ui.dialogs.EnterAtcDialog import net.dankito.banking.fints4java.android.ui.dialogs.EnterTanDialog import net.dankito.fints.FinTsClientCallback import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium -import net.dankito.fints.model.CustomerData -import net.dankito.fints.model.EnterTanGeneratorAtcResult -import net.dankito.fints.model.TanChallenge -import net.dankito.fints.model.TanProcedure +import net.dankito.fints.model.* import java.util.concurrent.CountDownLatch import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference @@ -35,7 +32,7 @@ class MainActivity : AppCompatActivity() { return supportedTanProcedures.first() } - override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String? { + override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { return getTanFromUserOffUiThread(customer, tanChallenge) } @@ -92,8 +89,8 @@ class MainActivity : AppCompatActivity() { // return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() // } - private fun getTanFromUserOffUiThread(customer: CustomerData, tanChallenge: TanChallenge): String? { - val enteredTan = AtomicReference(null) + private fun getTanFromUserOffUiThread(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { + val enteredTan = AtomicReference(null) val tanEnteredLatch = CountDownLatch(1) val account = presenter.getAccountForCustomer(customer) diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt index 3273faa6..640e165a 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt @@ -3,13 +3,11 @@ package net.dankito.banking.fints4java.android.ui import net.dankito.banking.ui.model.Account import net.dankito.banking.ui.model.AccountTransaction import net.dankito.banking.ui.model.BankAccount -import net.dankito.banking.ui.model.TanMedium import net.dankito.banking.ui.model.responses.AddAccountResponse import net.dankito.banking.ui.model.responses.GetTransactionsResponse import net.dankito.fints.FinTsClientCallback import net.dankito.fints.FinTsClientForCustomer import net.dankito.fints.banks.BankFinder -import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium import net.dankito.fints.model.BankInfo import net.dankito.fints.model.BankTransferData import net.dankito.fints.model.CustomerData @@ -144,16 +142,6 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service, } - open fun changeTanMediumAsync(newUsedTanMedium: TanMedium, account: Account, callback: (FinTsClientResponse) -> Unit) { - (newUsedTanMedium.originalObject as? TanGeneratorTanMedium)?.let { tanGeneratorTanMedium -> - getClientForAccount(account)?.changeTanMedium(tanGeneratorTanMedium, callback) - // TODO: find a way to update account.tanMedia afterwards - } - - // TODO: what to do if newActiveTanMedium.originalObject is not of type TanGeneratorTanMedium? - } - - open fun preloadBanksAsync() { searchBanksByBankCodeAsync("1") { } } diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt index 5e7043e5..fb8cd929 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt @@ -1,9 +1,7 @@ package net.dankito.banking.fints4java.android.ui.dialogs -import android.content.Context import android.os.Bundle import android.support.v4.app.DialogFragment -import android.support.v7.app.AlertDialog import android.support.v7.app.AppCompatActivity import android.text.InputType import android.view.LayoutInflater @@ -15,11 +13,11 @@ import net.dankito.banking.fints4java.android.ui.MainWindowPresenter import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener import net.dankito.banking.ui.model.Account -import net.dankito.banking.ui.model.TanMedium import net.dankito.banking.ui.model.TanMediumStatus +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium +import net.dankito.fints.model.EnterTanResult import net.dankito.fints.model.TanChallenge import net.dankito.fints.model.TanProcedureType -import net.dankito.fints.response.client.FinTsClientResponse import net.dankito.fints.tan.FlickercodeDecoder @@ -36,13 +34,13 @@ open class EnterTanDialog : DialogFragment() { protected lateinit var presenter: MainWindowPresenter - protected lateinit var tanEnteredCallback: (String?) -> Unit + protected lateinit var tanEnteredCallback: (EnterTanResult) -> Unit protected val tanMediumAdapter = TanMediumAdapter() open fun show(account: Account, tanChallenge: TanChallenge, presenter: MainWindowPresenter, activity: AppCompatActivity, - fullscreen: Boolean = false, tanEnteredCallback: (String?) -> Unit) { + fullscreen: Boolean = false, tanEnteredCallback: (EnterTanResult) -> Unit) { this.account = account this.tanChallenge = tanChallenge @@ -93,42 +91,23 @@ open class EnterTanDialog : DialogFragment() { rootView.spnTanMedium.adapter = tanMediumAdapter rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium -> if (selectedTanMedium.status != TanMediumStatus.Used) { - presenter.changeTanMediumAsync(selectedTanMedium, account) { response -> - handleChangeTanMediumResponse(selectedTanMedium, response) + (selectedTanMedium.originalObject as? TanGeneratorTanMedium)?.let { tanGeneratorTanMedium -> + tanEnteredCallback(EnterTanResult.userAsksToChangeTanMedium(tanGeneratorTanMedium)) + // TODO: find a way to update account.tanMedia afterwards + + dismiss() // TODO: really dismiss? what if changing TAN medium fails? } + + // TODO: what to do if newActiveTanMedium.originalObject is not of type TanGeneratorTanMedium? } } } - private fun handleChangeTanMediumResponse(newUsedTanMedium: TanMedium, response: FinTsClientResponse) { - activity?.let { activity -> - activity.runOnUiThread { - handleChangeTanMediumResponseOnUiThread(activity, newUsedTanMedium, response) - } - } - } - - - protected open fun handleChangeTanMediumResponseOnUiThread(context: Context, newUsedTanMedium: TanMedium, response: FinTsClientResponse) { - if (response.isSuccessful) { - dismiss() - - AlertDialog.Builder(context) - .setMessage(context.getString(R.string.dialog_enter_tan_tan_medium_successfully_changed, newUsedTanMedium.displayName)) - .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() } - .show() - } - else { - AlertDialog.Builder(context) - .setMessage(context.getString(R.string.dialog_enter_tan_error_changing_tan_medium, newUsedTanMedium.displayName, presenter.getErrorToShowToUser(response))) - .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() } - .show() - } - } - protected open fun enteringTanDone(enteredTan: String?) { - tanEnteredCallback(enteredTan) + val result = if (enteredTan != null) EnterTanResult.userEnteredTan(enteredTan) else EnterTanResult.userDidNotEnterTan() + + tanEnteredCallback(result) dismiss() } diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt index 1e3a7d99..81f97b22 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt @@ -356,19 +356,14 @@ open class FinTsClient @JvmOverloads constructor( open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData): FinTsClientResponse { - val lastCreatedMessage = messageBuilder.lastCreatedMessage - -// lastCreatedMessage?.let { closeDialog(bank, customer, ) } // TODO: close previous dialog - - var enteredAtc: EnterTanGeneratorAtcResult? = null if (bank.changeTanMediumParameters?.enteringAtcAndTanRequired == true) { enteredAtc = callback.enterTanGeneratorAtc(customer, newActiveTanMedium) if (enteredAtc == null) { - return FinTsClientResponse(Response(false, exception = - Exception("Bank requires to enter ATC and TAN in order to change TAN medium."))) // TODO: translate + val message = "Bank requires to enter ATC and TAN in order to change TAN medium." // TODO: translate + return FinTsClientResponse(Response(false, exception = Exception(message))) } } @@ -392,11 +387,6 @@ open class FinTsClient @JvmOverloads constructor( closeDialog(bank, customer, dialogData) - lastCreatedMessage?.let { - resendMessageInNewDialogAsync(lastCreatedMessage, bank, customer) - } - - return FinTsClientResponse(response) } @@ -433,24 +423,14 @@ open class FinTsClient @JvmOverloads constructor( } - protected open fun resendMessageInNewDialogAsync(message: MessageBuilderResult, bank: BankData, - customer: CustomerData) { - - threadPool.runAsync { - resendMessageInNewDialog(message, bank, customer) - } - } - protected open fun resendMessageInNewDialog(message: MessageBuilderResult, bank: BankData, - customer: CustomerData): FinTsClientResponse { - - log.info("Resending message ${message.messageBodySegments.map { it.dataElementsAndGroups.firstOrNull()?.format() }} in a new dialog") // TODO: remove again + customer: CustomerData): Response { val dialogData = DialogData() val initDialogResponse = initDialog(bank, customer, dialogData) if (initDialogResponse.successful == false) { - return FinTsClientResponse(initDialogResponse) + return initDialogResponse } @@ -460,7 +440,7 @@ open class FinTsClient @JvmOverloads constructor( closeDialog(bank, customer, dialogData) - return FinTsClientResponse(response) + return response } @@ -669,16 +649,19 @@ open class FinTsClient @JvmOverloads constructor( if (response.isStrongAuthenticationRequired) { response.tanResponse?.let { tanResponse -> // TODO: is this true for all tan procedures? - val enteredTan = callback.enterTan(customer, TanChallenge(tanResponse.challenge ?: "", + val enteredTanResult = callback.enterTan(customer, TanChallenge(tanResponse.challenge ?: "", tanResponse.challengeHHD_UC ?: "", customer.selectedTanProcedure)) - if (enteredTan == null) { + if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) { + return handleUserAsksToChangeTanMediumAndResendLastMessage(enteredTanResult.changeTanMediumTo, bank, customer, dialogData) + } + else if (enteredTanResult.enteredTan == null) { // i tried to send a HKTAN with cancelJob = true but then i saw there are no tan procedures that support cancellation (at least not at my bank) // but it's not required anyway, tan times out after some time. Simply don't respond anything and close dialog response.tanRequiredButNotProvided = true } else { - return sendTanToBank(enteredTan, tanResponse, bank, customer, dialogData) + return sendTanToBank(enteredTanResult.enteredTan, tanResponse, bank, customer, dialogData) } } } @@ -703,6 +686,24 @@ open class FinTsClient @JvmOverloads constructor( return getAndHandleResponseForMessageThatMayRequiresTan(message, bank, customer, dialogData) } + protected open fun handleUserAsksToChangeTanMediumAndResendLastMessage(changeTanMediumTo: TanGeneratorTanMedium, bank: BankData, + customer: CustomerData, dialogData: DialogData): Response { + + val lastCreatedMessage = messageBuilder.lastCreatedMessage + + lastCreatedMessage?.let { closeDialog(bank, customer, dialogData) } + + + val changeTanMediumResponse = changeTanMedium(changeTanMediumTo, bank, customer) + + if (changeTanMediumResponse.isSuccessful == false || lastCreatedMessage == null) { + return changeTanMediumResponse.toResponse() + } + + + return resendMessageInNewDialog(lastCreatedMessage, bank, customer) + } + protected open fun updateBankData(bank: BankData, response: Response) { response.getFirstSegmentById(InstituteSegmentId.BankParameters)?.let { bankParameters -> diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt index 1b805a33..0b1cf7ce 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt @@ -1,17 +1,14 @@ package net.dankito.fints import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium -import net.dankito.fints.model.CustomerData -import net.dankito.fints.model.EnterTanGeneratorAtcResult -import net.dankito.fints.model.TanChallenge -import net.dankito.fints.model.TanProcedure +import net.dankito.fints.model.* interface FinTsClientCallback { fun askUserForTanProcedure(supportedTanProcedures: List): TanProcedure? - fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String? + fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult /** * This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator. diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/model/EnterTanResult.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/model/EnterTanResult.kt new file mode 100644 index 00000000..35aa7e93 --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/model/EnterTanResult.kt @@ -0,0 +1,35 @@ +package net.dankito.fints.model + +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium + + +open class EnterTanResult constructor( + val enteredTan: String?, + val changeTanMediumTo: TanMedium? +) { + + companion object { + + fun userEnteredTan(enteredTan: String): EnterTanResult { + return EnterTanResult(enteredTan, null) + } + + fun userDidNotEnterTan(): EnterTanResult { + return EnterTanResult(null, null) + } + + fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium): EnterTanResult { + return EnterTanResult(null, changeTanMediumTo) + } + + } + + override fun toString(): String { + if (changeTanMediumTo != null) { + return "User asks to change TAN medium to $changeTanMediumTo" + } + + return "enteredTan = $enteredTan" + } + +} \ No newline at end of file diff --git a/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java b/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java index 4569818d..c30ca320 100644 --- a/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java +++ b/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java @@ -42,8 +42,8 @@ public class JavaShowcase { @Nullable @Override - public String enterTan(@NotNull CustomerData customer, @NotNull TanChallenge tanChallenge) { - return null; + public EnterTanResult enterTan(@NotNull CustomerData customer, @NotNull TanChallenge tanChallenge) { + return EnterTanResult.Companion.userDidNotEnterTan(); } @Nullable diff --git a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt index ee176d9e..eabfa675 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt @@ -37,10 +37,10 @@ class FinTsClientTest { return supportedTanProcedures.first() } - override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String? { + override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult { didAskUserToEnterTan.set(true) - return null + return EnterTanResult.userDidNotEnterTan() } override fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult? {