Skip to content

Commit

Permalink
Add Metadata (#409)
Browse files Browse the repository at this point in the history
* Randomized face direction

* Add halfway captures

* add stability timer

* Add docs, cleanup

* Move to util; add constants

* Bump versions

* Add useStrictMode (#362)

* Add useStrictMode

* Fix test

* Bump versions

* Active liveness UI (#363)

* Add useStrictMode

* wip

* New UI prototype, less finicky

* add docs

* More UI updates

* Fix test

* Add active liveness forced failure and update design (#364)

* Add useStrictMode

* wip

* New UI prototype, less finicky

* add docs

* More UI updates

* Add metadata

* Fix test

* Add forced failure

* update timeout

* remove unused value

* add breadcrumbs

* increase num liveness images and add doc

* prevent rotation

* Add CameraFrameCornerBorder

* restructure + loading/success/error

* cleanup

* Update library version

* Add smile directive

* Use Lottie for directive animations (#366)

* Add Lottie face animation

* Fix need light animation

* Add Enrollment v2 (#367)

* Add Enrollment v2

* Fix test

* Impose upper bound on active liveness head angle (#368)

* Impose upper bound on active liveness head angle

* Update condition

* Add missing compatibility properties, agent mode, and attribution

* Move to constants

* Bump lottie

* Fix bad version

* Metadata

* Allow parameter tuning

* Active liveness parameter tuning. Update face quality model input crop

* Add header metadata back for now

* Fix contour out of bounds

https://smile-identity.sentry.io/issues/5453193521

* Make feedback more responsive during active liveness

* ignore certain faces. debug output

* Update CHANGELOG

* Fix viewfinder rect

* Lint

* Merge

* Reset capture progress on orientation change (#382)

* Reset capture progress on orientation change

* Lint

* Bump versions

* UI update and task confirmation (#385)

* Parameter updates, clipboard copy, larger UI

* Fail active liveness after timeout (#390)

* Use oval cutout

* Update parameters

* Remove parameter tuning and debug output

* Add useStrictMode to top level composable

* Use Strict Mode naming on main screen

* Update versions

* MetadataAdapter comment

* Add metadata to prepUpload

* Track document image origin (#398)

* Track document image origin

* Update test

* Update test

* Update test

* Add fingerprint (#400)

* Track document image origin

* Update test

* Add fingerprint

* Use default empty string instead of lateinit var

* Update test

* Track metrics using CompositionLocal (#402)

* Track metrics using CompositionLocal

* Clear DocumentCapture metadata on retry

* Clarify some metadata

* Update naming and format

* Update names

* Send metadata on DocV

* Fix enum value

* Update CHANGELOG

* Merge

* Fix colors

* Remove fingerprint JS

* Update settings.gradle.kts

* Prepare for 10.2.1 release
  • Loading branch information
vanshg authored Jul 16, 2024
1 parent 1c1a79e commit e7a3cef
Show file tree
Hide file tree
Showing 30 changed files with 350 additions and 37 deletions.
2 changes: 0 additions & 2 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Release Notes

## Unreleased
## 10.2.1

* Wrap Composables in a `Surface` for additional background color customization
* Add metadata support

## 10.2.0

Expand Down
2 changes: 1 addition & 1 deletion lib/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
10.2.1-SNAPSHOT
10.2.2-SNAPSHOT
5 changes: 5 additions & 0 deletions lib/lib.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ composeCompiler {
metricsDestination = layout.buildDirectory.dir("compose_compiler")
}

moshi {
// Opt-in to enable moshi-sealed, disabled by default.
enableSealed.set(true)
}

mavenPublishing {
publishToMavenCentral(automaticRelease = true)
signAllPublications()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class SelfieCaptureScreenTest {
// given
val takePictureTag = "takePictureButton"
val viewModel: SelfieViewModel = spyk()
every { viewModel.analyzeImage(any()) } just Runs
every { viewModel.analyzeImage(any(), camSelector) } just Runs

// when
composeTestRule.apply {
Expand All @@ -143,6 +143,6 @@ class SelfieCaptureScreenTest {
}

// then
verify(atLeast = 1, timeout = 1000) { viewModel.analyzeImage(any()) }
verify(atLeast = 1, timeout = 1000) { viewModel.analyzeImage(any(), camSelector) }
}
}
7 changes: 7 additions & 0 deletions lib/src/main/java/com/smileidentity/SmileID.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.smileidentity

import android.annotation.SuppressLint
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE
import android.provider.Settings.Secure
import com.google.android.gms.common.moduleinstall.ModuleInstall
import com.google.android.gms.common.moduleinstall.ModuleInstallRequest
import com.google.mlkit.common.sdkinternal.MlKitContext
Expand Down Expand Up @@ -85,6 +87,7 @@ object SmileID {
internal var apiKey: String? = null

internal lateinit var fileSavePath: String
internal var fingerprint = ""

/**
* Initialize the SDK. This must be called before any other SDK methods.
Expand All @@ -98,6 +101,8 @@ object SmileID {
* source docs for [SmileIDCrashReporting]
* @param okHttpClient An optional [OkHttpClient.Builder] to use for the network requests
*/
// "Using device identifiers is not recommended other than for high value fraud prevention"
@SuppressLint("HardwareIds")
@JvmStatic
@JvmOverloads
fun initialize(
Expand Down Expand Up @@ -137,6 +142,8 @@ object SmileID {

// Usually looks like: /data/user/0/<package name>/app_SmileID
fileSavePath = context.getDir("SmileID", MODE_PRIVATE).absolutePath
// ANDROID_ID may be null. Since Android 8, each app has a different value
Secure.getString(context.contentResolver, Secure.ANDROID_ID)?.let { fingerprint = it }
}

/**
Expand Down
5 changes: 5 additions & 0 deletions lib/src/main/java/com/smileidentity/compose/SmileIDExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel
import com.smileidentity.SmileID
import com.smileidentity.compose.biometric.OrchestratedBiometricKYCScreen
import com.smileidentity.compose.components.LocalMetadata
import com.smileidentity.compose.components.SmileThemeSurface
import com.smileidentity.compose.consent.OrchestratedConsentScreen
import com.smileidentity.compose.consent.bvn.OrchestratedBvnConsentScreen
Expand Down Expand Up @@ -242,6 +243,7 @@ fun SmileID.DocumentVerification(
onResult: SmileIDCallback<DocumentVerificationResult> = {},
) {
SmileThemeSurface(colorScheme = colorScheme, typography = typography) {
val metadata = LocalMetadata.current
OrchestratedDocumentVerificationScreen(
modifier = modifier,
userId = userId,
Expand All @@ -264,6 +266,7 @@ fun SmileID.DocumentVerification(
captureBothSides = captureBothSides,
selfieFile = bypassSelfieCaptureWithFile,
extraPartnerParams = extraPartnerParams,
metadata = metadata,
)
},
),
Expand Down Expand Up @@ -327,6 +330,7 @@ fun SmileID.EnhancedDocumentVerificationScreen(
onResult: SmileIDCallback<EnhancedDocumentVerificationResult> = {},
) {
SmileThemeSurface(colorScheme = colorScheme, typography = typography) {
val metadata = LocalMetadata.current
OrchestratedDocumentVerificationScreen(
modifier = modifier,
userId = userId,
Expand All @@ -349,6 +353,7 @@ fun SmileID.EnhancedDocumentVerificationScreen(
captureBothSides = captureBothSides,
selfieFile = bypassSelfieCaptureWithFile,
extraPartnerParams = extraPartnerParams,
metadata = metadata,
)
},
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.smileidentity.compose.components

import android.annotation.SuppressLint
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.runtime.toMutableStateList
import com.smileidentity.models.v2.Metadata

@SuppressLint("ComposeCompositionLocalUsage")
val LocalMetadata = staticCompositionLocalOf { Metadata.default().items.toMutableStateList() }
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Typography
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.runtime.toMutableStateList
import com.smileidentity.models.v2.Metadata

@Composable
internal fun SmileThemeSurface(
colorScheme: ColorScheme,
typography: Typography,
content: @Composable () -> Unit,
) {
MaterialTheme(colorScheme = colorScheme, typography = typography) {
Surface(content = content)
CompositionLocalProvider(
LocalMetadata provides remember { Metadata.default().items.toMutableStateList() },
) {
MaterialTheme(colorScheme = colorScheme, typography = typography) {
Surface(content = content)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.smileidentity.compose.consent.bvn

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
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.ui.Modifier
Expand Down Expand Up @@ -35,6 +37,7 @@ internal fun OrchestratedBvnConsentScreen(
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Box(
modifier = modifier
.background(color = MaterialTheme.colorScheme.background)
.windowInsetsPadding(WindowInsets.statusBars)
.consumeWindowInsets(WindowInsets.statusBars)
.fillMaxSize(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
Expand All @@ -49,8 +50,10 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.smileidentity.R
import com.smileidentity.SmileIDCrashReporting
import com.smileidentity.compose.components.ImageCaptureConfirmationDialog
import com.smileidentity.compose.components.LocalMetadata
import com.smileidentity.compose.preview.Preview
import com.smileidentity.compose.preview.SmilePreviews
import com.smileidentity.models.v2.Metadatum
import com.smileidentity.util.createDocumentFile
import com.smileidentity.util.isValidDocumentImage
import com.smileidentity.util.toast
Expand Down Expand Up @@ -94,9 +97,17 @@ fun DocumentCaptureScreen(
onConfirm: (File) -> Unit,
onError: (Throwable) -> Unit,
modifier: Modifier = Modifier,
metadata: SnapshotStateList<Metadatum> = LocalMetadata.current,
onSkip: () -> Unit = { },
viewModel: DocumentCaptureViewModel = viewModel(
factory = viewModelFactory { DocumentCaptureViewModel(jobId, side, knownIdAspectRatio) },
factory = viewModelFactory {
DocumentCaptureViewModel(
jobId,
side,
knownIdAspectRatio,
metadata,
)
},
key = side.name,
),
) {
Expand Down Expand Up @@ -163,7 +174,7 @@ fun DocumentCaptureScreen(
confirmButtonText = stringResource(
id = R.string.si_doc_v_confirmation_dialog_confirm_button,
),
onConfirm = { onConfirm(documentImageToConfirm) },
onConfirm = { viewModel.onConfirm(documentImageToConfirm, onConfirm) },
retakeButtonText = stringResource(
id = R.string.si_doc_v_confirmation_dialog_retake_button,
),
Expand All @@ -183,7 +194,7 @@ fun DocumentCaptureScreen(
areEdgesDetected = uiState.areEdgesDetected,
showCaptureInProgress = uiState.showCaptureInProgress,
showManualCaptureButton = uiState.showManualCaptureButton,
onCaptureClicked = viewModel::captureDocument,
onCaptureClicked = viewModel::captureDocumentManually,
imageAnalyzer = viewModel::analyze,
onFocusEvent = viewModel::onFocusEvent,
modifier = modifier,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.smileidentity.compose.document

import android.os.Parcelable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
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.saveable.rememberSaveable
Expand Down Expand Up @@ -44,6 +46,7 @@ internal fun <T : Parcelable> OrchestratedDocumentVerificationScreen(
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Box(
modifier = modifier
.background(color = MaterialTheme.colorScheme.background)
.windowInsetsPadding(WindowInsets.statusBars)
.consumeWindowInsets(WindowInsets.statusBars)
.fillMaxSize(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.smileidentity.compose.selfie

import android.graphics.BitmapFactory
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
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.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
Expand All @@ -21,7 +24,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.smileidentity.R
import com.smileidentity.compose.components.ImageCaptureConfirmationDialog
import com.smileidentity.compose.components.LocalMetadata
import com.smileidentity.compose.components.ProcessingScreen
import com.smileidentity.models.v2.Metadatum
import com.smileidentity.results.SmartSelfieResult
import com.smileidentity.results.SmileIDCallback
import com.smileidentity.util.randomJobId
Expand All @@ -47,6 +52,7 @@ fun OrchestratedSelfieCaptureScreen(
showAttribution: Boolean = true,
showInstructions: Boolean = true,
extraPartnerParams: ImmutableMap<String, String> = persistentMapOf(),
metadata: SnapshotStateList<Metadatum> = LocalMetadata.current,
viewModel: SelfieViewModel = viewModel(
factory = viewModelFactory {
SelfieViewModel(
Expand All @@ -55,6 +61,7 @@ fun OrchestratedSelfieCaptureScreen(
jobId = jobId,
allowNewEnroll = allowNewEnroll,
skipApiSubmission = skipApiSubmission,
metadata = metadata,
extraPartnerParams = extraPartnerParams,
)
},
Expand All @@ -65,6 +72,7 @@ fun OrchestratedSelfieCaptureScreen(
var acknowledgedInstructions by rememberSaveable { mutableStateOf(false) }
Box(
modifier = modifier
.background(color = MaterialTheme.colorScheme.background)
.windowInsetsPadding(WindowInsets.statusBars)
.consumeWindowInsets(WindowInsets.statusBars)
.fillMaxSize(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand All @@ -36,8 +37,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.smileidentity.R
import com.smileidentity.compose.components.ForceBrightness
import com.smileidentity.compose.components.LocalMetadata
import com.smileidentity.compose.preview.Preview
import com.smileidentity.compose.preview.SmilePreviews
import com.smileidentity.models.v2.Metadatum
import com.smileidentity.util.randomJobId
import com.smileidentity.util.randomUserId
import com.smileidentity.viewmodel.MAX_FACE_AREA_THRESHOLD
Expand All @@ -64,6 +67,7 @@ fun SelfieCaptureScreen(
isEnroll: Boolean = true,
allowAgentMode: Boolean = true,
skipApiSubmission: Boolean = false,
metadata: SnapshotStateList<Metadatum> = LocalMetadata.current,
viewModel: SelfieViewModel = viewModel(
factory = viewModelFactory {
SelfieViewModel(
Expand All @@ -72,6 +76,7 @@ fun SelfieCaptureScreen(
jobId = jobId,
allowNewEnroll = allowNewEnroll,
skipApiSubmission = skipApiSubmission,
metadata = metadata,
)
},
),
Expand All @@ -89,7 +94,7 @@ fun SelfieCaptureScreen(
camSelector = camSelector,
implementationMode = ImplementationMode.Performance,
imageAnalyzer = cameraState.rememberImageAnalyzer(
analyze = viewModel::analyzeImage,
analyze = { viewModel.analyzeImage(it, camSelector) },
// Guarantees only one image will be delivered for analysis at a time
imageAnalysisBackpressureStrategy = KeepOnlyLatest,
),
Expand Down
Loading

0 comments on commit e7a3cef

Please sign in to comment.