Skip to content

Biometric search UX optimizations & Enrolment+#26

Merged
alex-vt merged 16 commits intomainfrom
enrol-plus-search-ux-optimizations
May 4, 2026
Merged

Biometric search UX optimizations & Enrolment+#26
alex-vt merged 16 commits intomainfrom
enrol-plus-search-ux-optimizations

Conversation

@alex-vt
Copy link
Copy Markdown
Collaborator

@alex-vt alex-vt commented Apr 21, 2026

What's new:

  • Biometric search optimizations: fewer button presses in the search forms
  • MFID auto-navigation to the matched record
  • Sequential search: option to jump to regular search if no expected biometric matches
  • Enrolment+: Possible Duplicates list with "None of the above" button to reuse last biometrics
  • Simprints feature code improvements & upstream-originating intent system fixes for operation in low-memory conditions: when SimCapture activities don't survive when new ones open or until SID returns the result

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the Simprints biometric search + enrollment flows across form, commons, and app modules, focusing on reducing user steps, adding “possible duplicates” handling, and improving resiliency when returning from external Simprints activities (including low-memory/process recreation scenarios).

Changes:

  • Add Simprints “possible duplicates” result mapping/handling and an Enrollment+ flow to review matches (with “None of the above” -> reuse last biometrics).
  • Add MFID/single-match auto-navigation behavior and biometric-search UX shortcuts (auto-launch, fallback to regular search).
  • Extend Simprints session persistence/state tracking to better survive lifecycle interruptions.

Reviewed changes

Copilot reviewed 46 out of 46 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
form/src/test/java/org/dhis2/form/ui/customintent/CustomIntentActivityResultContractTest.kt Adds tests for Simprints identifications/possible-duplicates parsing.
form/src/test/java/org/dhis2/form/simprints/SimprintsCustomIntentFormPresenterTest.kt Adds coverage for session clearing when launch is prepared with pending state.
form/src/main/res/values/strings.xml Renames/adds Simprints-specific placeholder strings.
form/src/main/java/org/dhis2/form/ui/provider/inputfield/CustomIntentProvider.kt Updates Compose custom-intent launch behavior + lifecycle refresh hooks.
form/src/main/java/org/dhis2/form/ui/customintent/CustomIntentActivityResultContract.kt Adds PossibleDuplicates result and passes extras/action through success results.
form/src/main/java/org/dhis2/form/ui/FormViewFragmentFactory.kt Adds callback wiring for Simprints custom intent + possible-duplicates flows.
form/src/main/java/org/dhis2/form/ui/FormView.kt Routes Simprints callouts to host activity + handles possible-duplicates navigation.
form/src/main/java/org/dhis2/form/simprints/SimprintsRememberCustomIntentFormPresenter.kt Adjusts placeholder text based on pending-enrollment source state.
form/src/main/java/org/dhis2/form/simprints/SimprintsPossibleDuplicatesSearchHandler.kt Adds composition local handler typealias for possible-duplicates navigation.
commons/src/test/kotlin/org/dhis2/commons/simprints/usecases/SimprintsResolvePossibleDuplicatesSearchUseCaseTest.kt Adds tests for resolving possible-duplicates search payload + session saving.
commons/src/test/kotlin/org/dhis2/commons/simprints/usecases/SimprintsHasAutoOpenEligibleIdentificationUseCaseTest.kt Adds tests for MFID auto-open eligibility detection.
commons/src/test/kotlin/org/dhis2/commons/simprints/usecases/SimprintsExtractIdentificationMatchesUseCaseTest.kt Adds tests for extracting GUID/confidence from identification payloads.
commons/src/test/kotlin/org/dhis2/commons/simprints/repository/SimprintsSessionRepositoryTest.kt Extends tests for pending-enrollment source tracking + clearing behavior.
commons/src/main/java/org/dhis2/commons/simprints/usecases/SimprintsResolvePossibleDuplicatesSearchUseCase.kt New use case to resolve duplicates payload into search input + persist session.
commons/src/main/java/org/dhis2/commons/simprints/usecases/SimprintsHasAutoOpenEligibleIdentificationUseCase.kt New use case for robust JSON-based MFID auto-open eligibility detection.
commons/src/main/java/org/dhis2/commons/simprints/usecases/SimprintsExtractIdentificationMatchesUseCase.kt New use case to parse identification payload into structured matches.
commons/src/main/java/org/dhis2/commons/simprints/repository/SimprintsSessionRepository.kt Adds pending-enrollment source state and new “from possible duplicates” marker.
app/src/test/java/org/dhis2/usescases/searchTrackEntity/SearchTEIViewModelTest.kt Updates/expands tests for new Simprints biometric + duplicates behaviors.
app/src/test/java/org/dhis2/usescases/enrollment/EnrollmentPresenterImplTest.kt Updates tests for modified enrollment finish + register-last parameters.
app/src/test/java/org/dhis2/simprints/SimprintsSearchViewModelTest.kt Expands tests for navigation/session-keeping + MFID auto-open logic.
app/src/test/java/org/dhis2/simprints/SimprintsResolveSingleBiometricSearchNavigationUseCaseTest.kt Adds tests for resolving single-match navigation targets.
app/src/test/java/org/dhis2/simprints/SimprintsLoadPossibleDuplicatesSearchResultsUseCaseTest.kt Adds tests for loading TEI results per GUID for duplicates review.
app/src/test/java/org/dhis2/simprints/SimprintsLoadBiometricSearchResultsUseCaseTest.kt Adds tests for ordered biometric search results paging flow.
app/src/test/java/org/dhis2/simprints/SimprintsEnrollmentViewModelTest.kt Expands tests for auto-enroll-last and restoration across recreation/errors.
app/src/main/res/values/strings.xml Adds user-facing strings for biometric search, duplicates, and actions.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/SimprintsSearchTeUiComponents.kt Adds UI components for fallback + “none of the above” actions.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/SearchTEUi.kt Makes search label read-only during Simprints flows + shows fallback button.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/SearchScreenConfigurator.kt Allows closing backdrop without animation for fast biometric navigation.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/BackdropManager.kt Adds withAnimation toggle to transitions.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/searchparameters/provider/ParameterSelectorItemProvider.kt Auto-launches Simprints identify callout on parameter expand.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/searchparameters/SearchParametersScreen.kt Adds Simprints identify launcher handling + no-matches banner + auto-open detection.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/listView/SearchTEList.kt Integrates possible-duplicates UI (“none of the above”) + fallback/cancel logic.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchTeiViewModelFactory.kt Switches from ordering use case to biometric-results loader use case.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchTEModule.java Adds DI for new Simprints navigation + biometric-results loader use cases.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchTEIViewModel.kt Adds duplicates-search mode, fallback behavior, and MFID auto-navigation wiring.
app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchTEActivity.kt Handles duplicates-search mode lifecycle, result signaling, and state persistence.
app/src/main/java/org/dhis2/usescases/enrollment/FormInjector.kt Threads Simprints launch callbacks into enrollment form builder.
app/src/main/java/org/dhis2/usescases/enrollment/EnrollmentPresenterImpl.kt Adjusts finish/register-last APIs + adds auto-enroll-last entrypoint.
app/src/main/java/org/dhis2/usescases/enrollment/EnrollmentActivity.kt Adds Simprints custom-intent launcher + duplicates-search -> auto-enroll-last flow.
app/src/main/java/org/dhis2/simprints/di/SimprintsSearchViewModelFactory.kt Adds dependency for single-result navigation resolver.
app/src/main/java/org/dhis2/simprints/SimprintsSearchViewModel.kt Adds MFID auto-open state, navigation flow channel, and session management changes.
app/src/main/java/org/dhis2/simprints/SimprintsResolveSingleBiometricSearchNavigationUseCase.kt New use case to resolve a single biometric match into a dashboard navigation target.
app/src/main/java/org/dhis2/simprints/SimprintsLoadPossibleDuplicatesSearchResultsUseCase.kt New use case to resolve multiple GUIDs into ordered TEI results.
app/src/main/java/org/dhis2/simprints/SimprintsLoadBiometricSearchResultsUseCase.kt New use case to load ordered Simprints biometric search results as PagingData.
app/src/main/java/org/dhis2/simprints/SimprintsEnrollmentViewModel.kt Adds auto-enroll-last action + pending-action restoration + stricter error clearing.
README.md Documents the new Simprints UX/enrollment flows and key code entrypoints.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@alex-vt alex-vt marked this pull request as ready for review April 22, 2026 10:25
Copy link
Copy Markdown
Collaborator

@TristramN TristramN left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 comments worth looking into, especially the process death one. But approved so you can tweak and continue as needed thanks Oleksii

Also apologies this is super late!

companion object {
private var fieldUid: String = ""
private var customIntent: CustomIntentModel? = null
private val SIMPRINTS_IDENTIFICATION_EXTRA_NAMES = listOf("identification", "identifications")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @alex-vt these changes made me notice something, which isn't a regression from this PR but could be an issue in general with how this companion object is used.

CustomIntentActivityResultContract.kt keeps fieldUid and customIntent as companion object mutable state.

After process death, both default back to "" / null, regardless of the contract instance — ActivityResultRegistry does not persist contract internals.

In EnrollmentActivity.kt the contract is held as a field on the activity and used for both createIntent and parseResult. In-process that's fine; on process death it isn't.

The PR widens its blast radius: the new possible-duplicates path silently degrades to Error("") after process death, which is a less obvious failure mode (the user has just authenticated against SID, expects a duplicates search, but could get a generic intent error).

We need to keep companion object fields in a saved state by the life cycle owner, and re-derive them on process re-creation.

}

private val pendingDashboardNavigation = AtomicReference<PendingDashboardNavigation?>(null)
private var pendingSimprintsMfidBiometricIdentification: PendingSimprintsMfidBiometricIdentification? =
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not be atomic as well?

It is written from onSimprintsBiometricIdentificationResult (activity result callback) and read/cleared from onSimprintsParameterSaved, clearPendingSession, clearPendingSessionIfNeeded. If those ever land on different dispatchers, I think the consume-and-clear in consumePendingSimprintsMfidBiometricIdentification is not atomic and two parallel saves could each see it as "pending" and trigger duplicate auto-navigation, or vice versa.

Recommend converting to AtomicReference for consistency with the sibling field, and using compareAndSet/exchange for the consume.

@alex-vt alex-vt merged commit de8d2d0 into main May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants