mirror of
https://github.com/bitwarden/android.git
synced 2026-05-06 07:48:22 -05:00
PM-26594: Move the QrCodeAnalyzer to the UI module (#5980)
This commit is contained in:
@@ -224,7 +224,6 @@ dependencies {
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.kotlinx.serialization)
|
||||
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)
|
||||
|
||||
@@ -50,8 +50,6 @@ import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.util.QrCodeAnalyzer
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.util.QrCodeAnalyzerImpl
|
||||
import com.bitwarden.authenticator.ui.platform.util.isPortrait
|
||||
import com.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.bitwarden.ui.platform.base.util.annotatedStringResource
|
||||
@@ -60,6 +58,8 @@ import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
||||
import com.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||
import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
|
||||
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.bitwarden.ui.platform.feature.qrcodescan.util.QrCodeAnalyzer
|
||||
import com.bitwarden.ui.platform.feature.qrcodescan.util.QrCodeAnalyzerImpl
|
||||
import com.bitwarden.ui.platform.resource.BitwardenDrawable
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.bitwarden.authenticator.ui.authenticator.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
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.util
|
||||
|
||||
import androidx.camera.core.ImageProxy
|
||||
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.
|
||||
*/
|
||||
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.planes[0].rowStride,
|
||||
image.height,
|
||||
0,
|
||||
0,
|
||||
image.width,
|
||||
image.height,
|
||||
false,
|
||||
)
|
||||
|
||||
val binaryBitmap = BinaryBitmap(HybridBinarizer(source))
|
||||
try {
|
||||
val result = MultiFormatReader().decode(
|
||||
/* image = */ binaryBitmap,
|
||||
/* hints = */
|
||||
mapOf(
|
||||
DecodeHintType.POSSIBLE_FORMATS to arrayListOf(BarcodeFormat.QR_CODE),
|
||||
DecodeHintType.ALSO_INVERTED to true,
|
||||
),
|
||||
)
|
||||
|
||||
qrCodeRead = true
|
||||
onQrCodeScanned(result.text)
|
||||
} catch (ignored: NotFoundException) {
|
||||
} finally {
|
||||
image.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function helps us prepare the byte buffer to be read.
|
||||
*/
|
||||
private fun ByteBuffer.toByteArray(): ByteArray =
|
||||
ByteArray(rewind().remaining()).also { get(it) }
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan
|
||||
|
||||
import androidx.camera.core.ImageProxy
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.util.QrCodeAnalyzer
|
||||
|
||||
/**
|
||||
* 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) }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import com.bitwarden.authenticator.ui.platform.base.AuthenticatorComposeTest
|
||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.ui.platform.feature.qrcodescan.util.FakeQrCodeAnalyzer
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
|
||||
Reference in New Issue
Block a user