Aperture: Switch to ZXing-C++

Change-Id: I97a6af09793feac8a51aca3b849925d85f8ebd9d
diff --git a/app/Android.bp b/app/Android.bp
index af0c230..e8d3aa8 100644
--- a/app/Android.bp
+++ b/app/Android.bp
@@ -46,6 +46,7 @@
         "Aperture_androidx.media3_media3-exoplayer",
         "Aperture_androidx.media3_media3-ui",
         "Aperture_com.google.zxing_core",
+        "Aperture_io.github.zxing-cpp_android",
         "Aperture_io.coil-kt_coil",
         "Aperture_io.coil-kt_coil-video",
     ],
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 95414d1..536ad70 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -108,6 +108,7 @@
 
     // ZXing
     implementation("com.google.zxing:core:3.5.3")
+    implementation("io.github.zxing-cpp:android:2.2.0")
 
     // Coil
     implementation("io.coil-kt:coil:2.4.0")
diff --git a/app/libs/Android.bp b/app/libs/Android.bp
index 0a24a7b..b4f8b52 100644
--- a/app/libs/Android.bp
+++ b/app/libs/Android.bp
@@ -946,3 +946,36 @@
     ],
     java_version: "1.7",
 }
+
+android_library_import {
+    name: "Aperture_io.github.zxing-cpp_android-nodeps",
+    aars: ["io/github/zxing-cpp/android/2.2.0/android-2.2.0.aar"],
+    sdk_version: "34",
+    min_sdk_version: "14",
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    static_libs: [
+        "Aperture_androidx.camera_camera-core",
+        "kotlin-stdlib-jdk8",
+    ],
+    extract_jni: true,
+}
+
+android_library {
+    name: "Aperture_io.github.zxing-cpp_android",
+    sdk_version: "34",
+    min_sdk_version: "14",
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    manifest: "io/github/zxing-cpp/android/2.2.0/AndroidManifest.xml",
+    static_libs: [
+        "Aperture_io.github.zxing-cpp_android-nodeps",
+        "Aperture_androidx.camera_camera-core",
+        "kotlin-stdlib-jdk8",
+    ],
+    java_version: "1.7",
+}
diff --git a/app/libs/io/github/zxing-cpp/android/2.2.0/AndroidManifest.xml b/app/libs/io/github/zxing-cpp/android/2.2.0/AndroidManifest.xml
new file mode 100644
index 0000000..8e40224
--- /dev/null
+++ b/app/libs/io/github/zxing-cpp/android/2.2.0/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="io.github.zxingcpp" >
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
\ No newline at end of file
diff --git a/app/libs/io/github/zxing-cpp/android/2.2.0/AndroidManifest.xml.license b/app/libs/io/github/zxing-cpp/android/2.2.0/AndroidManifest.xml.license
new file mode 100644
index 0000000..c0956dc
--- /dev/null
+++ b/app/libs/io/github/zxing-cpp/android/2.2.0/AndroidManifest.xml.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2024 zxing-cpp community
+
+SPDX-License-Identifier: Apache-2.0
diff --git a/app/libs/io/github/zxing-cpp/android/2.2.0/android-2.2.0.aar b/app/libs/io/github/zxing-cpp/android/2.2.0/android-2.2.0.aar
new file mode 100644
index 0000000..4abde84
--- /dev/null
+++ b/app/libs/io/github/zxing-cpp/android/2.2.0/android-2.2.0.aar
Binary files differ
diff --git a/app/libs/io/github/zxing-cpp/android/2.2.0/android-2.2.0.aar.license b/app/libs/io/github/zxing-cpp/android/2.2.0/android-2.2.0.aar.license
new file mode 100644
index 0000000..c0956dc
--- /dev/null
+++ b/app/libs/io/github/zxing-cpp/android/2.2.0/android-2.2.0.aar.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2024 zxing-cpp community
+
+SPDX-License-Identifier: Apache-2.0
diff --git a/app/src/main/java/org/lineageos/aperture/ext/ImageProxy.kt b/app/src/main/java/org/lineageos/aperture/ext/ImageProxy.kt
deleted file mode 100644
index b484966..0000000
--- a/app/src/main/java/org/lineageos/aperture/ext/ImageProxy.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 The LineageOS Project
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package org.lineageos.aperture.ext
-
-import androidx.camera.core.ImageProxy
-import com.google.zxing.PlanarYUVLuminanceSource
-
-private fun rotateYUVLuminancePlane(data: ByteArray, width: Int, height: Int): ByteArray {
-    val yuv = ByteArray(width * height)
-    // Rotate the Y luma
-    var i = 0
-    for (x in 0 until width) {
-        for (y in height - 1 downTo 0) {
-            yuv[i] = data[y * width + x]
-            i++
-        }
-    }
-    return yuv
-}
-
-internal val ImageProxy.planarYUVLuminanceSource: PlanarYUVLuminanceSource
-    get() {
-        val plane = planes[0]
-        val buffer = plane.buffer
-        var bytes = ByteArray(buffer.remaining())
-        buffer.get(bytes)
-
-        var width = width
-        var height = height
-
-        if (imageInfo.rotationDegrees == 90 || imageInfo.rotationDegrees == 270) {
-            bytes = rotateYUVLuminancePlane(bytes, width, height)
-            width = height.also { height = width }
-        }
-
-        return PlanarYUVLuminanceSource(
-            bytes, width, height, 0, 0, width, height, true
-        )
-    }
diff --git a/app/src/main/java/org/lineageos/aperture/qr/QrImageAnalyzer.kt b/app/src/main/java/org/lineageos/aperture/qr/QrImageAnalyzer.kt
index 354ca89..99ae658 100644
--- a/app/src/main/java/org/lineageos/aperture/qr/QrImageAnalyzer.kt
+++ b/app/src/main/java/org/lineageos/aperture/qr/QrImageAnalyzer.kt
@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022-2023 The LineageOS Project
+ * SPDX-FileCopyrightText: 2022-2024 The LineageOS Project
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -28,10 +28,9 @@
 import androidx.core.graphics.drawable.DrawableCompat
 import com.google.android.material.bottomsheet.BottomSheetDialog
 import com.google.android.material.button.MaterialButton
-import com.google.zxing.BinaryBitmap
-import com.google.zxing.MultiFormatReader
+import com.google.zxing.BarcodeFormat
 import com.google.zxing.Result
-import com.google.zxing.common.HybridBinarizer
+import io.github.zxingcpp.BarcodeReader
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
@@ -78,7 +77,11 @@
     }
 
     // QR
-    private val reader by lazy { MultiFormatReader() }
+    private val reader by lazy {
+        BarcodeReader().apply {
+            options.tryRotate = true
+        }
+    }
 
     private val qrTextClassifier by lazy {
         QrTextClassifier(activity, textClassificationManager.textClassifier)
@@ -86,23 +89,13 @@
 
     override fun analyze(image: ImageProxy) {
         image.use {
-            val source = image.planarYUVLuminanceSource
-
-            val result = runCatching {
-                reader.decodeWithState(BinaryBitmap(HybridBinarizer(source)))
-            }.getOrNull() ?: runCatching {
-                reader.decodeWithState(BinaryBitmap(HybridBinarizer(source.invert())))
-            }.getOrNull()
-
-            result?.let {
+            reader.read(image).firstOrNull()?.let {
                 showQrDialog(it)
             }
-
-            reader.reset()
         }
     }
 
-    private fun showQrDialog(result: Result) {
+    private fun showQrDialog(result: BarcodeReader.Result) {
         scope.launch(Dispatchers.Main) {
             if (bottomSheetDialog.isShowing) {
                 return@launch
@@ -113,7 +106,31 @@
 
             // Classify message
             val textClassification = withContext(Dispatchers.IO) {
-                qrTextClassifier.classifyText(result)
+                qrTextClassifier.classifyText(
+                    Result(
+                        text, result.bytes, null, when (result.format) {
+                            BarcodeReader.Format.NONE -> null
+                            BarcodeReader.Format.AZTEC -> BarcodeFormat.AZTEC
+                            BarcodeReader.Format.CODABAR -> BarcodeFormat.CODABAR
+                            BarcodeReader.Format.CODE_39 -> BarcodeFormat.CODE_39
+                            BarcodeReader.Format.CODE_93 -> BarcodeFormat.CODE_93
+                            BarcodeReader.Format.CODE_128 -> BarcodeFormat.CODE_128
+                            BarcodeReader.Format.DATA_BAR -> null
+                            BarcodeReader.Format.DATA_BAR_EXPANDED -> null
+                            BarcodeReader.Format.DATA_MATRIX -> BarcodeFormat.DATA_MATRIX
+                            BarcodeReader.Format.EAN_8 -> BarcodeFormat.EAN_8
+                            BarcodeReader.Format.EAN_13 -> BarcodeFormat.EAN_13
+                            BarcodeReader.Format.ITF -> BarcodeFormat.ITF
+                            BarcodeReader.Format.MAXICODE -> BarcodeFormat.MAXICODE
+                            BarcodeReader.Format.PDF_417 -> BarcodeFormat.PDF_417
+                            BarcodeReader.Format.QR_CODE -> BarcodeFormat.QR_CODE
+                            BarcodeReader.Format.MICRO_QR_CODE -> BarcodeFormat.QR_CODE
+                            BarcodeReader.Format.RMQR_CODE -> BarcodeFormat.QR_CODE
+                            BarcodeReader.Format.UPC_A -> BarcodeFormat.UPC_A
+                            BarcodeReader.Format.UPC_E -> BarcodeFormat.UPC_E
+                        }
+                    )
+                )
             }
 
             bottomSheetDialogData.text = textClassification.text
@@ -201,7 +218,7 @@
                             action = Intent.ACTION_SEND
                             type = ClipDescription.MIMETYPE_TEXT_PLAIN
                             putExtra(
-                                Intent.EXTRA_TEXT, result.text
+                                Intent.EXTRA_TEXT, text
                             )
                         },
                         activity.getString(androidx.transition.R.string.abc_shareactionprovider_share_with)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index de0c7c0..c1df78c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -14,6 +14,7 @@
     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
     repositories {
         maven("https://raw.githubusercontent.com/lineage-next/camerax-aperture/bdc457ba0021c05507c4bec14806c120e132a37f/.m2")
+        maven("https://raw.githubusercontent.com/lineage-next/zxingcpp-aperture/6d27bbc39b7b53e7de52054d532a61c2b48fa897/.m2")
         google()
         mavenCentral()
     }