mirror of
https://github.com/bitwarden/android.git
synced 2026-03-24 07:11:53 -05:00
PM-26594: Move the QrCodeAnalyzer to the UI module (#5980)
This commit is contained in:
@@ -57,6 +57,7 @@ dependencies {
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.browser)
|
||||
implementation(libs.androidx.camera.camera2)
|
||||
implementation(libs.androidx.compose.animation)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.material3.adaptive)
|
||||
@@ -72,6 +73,7 @@ dependencies {
|
||||
implementation(libs.kotlinx.serialization)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
implementation(libs.zxing.zxing.core)
|
||||
|
||||
// For now we are restricted to running Compose tests for debug builds only
|
||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
@@ -86,6 +88,7 @@ dependencies {
|
||||
testImplementation(libs.androidx.compose.ui.test)
|
||||
|
||||
testFixturesImplementation(libs.androidx.activity.compose)
|
||||
testFixturesImplementation(libs.androidx.camera.camera2)
|
||||
testFixturesImplementation(libs.androidx.compose.ui.test)
|
||||
testFixturesImplementation(libs.androidx.navigation.compose)
|
||||
testFixturesImplementation(libs.google.hilt.android.testing)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.bitwarden.ui.platform.feature.qrcodescan.util
|
||||
|
||||
import androidx.camera.core.ImageAnalysis
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
/**
|
||||
* An interface that is used to help scan QR codes.
|
||||
*/
|
||||
@Stable
|
||||
interface QrCodeAnalyzer : ImageAnalysis.Analyzer {
|
||||
|
||||
/**
|
||||
* The method that is called once the code is scanned.
|
||||
*/
|
||||
var onQrCodeScanned: (String) -> Unit
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.bitwarden.ui.platform.feature.qrcodescan.util
|
||||
|
||||
import androidx.camera.core.ImageProxy
|
||||
import com.bitwarden.annotation.OmitFromCoverage
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.BinaryBitmap
|
||||
import com.google.zxing.DecodeHintType
|
||||
import com.google.zxing.MultiFormatReader
|
||||
import com.google.zxing.NotFoundException
|
||||
import com.google.zxing.PlanarYUVLuminanceSource
|
||||
import com.google.zxing.common.HybridBinarizer
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
/**
|
||||
* A class setup to handle image analysis so that we can use the Zxing library
|
||||
* to scan QR codes and convert them to a string.
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
class QrCodeAnalyzerImpl : QrCodeAnalyzer {
|
||||
|
||||
/**
|
||||
* This will ensure the result is only sent once as multiple images with a valid
|
||||
* QR code can be sent for analysis.
|
||||
*/
|
||||
private var qrCodeRead = false
|
||||
|
||||
override lateinit var onQrCodeScanned: (String) -> Unit
|
||||
|
||||
override fun analyze(image: ImageProxy) {
|
||||
if (qrCodeRead) {
|
||||
return
|
||||
}
|
||||
|
||||
val source = PlanarYUVLuminanceSource(
|
||||
image.planes[0].buffer.toByteArray(),
|
||||
image.width,
|
||||
image.height,
|
||||
0,
|
||||
0,
|
||||
image.width,
|
||||
image.height,
|
||||
false,
|
||||
)
|
||||
val binaryBitmap = BinaryBitmap(HybridBinarizer(source))
|
||||
try {
|
||||
val result = MultiFormatReader().decode(
|
||||
binaryBitmap,
|
||||
mapOf(
|
||||
DecodeHintType.POSSIBLE_FORMATS to arrayListOf(BarcodeFormat.QR_CODE),
|
||||
DecodeHintType.ALSO_INVERTED to true,
|
||||
),
|
||||
)
|
||||
|
||||
qrCodeRead = true
|
||||
onQrCodeScanned(result.text)
|
||||
} catch (_: NotFoundException) {
|
||||
return
|
||||
} finally {
|
||||
image.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function helps us prepare the byte buffer to be read.
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
private fun ByteBuffer.toByteArray(): ByteArray =
|
||||
ByteArray(rewind().remaining()).also { get(it) }
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.bitwarden.ui.platform.feature.qrcodescan.util
|
||||
|
||||
import androidx.camera.core.ImageProxy
|
||||
|
||||
/**
|
||||
* A helper class that helps test scan outcomes.
|
||||
*/
|
||||
class FakeQrCodeAnalyzer : QrCodeAnalyzer {
|
||||
|
||||
override lateinit var onQrCodeScanned: (String) -> Unit
|
||||
|
||||
/**
|
||||
* The result of the scan that will be sent to the ViewModel (or `null` to indicate a
|
||||
* scanning error.
|
||||
*/
|
||||
var scanResult: String? = null
|
||||
|
||||
override fun analyze(image: ImageProxy) {
|
||||
scanResult?.let { onQrCodeScanned.invoke(it) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user