diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e3e18c27..732e8c46e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## 10.3.5 * Fix the camera is closed bug on document capture flow +* Enhanced doc v submitted as doc v +* Correct flow for selfie when showInstructions is false ## 10.3.4 diff --git a/lib/src/main/java/com/smileidentity/compose/SmileIDExt.kt b/lib/src/main/java/com/smileidentity/compose/SmileIDExt.kt index 2b0d15bdc..b3c13852f 100644 --- a/lib/src/main/java/com/smileidentity/compose/SmileIDExt.kt +++ b/lib/src/main/java/com/smileidentity/compose/SmileIDExt.kt @@ -21,6 +21,7 @@ import com.smileidentity.compose.nav.OrchestratedSelfieCaptureParams import com.smileidentity.compose.nav.ResultCallbacks import com.smileidentity.compose.nav.Routes import com.smileidentity.compose.nav.SelfieCaptureParams +import com.smileidentity.compose.nav.SerializableFile import com.smileidentity.compose.nav.getDocumentCaptureRoute import com.smileidentity.compose.nav.getSelfieCaptureRoute import com.smileidentity.compose.theme.colorScheme @@ -92,10 +93,14 @@ fun SmileID.SmartSelfieEnrollment( true, skipApiSubmission, ) + val screenDestination = getSelfieCaptureRoute(useStrictMode, commonParams) val orchestratedDestination = Routes.Orchestrated.SelfieRoute( - params = OrchestratedSelfieCaptureParams(commonParams), + params = OrchestratedSelfieCaptureParams( + commonParams, + startRoute = screenDestination, + showStartRoute = true, + ), ) - val screenDestination = getSelfieCaptureRoute(useStrictMode, commonParams) BaseSmileIDScreen( orchestratedDestination, screenDestination, @@ -159,10 +164,14 @@ fun SmileID.SmartSelfieAuthentication( isEnroll = false, skipApiSubmission, ) + val screenDestination = getSelfieCaptureRoute(useStrictMode, commonParams) val orchestratedDestination = Routes.Orchestrated.SelfieRoute( - params = OrchestratedSelfieCaptureParams(commonParams), + params = OrchestratedSelfieCaptureParams( + commonParams, + startRoute = screenDestination, + showStartRoute = true, + ), ) - val screenDestination = getSelfieCaptureRoute(useStrictMode, commonParams) BaseSmileIDScreen( orchestratedDestination, screenDestination, @@ -228,23 +237,22 @@ fun SmileID.DocumentVerification( onResult: SmileIDCallback = {}, ) { val commonParams = DocumentCaptureParams( - userId, - jobId, - allowNewEnroll, - allowAgentMode, - showAttribution, - showInstructions, - extraPartnerParams, + userId = userId, + jobId = jobId, + showInstructions = showInstructions, + showAttribution = showAttribution, + allowAgentMode = allowAgentMode, + allowGallerySelection = allowGalleryUpload, + knownIdAspectRatio = idAspectRatio, + allowNewEnroll = allowNewEnroll, countryCode = countryCode, + documentType = documentType, + captureBothSides = captureBothSides, + selfieFile = bypassSelfieCaptureWithFile?.let { SerializableFile.fromFile(it) }, + extraPartnerParams = extraPartnerParams, ) val screenDestination = getDocumentCaptureRoute( - countryCode, commonParams, - documentType, - captureBothSides, - idAspectRatio, - bypassSelfieCaptureWithFile, - allowGalleryUpload, ) val orchestratedDestination = Routes.Orchestrated.DocVRoute( params = OrchestratedDocumentParams(commonParams), @@ -315,23 +323,22 @@ fun SmileID.EnhancedDocumentVerificationScreen( onResult: SmileIDCallback = {}, ) { val commonParams = DocumentCaptureParams( - userId, - jobId, - allowNewEnroll, - allowAgentMode, - showAttribution, - showInstructions, - extraPartnerParams, + userId = userId, + jobId = jobId, + showInstructions = showInstructions, + showAttribution = showAttribution, + allowAgentMode = allowAgentMode, + allowGallerySelection = allowGalleryUpload, + knownIdAspectRatio = idAspectRatio, + allowNewEnroll = allowNewEnroll, countryCode = countryCode, + documentType = documentType, + captureBothSides = captureBothSides, + selfieFile = bypassSelfieCaptureWithFile?.let { SerializableFile.fromFile(it) }, + extraPartnerParams = extraPartnerParams, ) val screenDestination = getDocumentCaptureRoute( - countryCode, commonParams, - documentType, - captureBothSides, - idAspectRatio, - bypassSelfieCaptureWithFile, - allowGalleryUpload, ) val orchestratedDestination = Routes.Orchestrated.EnhancedDocVRoute( params = OrchestratedDocumentParams(commonParams), @@ -385,6 +392,25 @@ fun SmileID.BiometricKYC( typography: Typography = SmileID.typography, onResult: SmileIDCallback = {}, ) { + val commonParams = SelfieCaptureParams( + userId, + jobId, + allowNewEnroll, + allowAgentMode, + showAttribution, + showInstructions, + extraPartnerParams, + true, + skipApiSubmission = true, + ) + val selfieDestination = getSelfieCaptureRoute(false, commonParams) + val screenDestination = Routes.Orchestrated.SelfieRoute( + params = OrchestratedSelfieCaptureParams( + commonParams, + startRoute = selfieDestination, + showStartRoute = true, + ), + ) val orchestratedDestination = Routes.Orchestrated.BiometricKycRoute( OrchestratedBiometricCaptureParams( BiometricKYCParams( @@ -397,23 +423,13 @@ fun SmileID.BiometricKYC( allowNewEnroll = allowNewEnroll, extraPartnerParams = extraPartnerParams, ), + startRoute = screenDestination, + showStartRoute = true, ), ) - val selfieCaptureParams = SelfieCaptureParams( - userId, - jobId, - allowNewEnroll, - allowAgentMode, - showAttribution, - showInstructions, - extraPartnerParams, - true, - skipApiSubmission = true, - ) - val screenDestination = getSelfieCaptureRoute(false, selfieCaptureParams) BaseSmileIDScreen( orchestratedDestination, - screenDestination, + selfieDestination, ResultCallbacks(onBiometricKYCResult = onResult), modifier, colorScheme, diff --git a/lib/src/main/java/com/smileidentity/compose/biometric/OrchestratedBiometricKYCScreen.kt b/lib/src/main/java/com/smileidentity/compose/biometric/OrchestratedBiometricKYCScreen.kt index 0f3216c4a..ee0667867 100644 --- a/lib/src/main/java/com/smileidentity/compose/biometric/OrchestratedBiometricKYCScreen.kt +++ b/lib/src/main/java/com/smileidentity/compose/biometric/OrchestratedBiometricKYCScreen.kt @@ -10,18 +10,19 @@ import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.smileidentity.R import com.smileidentity.compose.nav.NavigationBackHandler -import com.smileidentity.compose.nav.OrchestratedSelfieCaptureParams import com.smileidentity.compose.nav.ProcessingScreenParams import com.smileidentity.compose.nav.ResultCallbacks import com.smileidentity.compose.nav.Routes -import com.smileidentity.compose.nav.SelfieCaptureParams import com.smileidentity.compose.nav.localNavigationState import com.smileidentity.models.IdInfo import com.smileidentity.results.BiometricKycResult @@ -43,9 +44,8 @@ internal fun OrchestratedBiometricKYCScreen( userId: String = rememberSaveable { randomUserId() }, jobId: String = rememberSaveable { randomJobId() }, allowNewEnroll: Boolean = false, - allowAgentMode: Boolean = false, - showAttribution: Boolean = true, - showInstructions: Boolean = true, + showStartRoute: Boolean = false, + startRoute: Routes? = null, extraPartnerParams: ImmutableMap = persistentMapOf(), viewModel: BiometricKycViewModel = viewModel( factory = viewModelFactory { @@ -70,6 +70,7 @@ internal fun OrchestratedBiometricKYCScreen( content() } val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + var startRouteShown by rememberSaveable { mutableStateOf(false) } resultCallbacks.onProcessingContinue = { viewModel.onFinished(onResult) } resultCallbacks.onProcessingClose = { viewModel.onFinished(onResult) } resultCallbacks.onSmartSelfieResult = { @@ -106,20 +107,10 @@ internal fun OrchestratedBiometricKYCScreen( ), ), ) - } else -> { + } showStartRoute && startRoute != null && !startRouteShown -> { + startRouteShown = true localNavigationState.orchestratedNavigation.navigateTo( - Routes.Orchestrated.SelfieRoute( - OrchestratedSelfieCaptureParams( - SelfieCaptureParams( - userId = userId, - jobId = jobId, - showInstructions = showInstructions, - showAttribution = showAttribution, - allowAgentMode = allowAgentMode, - skipApiSubmission = true, - ), - ), - ), + startRoute, ) } } diff --git a/lib/src/main/java/com/smileidentity/compose/nav/NavRoutesParams.kt b/lib/src/main/java/com/smileidentity/compose/nav/NavRoutesParams.kt index 6593d6539..f4ebe12ff 100644 --- a/lib/src/main/java/com/smileidentity/compose/nav/NavRoutesParams.kt +++ b/lib/src/main/java/com/smileidentity/compose/nav/NavRoutesParams.kt @@ -193,6 +193,7 @@ data class OrchestratedBiometricCaptureParams( ), ), ), + val showStartRoute: Boolean = false, ) : Parcelable @Serializable diff --git a/lib/src/main/java/com/smileidentity/compose/nav/NavUtil.kt b/lib/src/main/java/com/smileidentity/compose/nav/NavUtil.kt index 7a839168e..5a67b85ec 100644 --- a/lib/src/main/java/com/smileidentity/compose/nav/NavUtil.kt +++ b/lib/src/main/java/com/smileidentity/compose/nav/NavUtil.kt @@ -10,7 +10,6 @@ import androidx.compose.ui.res.stringResource import androidx.navigation.NavDestination import androidx.navigation.NavType import com.smileidentity.R -import java.io.File import java.net.URLDecoder import java.net.URLEncoder import java.nio.charset.StandardCharsets @@ -40,16 +39,7 @@ class CustomNavType( } @Composable -internal fun getDocumentCaptureRoute( - countryCode: String, - params: DocumentCaptureParams, - documentType: String?, - captureBothSides: Boolean, - idAspectRatio: Float?, - bypassSelfieCaptureWithFile: File?, - allowGalleryUpload: Boolean, -): Routes { - val serializableFile = bypassSelfieCaptureWithFile?.let { SerializableFile.fromFile(it) } +internal fun getDocumentCaptureRoute(params: DocumentCaptureParams): Routes { return if (params.showInstructions) { Routes.Document.InstructionScreen( params = DocumentInstructionParams( @@ -57,7 +47,7 @@ internal fun getDocumentCaptureRoute( stringResource(R.string.si_doc_v_instruction_title), stringResource(R.string.si_verify_identity_instruction_subtitle), params.showAttribution, - allowGalleryUpload, + params.allowGallerySelection, showSkipButton = false, ), ) @@ -69,18 +59,18 @@ internal fun getDocumentCaptureRoute( showInstructions = true, showAttribution = params.showAttribution, allowAgentMode = params.allowAgentMode, - allowGallerySelection = allowGalleryUpload, + allowGallerySelection = params.allowGallerySelection, showSkipButton = params.showSkipButton, instructionsHeroImage = params.instructionsHeroImage, instructionsTitleText = params.instructionsTitleText, instructionsSubtitleText = params.instructionsSubtitleText, captureTitleText = params.captureTitleText, - knownIdAspectRatio = idAspectRatio, + knownIdAspectRatio = params.knownIdAspectRatio, allowNewEnroll = params.allowNewEnroll, - countryCode = countryCode, - documentType = documentType, - captureBothSides = captureBothSides, - selfieFile = serializableFile, + countryCode = params.countryCode, + documentType = params.documentType, + captureBothSides = params.captureBothSides, + selfieFile = params.selfieFile, extraPartnerParams = params.extraPartnerParams, ), ) diff --git a/lib/src/main/java/com/smileidentity/compose/nav/SmileIDNav.kt b/lib/src/main/java/com/smileidentity/compose/nav/SmileIDNav.kt index 734ec0ac0..38b782815 100644 --- a/lib/src/main/java/com/smileidentity/compose/nav/SmileIDNav.kt +++ b/lib/src/main/java/com/smileidentity/compose/nav/SmileIDNav.kt @@ -149,10 +149,9 @@ internal fun NavGraphBuilder.orchestratedNavGraph( idInfo = params.captureParams.idInfo, userId = params.captureParams.userId, jobId = params.captureParams.jobId, + startRoute = params.startRoute, + showStartRoute = params.showStartRoute, allowNewEnroll = params.captureParams.allowNewEnroll, - allowAgentMode = params.captureParams.allowAgentMode, - showAttribution = params.captureParams.showAttribution, - showInstructions = params.captureParams.showInstructions, extraPartnerParams = params.captureParams.extraPartnerParams, onResult = { resultCallbacks.onBiometricKYCResult?.invoke(it) }, ) @@ -224,7 +223,7 @@ internal fun NavGraphBuilder.orchestratedNavGraph( viewModel = viewModel( factory = viewModelFactory { EnhancedDocumentVerificationViewModel( - jobType = JobType.DocumentVerification, + jobType = JobType.EnhancedDocumentVerification, userId = params.captureParams.userId, jobId = params.captureParams.jobId, allowNewEnroll = params.captureParams.allowNewEnroll, diff --git a/sample/src/main/java/com/smileidentity/sample/activity/JavaActivity.java b/sample/src/main/java/com/smileidentity/sample/activity/JavaActivity.java index 7f99baa99..efb02b479 100644 --- a/sample/src/main/java/com/smileidentity/sample/activity/JavaActivity.java +++ b/sample/src/main/java/com/smileidentity/sample/activity/JavaActivity.java @@ -11,10 +11,13 @@ import androidx.fragment.app.FragmentActivity; import com.smileidentity.SmileID; +import com.smileidentity.fragment.BiometricKYCFragment; import com.smileidentity.fragment.DocumentVerificationFragment; import com.smileidentity.fragment.EnhancedDocumentVerificationFragment; import com.smileidentity.fragment.SmartSelfieAuthenticationFragment; import com.smileidentity.fragment.SmartSelfieEnrollmentFragment; +import com.smileidentity.models.IdInfo; +import com.smileidentity.results.BiometricKycResult; import com.smileidentity.results.DocumentVerificationResult; import com.smileidentity.results.SmartSelfieResult; import com.smileidentity.results.SmileIDResult; @@ -44,12 +47,55 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { .setOnClickListener(v -> doSmartSelfieAuthentication()); findViewById(R.id.button_smart_selfie_enrollment) .setOnClickListener(v -> doSmartSelfieEnrollment()); + findViewById(R.id.button_biometric_authentication) + .setOnClickListener(v -> doBiometricKYC()); findViewById(R.id.button_document_verification) .setOnClickListener(v -> doDocumentVerification()); findViewById(R.id.button_enhanced_document_verification) .setOnClickListener(v -> doEnhancedDocumentVerification()); } + private void doBiometricKYC() { + IdInfo idInfo = new IdInfo("GH", "PASSPORT", "1234567890", + null, null, null, null, null, null); + BiometricKYCFragment biometricKYCFragment = BiometricKYCFragment + .newInstance(idInfo); + getSupportFragmentManager().setFragmentResultListener( + BiometricKYCFragment.KEY_REQUEST, + this, + (requestKey, result) -> { + SmileIDResult biometricKycResult = + BiometricKYCFragment.resultFromBundle(result); + Timber.v("BiometricKYCFragment Result: %s", biometricKycResult); + if (biometricKycResult instanceof SmileIDResult.Success successResult) { + File selfieFile = successResult.getData().getSelfieFile(); + List livenessFiles = successResult.getData().getLivenessFiles(); + boolean jobSubmitted = successResult.getData().getDidSubmitBiometricKycJob(); + // When offline mode is enabled, the job is saved offline and can be submitted later. + if (jobSubmitted) { + Timber.v("BiometricKYCFragment Job Submitted"); + } else { + Timber.v("BiometricKYCFragment Job saved offline."); + } + } else if (biometricKycResult instanceof SmileIDResult.Error error) { + Throwable throwable = error.getThrowable(); + Timber.v("BiometricKYCFragment Error: %s", throwable.getMessage()); + } + getSupportFragmentManager() + .beginTransaction() + .remove(biometricKYCFragment) + .commit(); + hideProductFragment(); + } + ); + + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fragment_container, biometricKYCFragment) + .commit(); + showProductFragment(); + } + private void doSmartSelfieEnrollment() { SmartSelfieEnrollmentFragment smartSelfieFragment = SmartSelfieEnrollmentFragment .newInstance(); diff --git a/sample/src/main/res/layout/activity_java.xml b/sample/src/main/res/layout/activity_java.xml index 37058e32c..47590b7ad 100644 --- a/sample/src/main/res/layout/activity_java.xml +++ b/sample/src/main/res/layout/activity_java.xml @@ -22,6 +22,13 @@ android:layout_marginTop="16dp" android:text="@string/si_smart_selfie_authentication_product_name" /> +