Skip to content

Commit 90290f3

Browse files
authored
Provide authentication fragment if strong customer authorization is activated (APPS-2409) (#263)
1 parent 60d2b67 commit 90290f3

File tree

8 files changed

+119
-2
lines changed

8 files changed

+119
-2
lines changed

core/src/main/java/io/snabble/sdk/checkout/Checkout.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ package io.snabble.sdk.checkout
33
import androidx.annotation.RestrictTo
44
import androidx.annotation.VisibleForTesting
55
import androidx.lifecycle.LiveData
6-
import io.snabble.sdk.*
6+
import io.snabble.sdk.FulfillmentState
7+
import io.snabble.sdk.MutableAccessibleLiveData
8+
import io.snabble.sdk.PaymentMethod
9+
import io.snabble.sdk.Product
10+
import io.snabble.sdk.Project
11+
import io.snabble.sdk.Snabble
712
import io.snabble.sdk.Snabble.instance
813
import io.snabble.sdk.payment.PaymentCredentials
914
import io.snabble.sdk.shoppingcart.ShoppingCart
1015
import io.snabble.sdk.utils.Dispatch
1116
import io.snabble.sdk.utils.Logger
1217
import java.io.File
13-
import java.util.*
1418
import java.util.concurrent.Future
1519

1620
class Checkout @JvmOverloads constructor(
@@ -499,6 +503,7 @@ class Checkout @JvmOverloads constructor(
499503
|| state == CheckoutState.PAYMENT_PROCESSING
500504
|| (state == CheckoutState.PAYMENT_APPROVED && !areAllFulfillmentsClosed())
501505
|| state == CheckoutState.PAYONE_SEPA_MANDATE_REQUIRED
506+
|| state == CheckoutState.AUTHENTICATING
502507
) {
503508
scheduleNextPoll()
504509
}
@@ -580,6 +585,10 @@ class Checkout @JvmOverloads constructor(
580585
notifyStateChanged(CheckoutState.PAYMENT_PROCESSING)
581586
}
582587

588+
CheckState.AUTHENTICATING -> {
589+
notifyStateChanged(CheckoutState.AUTHENTICATING)
590+
}
591+
583592
CheckState.SUCCESSFUL -> {
584593
val exitToken = checkoutProcess.exitToken
585594
return if (exitToken != null && (exitToken.format.isNullOrEmpty() || exitToken.value.isNullOrEmpty())) {

core/src/main/java/io/snabble/sdk/checkout/CheckoutApi.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ enum class CheckState {
119119
@SerializedName("unauthorized") UNAUTHORIZED,
120120
@SerializedName("pending") PENDING,
121121
@SerializedName("processing") PROCESSING,
122+
@SerializedName("authenticating") AUTHENTICATING,
122123
@SerializedName("successful") SUCCESSFUL,
123124
@SerializedName("transferred") TRANSFERRED,
124125
@SerializedName("failed") FAILED
@@ -387,6 +388,9 @@ data class CheckoutProcessResponse(
387388
val authorizePaymentLink: String?
388389
get() = links?.get("authorizePayment")?.href
389390

391+
val paymentRedirect: String?
392+
get() = links?.get("paymentRedirect")?.href
393+
390394
val originCandidateLink: String?
391395
get() = paymentResult?.originCandidateLink
392396
}

core/src/main/java/io/snabble/sdk/checkout/CheckoutState.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ enum class CheckoutState {
2626
*/
2727
VERIFYING_PAYMENT_METHOD,
2828

29+
/**
30+
* The payment need further authentication.
31+
* Use the paymentRedirect link provided for further authentication.
32+
*/
33+
AUTHENTICATING,
34+
2935
/**
3036
* Age needs to be verified
3137
*/
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package io.snabble.sdk.ui.checkout
2+
3+
import android.os.Bundle
4+
import android.view.View
5+
import android.webkit.CookieManager
6+
import android.webkit.WebResourceRequest
7+
import android.webkit.WebSettings
8+
import android.webkit.WebView
9+
import android.webkit.WebViewClient
10+
import io.snabble.sdk.Snabble
11+
import io.snabble.sdk.ui.BaseFragment
12+
import io.snabble.sdk.ui.R
13+
import io.snabble.sdk.utils.Logger
14+
15+
class AuthenticationFragment : BaseFragment(R.layout.snabble_fragment_authentication) {
16+
override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) {
17+
super.onActualViewCreated(view, savedInstanceState)
18+
19+
val currentCheckout = Snabble.checkedInProject.value?.checkout
20+
21+
// Setup your views here after inflation
22+
val webview = view.findViewById<WebView>(R.id.authentication_webview)
23+
webview.setupCookies()
24+
25+
// Configure WebView settings
26+
webview.settings.apply {
27+
javaScriptEnabled = true
28+
domStorageEnabled = true
29+
loadWithOverviewMode = true
30+
useWideViewPort = true
31+
setSupportZoom(true)
32+
builtInZoomControls = true
33+
displayZoomControls = false
34+
35+
// Additional cookie-related settings
36+
databaseEnabled = true
37+
cacheMode = WebSettings.LOAD_DEFAULT
38+
}
39+
40+
webview.webViewClient = object : WebViewClient() {
41+
override fun onReceivedError(view: WebView?, errorCode: Int, description: String?, failingUrl: String?) {
42+
Logger.d("onReceivedError $failingUrl")
43+
}
44+
45+
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
46+
when (request.url.toString()) {
47+
SUCCESS,
48+
ERROR,
49+
BACK -> {
50+
// No need to pop it since we're polling for the checkout state in the activity
51+
// and navigate away as soon the get an update state
52+
return true
53+
}
54+
}
55+
return super.shouldOverrideUrlLoading(view, request)
56+
}
57+
}
58+
59+
val redirectUrl = currentCheckout?.checkoutProcess?.paymentRedirect
60+
redirectUrl?.let {
61+
webview.loadUrl(it)
62+
}
63+
}
64+
65+
// Extension function for cleaner code
66+
fun WebView.setupCookies() {
67+
val cookieManager = CookieManager.getInstance()
68+
cookieManager.setAcceptCookie(true)
69+
cookieManager.setAcceptThirdPartyCookies(this, true)
70+
cookieManager.flush()
71+
}
72+
73+
private companion object {
74+
75+
const val SUCCESS = "snabble://payone/success"
76+
const val ERROR = "snabble://payone/error"
77+
const val BACK = "snabble://payone/back"
78+
}
79+
}

ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ class CheckoutActivity : FragmentActivity() {
214214
}
215215
}
216216

217+
CheckoutState.AUTHENTICATING -> R.id.snabble_nav_authentication
218+
217219
CheckoutState.DEPOSIT_RETURN_REDEMPTION_FAILED,
218220
CheckoutState.PAYMENT_ABORTED -> {
219221
finish()

ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ val CheckoutState.isCheckoutState: Boolean
2222
CheckoutState.WAIT_FOR_GATEKEEPER,
2323
CheckoutState.WAIT_FOR_APPROVAL,
2424
CheckoutState.PAYMENT_PROCESSING,
25+
CheckoutState.AUTHENTICATING,
2526
CheckoutState.PAYMENT_APPROVED,
2627
CheckoutState.DENIED_TOO_YOUNG,
2728
CheckoutState.DENIED_BY_PAYMENT_PROVIDER,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="match_parent"
5+
android:fitsSystemWindows="true">
6+
7+
<WebView
8+
android:id="@+id/authentication_webview"
9+
android:layout_width="match_parent"
10+
android:layout_height="match_parent" />
11+
</FrameLayout>

ui/src/main/res/navigation/snabble_nav_checkout.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@
3737
android:name="io.snabble.sdk.ui.checkout.PaymentStatusFragment"
3838
android:label="@string/Snabble.Checkout.title" />
3939

40+
<fragment
41+
android:id="@+id/snabble_nav_authentication"
42+
android:name="io.snabble.sdk.ui.checkout.AuthenticationFragment"
43+
android:label="@string/Snabble.Checkout.title" />
44+
4045
<fragment
4146
android:id="@+id/snabble_nav_payment_payone_sepa_mandate"
4247
android:name="io.snabble.sdk.ui.payment.payone.sepa.mandate.PayoneSepaMandateFragment"

0 commit comments

Comments
 (0)