Implemented generating EPC QR code on Android

This commit is contained in:
dankito 2020-11-15 21:08:03 +01:00
parent e421cdb176
commit c8d1a1a98c
10 changed files with 239 additions and 35 deletions

View File

@ -10,7 +10,7 @@ import java.io.ByteArrayOutputStream
class QrCodeGenerator {
fun generateQrCode(informationToEncode: String, config: EncodeToQrCodeConfig = EncodeToQrCodeConfig()): ByteArray {
fun generateQrCodeAsByteArray(informationToEncode: String, config: EncodeToQrCodeConfig = EncodeToQrCodeConfig()): ByteArray {
val bitMatrix = QRCodeWriter().encode(informationToEncode, BarcodeFormat.QR_CODE, config.width, config.height)
val bitmap = Bitmap.createBitmap(config.width, config.height, Bitmap.Config.RGB_565)
@ -26,4 +26,17 @@ class QrCodeGenerator {
return blob.toByteArray()
}
fun generateQrCode(informationToEncode: String, config: EncodeToQrCodeConfig = EncodeToQrCodeConfig()): Bitmap {
val bitMatrix = QRCodeWriter().encode(informationToEncode, BarcodeFormat.QR_CODE, config.width, config.height)
val bitmap = Bitmap.createBitmap(config.width, config.height, Bitmap.Config.RGB_565)
for (x in 0 until config.width) {
for (y in 0 until config.height) {
bitmap.setPixel(x, y, if (bitMatrix.get(x, y)) Color.BLACK else Color.WHITE)
}
}
return bitmap
}
}

View File

@ -2,8 +2,15 @@ package net.codinux.banking.epcqrcode
open class EncodeToQrCodeConfig(
open val width: Int = 500,
open val height: Int = 500,
open val width: Int = DefaultWidth,
open val height: Int = DefaultHeight,
open val format: ImageFormat = ImageFormat.PNG,
open val encoding: EpcQrCodeCharacterSet = EpcQrCodeCharacterSet.UTF_8
)
) {
companion object {
const val DefaultWidth = 350
const val DefaultHeight = 350
}
}

View File

@ -12,6 +12,8 @@ dependencies {
implementation("androidx.core:core-ktx:1.2.0")
implementation("androidx.appcompat:appcompat:1.1.0")
implementation("androidx.constraintlayout:constraintlayout:1.1.3")
implementation("com.google.android.material:material:1.2.1")
}
android {

View File

@ -0,0 +1,21 @@
package net.codinux.banking.epcqrcode
import android.content.Context
import android.os.IBinder
import android.view.View
import android.view.inputmethod.InputMethodManager
import com.google.android.material.textfield.TextInputEditText
fun Context.hideKeyboard(anyViewInHierarchy: View, flags: Int = 0) {
hideKeyboard(anyViewInHierarchy.windowToken, flags)
}
fun Context.hideKeyboard(windowToken: IBinder, flags: Int = 0) {
val keyboard = this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
keyboard.hideSoftInputFromWindow(windowToken, flags)
}
val TextInputEditText.string: String
get() = this.text?.toString() ?: ""

View File

@ -1,25 +1,50 @@
package net.codinux.banking.epcqrcode
import android.graphics.BitmapFactory
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnGenerateQrCode.setOnClickListener { generateQrCode() }
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
txtMessage.text = MppTest().showMessage()
private fun generateQrCode() {
hideKeyboard(edtxtReference)
val qrCodeContent = EpcQrCodeCreator().generateAsString(CreatorParam("Mahatma Gandhi", "IN00123456789876543210", null, 1234.56, "Struggle for independence"))
val imageBytes = QrCodeGenerator().generateQrCode(qrCodeContent)
imgGeneratedQrCode.setImageBitmap(BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size))
val param = CreatorParam(edtxtReceiver.string, edtxtIban.string, edtxtBic.string, map(edtxtAmount.string), edtxtReference.string)
generateQrCodeAsync(param) { createdQrCode ->
imgGeneratedQrCode.setImageBitmap(createdQrCode)
}
}
private fun generateQrCodeAsync(param: CreatorParam, done: (Bitmap) -> Unit) {
thread {
val density = resources.displayMetrics.density
val config = EncodeToQrCodeConfig((EncodeToQrCodeConfig.DefaultWidth * density).toInt(), (EncodeToQrCodeConfig.DefaultHeight * density).toInt())
val qrCodeContent = EpcQrCodeCreator().generateAsString(param)
// TODO: this takes a very long time. Improve it
val generatedQrCode = QrCodeGenerator().generateQrCode(qrCodeContent, config)
runOnUiThread {
done(generatedQrCode)
}
}
}
private fun map(amount: String): Double? {
return amount.replace(',', '.').toDoubleOrNull()
}
}

View File

@ -1,28 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginLeft="@dimen/activity_main_margin_start_end"
android:layout_marginStart="@dimen/activity_main_margin_start_end"
android:layout_marginRight="@dimen/activity_main_margin_start_end"
android:layout_marginEnd="@dimen/activity_main_margin_start_end"
>
<TextView
android:id="@+id/txtMessage"
android:layout_width="wrap_content"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
tools:context=".MainActivity">
<ImageView
android:id="@+id/imgGeneratedQrCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
/>
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="@dimen/form_edit_text_height"
android:layout_marginTop="@dimen/form_edit_text_margin_top"
android:layout_marginBottom="@dimen/form_edit_text_margin_bottom"
android:hint="@string/receiver"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edtxtReceiver"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="@dimen/form_edit_text_height"
android:layout_marginTop="@dimen/form_edit_text_margin_top"
android:layout_marginBottom="@dimen/form_edit_text_margin_bottom"
android:hint="@string/iban"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edtxtIban"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="@dimen/form_edit_text_height"
android:layout_marginTop="@dimen/form_edit_text_margin_top"
android:layout_marginBottom="@dimen/form_edit_text_margin_bottom"
android:hint="@string/bic"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edtxtBic"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="@dimen/form_edit_text_height"
android:layout_marginTop="@dimen/form_edit_text_margin_top"
android:layout_marginBottom="@dimen/form_edit_text_margin_bottom"
android:hint="@string/amount"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edtxtAmount"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="@dimen/form_edit_text_height"
android:layout_marginTop="@dimen/form_edit_text_margin_top"
android:layout_marginBottom="@dimen/form_edit_text_margin_bottom"
android:hint="@string/reference"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edtxtReference"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnGenerateQrCode"
android:layout_width="match_parent"
android:layout_height="@dimen/generate_button_height"
android:layout_marginTop="@dimen/generate_button_margin_top"
android:layout_marginBottom="@dimen/generate_button_margin_bottom"
android:textAllCaps="false"
android:text="@string/generate"
/>
<ImageView
android:id="@+id/imgGeneratedQrCode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/generated_qr_code_bottom_margin"
android:scaleType="fitCenter"
/>
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="receiver">Empfänger</string>
<string name="iban">IBAN</string>
<string name="bic">BIC</string>
<string name="amount">Betrag</string>
<string name="reference">Verwendungszweck</string>
<string name="generate">Erstellen</string>
</resources>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="activity_main_margin_start_end">4dp</dimen>
<dimen name="form_edit_text_height">60dp</dimen>
<dimen name="form_edit_text_margin_top">6dp</dimen>
<dimen name="form_edit_text_margin_bottom">6dp</dimen>
<dimen name="generate_button_height">55dp</dimen>
<dimen name="generate_button_margin_top">8dp</dimen>
<dimen name="generate_button_margin_bottom">20dp</dimen>
<dimen name="generated_qr_code_bottom_margin">6dp</dimen>
</resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="receiver">Receiver</string>
<string name="iban">IBAN</string>
<string name="bic">BIC</string>
<string name="amount">Amount</string>
<string name="reference">Reference</string>
<string name="generate">Generate</string>
</resources>

View File

@ -5,4 +5,4 @@
"Amount" = "Betrag";
"Reference" = "Verwendungszweck";
"Generate" = "Erzeugen";
"Generate" = "Erstellen";