diff --git a/barcode_kaiteki/.gitignore b/barcode_kaiteki/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/barcode_kaiteki/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/barcode_kaiteki/build.gradle b/barcode_kaiteki/build.gradle deleted file mode 100644 index ebc5e92b..00000000 --- a/barcode_kaiteki/build.gradle +++ /dev/null @@ -1,46 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' - -android { - compileSdkVersion 30 - - defaultConfig { - minSdkVersion 21 - targetSdkVersion 30 - versionCode 1 - versionName "1.1.1" - } - - compileOptions { - kotlinOptions.freeCompilerArgs += ['-module-name', "barcode.kaiteki"] - targetCompatibility = JavaVersion.VERSION_1_8 - sourceCompatibility = JavaVersion.VERSION_1_8 - } - - // For Kotlin projects - kotlinOptions { - jvmTarget = "1.8" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'com.google.android.material:material:1.3.0-alpha03' - - api 'androidx.camera:camera-core:1.0.0-alpha03' - api 'androidx.camera:camera-camera2:1.0.0-alpha03' - - api 'com.google.zxing:core:3.4.0' -} diff --git a/barcode_kaiteki/proguard-rules.pro b/barcode_kaiteki/proguard-rules.pro deleted file mode 100644 index f1b42451..00000000 --- a/barcode_kaiteki/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/barcode_kaiteki/src/main/AndroidManifest.xml b/barcode_kaiteki/src/main/AndroidManifest.xml deleted file mode 100644 index 39b96b11..00000000 --- a/barcode_kaiteki/src/main/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/BarcodeAnalyzer.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/BarcodeAnalyzer.kt deleted file mode 100644 index 51f459a1..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/BarcodeAnalyzer.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.kroegerama.kaiteki.bcode - -import android.graphics.ImageFormat -import android.util.Log -import androidx.camera.core.ImageAnalysis -import androidx.camera.core.ImageProxy -import com.google.zxing.BinaryBitmap -import com.google.zxing.MultiFormatReader -import com.google.zxing.PlanarYUVLuminanceSource -import com.google.zxing.Result -import com.google.zxing.common.HybridBinarizer - -internal interface ResultListener { - fun onResult(result: Result, imageWidth: Int, imageHeight: Int, imageRotation: Int) - fun onNoResult() -} - -internal class BarcodeAnalyzer( - private val listener: ResultListener, - private val reader: MultiFormatReader -) : ImageAnalysis.Analyzer { - - var enabled = true - var inverted = false - - override fun analyze(image: ImageProxy, rotationDegrees: Int) { - if (!enabled) return - - //YUV_420 is normally the input type here, but other YUV types are also supported in theory - if (ImageFormat.YUV_420_888 != image.format && ImageFormat.YUV_422_888 != image.format && ImageFormat.YUV_444_888 != image.format) { - Log.e(TAG, "Unexpected format: ${image.format}") - listener.onNoResult() - return - } - val byteBuffer = image.image?.planes?.firstOrNull()?.buffer - if (byteBuffer == null) { - listener.onNoResult() - return - } - - var data = ByteArray(byteBuffer.remaining()).also { byteBuffer.get(it) } - - var width = image.width - var height = image.height - -// val rotatedData = ByteArray(data.size) -// for (y in 0 until height) { -// for (x in 0 until width) rotatedData[x * height + height - y - 1] = data[x + y * width] -// } -// -// data = rotatedData -// val tmp = width -// width = height -// height = tmp - - val source = PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false).let { - if (inverted) it.invert() else it - } - val bitmap = BinaryBitmap(HybridBinarizer(source)) - - try { - val result = reader.decodeWithState(bitmap) - listener.onResult(result, width, height, rotationDegrees) - } catch (e: Exception) { - listener.onNoResult() - } - } - - companion object { - private const val TAG = "BarcodeAnalyzer" - } -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/BarcodeResultListener.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/BarcodeResultListener.kt deleted file mode 100644 index b75c67c6..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/BarcodeResultListener.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.kroegerama.kaiteki.bcode - -import com.google.zxing.Result - -interface BarcodeResultListener { - - /** - * @param result zxing result - * - * @return return true to dismiss the dialog/fragment - */ - fun onBarcodeResult(result: Result): Boolean - - fun onBarcodeScanCancelled() - -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/DebugUtils.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/DebugUtils.kt deleted file mode 100644 index 858e739e..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/DebugUtils.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.kroegerama.kaiteki.bcode - -import android.graphics.* -import android.media.Image -import com.google.zxing.PlanarYUVLuminanceSource -import java.io.ByteArrayOutputStream - -internal fun Image.toBitmap(): Bitmap { - val yBuffer = planes[0].buffer // Y - val uBuffer = planes[1].buffer // U - val vBuffer = planes[2].buffer // V - - val ySize = yBuffer.remaining() - val uSize = uBuffer.remaining() - val vSize = vBuffer.remaining() - - val nv21 = ByteArray(ySize + uSize + vSize) - - //U and V are swapped - yBuffer.get(nv21, 0, ySize) - vBuffer.get(nv21, ySize, vSize) - uBuffer.get(nv21, ySize + vSize, uSize) - - val yuvImage = YuvImage(nv21, ImageFormat.NV21, this.width, this.height, null) - val out = ByteArrayOutputStream() - yuvImage.compressToJpeg(Rect(0, 0, yuvImage.width, yuvImage.height), 50, out) - val imageBytes = out.toByteArray() - return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) -} - -internal fun PlanarYUVLuminanceSource.toBitmap() = - Bitmap.createBitmap(renderThumbnail(), thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888) \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/Utils.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/Utils.kt deleted file mode 100644 index fd8b0049..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/Utils.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.kroegerama.kaiteki.bcode - -import android.Manifest -import android.content.Context -import android.content.pm.PackageManager -import android.content.res.TypedArray -import android.os.Build -import android.util.AttributeSet -import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment - -internal fun AttributeSet?.handleArguments( - context: Context, attrs: IntArray, defStyleAttr: Int, defStyleRes: Int, - block: TypedArray.() -> Unit -) = this?.let { - val arr = context.obtainStyledAttributes(it, attrs, defStyleAttr, defStyleRes) - block(arr) - arr.recycle() -} - -internal typealias Style = R.styleable - -internal val Context.hasCameraPermission - get() = isPermissionGranted(Manifest.permission.CAMERA) - -internal fun Fragment.requestCameraPermission(requestCode: Int) = - requestPermission(Manifest.permission.CAMERA, requestCode) - -internal val IntArray.isPermissionGranted - get() = size > 0 && get(0) == PackageManager.PERMISSION_GRANTED - -private fun Context.isPermissionGranted(permission: String) = - ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED - -private fun Fragment.requestPermission(permission: String, requestCode: Int) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return - if (context?.isPermissionGranted(permission) == true) return - requestPermissions(arrayOf(permission), requestCode) -} - -internal class Debouncer( - val debounceTime: Int -) { - private var lastShot = 0L - - operator fun invoke(block: () -> T) = if (System.currentTimeMillis() - lastShot > debounceTime) { - block.invoke().also { - lastShot = System.currentTimeMillis() - } - } else { - null - } -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeAlertDialog.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeAlertDialog.kt deleted file mode 100644 index 4c10ef08..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeAlertDialog.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.kroegerama.kaiteki.bcode.ui - -import android.content.Context -import android.os.Handler -import android.util.Log -import android.view.LayoutInflater -import android.widget.Toast -import androidx.appcompat.app.AlertDialog -import androidx.core.os.postDelayed -import androidx.lifecycle.LifecycleOwner -import com.google.zxing.BarcodeFormat -import com.google.zxing.Result -import com.kroegerama.kaiteki.bcode.BarcodeResultListener -import com.kroegerama.kaiteki.bcode.R -import com.kroegerama.kaiteki.bcode.hasCameraPermission -import com.kroegerama.kaiteki.bcode.views.BarcodeView - - -fun Context.showBarcodeAlertDialog( - owner: LifecycleOwner, - listener: BarcodeResultListener, - formats: List = listOf(BarcodeFormat.QR_CODE), - barcodeInverted: Boolean = false -) { - if (!hasCameraPermission) { - Log.w("BarcodeAlertDialog", "Camera permission required") - Toast.makeText(this, "Camera permission required", Toast.LENGTH_LONG).show() - return - } - - val view = LayoutInflater.from(this).inflate(R.layout.dlg_barcode, null, false) - val bcode = view.findViewById(R.id.bcode) - val handler = Handler() - - val dlg = AlertDialog.Builder(this) - .setOnDismissListener { bcode.unbind() } - .setView(view) - .setOnCancelListener { - listener.onBarcodeScanCancelled() - } - .setNegativeButton(android.R.string.cancel) { _, _ -> - listener.onBarcodeScanCancelled() - } - .show() - - bcode.setFormats(formats) - bcode.setBarcodeInverted(barcodeInverted) - bcode.setBarcodeResultListener(object : BarcodeResultListener { - override fun onBarcodeResult(result: Result): Boolean { - val doDismiss = listener.onBarcodeResult(result) - if (doDismiss) { - handler.postDelayed(500) { - dlg.dismiss() - } - } - return doDismiss - } - - override fun onBarcodeScanCancelled() { - //Ignore: BarcodeView will never emit this event - } - }) - - bcode.bindToLifecycle(owner) -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeBottomSheet.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeBottomSheet.kt deleted file mode 100644 index 63e6f02a..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeBottomSheet.kt +++ /dev/null @@ -1,109 +0,0 @@ -package com.kroegerama.kaiteki.bcode.ui - -import android.content.DialogInterface -import android.os.Bundle -import android.os.Handler -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.core.os.bundleOf -import androidx.core.os.postDelayed -import androidx.fragment.app.FragmentManager -import com.google.android.material.bottomsheet.BottomSheetDialogFragment -import com.google.zxing.BarcodeFormat -import com.google.zxing.Result -import com.kroegerama.kaiteki.bcode.* -import kotlinx.android.synthetic.main.dlg_barcode.* - -class BarcodeBottomSheet : BottomSheetDialogFragment(), BarcodeResultListener { - - private val formats: List? by lazy { - arguments?.getSerializable(KEY_FORMATS) as List - } - - private val barcodeInverted by lazy { - arguments?.getBoolean(KEY_INVERTED, false) ?: false - } - - private val handler = Handler() - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - inflater.inflate(R.layout.dlg_barcode, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - formats?.let(bcode::setFormats) - bcode.setBarcodeInverted(barcodeInverted) - bcode.setBarcodeResultListener(this) - - if (requireContext().hasCameraPermission) { - bcode.bindToLifecycle(this) - } else { - requestCameraPermission(REQUEST_CAMERA) - } - } - - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - when (requestCode) { - REQUEST_CAMERA -> - if (grantResults.isPermissionGranted) - bcode.bindToLifecycle(this) - else - dismissAllowingStateLoss() - } - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - } - - override fun onStop() { - super.onStop() - bcode.unbind() - } - - override fun onBarcodeResult(result: Result): Boolean { - if ((parentFragment as? BarcodeResultListener)?.onBarcodeResult(result) == true) { - handler.postDelayed(500) { - dismiss() - } - return true - } else if ((activity as? BarcodeResultListener)?.onBarcodeResult(result) == true) { - handler.postDelayed(500) { - dismiss() - } - return true - } - return false - } - - override fun onBarcodeScanCancelled() { - //Ignore: BarcodeView will never emit this event - } - - override fun onCancel(dialog: DialogInterface) { - (parentFragment as? BarcodeResultListener)?.onBarcodeScanCancelled() - (activity as? BarcodeResultListener)?.onBarcodeScanCancelled() - super.onCancel(dialog) - } - - companion object { - - private const val KEY_FORMATS = "formats" - private const val KEY_INVERTED = "inverted" - - private const val REQUEST_CAMERA = 0xbb_ca - - fun show( - fm: FragmentManager, - formats: List = listOf(BarcodeFormat.QR_CODE), - barcodeInverted: Boolean = false, - tag: String? = null - ) = BarcodeBottomSheet().apply { - arguments = bundleOf( - KEY_FORMATS to formats, - KEY_INVERTED to barcodeInverted - ) - - show(fm, tag) - } - } -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeDialog.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeDialog.kt deleted file mode 100644 index a67aa3fe..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeDialog.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.kroegerama.kaiteki.bcode.ui - -import android.content.DialogInterface -import android.os.Bundle -import android.os.Handler -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.Window -import androidx.core.os.bundleOf -import androidx.core.os.postDelayed -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.FragmentManager -import com.google.zxing.BarcodeFormat -import com.google.zxing.Result -import com.kroegerama.kaiteki.bcode.* -import kotlinx.android.synthetic.main.dlg_barcode.* - -open class BarcodeDialog : DialogFragment(), BarcodeResultListener { - - private val formats: List? by lazy { - arguments?.getSerializable(KEY_FORMATS) as List - } - - private val barcodeInverted by lazy { - arguments?.getBoolean(KEY_INVERTED, false) ?: false - } - - private val handler = Handler() - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - inflater.inflate(R.layout.dlg_barcode, container, false).also { - dialog?.window?.run { - requestFeature(Window.FEATURE_NO_TITLE) - requestFeature(Window.FEATURE_SWIPE_TO_DISMISS) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - formats?.let(bcode::setFormats) - bcode.setBarcodeInverted(barcodeInverted) - bcode.setBarcodeResultListener(this) - - if (requireContext().hasCameraPermission) { - bcode.bindToLifecycle(this) - } else { - requestCameraPermission(REQUEST_CAMERA) - } - } - - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - when (requestCode) { - REQUEST_CAMERA -> - if (grantResults.isPermissionGranted) - bcode.bindToLifecycle(this) - else - dismissAllowingStateLoss() - } - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - } - - override fun onBarcodeScanCancelled() { - //Ignore: BarcodeView will never emit this event - } - - override fun onStop() { - super.onStop() - bcode.unbind() - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) - } - - override fun onBarcodeResult(result: Result): Boolean { - if ((parentFragment as? BarcodeResultListener)?.onBarcodeResult(result) == true) { - handler.postDelayed(500) { - dismiss() - } - return true - } else if ((activity as? BarcodeResultListener)?.onBarcodeResult(result) == true) { - handler.postDelayed(500) { - dismiss() - } - return true - } - return false - } - - override fun onCancel(dialog: DialogInterface) { - (parentFragment as? BarcodeResultListener)?.onBarcodeScanCancelled() - (activity as? BarcodeResultListener)?.onBarcodeScanCancelled() - super.onCancel(dialog) - } - - companion object { - - private const val KEY_FORMATS = "formats" - private const val KEY_INVERTED = "inverted" - - private const val REQUEST_CAMERA = 0xbd_ca - - fun show( - fm: FragmentManager, - formats: List = listOf(BarcodeFormat.QR_CODE), - barcodeInverted: Boolean = false, - tag: String? = null - ) = BarcodeDialog().apply { - arguments = bundleOf( - KEY_FORMATS to formats, - KEY_INVERTED to barcodeInverted - ) - - show(fm, tag) - } - } -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeFragment.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeFragment.kt deleted file mode 100644 index a5214623..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/ui/BarcodeFragment.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.kroegerama.kaiteki.bcode.ui - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment -import com.google.zxing.BarcodeFormat -import com.google.zxing.Result -import com.kroegerama.kaiteki.bcode.* -import kotlinx.android.synthetic.main.dlg_barcode.* - -class BarcodeFragment : Fragment(), BarcodeResultListener { - - private val formats: List? by lazy { - arguments?.getSerializable(KEY_FORMATS) as List - } - - private val barcodeInverted by lazy { - arguments?.getBoolean(KEY_INVERTED, false) ?: false - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - inflater.inflate(R.layout.dlg_barcode, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - formats?.let(bcode::setFormats) - bcode.setBarcodeInverted(barcodeInverted) - bcode.setBarcodeResultListener(this) - - if (requireContext().hasCameraPermission) { - bcode.bindToLifecycle(this) - } else { - requestCameraPermission(REQUEST_CAMERA) - } - } - - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - when (requestCode) { - REQUEST_CAMERA -> - if (grantResults.isPermissionGranted) - bcode.bindToLifecycle(this) - } - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - } - - override fun onStop() { - super.onStop() - bcode.unbind() - } - - override fun onBarcodeResult(result: Result): Boolean { - if ((parentFragment as? BarcodeResultListener)?.onBarcodeResult(result) == true) { - return true - } else if ((activity as? BarcodeResultListener)?.onBarcodeResult(result) == true) { - return true - } - return false - } - - override fun onBarcodeScanCancelled() { - //Ignore: BarcodeView will never emit this event - } - - companion object { - private const val KEY_FORMATS = "formats" - private const val KEY_INVERTED = "inverted" - - private const val REQUEST_CAMERA = 0xbf_ca - - fun makeInstance( - formats: List = listOf(BarcodeFormat.QR_CODE), - barcodeInverted: Boolean = false - ) = BarcodeFragment().apply { - arguments = bundleOf( - KEY_FORMATS to formats, - KEY_INVERTED to barcodeInverted - ) - } - } -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/views/BarcodeView.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/views/BarcodeView.kt deleted file mode 100644 index b820c7c7..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/views/BarcodeView.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.kroegerama.kaiteki.bcode.views - -import android.content.Context -import android.content.res.Resources -import android.graphics.Color -import android.graphics.Matrix -import android.os.Handler -import android.os.HandlerThread -import android.util.* -import android.view.LayoutInflater -import android.view.Surface -import android.view.TextureView -import android.view.ViewGroup -import android.widget.FrameLayout -import androidx.camera.core.* -import androidx.lifecycle.LifecycleOwner -import com.google.zxing.BarcodeFormat -import com.google.zxing.DecodeHintType -import com.google.zxing.MultiFormatReader -import com.google.zxing.Result -import com.kroegerama.kaiteki.bcode.* -import com.kroegerama.kaiteki.bcode.R -import kotlin.math.max - -class BarcodeView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : FrameLayout(context, attrs, defStyleAttr), ResultListener { - - private val textureView: TextureView - private val resultView: ResultPointView - - private var bufferSize = SizeF(0f, 0f) - - private var listener: BarcodeResultListener? = null - - private val barcodeReader by lazy { MultiFormatReader() } - - private val analyzer by lazy { BarcodeAnalyzer(this, barcodeReader) } - - private val resultDebouncer = Debouncer(500) - - init { - LayoutInflater.from(context).inflate(R.layout.barcode_view, this) - - keepScreenOn = true - - textureView = findViewById(R.id.textureView) - resultView = findViewById(R.id.resultView) - - attrs.handleArguments(context, Style.BarcodeView, defStyleAttr, 0) { - resultView.showResultPoints = getBoolean(Style.BarcodeView_showResultPoints, true) - resultView.setResultPointColor(getColor(Style.BarcodeView_resultPointColor, Color.GREEN)) - val defaultSize = - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, Resources.getSystem().displayMetrics) - resultView.setPointSize(getDimension(Style.BarcodeView_resultPointSize, defaultSize)) - analyzer.inverted = getBoolean(Style.BarcodeView_barcodeInverted, false) - } - - textureView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> - updateTransform() - } - } - - override fun onResult(result: Result, imageWidth: Int, imageHeight: Int, imageRotation: Int) { - resultView.setResult(result, imageWidth, imageHeight, imageRotation) - - val d = resultDebouncer { - listener?.onBarcodeResult(result) - } - if (d == true) { - // dialog/fragment will be dismissed -> do not send any more events - listener = null - } - } - - override fun onNoResult() { - resultView.clear() - } - - fun setBarcodeResultListener(listener: BarcodeResultListener) { - this.listener = listener - } - - /** - * enable scanning of inverted barcodes (e.g. white QR Code on black background) - */ - fun setBarcodeInverted(inverted: Boolean) { - analyzer.inverted = inverted - } - - fun bindToLifecycle(owner: LifecycleOwner) { - textureView.post { startPreview(owner) } - } - - fun unbind() { - resultView.clear() - listener = null - CameraX.unbindAll() - } - - fun setFormats(formats: List) = barcodeReader.setHints( - mapOf( - DecodeHintType.POSSIBLE_FORMATS to formats - ) - ) - - private fun startPreview(owner: LifecycleOwner) { - val metrics = DisplayMetrics().also { textureView.display.getRealMetrics(it) } - val screenSize = Size(metrics.widthPixels, metrics.heightPixels) - val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels) - val screenRotation = textureView.display.rotation - - val previewConfig = PreviewConfig.Builder().apply { - setLensFacing(CameraX.LensFacing.BACK) - setTargetResolution(screenSize / 2) - setTargetAspectRatio(screenAspectRatio) - setTargetRotation(screenRotation) - }.build() - - val preview = Preview(previewConfig).apply { - setOnPreviewOutputUpdateListener(::previewOutputUpdated) - } - - val analysisConfig = ImageAnalysisConfig.Builder().apply { - setLensFacing(CameraX.LensFacing.BACK) - setTargetResolution(screenSize / 2) - setTargetAspectRatio(screenAspectRatio) - setTargetRotation(textureView.display.rotation) - - setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE) - val analyzerThread = HandlerThread("BarcodeAnalyzer").apply { start() } - setCallbackHandler(Handler(analyzerThread.looper)) - }.build() - - val analysis = ImageAnalysis(analysisConfig).apply { analyzer = this@BarcodeView.analyzer } - - CameraX.bindToLifecycle(owner, preview, analysis) - } - - private fun previewOutputUpdated(output: Preview.PreviewOutput) { - // https://github.com/android/camera/blob/848cf1e2c8404599050d79086dee1d0c8951b66e/CameraXBasic/app/src/main/java/com/android/example/cameraxbasic/utils/AutoFitPreviewBuilder.kt#L100 - (textureView.parent as? ViewGroup)?.apply { - val idx = indexOfChild(textureView) - removeView(textureView) - addView(textureView, idx) - textureView.surfaceTexture = output.surfaceTexture - } - - bufferSize = SizeF(output.textureSize.height.toFloat(), output.textureSize.width.toFloat()) - updateTransform() - } - - private fun updateTransform() { - val viewFinderWidth = textureView.width.toFloat() - val viewFinderHeight = textureView.height.toFloat() - val viewFinderRotation = when (textureView.display.rotation) { - Surface.ROTATION_0 -> 0 - Surface.ROTATION_90 -> 90 - Surface.ROTATION_180 -> 180 - Surface.ROTATION_270 -> 270 - else -> return - } - val matrix = Matrix() - val centerX = viewFinderWidth / 2f - val centerY = viewFinderHeight / 2f - - matrix.postRotate(-viewFinderRotation.toFloat(), centerX, centerY) - - val bufferRatio = bufferSize.width / bufferSize.height - val viewRatio = viewFinderWidth / viewFinderHeight - - if (bufferRatio > viewRatio) { - val factor = bufferRatio / viewRatio - matrix.preScale(factor, 1f, centerX, centerY) - } else { - val factor = viewRatio / bufferRatio - matrix.preScale(1f, factor, centerX, centerY) - } - - if (viewFinderRotation % 180 != 0) { - if (bufferRatio > viewRatio) { - val s = 1f / bufferRatio - matrix.preScale(s, s, centerX, centerY) - } else { - val s = max(bufferRatio, 1f / viewRatio) - matrix.preScale(s, s, centerX, centerY) - } - } - -// val dbgScale = .95f -// matrix.preScale(dbgScale, dbgScale, centerX, centerY) - - textureView.setTransform(matrix) - } -} - -private operator fun Size.div(other: Int): Size = Size(width / other, height / other) diff --git a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/views/ResultPointView.kt b/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/views/ResultPointView.kt deleted file mode 100644 index 9cb98d7c..00000000 --- a/barcode_kaiteki/src/main/java/com/kroegerama/kaiteki/bcode/views/ResultPointView.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.kroegerama.kaiteki.bcode.views - -import android.content.Context -import android.content.res.Resources -import android.graphics.* -import android.util.AttributeSet -import android.util.TypedValue -import android.view.View -import androidx.annotation.ColorInt -import com.google.zxing.Result -import com.kroegerama.kaiteki.bcode.BuildConfig -import com.kroegerama.kaiteki.bcode.Style -import com.kroegerama.kaiteki.bcode.handleArguments -import kotlin.math.max - -class ResultPointView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : View(context, attrs, defStyleAttr) { - - private val pPoints = Paint().apply { - style = Paint.Style.STROKE - color = Color.GREEN - strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, Resources.getSystem().displayMetrics) - strokeCap = Paint.Cap.ROUND - } - - private var resultPoints = floatArrayOf() - private var rect = RectF() - - var showResultPoints = true - set(value) { - field = value - invalidate() - } - - init { - attrs.handleArguments(context, Style.ResultPointView, defStyleAttr, 0) { - showResultPoints = getBoolean(Style.ResultPointView_showResultPoints, showResultPoints) - - pPoints.color = getColor(Style.ResultPointView_resultPointColor, pPoints.color) - pPoints.strokeWidth = - getDimension(Style.ResultPointView_resultPointSize, pPoints.strokeWidth) - } - } - - fun setResultPointColor(@ColorInt color: Int) { - pPoints.color = color - invalidate() - } - - fun setPointSize(size: Float) { - pPoints.strokeWidth = size - } - - fun clear() { - resultPoints = floatArrayOf() - - postInvalidate() - } - - fun setResult(result: Result, imageWidth: Int, imageHeight: Int, imageRotation: Int) { - if (!showResultPoints) return - - val localMatrix = createMatrix(imageWidth.toFloat(), imageHeight.toFloat(), imageRotation) - - resultPoints = result.resultPoints.flatMap { listOf(it.x, it.y) }.toFloatArray() - localMatrix.mapPoints(resultPoints) - - if (BuildConfig.DEBUG) { - rect = RectF(0f, 0f, imageWidth.toFloat(), imageHeight.toFloat()) - localMatrix.mapRect(rect) - } - - postInvalidate() - } - - private fun createMatrix(imageWidth: Float, imageHeight: Float, imageRotation: Int) = Matrix().apply { - preTranslate((width - imageWidth) / 2f, (height - imageHeight) / 2f) - preRotate(imageRotation.toFloat(), imageWidth / 2f, imageHeight / 2f) - - val wScale: Float - val hScale: Float - - if (imageRotation % 180 == 0) { - wScale = width.toFloat() / imageWidth - hScale = height.toFloat() / imageHeight - } else { - wScale = height.toFloat() / imageWidth - hScale = width.toFloat() / imageHeight - - } - - val scale = max(wScale, hScale) - preScale(scale, scale, imageWidth / 2f, imageHeight / 2f) - } - - override fun onDraw(canvas: Canvas) { - if (showResultPoints) canvas.drawPoints(resultPoints, pPoints) - - if (BuildConfig.DEBUG) canvas.drawRect(rect, pPoints) - } -} \ No newline at end of file diff --git a/barcode_kaiteki/src/main/res/layout/barcode_view.xml b/barcode_kaiteki/src/main/res/layout/barcode_view.xml deleted file mode 100644 index d22acedd..00000000 --- a/barcode_kaiteki/src/main/res/layout/barcode_view.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/barcode_kaiteki/src/main/res/layout/dlg_barcode.xml b/barcode_kaiteki/src/main/res/layout/dlg_barcode.xml deleted file mode 100644 index bcae9b0d..00000000 --- a/barcode_kaiteki/src/main/res/layout/dlg_barcode.xml +++ /dev/null @@ -1,9 +0,0 @@ - - \ No newline at end of file diff --git a/barcode_kaiteki/src/main/res/values/attrs.xml b/barcode_kaiteki/src/main/res/values/attrs.xml deleted file mode 100644 index 7d85a540..00000000 --- a/barcode_kaiteki/src/main/res/values/attrs.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0a12c5ee..c67a2022 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.0' + classpath 'com.android.tools.build:gradle:4.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.5' classpath 'com.google.firebase:perf-plugin:1.3.5' diff --git a/settings.gradle b/settings.gradle index 92cc56d8..0430cd8b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ include ':dynamic_gramm' -include ':app', ':pointmobilescannerlibrary', ':dynamic_vgalimenti', ':dynamic__base', ':zebrascannerlibrary', ':honeywellscannerlibrary', ':dynamic_ime', ':dynamic_frudis', ':dynamic_saporiveri_pv', ':keyobardemulatorscannerlibrary', ':barcode_base_android_library', ':dynamic_saporiveri', ':barcode_kaiteki' +include ':app', ':pointmobilescannerlibrary', ':dynamic_vgalimenti', ':dynamic__base', ':zebrascannerlibrary', ':honeywellscannerlibrary', ':dynamic_ime', ':dynamic_frudis', ':dynamic_saporiveri_pv', ':keyobardemulatorscannerlibrary', ':barcode_base_android_library', ':dynamic_saporiveri'