Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Identity][CardScan] Move callback from present to creation #4778

Merged
merged 11 commits into from Mar 30, 2022
Expand Up @@ -51,7 +51,13 @@ abstract class MainActivity : AppCompatActivity() {
// brandLogo = Uri.parse("https://path/to/a/logo.jpg")
brandLogo = logoUri
)
)
) {
Snackbar.make(
binding.root,
"Verification result: $it",
Snackbar.LENGTH_SHORT
).show()
}

binding.startVerification.setOnClickListener {
binding.startVerification.isEnabled = false
Expand Down Expand Up @@ -100,9 +106,7 @@ abstract class MainActivity : AppCompatActivity() {
identityVerificationSheet.present(
verificationSessionId = it.verificationSessionId,
ephemeralKeySecret = it.ephemeralKeySecret
) { verificationResult ->
showSnackBar("Verification result: $verificationResult")
}
)
}
} catch (t: Throwable) {
showSnackBar("Fail to decode")
Expand Down
22 changes: 13 additions & 9 deletions identity/api/identity.api
Expand Up @@ -15,12 +15,12 @@ public final class com/stripe/android/identity/IdentityActivity$inlined$sam$i$an

public abstract interface class com/stripe/android/identity/IdentityVerificationSheet {
public static final field Companion Lcom/stripe/android/identity/IdentityVerificationSheet$Companion;
public abstract fun present (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public abstract fun present (Ljava/lang/String;Ljava/lang/String;)V
}

public final class com/stripe/android/identity/IdentityVerificationSheet$Companion {
public final fun create (Landroidx/activity/ComponentActivity;Lcom/stripe/android/identity/IdentityVerificationSheet$Configuration;)Lcom/stripe/android/identity/IdentityVerificationSheet;
public final fun create (Landroidx/fragment/app/Fragment;Lcom/stripe/android/identity/IdentityVerificationSheet$Configuration;)Lcom/stripe/android/identity/IdentityVerificationSheet;
public final fun create (Landroidx/activity/ComponentActivity;Lcom/stripe/android/identity/IdentityVerificationSheet$Configuration;Lcom/stripe/android/identity/IdentityVerificationSheet$IdentityVerificationCallback;)Lcom/stripe/android/identity/IdentityVerificationSheet;
public final fun create (Landroidx/fragment/app/Fragment;Lcom/stripe/android/identity/IdentityVerificationSheet$Configuration;Lcom/stripe/android/identity/IdentityVerificationSheet$IdentityVerificationCallback;)Lcom/stripe/android/identity/IdentityVerificationSheet;
}

public final class com/stripe/android/identity/IdentityVerificationSheet$Configuration {
Expand All @@ -34,25 +34,29 @@ public final class com/stripe/android/identity/IdentityVerificationSheet$Configu
public fun toString ()Ljava/lang/String;
}

public abstract class com/stripe/android/identity/IdentityVerificationSheet$VerificationResult : android/os/Parcelable {
public abstract interface class com/stripe/android/identity/IdentityVerificationSheet$IdentityVerificationCallback {
public abstract fun onVerificationFlowResult (Lcom/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult;)V
}

public abstract class com/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult : android/os/Parcelable {
public final synthetic fun toBundle ()Landroid/os/Bundle;
}

public final class com/stripe/android/identity/IdentityVerificationSheet$VerificationResult$Canceled : com/stripe/android/identity/IdentityVerificationSheet$VerificationResult {
public final class com/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult$Canceled : com/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult {
public static final field CREATOR Landroid/os/Parcelable$Creator;
public static final field INSTANCE Lcom/stripe/android/identity/IdentityVerificationSheet$VerificationResult$Canceled;
public static final field INSTANCE Lcom/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult$Canceled;
public fun describeContents ()I
public fun writeToParcel (Landroid/os/Parcel;I)V
}

public final class com/stripe/android/identity/IdentityVerificationSheet$VerificationResult$Completed : com/stripe/android/identity/IdentityVerificationSheet$VerificationResult {
public final class com/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult$Completed : com/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult {
public static final field CREATOR Landroid/os/Parcelable$Creator;
public static final field INSTANCE Lcom/stripe/android/identity/IdentityVerificationSheet$VerificationResult$Completed;
public static final field INSTANCE Lcom/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult$Completed;
public fun describeContents ()I
public fun writeToParcel (Landroid/os/Parcel;I)V
}

public final class com/stripe/android/identity/IdentityVerificationSheet$VerificationResult$Failed : com/stripe/android/identity/IdentityVerificationSheet$VerificationResult {
public final class com/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult$Failed : com/stripe/android/identity/IdentityVerificationSheet$VerificationFlowResult {
public static final field CREATOR Landroid/os/Parcelable$Creator;
public fun <init> (Ljava/lang/Throwable;)V
public fun describeContents ()I
Expand Down
Expand Up @@ -14,7 +14,7 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import com.stripe.android.camera.CameraPermissionCheckingActivity
import com.stripe.android.identity.IdentityVerificationSheet.VerificationResult
import com.stripe.android.identity.IdentityVerificationSheet.VerificationFlowResult
import com.stripe.android.identity.databinding.IdentityActivityBinding
import com.stripe.android.identity.navigation.ErrorFragment
import com.stripe.android.identity.navigation.IdentityFragmentFactory
Expand Down Expand Up @@ -120,7 +120,7 @@ internal class IdentityActivity : CameraPermissionCheckingActivity(), Verificati
)
}

override fun finishWithResult(result: VerificationResult) {
override fun finishWithResult(result: VerificationFlowResult) {
setResult(
Activity.RESULT_OK,
Intent().putExtras(result.toBundle())
Expand Down
Expand Up @@ -25,25 +25,25 @@ interface IdentityVerificationSheet {
/**
* Result of verification.
*/
sealed class VerificationResult : Parcelable {
sealed class VerificationFlowResult : Parcelable {
@Parcelize
object Completed : VerificationResult()
object Completed : VerificationFlowResult()

@Parcelize
object Canceled : VerificationResult()
object Canceled : VerificationFlowResult()

@Parcelize
class Failed(val throwable: Throwable) : VerificationResult()
class Failed(val throwable: Throwable) : VerificationFlowResult()

@JvmSynthetic
fun toBundle() = bundleOf(EXTRA to this)

internal companion object {
private const val EXTRA = "extra_args"

fun fromIntent(intent: Intent?): VerificationResult {
fun fromIntent(intent: Intent?): VerificationFlowResult {
return intent?.getParcelableExtra(EXTRA)
?: Failed(IllegalStateException("Failed to get VerificationResult from Intent"))
?: Failed(IllegalStateException("Failed to get VerificationFlowResult from Intent"))
}
}
}
Expand All @@ -53,32 +53,44 @@ interface IdentityVerificationSheet {
*/
fun present(
verificationSessionId: String,
ephemeralKeySecret: String,
onFinished: (verificationResult: VerificationResult) -> Unit
ephemeralKeySecret: String
)

/**
* Callback to notify when identity verification finishes and a result is available.
*/
fun interface IdentityVerificationCallback {
fun onVerificationFlowResult(result: VerificationFlowResult)
}

companion object {
/**
* Creates a [IdentityVerificationSheet] instance with [ComponentActivity].
*
* This API registers an [ActivityResultLauncher] into the
* [ComponentActivity], it must be called before the [ComponentActivity]
* [ComponentActivity] and notifies its result to [identityVerificationCallback], it must
* be called before the [ComponentActivity]
* is created (in the onCreate method).
*/
fun create(
from: ComponentActivity,
configuration: Configuration,
): IdentityVerificationSheet = StripeIdentityVerificationSheet(from, configuration)
identityVerificationCallback: IdentityVerificationCallback
): IdentityVerificationSheet =
StripeIdentityVerificationSheet(from, configuration, identityVerificationCallback)

/**
* Creates a [IdentityVerificationSheet] instance with [Fragment].
*
* This API registers an [ActivityResultLauncher] into the [Fragment], it must be called
* before the [Fragment] is created (in the onCreate method).
* This API registers an [ActivityResultLauncher] into the [Fragment] and notifies its
* result to [identityVerificationCallback], it must be called before the [Fragment] is
* created (in the onCreate method).
*/
fun create(
from: Fragment,
configuration: Configuration,
): IdentityVerificationSheet = StripeIdentityVerificationSheet(from, configuration)
identityVerificationCallback: IdentityVerificationCallback
): IdentityVerificationSheet =
StripeIdentityVerificationSheet(from, configuration, identityVerificationCallback)
}
}
Expand Up @@ -9,7 +9,7 @@ import androidx.core.os.bundleOf
import kotlinx.parcelize.Parcelize

internal class IdentityVerificationSheetContract :
ActivityResultContract<IdentityVerificationSheetContract.Args, IdentityVerificationSheet.VerificationResult>() {
ActivityResultContract<IdentityVerificationSheetContract.Args, IdentityVerificationSheet.VerificationFlowResult>() {

@Parcelize
internal data class Args(
Expand Down Expand Up @@ -38,7 +38,7 @@ internal class IdentityVerificationSheetContract :
override fun parseResult(
resultCode: Int,
intent: Intent?
): IdentityVerificationSheet.VerificationResult {
return IdentityVerificationSheet.VerificationResult.fromIntent(intent)
): IdentityVerificationSheet.VerificationFlowResult {
return IdentityVerificationSheet.VerificationFlowResult.fromIntent(intent)
}
}
Expand Up @@ -7,34 +7,32 @@ import androidx.fragment.app.Fragment

internal class StripeIdentityVerificationSheet private constructor(
activityResultCaller: ActivityResultCaller,
private val configuration: IdentityVerificationSheet.Configuration
private val configuration: IdentityVerificationSheet.Configuration,
identityVerificationCallback: IdentityVerificationSheet.IdentityVerificationCallback
) : IdentityVerificationSheet {

constructor(
from: ComponentActivity,
configuration: IdentityVerificationSheet.Configuration
) : this(from as ActivityResultCaller, configuration)
configuration: IdentityVerificationSheet.Configuration,
identityVerificationCallback: IdentityVerificationSheet.IdentityVerificationCallback
) : this(from as ActivityResultCaller, configuration, identityVerificationCallback)

constructor(
from: Fragment,
configuration: IdentityVerificationSheet.Configuration
) : this(from as ActivityResultCaller, configuration)
configuration: IdentityVerificationSheet.Configuration,
identityVerificationCallback: IdentityVerificationSheet.IdentityVerificationCallback
) : this(from as ActivityResultCaller, configuration, identityVerificationCallback)

private val activityResultLauncher: ActivityResultLauncher<IdentityVerificationSheetContract.Args> =
activityResultCaller.registerForActivityResult(
IdentityVerificationSheetContract(),
::onResult
identityVerificationCallback::onVerificationFlowResult
)

private var onFinished: ((verificationResult: IdentityVerificationSheet.VerificationResult) -> Unit)? =
null

override fun present(
verificationSessionId: String,
ephemeralKeySecret: String,
onFinished: (verificationResult: IdentityVerificationSheet.VerificationResult) -> Unit
) {
this.onFinished = onFinished
activityResultLauncher.launch(
IdentityVerificationSheetContract.Args(
verificationSessionId,
Expand All @@ -43,10 +41,4 @@ internal class StripeIdentityVerificationSheet private constructor(
)
)
}

private fun onResult(verificationResult: IdentityVerificationSheet.VerificationResult) {
onFinished?.let {
it(verificationResult)
}
}
}
Expand Up @@ -4,5 +4,5 @@ package com.stripe.android.identity
* An interface to indicate this class is able to finish verification flow with result.
*/
internal fun interface VerificationFlowFinishable {
fun finishWithResult(result: IdentityVerificationSheet.VerificationResult)
fun finishWithResult(result: IdentityVerificationSheet.VerificationFlowResult)
}
Expand Up @@ -37,7 +37,7 @@ internal class ConfirmationFragment(
binding = ConfirmationFragmentBinding.inflate(inflater, container, false)
binding.kontinue.setOnClickListener {
verificationFlowFinishable.finishWithResult(
IdentityVerificationSheet.VerificationResult.Completed
IdentityVerificationSheet.VerificationFlowResult.Completed
)
}
return binding.root
Expand Down
Expand Up @@ -49,7 +49,7 @@ internal class ConsentFragment(
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
verificationFlowFinishable.finishWithResult(
IdentityVerificationSheet.VerificationResult.Canceled
IdentityVerificationSheet.VerificationFlowResult.Canceled
)
}
}
Expand Down
Expand Up @@ -8,7 +8,7 @@ import androidx.core.os.bundleOf
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import com.stripe.android.identity.IdentityVerificationSheet
import com.stripe.android.identity.IdentityVerificationSheet.VerificationResult.Failed
import com.stripe.android.identity.IdentityVerificationSheet.VerificationFlowResult.Failed
import com.stripe.android.identity.R
import com.stripe.android.identity.VerificationFlowFinishable
import com.stripe.android.identity.networking.models.VerificationPageDataRequirementError
Expand Down Expand Up @@ -102,7 +102,7 @@ internal class ErrorFragment(
/**
* Navigate to error fragment with failed reason. This would be the final destination of
* verification flow, clicking back button would end the follow with
* [IdentityVerificationSheet.VerificationResult.Failed] with [failedReason].
* [IdentityVerificationSheet.VerificationFlowResult.Failed] with [failedReason].
*/
fun NavController.navigateToErrorFragmentWithFailedReason(
context: Context,
Expand Down
Expand Up @@ -85,7 +85,7 @@ class ConfirmationFragmentTest {
binding.kontinue.callOnClick()

verify(mockVerificationFlowFinishable).finishWithResult(
eq(IdentityVerificationSheet.VerificationResult.Completed)
eq(IdentityVerificationSheet.VerificationFlowResult.Completed)
)
}
}
Expand Down
Expand Up @@ -7,7 +7,7 @@ import androidx.navigation.Navigation
import androidx.navigation.testing.TestNavHostController
import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import com.stripe.android.identity.IdentityVerificationSheet.VerificationResult
import com.stripe.android.identity.IdentityVerificationSheet.VerificationFlowResult
import com.stripe.android.identity.R
import com.stripe.android.identity.VerificationFlowFinishable
import com.stripe.android.identity.databinding.BaseErrorFragmentBinding
Expand Down Expand Up @@ -92,7 +92,7 @@ class ErrorFragmentTest {
assertThat(binding.bottomButton.text).isEqualTo(TEST_GO_BACK_BUTTON_TEXT)

binding.bottomButton.callOnClick()
val resultCaptor = argumentCaptor<VerificationResult.Failed>()
val resultCaptor = argumentCaptor<VerificationFlowResult.Failed>()
verify(mockVerificationFlowFinishable).finishWithResult(
resultCaptor.capture()
)
Expand Down
Expand Up @@ -36,7 +36,11 @@ class CardImageVerificationDemoActivity : AppCompatActivity() {
setContentView(viewBinding.root)

val cardImageVerificationSheet =
CardImageVerificationSheet.create(this, settings.publishableKey)
CardImageVerificationSheet.create(
this,
settings.publishableKey,
cardImageVerificationResultCallback = this::onScanFinished
)

viewBinding.generateCivIntent.setOnClickListener {
Fuel.post("${settings.backendUrl}/card-set/checkout")
Expand Down Expand Up @@ -97,8 +101,7 @@ class CardImageVerificationDemoActivity : AppCompatActivity() {
viewBinding.launchScanButton.setOnClickListener {
cardImageVerificationSheet.present(
viewBinding.civIdText.text.toString(),
viewBinding.civSecretText.text.toString(),
this::onScanFinished,
viewBinding.civSecretText.text.toString()
)
}
}
Expand Down
@@ -1,7 +1,7 @@
package com.stripe.android.stripecardscan.example

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.stripe.android.stripecardscan.cardscan.CardScanSheet
import com.stripe.android.stripecardscan.cardscan.CardScanSheetResult
import com.stripe.android.stripecardscan.example.databinding.ActivityCardScanDemoBinding
Expand All @@ -17,10 +17,10 @@ class CardScanDemoActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(viewBinding.root)

val cardScanSheet = CardScanSheet.create(this, settings.publishableKey)
val cardScanSheet = CardScanSheet.create(this, settings.publishableKey, ::onScanFinished)

viewBinding.launchScanButton.setOnClickListener {
cardScanSheet.present(this::onScanFinished)
cardScanSheet.present()
}
}

Expand Down
Expand Up @@ -20,7 +20,7 @@ class CardScanFragmentDemoActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(viewBinding.root)

cardScanSheet = CardScanSheet.create(this, settings.publishableKey)
cardScanSheet = CardScanSheet.create(this, settings.publishableKey, ::onScanFinished)

viewBinding.launchScanButton.setOnClickListener {
attachCardScanFragment()
Expand Down