From aa88c751dd832b792978552aa8df6a84ae60e717 Mon Sep 17 00:00:00 2001 From: dankl Date: Thu, 2 Jan 2020 00:02:35 +0100 Subject: [PATCH] Implemented parsing and displaying images for chipTan-QR and PhotoTan; extracted TanImageSizeControlView --- .../android/ui/dialogs/EnterTanDialog.kt | 26 ++++-- .../ui/views/ChipTanFlickerCodeView.kt | 1 + .../ui/views/TanImageSizeControlsView.kt | 24 ++++++ .../android/ui/views/TanImageView.kt | 80 +++++++++++++++++++ .../src/main/res/layout/dialog_enter_tan.xml | 9 +++ .../src/main/res/layout/view_flicker_code.xml | 30 ++----- .../src/main/res/layout/view_tan_image.xml | 26 ++++++ .../layout/view_tan_image_size_controls.xml | 32 ++++++++ .../src/main/res/values/dimens.xml | 9 ++- .../src/main/res/values/strings.xml | 7 +- .../kotlin/net/dankito/fints/tan/TanImage.kt | 13 +++ .../net/dankito/fints/tan/TanImageDecoder.kt | 45 +++++++++++ 12 files changed, 270 insertions(+), 32 deletions(-) create mode 100644 fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageSizeControlsView.kt create mode 100644 fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageView.kt create mode 100644 fints4javaAndroidApp/src/main/res/layout/view_tan_image.xml create mode 100644 fints4javaAndroidApp/src/main/res/layout/view_tan_image_size_controls.xml create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/tan/TanImage.kt create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/tan/TanImageDecoder.kt 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 f845e212..cee01f00 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,6 +1,7 @@ package net.dankito.banking.fints4java.android.ui.dialogs import android.content.Context +import android.graphics.BitmapFactory import android.os.Bundle import android.support.v4.app.DialogFragment import android.support.v7.app.AlertDialog @@ -11,6 +12,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Spinner import kotlinx.android.synthetic.main.dialog_enter_tan.view.* +import kotlinx.android.synthetic.main.view_tan_image.view.* import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.mapper.fints4javaModelMapper import net.dankito.banking.fints4java.android.ui.MainWindowPresenter @@ -26,11 +28,14 @@ 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 +import net.dankito.fints.tan.TanImageDecoder open class EnterTanDialog : DialogFragment() { companion object { + val OpticalTanProcedures = listOf(TanProcedureType.ChipTanOptisch, TanProcedureType.ChipTanQrCode, TanProcedureType.PhotoTan) + const val DialogTag = "EnterTanDialog" } @@ -70,17 +75,28 @@ open class EnterTanDialog : DialogFragment() { } protected open fun setupUI(rootView: View) { - val flickerCodeView = rootView.flickerCodeView - setupSelectTanProcedureView(rootView) - if (tanChallenge.tanProcedure.type == TanProcedureType.ChipTanOptisch) { + if (OpticalTanProcedures.contains(tanChallenge.tanProcedure.type)) { if (account.tanMedia.isNotEmpty()) { setupSelectTanMediumView(rootView) } - flickerCodeView.visibility = View.VISIBLE - flickerCodeView.setCode(FlickercodeDecoder().decodeChallenge(tanChallenge.tanChallenge)) + if (tanChallenge.tanProcedure.type == TanProcedureType.ChipTanOptisch) { + val flickerCodeView = rootView.flickerCodeView + flickerCodeView.visibility = View.VISIBLE + flickerCodeView.setCode(FlickercodeDecoder().decodeChallenge(tanChallenge.tanChallenge)) + } + else if (tanChallenge.tanProcedure.type == TanProcedureType.ChipTanQrCode + || tanChallenge.tanProcedure.type == TanProcedureType.PhotoTan) { + rootView.tanImageView.visibility = View.VISIBLE + + TanImageDecoder().decodeChallenge(tanChallenge.tanChallenge)?.let { tanImage -> + val bitmap = BitmapFactory.decodeByteArray(tanImage.imageBytes, 0, tanImage.imageBytes.size) + rootView.imgTanImageView.setImageBitmap(bitmap) + } + // TODO: what to do if decoding fails? At least a message should get shown to user + } rootView.edtxtEnteredTan.inputType = InputType.TYPE_CLASS_NUMBER } diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt index 09f81ec7..ca79fb81 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/ChipTanFlickerCodeView.kt @@ -6,6 +6,7 @@ import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import kotlinx.android.synthetic.main.view_flicker_code.view.* +import kotlinx.android.synthetic.main.view_tan_image_size_controls.view.* import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.util.FlickercodeAnimator import net.dankito.fints.tan.Bit diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageSizeControlsView.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageSizeControlsView.kt new file mode 100644 index 00000000..ddcfc5bd --- /dev/null +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageSizeControlsView.kt @@ -0,0 +1,24 @@ +package net.dankito.banking.fints4java.android.ui.views + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import net.dankito.banking.fints4java.android.R + + +open class TanImageSizeControlsView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + + init { + setupUi(context) + } + + private fun setupUi(context: Context) { + val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + inflater.inflate(R.layout.view_tan_image_size_controls, this, true) + } + +} \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageView.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageView.kt new file mode 100644 index 00000000..390bb021 --- /dev/null +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/views/TanImageView.kt @@ -0,0 +1,80 @@ +package net.dankito.banking.fints4java.android.ui.views + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.LinearLayout +import kotlinx.android.synthetic.main.view_tan_image.view.* +import kotlinx.android.synthetic.main.view_tan_image_size_controls.view.* +import net.dankito.banking.fints4java.android.R + + +open class TanImageView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + companion object { + const val ChangeSizeStepSizeDp = 10f + } + + + protected val MinHeight: Int + + protected val MaxHeight: Int + + protected lateinit var imgTanImageView: ImageView + + + init { + MinHeight = convertDpToPx(context, 150f).toInt() + MaxHeight = convertDpToPx(context, 500f).toInt() + + setupUi(context) + } + + private fun setupUi(context: Context) { + val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + val rootView = inflater.inflate(R.layout.view_tan_image, this, true) + + imgTanImageView = rootView.imgTanImageView + + rootView.btnIncreaseSize.setOnClickListener { increaseSize() } + rootView.btnDecreaseSize.setOnClickListener { decreaseSize() } + } + + + open fun increaseSize() { + changeSizeBy(ChangeSizeStepSizeDp) + } + + open fun decreaseSize() { + changeSizeBy(ChangeSizeStepSizeDp * -1) + } + + protected open fun changeSizeBy(changeSizeBy: Float) { + val params = imgTanImageView.layoutParams + val newWidthAndHeight = params.height + convertDpToPx(context, changeSizeBy).toInt() + + if (newWidthAndHeight in MinHeight..MaxHeight) { + params.height = newWidthAndHeight + params.width = newWidthAndHeight + + imgTanImageView.layoutParams = params // TODO: needed? + + requestLayout() + } + } + + /** + * This method converts dp unit to equivalent pixels, depending on device density. + * + * @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels + * @param context Context to get resources and device specific display metrics + * @return A float value to represent px equivalent to dp depending on device density + */ + open fun convertDpToPx(context: Context, dp: Float): Float { + return dp * context.resources.displayMetrics.density + } + +} \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml b/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml index 234657e5..459200be 100644 --- a/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml +++ b/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml @@ -69,6 +69,15 @@ android:visibility="gone" /> + + - - -