diff --git a/build.gradle b/build.gradle
index 3e563df32..de0b7774a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
buildscript {
ext {
- androidGradlePluginVersion = '9.3.1'
+ androidGradlePluginVersion = '9.4.1'
kotlinVersion = '2.1.20'
kspVersion = '2.1.20-1.0.32'
dokkaVersion = '1.9.20'
diff --git a/sdk/src/main/AndroidManifest.xml b/sdk/src/main/AndroidManifest.xml
index 59aaab951..b318e16c0 100644
--- a/sdk/src/main/AndroidManifest.xml
+++ b/sdk/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
@@ -39,7 +39,7 @@
diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/web/customtab/POCustomTabAuthorizationActivity.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/web/customtab/POCustomTabAuthorizationActivity.kt
index 738502c1a..092526f71 100644
--- a/sdk/src/main/kotlin/com/processout/sdk/ui/web/customtab/POCustomTabAuthorizationActivity.kt
+++ b/sdk/src/main/kotlin/com/processout/sdk/ui/web/customtab/POCustomTabAuthorizationActivity.kt
@@ -2,9 +2,7 @@ package com.processout.sdk.ui.web.customtab
import android.app.Activity
import android.content.Intent
-import android.content.pm.ActivityInfo
import android.net.Uri
-import android.os.Build
import android.os.Bundle
import androidx.activity.addCallback
import androidx.activity.viewModels
@@ -61,12 +59,6 @@ class POCustomTabAuthorizationActivity : AppCompatActivity() {
@Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- // This is a workaround for crash on Android 8.0 (API level 26).
- // https://issuetracker.google.com/issues/68454482
- // https://stackoverflow.com/questions/48072438/java-lang-illegalstateexception-only-fullscreen-opaque-activities-can-request-o
- requestedOrientation = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O)
- ActivityInfo.SCREEN_ORIENTATION_BEHIND else ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
-
onBackPressedDispatcher.addCallback(this) {
// Ignore back press to avoid finishing activity without a result.
// Cancelled result will be provided from onResume() when going back from the Custom Tab.
@@ -168,8 +160,8 @@ class POCustomTabAuthorizationActivity : AppCompatActivity() {
result.onFailure { POLogger.info("Custom Chrome Tabs failure: %s", it) }
when (configuration.resultApi) {
Android -> when (result) {
- is ProcessOutActivityResult.Success -> setActivityResult(Activity.RESULT_OK, result)
- is ProcessOutActivityResult.Failure -> setActivityResult(Activity.RESULT_CANCELED, result)
+ is ProcessOutActivityResult.Success -> setActivityResult(RESULT_OK, result)
+ is ProcessOutActivityResult.Failure -> setActivityResult(RESULT_CANCELED, result)
}
Dispatcher -> resultDispatcher.dispatch(result)
}
diff --git a/sdk/src/main/kotlin/com/processout/sdk/ui/web/webview/POWebViewAuthorizationActivity.kt b/sdk/src/main/kotlin/com/processout/sdk/ui/web/webview/POWebViewAuthorizationActivity.kt
index 93a4ed1e1..1b43e43ba 100644
--- a/sdk/src/main/kotlin/com/processout/sdk/ui/web/webview/POWebViewAuthorizationActivity.kt
+++ b/sdk/src/main/kotlin/com/processout/sdk/ui/web/webview/POWebViewAuthorizationActivity.kt
@@ -1,8 +1,6 @@
package com.processout.sdk.ui.web.webview
-import android.app.Activity
import android.content.Intent
-import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Build
import android.os.Bundle
@@ -33,12 +31,6 @@ class POWebViewAuthorizationActivity : AppCompatActivity() {
@Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- // This is a workaround for crash on Android 8.0 (API level 26).
- // https://issuetracker.google.com/issues/68454482
- // https://stackoverflow.com/questions/48072438/java-lang-illegalstateexception-only-fullscreen-opaque-activities-can-request-o
- requestedOrientation = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O)
- ActivityInfo.SCREEN_ORIENTATION_BEHIND else ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
-
if (intent.getBooleanExtra(EXTRA_FORCE_FINISH, false)) {
POLogger.info("Activity is started to clear the back stack and finished immediately before it's created.")
finish()
@@ -87,8 +79,8 @@ class POWebViewAuthorizationActivity : AppCompatActivity() {
if (!isFinishing) {
when (configuration.resultApi) {
Android -> when (result) {
- is ProcessOutActivityResult.Success -> setActivityResult(Activity.RESULT_OK, result)
- is ProcessOutActivityResult.Failure -> setActivityResult(Activity.RESULT_CANCELED, result)
+ is ProcessOutActivityResult.Success -> setActivityResult(RESULT_OK, result)
+ is ProcessOutActivityResult.Failure -> setActivityResult(RESULT_CANCELED, result)
}
Dispatcher -> resultDispatcher.dispatch(result)
}
@@ -104,7 +96,7 @@ class POWebViewAuthorizationActivity : AppCompatActivity() {
super.finish()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
overrideActivityTransition(
- Activity.OVERRIDE_TRANSITION_CLOSE,
+ OVERRIDE_TRANSITION_CLOSE,
R.anim.po_slide_in_left,
R.anim.po_slide_out_right
)
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationInteractor.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationInteractor.kt
index f2dd1936d..fd00e1fa8 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationInteractor.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationInteractor.kt
@@ -60,7 +60,7 @@ internal class CardTokenizationInteractor(
private val cardsRepository: POCardsRepository,
private val cardSchemeProvider: CardSchemeProvider,
private val addressSpecificationProvider: AddressSpecificationProvider,
- private val eventDispatcher: POEventDispatcher
+ val eventDispatcher: POEventDispatcher
) : BaseInteractor() {
private companion object {
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt
index b1783648b..124dbcc12 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/CardTokenizationViewModel.kt
@@ -74,6 +74,8 @@ internal class CardTokenizationViewModel private constructor(
val sideEffects = interactor.sideEffects
+ val eventDispatcher = interactor.eventDispatcher
+
init {
addCloseable(interactor.interactorScope)
}
diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/component/POCardTokenizationViewComponent.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/component/POCardTokenizationViewComponent.kt
index 2a395b794..ce1cb32b8 100644
--- a/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/component/POCardTokenizationViewComponent.kt
+++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/tokenization/component/POCardTokenizationViewComponent.kt
@@ -37,6 +37,7 @@ import com.processout.sdk.ui.card.tokenization.screen.CardTokenizationScreen
import com.processout.sdk.ui.core.theme.ProcessOutTheme
import com.processout.sdk.ui.shared.configuration.POBottomSheetConfiguration
import com.processout.sdk.ui.shared.configuration.POBottomSheetConfiguration.Height.WrapContent
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -50,15 +51,12 @@ class POCardTokenizationViewComponent private constructor(
val view: View,
private var configuration: POCardTokenizationConfiguration,
private val viewModel: CardTokenizationViewModel,
- private val lifecycleOwner: LifecycleOwner,
private val cardScannerLauncher: POCardScannerLauncher,
private val delegate: POCardTokenizationDelegate,
private val callback: (ProcessOutResult) -> Unit,
private val eventDispatcher: POEventDispatcher
) {
- private val scope = lifecycleOwner.lifecycleScope
-
companion object {
/**
* Creates the card tokenization view component from a Fragment.
@@ -71,12 +69,11 @@ class POCardTokenizationViewComponent private constructor(
callback: (ProcessOutResult) -> Unit
): POCardTokenizationViewComponent {
val configuration = configuration.map()
- val eventDispatcher = POEventDispatcher()
val viewModel: CardTokenizationViewModel by from.viewModels {
CardTokenizationViewModel.Factory(
app = from.requireActivity().application,
configuration = configuration,
- eventDispatcher = eventDispatcher
+ eventDispatcher = POEventDispatcher()
)
}
return POCardTokenizationViewComponent(
@@ -87,7 +84,6 @@ class POCardTokenizationViewComponent private constructor(
),
configuration = configuration,
viewModel = viewModel,
- lifecycleOwner = from,
cardScannerLauncher = POCardScannerLauncher.create(
from = from,
callback = { result ->
@@ -96,8 +92,12 @@ class POCardTokenizationViewComponent private constructor(
),
delegate = delegate,
callback = callback,
- eventDispatcher = eventDispatcher
- )
+ eventDispatcher = viewModel.eventDispatcher
+ ).apply {
+ from.viewLifecycleOwnerLiveData.observe(from) { lifecycleOwner ->
+ init(lifecycleOwner)
+ }
+ }
}
/**
@@ -111,12 +111,11 @@ class POCardTokenizationViewComponent private constructor(
callback: (ProcessOutResult) -> Unit
): POCardTokenizationViewComponent {
val configuration = configuration.map()
- val eventDispatcher = POEventDispatcher()
val viewModel: CardTokenizationViewModel by from.viewModels {
CardTokenizationViewModel.Factory(
app = from.application,
configuration = configuration,
- eventDispatcher = eventDispatcher
+ eventDispatcher = POEventDispatcher()
)
}
return POCardTokenizationViewComponent(
@@ -127,7 +126,6 @@ class POCardTokenizationViewComponent private constructor(
),
configuration = configuration,
viewModel = viewModel,
- lifecycleOwner = from,
cardScannerLauncher = POCardScannerLauncher.create(
from = from,
callback = { result ->
@@ -136,8 +134,10 @@ class POCardTokenizationViewComponent private constructor(
),
delegate = delegate,
callback = callback,
- eventDispatcher = eventDispatcher
- )
+ eventDispatcher = viewModel.eventDispatcher
+ ).apply {
+ init(lifecycleOwner = from)
+ }
}
private fun POCardTokenizationViewComponentConfiguration.map() =
@@ -180,35 +180,36 @@ class POCardTokenizationViewComponent private constructor(
}
}
- init {
- dispatchEvents()
- dispatchState()
- dispatchTokenizedCard()
- dispatchEligibility()
- dispatchPreferredScheme()
- dispatchShouldContinue()
- collectSideEffects()
- collectCompletion()
+ private fun init(lifecycleOwner: LifecycleOwner) {
+ val coroutineScope = lifecycleOwner.lifecycleScope
+ dispatchEvents(coroutineScope)
+ dispatchState(coroutineScope)
+ dispatchTokenizedCard(coroutineScope)
+ dispatchEligibility(coroutineScope)
+ dispatchPreferredScheme(coroutineScope)
+ dispatchShouldContinue(coroutineScope)
+ collectSideEffects(lifecycleOwner)
+ collectCompletion(lifecycleOwner)
viewModel.start()
}
- private fun dispatchEvents() {
+ private fun dispatchEvents(coroutineScope: CoroutineScope) {
eventDispatcher.subscribe(
- coroutineScope = scope
+ coroutineScope
) { delegate.onEvent(it) }
}
- private fun dispatchState() {
+ private fun dispatchState(coroutineScope: CoroutineScope) {
eventDispatcher.subscribe(
- coroutineScope = scope
+ coroutineScope
) { delegate.onStateChanged(it) }
}
- private fun dispatchTokenizedCard() {
+ private fun dispatchTokenizedCard(coroutineScope: CoroutineScope) {
eventDispatcher.subscribeForRequest(
- coroutineScope = scope
+ coroutineScope
) { request ->
- scope.launch {
+ coroutineScope.launch {
val result = delegate.processTokenizedCard(
card = request.card,
saveCard = request.saveCard
@@ -218,11 +219,11 @@ class POCardTokenizationViewComponent private constructor(
}
}
- private fun dispatchEligibility() {
+ private fun dispatchEligibility(coroutineScope: CoroutineScope) {
eventDispatcher.subscribeForRequest(
- coroutineScope = scope
+ coroutineScope
) { request ->
- scope.launch {
+ coroutineScope.launch {
val eligibility = delegate.evaluateEligibility(
iin = request.iin,
issuerInformation = request.issuerInformation
@@ -232,30 +233,30 @@ class POCardTokenizationViewComponent private constructor(
}
}
- private fun dispatchPreferredScheme() {
+ private fun dispatchPreferredScheme(coroutineScope: CoroutineScope) {
eventDispatcher.subscribeForRequest(
- coroutineScope = scope
+ coroutineScope
) { request ->
- scope.launch {
+ coroutineScope.launch {
val preferredScheme = delegate.preferredScheme(request.issuerInformation)
eventDispatcher.send(request.toResponse(preferredScheme))
}
}
}
- private fun dispatchShouldContinue() {
+ private fun dispatchShouldContinue(coroutineScope: CoroutineScope) {
eventDispatcher.subscribeForRequest(
- coroutineScope = scope
+ coroutineScope
) { request ->
- scope.launch {
+ coroutineScope.launch {
val shouldContinue = delegate.shouldContinue(request.failure)
eventDispatcher.send(request.toResponse(shouldContinue))
}
}
}
- private fun collectSideEffects() {
- scope.launch {
+ private fun collectSideEffects(lifecycleOwner: LifecycleOwner) {
+ lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(state = Lifecycle.State.STARTED) {
withContext(Dispatchers.Main.immediate) {
viewModel.sideEffects.collect { sideEffect ->
@@ -270,8 +271,8 @@ class POCardTokenizationViewComponent private constructor(
}
}
- private fun collectCompletion() {
- scope.launch {
+ private fun collectCompletion(lifecycleOwner: LifecycleOwner) {
+ lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(state = Lifecycle.State.STARTED) {
viewModel.completion.collect { completion ->
when (completion) {