Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
infra:orchestrator-data
infra:enrolment-records:repository
infra:enrolment-records:realm-store
infra:enrolment-records:room-store
infra:recent-user-activity
infra:config-store
infra:config-sync
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import androidx.room.gradle.RoomExtension
import com.android.build.api.dsl.LibraryExtension
import common.api
import common.configureDbEncryptionBuild
import common.getLibs
import common.implementation
Expand Down Expand Up @@ -38,7 +39,7 @@ class LibraryRoomConventionPlugin : Plugin<Project> {

val libs = getLibs()
dependencies {
implementation(libs, "androidX.Room.core")
api(libs, "androidX.Room.core")
implementation(libs, "androidX.Room.ktx")
ksp(libs, "androidX.Room.compiler")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ fun Project.configureDbEncryptionBuild() {
}

getByName(BuildTypes.DEBUG) {
buildConfigField("Boolean", "DB_ENCRYPTION", "$propDbEncrypted")
// Set false only if running tests
Comment thread
meladRaouf marked this conversation as resolved.
val isTestTask = gradle.startParameter.taskNames.any {
it.contains("test", ignoreCase = true) || it.contains("connected", ignoreCase = true)
}

val dbEncryptionValue = if (isTestTask) "false" else "$propDbEncrypted"
buildConfigField("Boolean", "DB_ENCRYPTION", dbEncryptionValue)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package com.simprints.feature.dashboard.debug

import android.graphics.Color
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableString
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.view.View
import androidx.core.graphics.toColorInt
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.work.WorkManager
import com.simprints.core.DispatcherIO
import com.simprints.feature.dashboard.R
import com.simprints.feature.dashboard.databinding.FragmentDebugBinding
import com.simprints.infra.authstore.AuthStore
import com.simprints.infra.enrolment.records.repository.local.EnrolmentRecordLocalDataSource
import com.simprints.infra.enrolment.records.repository.EnrolmentRecordRepository
import com.simprints.infra.events.EventRepository
import com.simprints.infra.eventsync.EventSyncManager
import com.simprints.infra.eventsync.status.models.EventSyncWorkerState
Expand Down Expand Up @@ -43,7 +43,7 @@ internal class DebugFragment : Fragment(R.layout.fragment_debug) {
lateinit var eventRepository: EventRepository

@Inject
lateinit var enrolmentRecordRepository: EnrolmentRecordLocalDataSource
lateinit var enrolmentRecordRepository: EnrolmentRecordRepository

@Inject
@DispatcherIO
Expand Down Expand Up @@ -71,7 +71,7 @@ internal class DebugFragment : Fragment(R.layout.fragment_debug) {
val ssb = SpannableStringBuilder(
coloredText(
"\n$message",
Color.parseColor(getRandomColor()),
getRandomColor().toColorInt(),
),
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.simprints.matcher.usecases

import com.simprints.core.AvailableProcessors
import com.simprints.core.DispatcherBG
import com.simprints.core.DispatcherIO
import com.simprints.face.infra.basebiosdk.matching.FaceIdentity
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.basebiosdk.matching.FaceSample
Expand All @@ -20,19 +18,15 @@ import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
import kotlin.math.min
import com.simprints.infra.enrolment.records.repository.domain.models.FaceIdentity as DomainFaceIdentity

internal class FaceMatcherUseCase @Inject constructor(
private val enrolmentRecordRepository: EnrolmentRecordRepository,
private val resolveFaceBioSdk: ResolveFaceBioSdkUseCase,
private val createRanges: CreateRangesUseCase,
@AvailableProcessors private val availableProcessors: Int,
@DispatcherBG private val dispatcherBG: CoroutineDispatcher,
@DispatcherIO private val dispatcherIO: CoroutineDispatcher,
) : MatcherUseCase {
override val crashReportTag = LoggingConstants.CrashReportTag.FACE_MATCHING

Expand Down Expand Up @@ -73,9 +67,6 @@ internal class FaceMatcherUseCase @Inject constructor(
// as it's count function does not take into account filtering criteria
val loadedCandidates = AtomicInteger(0)
val ranges = createRanges(expectedCandidates)
// if number of ranges less than the number of cores then use the number of ranges
val numConsumers = min(availableProcessors, ranges.size)

val resultSet = MatchResultSet<FaceMatchResult.Item>()
val candidatesChannel = enrolmentRecordRepository
.loadFaceIdentities(
Expand All @@ -84,22 +75,14 @@ internal class FaceMatcherUseCase @Inject constructor(
dataSource = matchParams.biometricDataSource,
project = project,
scope = this,
onCandidateLoaded = {
loadedCandidates.incrementAndGet()
this.trySend(MatcherState.CandidateLoaded)
},
)

// Start Consumers in BG thread
val consumerJobs = List(numConsumers) {
launch(dispatcherBG) {
consumeAndMatch(candidatesChannel, samples, resultSet, bioSdk)
) {
loadedCandidates.incrementAndGet()
this@channelFlow.send(MatcherState.CandidateLoaded)
}
}
// Wait for all to complete
consumerJobs.forEach { it.join() }

consumeAndMatch(candidatesChannel, samples, resultSet, bioSdk)
send(MatcherState.Success(resultSet.toList(), loadedCandidates.get(), bioSdk.matcherName))
}.flowOn(dispatcherIO)
}.flowOn(dispatcherBG)

suspend fun consumeAndMatch(
candidatesChannel: ReceiveChannel<List<DomainFaceIdentity>>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.simprints.matcher.usecases

import com.simprints.core.AvailableProcessors
import com.simprints.core.DispatcherBG
import com.simprints.core.DispatcherIO
import com.simprints.core.domain.common.FlowType
import com.simprints.core.domain.fingerprint.IFingerIdentifier
import com.simprints.fingerprint.infra.basebiosdk.matching.domain.FingerIdentifier
Expand All @@ -25,20 +23,16 @@ import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
import kotlin.math.min
import com.simprints.infra.enrolment.records.repository.domain.models.FingerprintIdentity as DomainFingerprintIdentity

internal class FingerprintMatcherUseCase @Inject constructor(
private val enrolmentRecordRepository: EnrolmentRecordRepository,
private val resolveBioSdkWrapper: ResolveBioSdkWrapperUseCase,
private val configManager: ConfigManager,
private val createRanges: CreateRangesUseCase,
@AvailableProcessors private val availableProcessors: Int,
@DispatcherBG private val dispatcherBG: CoroutineDispatcher,
@DispatcherIO private val dispatcherIO: CoroutineDispatcher,
) : MatcherUseCase {
override val crashReportTag = LoggingConstants.CrashReportTag.FINGER_MATCHING

Expand Down Expand Up @@ -79,7 +73,6 @@ internal class FingerprintMatcherUseCase @Inject constructor(
val loadedCandidates = AtomicInteger(0)
val ranges = createRanges(expectedCandidates)
// if number of ranges less than the number of cores then use the number of ranges
val numConsumers = min(availableProcessors, ranges.size)
val channel = enrolmentRecordRepository.loadFingerprintIdentities(
query = queryWithSupportedFormat,
ranges = ranges,
Expand All @@ -88,23 +81,16 @@ internal class FingerprintMatcherUseCase @Inject constructor(
project = project,
) {
loadedCandidates.incrementAndGet()
trySend(MatcherState.CandidateLoaded)
this@channelFlow.send(MatcherState.CandidateLoaded)
}

val resultSet = MatchResultSet<FingerprintMatchResult.Item>()

// Start Consumers in BG thread
val consumerJobs = List(numConsumers) {
launch(dispatcherBG) {
consumeAndMatch(channel, samples, resultSet, bioSdkWrapper, matchParams)
}
}
// Wait for all to complete
consumerJobs.forEach { it.join() }
consumeAndMatch(channel, samples, resultSet, bioSdkWrapper, matchParams)

Simber.i("Matched $loadedCandidates candidates", tag = crashReportTag)
send(MatcherState.Success(resultSet.toList(), loadedCandidates.get(), bioSdkWrapper.matcherName))
}.flowOn(dispatcherIO)
}.flowOn(dispatcherBG)

private suspend fun consumeAndMatch(
channel: ReceiveChannel<List<DomainFingerprintIdentity>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.simprints.testtools.common.coroutines.TestCoroutineRule
import io.mockk.*
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -54,8 +55,6 @@ internal class FaceMatcherUseCaseTest {
enrolmentRecordRepository,
resolveFaceBioSdk,
createRangesUseCase,
4,
testCoroutineRule.testCoroutineDispatcher,
testCoroutineRule.testCoroutineDispatcher,
)
}
Expand Down Expand Up @@ -127,10 +126,14 @@ internal class FaceMatcherUseCaseTest {
)
coEvery { enrolmentRecordRepository.count(any(), any()) } returns 1
coEvery { createRangesUseCase(any()) } returns listOf(0..99)
coEvery { enrolmentRecordRepository.loadFaceIdentities(any(), any(), any(), any(), any(), any()) } coAnswers {
every {
enrolmentRecordRepository.loadFaceIdentities(any(), any(), any(), any(), any(), any())
} answers {
// Call the onCandidateLoaded callback (5th parameter)
val onCandidateLoaded = arg<() -> Unit>(5)
onCandidateLoaded()
val onCandidateLoaded: suspend () -> Unit = arg(5)
runBlocking {
onCandidateLoaded()
}

// Return the face identities
createTestChannel(faceIdentities)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ internal class FingerprintMatcherUseCaseTest {
resolveBioSdkWrapperUseCase,
configManager,
createRangesUseCase,
4,
testCoroutineRule.testCoroutineDispatcher,
testCoroutineRule.testCoroutineDispatcher,
)
}
Expand Down
1 change: 0 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ testing-AndroidX-core = { module = "androidx.arch.core:core-testing", version.re
testing-AndroidX-orchestrator = { module = "androidx.test:orchestrator", version.ref = "androidx_test_orchestrator_version" }
testing-AndroidX-runner = { module = "androidx.test:runner", version.ref = "androidx_version" }
testing-AndroidX-room = { module = "androidx.room:room-testing", version.ref = "androidx_room_version" }
testing-AndroidX-navigation = { module = "androidx.navigation:navigation-testing", version.ref = "androidx_navigation_version" }
testing-AndroidX-uiAutomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "uiAutomator_version" }

# Dependencies of the included build-logic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class TokenizationProcessor @Inject constructor(
encrypted: TokenizableString.Tokenized,
tokenKeyType: TokenKeyType,
project: Project,
logError: Boolean = true
logError: Boolean = true,
): TokenizableString {
val moduleKeyset = project.tokenizationKeys[tokenKeyType] ?: return encrypted
return try {
Expand All @@ -62,4 +62,18 @@ class TokenizationProcessor @Inject constructor(
encrypted
}
}

fun tokenizeIfNecessary(
tokenizableString: TokenizableString,
tokenKeyType: TokenKeyType,
project: Project,
) = when (tokenizableString) {
is TokenizableString.Raw -> encrypt(
decrypted = tokenizableString,
tokenKeyType = tokenKeyType,
project = project,
)

is TokenizableString.Tokenized -> tokenizableString
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import io.realm.kotlin.MutableRealm
import io.realm.kotlin.Realm
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.RealmSingleQuery
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
Expand All @@ -43,7 +44,7 @@ class ProjectRealmMigrationTest {
private lateinit var realmQuery: RealmQuery<DbProject>

private lateinit var blockCapture: CapturingSlot<(MutableRealm) -> Any>
private lateinit var readBlockCapture: CapturingSlot<(Realm) -> Any>
private lateinit var readBlockCapture: CapturingSlot<suspend (Realm) -> Any>

private lateinit var projectRealmMigration: ProjectRealmMigration

Expand All @@ -56,7 +57,7 @@ class ProjectRealmMigrationTest {

every { realm.query<DbProject>(any(), any(), any()) } returns realmQuery
coEvery { realmWrapper.readRealm(capture(readBlockCapture)) } answers {
readBlockCapture.captured.invoke(realm)
runBlocking { readBlockCapture.captured.invoke(realm) }
}
coEvery { realmWrapper.writeRealm(capture(blockCapture)) } answers {
blockCapture.captured.invoke(mutableRealm)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ data class FaceSample(

other as FaceSample

if (!template.contentEquals(other.template)) return false
Comment thread
meladRaouf marked this conversation as resolved.

return true
return template.contentEquals(other.template)
}

override fun hashCode(): Int = template.contentHashCode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface RealmWrapper {
/**
* Returns read-only Realm instance for data fetching.
*/
suspend fun <R> readRealm(block: (Realm) -> R): R
suspend fun <R> readRealm(block: suspend (Realm) -> R): R

/**
* Executes provided block with a writable Realm instance ensuring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class RealmWrapperImpl @Inject constructor(
/**
* Executes provided block ensuring a valid Realm instance is used and closed.
*/
override suspend fun <R> readRealm(block: (Realm) -> R): R = withContext(dispatcher) { block(getRealm()) }
override suspend fun <R> readRealm(block: suspend (Realm) -> R): R = withContext(dispatcher) { block(getRealm()) }

/**
* Executes provided block in a transaction ensuring a valid Realm instance is used and closed.
Expand Down
1 change: 1 addition & 0 deletions infra/enrolment-records/repository/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {
implementation(project(":infra:config-store"))
implementation(project(":infra:auth-store"))
implementation(project(":infra:enrolment-records:realm-store"))
implementation(project(":infra:enrolment-records:room-store"))
implementation(project(":infra:events"))

implementation(libs.libsimprints)
Expand Down
Loading