From 0d8070654d894cc88546e54f7c833a8eeeb70f98 Mon Sep 17 00:00:00 2001 From: josephj Date: Thu, 5 Sep 2024 16:34:16 +0200 Subject: [PATCH 001/102] Create libs.versions.toml and migrate dependencies to it COAND-977 --- 3ds2/build.gradle | 22 ++-- ach/build.gradle | 22 ++-- action-core/build.gradle | 20 +-- action/build.gradle | 20 +-- await/build.gradle | 20 +-- bacs/build.gradle | 20 +-- bcmc/build.gradle | 20 +-- blik/build.gradle | 22 ++-- boleto/build.gradle | 20 +-- build.gradle | 24 ++-- card/build.gradle | 22 ++-- cashapppay/build.gradle | 22 ++-- checkout-core/build.gradle | 28 ++-- components-compose/build.gradle | 16 +-- components-core/build.gradle | 45 ++++--- config/gradle/buildConfig.gradle | 2 +- config/gradle/detekt.gradle | 6 +- config/gradle/dokka.gradle | 2 + config/gradle/dokkaRoot.gradle | 2 + config/gradle/jacoco.gradle | 4 +- config/gradle/ktlint.gradle | 2 +- config/gradle/release.gradle | 4 +- config/gradle/sonarcloud.gradle | 2 + config/module/template/build.gradle | 12 +- convenience-stores-jp/build.gradle | 16 +-- cse/build.gradle | 24 ++-- dependencies.gradle | 193 ---------------------------- dotpay/build.gradle | 18 +-- drop-in-compose/build.gradle | 16 +-- drop-in/build.gradle | 26 ++-- econtext/build.gradle | 20 +-- entercash/build.gradle | 18 +-- eps/build.gradle | 18 +-- example-app/build.gradle | 82 ++++++------ giftcard/build.gradle | 20 +-- googlepay/build.gradle | 22 ++-- gradle/libs.versions.toml | 189 +++++++++++++++++++++++++++ ideal/build.gradle | 22 ++-- instant/build.gradle | 20 +-- issuer-list/build.gradle | 22 ++-- lint/build.gradle | 10 +- mbway/build.gradle | 20 +-- meal-voucher-fr/build.gradle | 18 +-- molpay/build.gradle | 18 +-- online-banking-core/build.gradle | 26 ++-- online-banking-cz/build.gradle | 16 +-- online-banking-jp/build.gradle | 16 +-- online-banking-pl/build.gradle | 18 +-- online-banking-sk/build.gradle | 16 +-- openbanking/build.gradle | 18 +-- paybybank/build.gradle | 20 +-- payeasy/build.gradle | 16 +-- qr-code/build.gradle | 22 ++-- redirect/build.gradle | 20 +-- sepa/build.gradle | 20 +-- sessions-core/build.gradle | 25 ++-- settings.gradle | 1 + seven-eleven/build.gradle | 16 +-- test-core/build.gradle | 16 +-- twint-action/build.gradle | 24 ++-- twint/build.gradle | 22 ++-- ui-core/build.gradle | 36 +++--- upi/build.gradle | 20 +-- voucher/build.gradle | 22 ++-- wechatpay/build.gradle | 22 ++-- 65 files changed, 789 insertions(+), 794 deletions(-) delete mode 100644 dependencies.gradle create mode 100644 gradle/libs.versions.toml diff --git a/3ds2/build.gradle b/3ds2/build.gradle index ea830ff4ad..abccc27aa7 100644 --- a/3ds2/build.gradle +++ b/3ds2/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.adyen3ds2' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -41,14 +41,14 @@ dependencies { api project(':ui-core') // Dependencies - api libraries.adyen3ds2 + api libs.adyen3ds2 //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/ach/build.gradle b/ach/build.gradle index b0b2a8cc57..11b02cd4b7 100644 --- a/ach/build.gradle +++ b/ach/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact ext.mavenArtifactId = "ach" @@ -12,11 +12,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.ach' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -37,15 +37,15 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':cse')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/action-core/build.gradle b/action-core/build.gradle index 930de80af5..a7746a1f28 100644 --- a/action-core/build.gradle +++ b/action-core/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "action-core" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.action.core' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -56,8 +56,8 @@ dependencies { testImplementation project(':wechatpay') testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/action/build.gradle b/action/build.gradle index 8b29e53d30..40f2fec0b0 100644 --- a/action/build.gradle +++ b/action/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "action" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.action' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -39,8 +39,8 @@ dependencies { //Tests testImplementation testFixtures(project(':test-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/await/build.gradle b/await/build.gradle index e18bc85997..d4fce540a3 100644 --- a/await/build.gradle +++ b/await/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "await" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.await' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -43,8 +43,8 @@ dependencies { testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/bacs/build.gradle b/bacs/build.gradle index e9e9b82fae..d13952589b 100644 --- a/bacs/build.gradle +++ b/bacs/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.bacs' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -43,13 +43,13 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/bcmc/build.gradle b/bcmc/build.gradle index 30e0d8c221..7bab02254a 100644 --- a/bcmc/build.gradle +++ b/bcmc/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.bcmc' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -48,12 +48,12 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/blik/build.gradle b/blik/build.gradle index 55d75fc920..7e1232ec50 100644 --- a/blik/build.gradle +++ b/blik/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.blik' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -43,14 +43,14 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/boleto/build.gradle b/boleto/build.gradle index 618fa39108..fad366b0d1 100644 --- a/boleto/build.gradle +++ b/boleto/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "boleto" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.boleto' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -42,13 +42,13 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/build.gradle b/build.gradle index 0f2b8b9929..127b19833d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,18 +1,14 @@ -buildscript { - apply from: './dependencies.gradle' -} - plugins { - id 'com.android.application' version "$android_gradle_plugin_version" apply false - id 'com.android.library' version "$android_gradle_plugin_version" apply false - id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false - id 'com.google.devtools.ksp' version "$ksp_version" apply false - id 'com.google.dagger.hilt.android' version "$hilt_version" apply false - id 'io.gitlab.arturbosch.detekt' version "$detekt_gradle_plugin_version" - id 'org.jetbrains.dokka' version "$dokka_version" - id 'org.sonarqube' version "$sonarqube_version" - id 'jacoco' - id 'org.jetbrains.kotlinx.binary-compatibility-validator' version "$binary_compatibility_validator_version" + alias libs.plugins.android.application apply false + alias libs.plugins.android.library apply false + alias libs.plugins.jetbrains.kotlin.android apply false + alias libs.plugins.ksp apply false + alias libs.plugins.hilt apply false + alias libs.plugins.detekt + alias libs.plugins.dokka + alias libs.plugins.sonarqube + alias libs.plugins.jacoco + alias libs.plugins.binary.compatibility.validator } apply from: "config/gradle/dokkaRoot.gradle" diff --git a/card/build.gradle b/card/build.gradle index 5f185472d6..85bba90640 100644 --- a/card/build.gradle +++ b/card/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.card' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -49,7 +49,7 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) @@ -57,8 +57,8 @@ dependencies { testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':cse')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/cashapppay/build.gradle b/cashapppay/build.gradle index 4469b9f7ce..aaa0167f39 100644 --- a/cashapppay/build.gradle +++ b/cashapppay/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "cashapppay" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.cashapppay' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -48,13 +48,13 @@ dependencies { api project(':sessions-core') api project(':ui-core') - api libraries.cashAppPay - implementation libraries.material + api libs.cash.app.pay + implementation libs.material testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/checkout-core/build.gradle b/checkout-core/build.gradle index 02ca7d14d9..ab2fee0f5c 100644 --- a/checkout-core/build.gradle +++ b/checkout-core/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "checkout-core" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.core' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -33,14 +33,14 @@ android { dependencies { // Dependencies - api libraries.androidx.annotation - api libraries.kotlinCoroutines - implementation libraries.okhttp - api libraries.parcelize + api libs.androidx.annotation + api libs.bundles.kotlin.coroutines + implementation libs.okhttp + api libs.parcelize //Tests - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - androidTestImplementation testLibraries.androidTest - androidTestImplementation testLibraries.espresso + testImplementation libs.json + testImplementation libs.bundles.junit + androidTestImplementation libs.bundles.androidx.test + androidTestImplementation libs.bundles.espresso } diff --git a/components-compose/build.gradle b/components-compose/build.gradle index 4d6f3892b6..f46433e8b4 100644 --- a/components-compose/build.gradle +++ b/components-compose/build.gradle @@ -7,8 +7,8 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android } // Maven artifact @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.components.compose' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -35,7 +35,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion = compose_compiler_version + kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() } } @@ -45,6 +45,6 @@ dependencies { api project(':sessions-core') api project(':ui-core') - implementation platform(libraries.compose.bom) - implementation libraries.compose.viewmodel + implementation platform(libs.compose.bom) + implementation libs.compose.viewmodel } diff --git a/components-core/build.gradle b/components-core/build.gradle index 8e357861ec..5b50e5c1d1 100644 --- a/components-core/build.gradle +++ b/components-core/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.components.core' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -41,24 +41,23 @@ dependencies { api project(':checkout-core') // Dependencies - api libraries.kotlinCoroutines - api libraries.androidx.activity - api libraries.androidx.fragment - api libraries.androidx.lifecycle + api libs.androidx.activity + api libs.androidx.fragment + api libs.bundles.androidx.lifecycle //Tests testImplementation testFixtures(project(':test-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.androidx.lifecycle - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito - testImplementation testLibraries.robolectric - - androidTestImplementation testLibraries.androidTest - androidTestImplementation testLibraries.mockitoAndroid - androidTestImplementation testLibraries.espresso - - testFixturesImplementation testLibraries.junit5 - testFixturesImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.androidx.test.lifecycle + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito + testImplementation libs.robolectric + + androidTestImplementation libs.bundles.androidx.test + androidTestImplementation libs.bundles.mockito.android + androidTestImplementation libs.bundles.espresso + + testFixturesImplementation libs.bundles.junit + testFixturesImplementation libs.bundles.mockito } diff --git a/config/gradle/buildConfig.gradle b/config/gradle/buildConfig.gradle index f43cf2bbcb..20a0c77080 100644 --- a/config/gradle/buildConfig.gradle +++ b/config/gradle/buildConfig.gradle @@ -8,7 +8,7 @@ android { defaultConfig { - buildConfigField "String", "CHECKOUT_VERSION", "\"$version_name\"" + buildConfigField "String", "CHECKOUT_VERSION", "\"${libs.versions.version.name}\"" } buildFeatures { diff --git a/config/gradle/detekt.gradle b/config/gradle/detekt.gradle index f9ef026d92..4026d8bb3f 100644 --- a/config/gradle/detekt.gradle +++ b/config/gradle/detekt.gradle @@ -12,10 +12,12 @@ * Docs: https://github.com/detekt/detekt/ */ +// cannot reference the plugins declared in the version catalogs here because it requires the use of the `plugins` block instead of the `apply plugin` command +// the `plugins` block cannot be used in gradle files such as this one, which are imported into other gradle files with the `apply from` command apply plugin: 'io.gitlab.arturbosch.detekt' detekt { - toolVersion = "$project.detekt_version" + toolVersion = "${libs.versions.detekt.get()}" input = files("src") @@ -36,7 +38,7 @@ tasks.named("detekt").configure { } dependencies { - detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:$detekt_version" + detektPlugins libs.detekt } tasks.detekt.jvmTarget = JavaVersion.VERSION_1_8.toString() diff --git a/config/gradle/dokka.gradle b/config/gradle/dokka.gradle index 9494fbbfba..4f5db35fd3 100644 --- a/config/gradle/dokka.gradle +++ b/config/gradle/dokka.gradle @@ -8,6 +8,8 @@ // only apply dokka if module supports kotlin project.plugins.withId("kotlin-android") { + // cannot reference the plugins declared in the version catalogs here because it requires the use of the `plugins` block instead of the `apply plugin` command + // the `plugins` block cannot be used in gradle files such as this one, which are imported into other gradle files with the `apply from` command apply plugin: "org.jetbrains.dokka" tasks.register("javadocJar", Jar) { diff --git a/config/gradle/dokkaRoot.gradle b/config/gradle/dokkaRoot.gradle index 8ce02b9404..41174d3c88 100644 --- a/config/gradle/dokkaRoot.gradle +++ b/config/gradle/dokkaRoot.gradle @@ -6,6 +6,8 @@ * Created by josephj on 15/2/2021. */ +// cannot reference the plugins declared in the version catalogs here because it requires the use of the `plugins` block instead of the `apply plugin` command +// the `plugins` block cannot be used in gradle files such as this one, which are imported into other gradle files with the `apply from` command apply plugin: "org.jetbrains.dokka" tasks.named("dokkaHtmlMultiModule") { diff --git a/config/gradle/jacoco.gradle b/config/gradle/jacoco.gradle index 1e1ee9d25d..aad6ee5669 100644 --- a/config/gradle/jacoco.gradle +++ b/config/gradle/jacoco.gradle @@ -1,3 +1,5 @@ +// cannot reference the plugins declared in the version catalogs here because it requires the use of the `plugins` block instead of the `apply plugin` command +// the `plugins` block cannot be used in gradle files such as this one, which are imported into other gradle files with the `apply from` command apply plugin: 'jacoco' if (project.hasProperty('android')) { @@ -10,7 +12,7 @@ if (project.hasProperty('android')) { project.afterEvaluate { jacoco { - toolVersion = "$jacoco_version" + toolVersion = "${libs.versions.jacoco}" } tasks.withType(Test).configureEach { diff --git a/config/gradle/ktlint.gradle b/config/gradle/ktlint.gradle index 1bde8ae02b..c351a66917 100644 --- a/config/gradle/ktlint.gradle +++ b/config/gradle/ktlint.gradle @@ -17,7 +17,7 @@ configurations { } dependencies { - ktlint "com.pinterest.ktlint:ktlint-cli:$ktlint_version" + ktlint libs.ktlint.cli } tasks.register("ktlint", JavaExec) { diff --git a/config/gradle/release.gradle b/config/gradle/release.gradle index f0bc33c90d..5b318a1eb9 100644 --- a/config/gradle/release.gradle +++ b/config/gradle/release.gradle @@ -5,6 +5,8 @@ * * Created by ran on 6/2/2019. */ +// cannot reference the plugins declared in the version catalogs here because it requires the use of the `plugins` block instead of the `apply plugin` command +// the `plugins` block cannot be used in gradle files such as this one, which are imported into other gradle files with the `apply from` command apply plugin: "maven-publish" apply plugin: "signing" @@ -35,7 +37,7 @@ if (secretPropsFile.exists()) { final theGroupId = "com.adyen.checkout" final theArtifactId = project.mavenArtifactId -final theVersion = project.version_name +final theVersion = libs.versions.version.name.get() final theName = project.mavenArtifactName final theDescription = project.mavenArtifactDescription diff --git a/config/gradle/sonarcloud.gradle b/config/gradle/sonarcloud.gradle index bc3b8a92ef..161a714e69 100644 --- a/config/gradle/sonarcloud.gradle +++ b/config/gradle/sonarcloud.gradle @@ -34,6 +34,8 @@ project(":test-core") { } subprojects { + // cannot reference the plugins declared in the version catalogs here because it requires the use of the `plugins` block instead of the `apply plugin` command + // the `plugins` block cannot be used in gradle files such as this one, which are imported into other gradle files with the `apply from` command apply plugin: 'org.sonarqube' sonar { diff --git a/config/module/template/build.gradle b/config/module/template/build.gradle index a9cdb3bf30..b020885605 100644 --- a/config/module/template/build.gradle +++ b/config/module/template/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'com.android.library' - id 'kotlin-android' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android } ext.mavenArtifactId = "#module_name" @@ -10,13 +10,11 @@ ext.mavenArtifactDescription = "Adyen checkout #module_name component client for apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version - versionCode version_code - versionName version_name + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" diff --git a/convenience-stores-jp/build.gradle b/convenience-stores-jp/build.gradle index e709c6c5c6..a07267a3fe 100644 --- a/convenience-stores-jp/build.gradle +++ b/convenience-stores-jp/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -13,11 +13,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.conveniencestoresjp' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -32,6 +32,6 @@ dependencies { api project(':econtext') testImplementation testFixtures(project(':test-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito } diff --git a/cse/build.gradle b/cse/build.gradle index 4f6a0a32c0..8f9532efec 100644 --- a/cse/build.gradle +++ b/cse/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -13,11 +13,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.cse' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -33,11 +33,11 @@ dependencies { api project(':checkout-core') //Tests - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.jose4j + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.jose4j - testFixturesImplementation testLibraries.junit5 - testFixturesImplementation testLibraries.mockito + testFixturesImplementation libs.bundles.junit + testFixturesImplementation libs.bundles.mockito } diff --git a/dependencies.gradle b/dependencies.gradle deleted file mode 100644 index dd9a69ff41..0000000000 --- a/dependencies.gradle +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2022 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - * - * Created by oscars on 8/6/2022. - */ - -ext { - // SDK - compile_sdk_version = 34 - target_sdk_version = 34 - min_sdk_version = 21 - - // App version - // just for example app, don't need to increment - version_code = 1 - // The version_name format is "major.minor.patch(-(alpha|beta|rc)[0-9]{2}){0,1}" (e.g. 3.0.0, 3.1.1-alpha04 or 3.1.4-rc01 etc). - version_name = "5.7.0" - - // Build Script - android_gradle_plugin_version = '8.5.1' - kotlin_version = '1.9.24' - ksp_version = '1.9.24-1.0.20' - detekt_gradle_plugin_version = "1.23.7" - dokka_version = "1.9.20" - hilt_version = "2.52" - compose_compiler_version = '1.5.14' - - // Code quality - detekt_version = "1.23.7" - jacoco_version = '0.8.12' - ktlint_version = '1.3.1' - sonarqube_version = '5.0.0.4638' - binary_compatibility_validator_version = "0.16.0" - - // Android Dependencies - activity_version = "1.9.2" - annotation_version = "1.8.0" - appcompat_version = "1.7.0" - autofill_version = "1.3.0-alpha01" - browser_version = "1.8.0" - coroutines_version = "1.8.1" - fragment_version = "1.8.3" - lifecycle_version = "2.8.3" - material_version = "1.12.0" - recyclerview_version = "1.3.2" - constraintlayout_version = '2.1.4' - - // Compose Dependencies - compose_activity_version = '1.9.2' - compose_bom_version = '2024.06.00' - compose_hilt_version = '1.2.0' - compose_viewmodel_version = '2.8.3' - - // Adyen Dependencies - adyen3ds2_version = "2.2.21" - - // External Dependencies - cash_app_pay_version = '2.5.0' - google_pay_compose_button_version = '1.0.0' - okhttp_version = "4.12.0" - play_services_wallet_version = '19.4.0' - twint_version = '8.0.0' - wechat_pay_version = "6.8.0" - - // Example app - leak_canary_version = '2.14' - moshi_adapters_version = '1.15.1' - moshi_kotlin_adapter_version = '1.15.1' - okhttp_logging_version = "4.12.0" - preference_version = "1.2.1" - retrofit2_version = '2.11.0' - - // Tests - arch_core_testing_version = "2.2.0" - barista_version = "4.3.0" - espresso_version = "3.6.1" - json_version = '20240303' - jose4j_version = '0.9.6' - junit_jupiter_version = "5.11.1" - konsist_version = "0.16.1" - lint_version = "31.7.0" - mockito_kotlin_version = "5.4.0" - mockito_version = "5.12.0" - robolectric_version = "4.13" - test_ext_version = "1.2.1" - test_rules_version = "1.6.1" - turbine_version = "1.1.0" - uiautomator_version = "2.3.0" - - libraries = [ - adyen3ds2 : "com.adyen.threeds:adyen-3ds2:$adyen3ds2_version", - androidx : [ - activity : "androidx.activity:activity:$activity_version", - annotation : "androidx.annotation:annotation:$annotation_version", - appcompat : "androidx.appcompat:appcompat:$appcompat_version", - autofill : "androidx.autofill:autofill:$autofill_version", - browser : "androidx.browser:browser:$browser_version", - constraintlayout: "androidx.constraintlayout:constraintlayout:$constraintlayout_version", - fragment : "androidx.fragment:fragment-ktx:$fragment_version", - lifecycle : [ - "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version", - "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - ], - preference : "androidx.preference:preference-ktx:$preference_version", - recyclerview : "androidx.recyclerview:recyclerview:$recyclerview_version" - ], - cashAppPay : "app.cash.paykit:core:$cash_app_pay_version", - compose : [ - activity : "androidx.activity:activity-compose:$compose_activity_version", - bom : "androidx.compose:compose-bom:$compose_bom_version", - hilt : "androidx.hilt:hilt-navigation-compose:$compose_hilt_version", - material : 'androidx.compose.material3:material3', - ui : [ - 'androidx.compose.ui:ui', - 'androidx.compose.ui:ui-graphics', - 'androidx.compose.ui:ui-tooling-preview', - ], - viewmodel: "androidx.lifecycle:lifecycle-viewmodel-compose:$compose_viewmodel_version" - ], - googlePay : [ - composeButton : "com.google.pay.button:compose-pay-button:$google_pay_compose_button_version", - playServicesWallet: "com.google.android.gms:play-services-wallet:$play_services_wallet_version", - ], - hilt : "com.google.dagger:hilt-android:$hilt_version", - hiltCompiler : "com.google.dagger:hilt-compiler:$hilt_version", - kotlinCoroutines: [ - "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version", - "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - ], - leakCanary : "com.squareup.leakcanary:leakcanary-android:$leak_canary_version", - material : "com.google.android.material:material:$material_version", - moshi : [ - "com.squareup.moshi:moshi-adapters:$moshi_adapters_version", - "com.squareup.moshi:moshi-kotlin:$moshi_kotlin_adapter_version" - ], - okhttp : "com.squareup.okhttp3:okhttp:$okhttp_version", - okhttpLogging : "com.squareup.okhttp3:logging-interceptor:$okhttp_logging_version", - parcelize : "org.jetbrains.kotlin:kotlin-parcelize-runtime:$kotlin_version", - retrofit : [ - "com.squareup.retrofit2:retrofit:$retrofit2_version", - "com.squareup.retrofit2:converter-moshi:$retrofit2_version" - ], - twint : "ch.twint.payment.sdk:android-sdk:$twint_version", - wechat : "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:$wechat_pay_version" - ] - - testLibraries = [ - androidTest : [ - "androidx.test:rules:$test_rules_version", - "androidx.test.ext:junit-ktx:$test_ext_version", - "androidx.test.uiautomator:uiautomator:$uiautomator_version" - ], - androidx : [ - lifecycle: "androidx.arch.core:core-testing:$arch_core_testing_version" - ], - barista : "com.adevinta.android:barista:$barista_version", - espresso : [ - "androidx.test.espresso:espresso-contrib:$espresso_version", - "androidx.test.espresso:espresso-core:$espresso_version", - "androidx.test.espresso:espresso-intents:$espresso_version" - ], - hilt : "com.google.dagger:hilt-android-testing:$hilt_version", - hiltCompiler : "com.google.dagger:hilt-android-compiler:$hilt_version", - jose4j : "org.bitbucket.b_c:jose4j:$jose4j_version", - json : "org.json:json:$json_version", - junit5 : [ - "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version", - "org.junit.jupiter:junit-jupiter-engine:$junit_jupiter_version", - "org.junit.jupiter:junit-jupiter-params:$junit_jupiter_version", - "org.junit.vintage:junit-vintage-engine:$junit_jupiter_version", - ], - konsist : "com.lemonappdev:konsist:$konsist_version", - kotlinCoroutines: [ - "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version", - "app.cash.turbine:turbine:$turbine_version" - ], - lint : "com.android.tools.lint:lint:$lint_version", - lintApi : "com.android.tools.lint:lint-api:$lint_version", - lintTests : "com.android.tools.lint:lint-tests:$lint_version", - mockito : [ - "org.mockito:mockito-junit-jupiter:$mockito_version", - "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" - ], - mockitoAndroid : [ - "org.mockito:mockito-android:$mockito_version", - "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" - ], - mockWebServer : "com.squareup.okhttp3:mockwebserver:$okhttp_version", - robolectric : "org.robolectric:robolectric:$robolectric_version" - ] -} diff --git a/dotpay/build.gradle b/dotpay/build.gradle index dd4376d7dc..5c156c8495 100644 --- a/dotpay/build.gradle +++ b/dotpay/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.dotpay' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -38,9 +38,9 @@ dependencies { api project(':issuer-list') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests - testImplementation testLibraries.junit5 + testImplementation libs.bundles.junit } diff --git a/drop-in-compose/build.gradle b/drop-in-compose/build.gradle index b6d9386957..ccc7432407 100644 --- a/drop-in-compose/build.gradle +++ b/drop-in-compose/build.gradle @@ -7,8 +7,8 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android } // Maven artifact @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.dropin.compose' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -35,7 +35,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion = compose_compiler_version + kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() } } @@ -43,6 +43,6 @@ dependencies { // Checkout api project(':drop-in') - implementation platform(libraries.compose.bom) - implementation libraries.compose.activity + implementation platform(libs.compose.bom) + implementation libs.compose.activity } diff --git a/drop-in/build.gradle b/drop-in/build.gradle index 293e17728a..02829d7f4e 100644 --- a/drop-in/build.gradle +++ b/drop-in/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.dropin' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -80,15 +80,15 @@ dependencies { api project(':wechatpay') // Dependencies - implementation libraries.androidx.recyclerview - implementation libraries.material + implementation libs.androidx.recyclerview + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) - testImplementation testLibraries.androidx.lifecycle - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.androidx.test.lifecycle + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/econtext/build.gradle b/econtext/build.gradle index 732b2f8441..a6d04d84f9 100644 --- a/econtext/build.gradle +++ b/econtext/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.econtext' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -43,7 +43,7 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation project(':3ds2') @@ -52,7 +52,7 @@ dependencies { testImplementation project(':wechatpay') testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/entercash/build.gradle b/entercash/build.gradle index c794d5f23a..21de4fbcf9 100644 --- a/entercash/build.gradle +++ b/entercash/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.entercash' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -38,9 +38,9 @@ dependencies { api project(':issuer-list') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests - testImplementation testLibraries.junit5 + testImplementation libs.bundles.junit } diff --git a/eps/build.gradle b/eps/build.gradle index e9a92f9234..8dddf52b40 100644 --- a/eps/build.gradle +++ b/eps/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.eps' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -38,9 +38,9 @@ dependencies { api project(':issuer-list') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests - testImplementation testLibraries.junit5 + testImplementation libs.bundles.junit } diff --git a/example-app/build.gradle b/example-app/build.gradle index 2a4897b808..b0492f1442 100644 --- a/example-app/build.gradle +++ b/example-app/build.gradle @@ -7,10 +7,10 @@ */ plugins { - id 'com.android.application' - id 'kotlin-android' - id 'com.google.devtools.ksp' - id 'dagger.hilt.android.plugin' + alias libs.plugins.android.application + alias libs.plugins.kotlin.android + alias libs.plugins.ksp + alias libs.plugins.hilt } apply from: "${rootDir}/config/gradle/codeQuality.gradle" @@ -31,16 +31,16 @@ def isIDEBuild() { } android { - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { applicationId "com.adyen.checkout.example" namespace "com.adyen.checkout.example" - minSdk min_sdk_version - targetSdk target_sdk_version - versionCode version_code - versionName version_name + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() + versionCode libs.versions.version.code.get().toInteger() + versionName libs.versions.version.name.get() testInstrumentationRunner 'com.adyen.checkout.test.HiltTestRunner' } @@ -63,7 +63,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion = compose_compiler_version + kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() } } @@ -75,47 +75,47 @@ dependencies { // implementation "com.adyen.checkout:components-compose:5.7.0" // Dependencies - implementation libraries.kotlinCoroutines + implementation libs.bundles.kotlin.coroutines - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview - implementation libraries.androidx.constraintlayout - implementation libraries.androidx.preference + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview + implementation libs.androidx.constraintlayout + implementation libs.androidx.preference - implementation platform(libraries.compose.bom) - implementation libraries.compose.ui - implementation libraries.compose.activity - implementation libraries.compose.hilt - implementation libraries.compose.material - implementation libraries.compose.viewmodel + implementation platform(libs.compose.bom) + implementation libs.bundles.compose.ui + implementation libs.compose.activity + implementation libs.compose.hilt + implementation libs.compose.material + implementation libs.compose.viewmodel - implementation libraries.material + implementation libs.material - implementation libraries.retrofit - implementation libraries.moshi - implementation libraries.okhttpLogging + implementation libs.bundles.retrofit + implementation libs.bundles.moshi + implementation libs.okhttp.logging - implementation libraries.hilt - ksp libraries.hiltCompiler + implementation libs.hilt + ksp libs.hilt.compiler - implementation libraries.googlePay.composeButton + implementation libs.google.pay.compose.button - debugImplementation libraries.leakCanary - debugImplementation 'androidx.compose.ui:ui-tooling' - debugImplementation 'androidx.compose.ui:ui-test-manifest' + debugImplementation libs.leak.canary + debugImplementation libs.compose.ui.tooling + debugImplementation libs.compose.ui.test.manifest // Tests - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.konsist + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.konsist - androidTestImplementation testLibraries.androidTest - androidTestImplementation testLibraries.barista - androidTestImplementation testLibraries.espresso - androidTestImplementation testLibraries.hilt - androidTestImplementation testLibraries.kotlinCoroutines - androidTestImplementation testLibraries.mockWebServer + androidTestImplementation libs.bundles.androidx.test + androidTestImplementation libs.barista + androidTestImplementation libs.bundles.espresso + androidTestImplementation libs.hilt.test + androidTestImplementation libs.bundles.kotlin.coroutines.test + androidTestImplementation libs.mock.web.server - kspAndroidTest testLibraries.hiltCompiler + kspAndroidTest libs.hilt.compiler.test } diff --git a/giftcard/build.gradle b/giftcard/build.gradle index 43aec15b48..35b2f76d31 100644 --- a/giftcard/build.gradle +++ b/giftcard/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "giftcard" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.giftcard' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -47,14 +47,14 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':cse')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/googlepay/build.gradle b/googlepay/build.gradle index a00b361b4a..ecd8f4e789 100644 --- a/googlepay/build.gradle +++ b/googlepay/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.googlepay' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -40,15 +40,15 @@ dependencies { api project(':sessions-core') // Dependencies - api libraries.googlePay.playServicesWallet + api libs.google.pay.play.services.wallet //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':action-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000..342b5e7584 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,189 @@ +[versions] +# SDK +compile-sdk = "34" +target-sdk = "34" +min-sdk = "21" + +# App version, only used for example app, no need to increment +version-code = "1" +# The version-name format is "major.minor.patch(-(alpha|beta|rc)[0-9]{2}){0,1}" (e.g. 3.0.0, 3.1.1-alpha04 or 3.1.4-rc01 etc). +version-name = "5.7.0" + +# Build script +android-gradle-plugin = "8.5.1" +kotlin = "1.9.24" +ksp = "1.9.24-1.0.20" +dokka = "1.9.20" +hilt = "2.52" +compose-compiler = "1.5.14" + +# Code quality +detekt = "1.23.7" +jacoco = "0.8.12" +ktlint = "1.3.1" +sonarqube = "5.0.0.4638" +binary-compatibility-validator = "0.16.0" + +# Android dependencies +activity = "1.9.2" +annotation = "1.8.0" +appcompat = "1.7.0" +autofill = "1.3.0-alpha01" +browser = "1.8.0" +coroutines = "1.8.1" +fragment = "1.8.3" +lifecycle = "2.8.3" +material = "1.12.0" +recyclerview = "1.3.2" +constraintlayout = "2.1.4" + +# Compose dependencies +compose-activity = "1.9.2" +compose-bom = "2024.06.00" +compose-hilt = "1.2.0" +compose-viewmodel = "2.8.3" + +# Adyen dependencies +adyen3ds2 = "2.2.20" + +# External dependencies +cash-app-pay = "2.5.0" +google-pay-compose-button = "1.0.0" +okhttp = "4.12.0" +play-services-wallet = "19.4.0" +twint = "8.0.0" +wechat-pay = "6.8.0" + +# Example app +leak-canary = "2.14" +moshi-adapters = "1.15.1" +moshi-kotlin-adapter = "1.15.1" +okhttp-logging = "4.12.0" +preference = "1.2.1" +retrofit2 = "2.11.0" + +# Tests +arch-core-testing = "2.2.0" +barista = "4.3.0" +espresso = "3.6.1" +json = "20240303" +jose4j = "0.9.6" +junit-jupiter = "5.11.1" +konsist = "0.16.1" +lint = "31.7.0" +mockito-kotlin = "5.4.0" +mockito = "5.12.0" +robolectric = "4.13" +test-ext = "1.2.1" +test-rules = "1.6.1" +turbine = "1.1.0" +uiautomator = "2.3.0" + +[libraries] + +# Production libraries +adyen3ds2 = { group = "com.adyen.threeds", name = "adyen-3ds2", version.ref = "adyen3ds2" } +androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } +androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +androidx-autofill = { group = "androidx.autofill", name = "autofill", version.ref = "autofill" } +androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "browser" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } +androidx-fragment = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragment" } +androidx-lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } +androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" } +androidx-preference = { group = "androidx.preference", name = "preference-ktx", version.ref = "preference" } +androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" } +cash-app-pay = { group = "app.cash.paykit", name = "core", version.ref = "cash-app-pay" } +compose-activity = { group = "androidx.activity", name = "activity-compose", version.ref = "compose-activity" } +compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } +compose-hilt = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "compose-hilt" } +compose-material = { group = "androidx.compose.material3", name = "material3" } +compose-ui-main = { group = "androidx.compose.ui", name = "ui" } +compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +compose-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "compose-viewmodel" } +google-pay-compose-button = { group = "com.google.pay.button", name = "compose-pay-button", version.ref = "google-pay-compose-button" } +google-pay-play-services-wallet = { group = "com.google.android.gms", name = "play-services-wallet", version.ref = "play-services-wallet" } +hilt = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } +hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" } +kotlin-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" } +kotlin-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" } +leak-canary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "leak-canary" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +moshi-adapters = { group = "com.squareup.moshi", name = "moshi-adapters", version.ref = "moshi-adapters" } +moshi-kotlin = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "moshi-kotlin-adapter" } +okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp-logging" } +parcelize = { group = "org.jetbrains.kotlin", name = "kotlin-parcelize-runtime", version.ref = "kotlin" } +retrofit-main = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit2" } +retrofit-converter-moshi = { group = "com.squareup.retrofit2", name = "converter-moshi", version.ref = "retrofit2" } +wechat = { group = "com.tencent.mm.opensdk", name = "wechat-sdk-android-without-mta", version.ref = "wechat-pay" } +detekt = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } +ktlint-cli = { group = "com.pinterest.ktlint", name = "ktlint-cli", version.ref = "ktlint" } +twint = { group = "ch.twint.payment.sdk", name = "android-sdk", version.ref = "twint" } + +# Test libraries +androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "test-rules" } +androidx-test-junit-ktx = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "test-ext" } +androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" } +androidx-test-lifecycle = { group = "androidx.arch.core", name = "core-testing", version.ref = "arch-core-testing" } +barista = { group = "com.adevinta.android", name = "barista", version.ref = "barista" } +espresso-contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "espresso" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" } +espresso-intents = { group = "androidx.test.espresso", name = "espresso-intents", version.ref = "espresso" } +hilt-test = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" } +hilt-compiler-test = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" } +jose4j = { group = "org.bitbucket.b_c", name = "jose4j", version.ref = "jose4j" } +json = { group = "org.json", name = "json", version.ref = "json" } +junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter" } +junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter" } +junit-jupiter-params = { group = "org.junit.jupiter", name = "junit-jupiter-params", version.ref = "junit-jupiter" } +junit-vintage-engine = { group = "org.junit.vintage", name = "junit-vintage-engine", version.ref = "junit-jupiter" } +konsist = { group = "com.lemonappdev", name = "konsist", version.ref = "konsist" } +kotlinx-test-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" } +cash-app-turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine" } +lint = { group = "com.android.tools.lint", name = "lint", version.ref = "lint" } +lint-api = { group = "com.android.tools.lint", name = "lint-api", version.ref = "lint" } +lint-tests = { group = "com.android.tools.lint", name = "lint-tests", version.ref = "lint" } +mockito-junit-jupiter = { group = "org.mockito", name = "mockito-junit-jupiter", version.ref = "mockito" } +mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } +mockito-android-main = { group = "org.mockito", name = "mockito-android", version.ref = "mockito" } +mock-web-server = { group = "com.squareup.okhttp3", name = "mockwebserver", version.ref = "okhttp" } +robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" } + +[bundles] + +# Production bundles +androidx-lifecycle = ["androidx-lifecycle-runtime", "androidx-lifecycle-viewmodel-ktx"] +compose-ui = ["compose-ui-main", "compose-ui-graphics", "compose-ui-tooling-preview"] +kotlin-coroutines = ["kotlin-coroutines-core", "kotlin-coroutines-android"] +moshi = ["moshi-adapters", "moshi-kotlin"] +retrofit = ["retrofit-main", "retrofit-converter-moshi"] + +# Test bundles +androidx-test = ["androidx-test-rules", "androidx-test-junit-ktx", "androidx-test-uiautomator"] +espresso = ["espresso-contrib", "espresso-core", "espresso-intents"] +junit = ["junit-jupiter-api", "junit-jupiter-engine", "junit-jupiter-params", "junit-vintage-engine"] +kotlin-coroutines-test = ["kotlinx-test-coroutines", "cash-app-turbine"] +mockito = ["mockito-junit-jupiter", "mockito-kotlin"] +mockito-android = ["mockito-android-main", "mockito-kotlin"] + +[plugins] +android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } +android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } +kotlin = { id = "kotlin" } +kotlin-android = { id = "kotlin-android" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } +kotlin-parcelize = { id = "kotlin-parcelize" } +jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" } +jacoco = { id = "jacoco" } +binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } + + diff --git a/ideal/build.gradle b/ideal/build.gradle index 437407889b..e838d0b77c 100644 --- a/ideal/build.gradle +++ b/ideal/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.ideal' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -38,14 +38,14 @@ dependencies { api project(':issuer-list') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/instant/build.gradle b/instant/build.gradle index 409beb93b7..93582e131b 100644 --- a/instant/build.gradle +++ b/instant/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -13,11 +13,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.instant' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -33,13 +33,13 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/issuer-list/build.gradle b/issuer-list/build.gradle index da4d191bf4..fa3fe1fcf6 100644 --- a/issuer-list/build.gradle +++ b/issuer-list/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.issuerlist' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -43,8 +43,8 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests testImplementation project(':3ds2') @@ -53,7 +53,7 @@ dependencies { testImplementation project(':wechatpay') testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/lint/build.gradle b/lint/build.gradle index d82d0023db..478ebc79a9 100644 --- a/lint/build.gradle +++ b/lint/build.gradle @@ -7,7 +7,7 @@ */ plugins { - id 'kotlin' + alias libs.plugins.kotlin } java { @@ -20,11 +20,11 @@ kotlin { } dependencies { - compileOnly testLibraries.lintApi + compileOnly libs.lint.api - testImplementation testLibraries.junit5 - testImplementation testLibraries.lint - testImplementation testLibraries.lintTests + testImplementation libs.bundles.junit + testImplementation libs.lint + testImplementation libs.lint.tests } jar { diff --git a/mbway/build.gradle b/mbway/build.gradle index a13216c40e..2bc16bdc5e 100644 --- a/mbway/build.gradle +++ b/mbway/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "mbway" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.mbway' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -42,13 +42,13 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/meal-voucher-fr/build.gradle b/meal-voucher-fr/build.gradle index dcdce4b80c..2862605b79 100644 --- a/meal-voucher-fr/build.gradle +++ b/meal-voucher-fr/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "meal-voucher-fr" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.mealvoucherfr' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -47,7 +47,7 @@ dependencies { testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/molpay/build.gradle b/molpay/build.gradle index 70ff6332be..b935fb7bd4 100644 --- a/molpay/build.gradle +++ b/molpay/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.molpay' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -38,9 +38,9 @@ dependencies { api project(':issuer-list') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests - testImplementation testLibraries.junit5 + testImplementation libs.bundles.junit } diff --git a/online-banking-core/build.gradle b/online-banking-core/build.gradle index a9fa18f9a6..0ff5e4cbdc 100644 --- a/online-banking-core/build.gradle +++ b/online-banking-core/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "online-banking-core" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.onlinebankingcore' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -42,17 +42,17 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview - implementation libraries.material - implementation libraries.androidx.browser + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview + implementation libs.material + implementation libs.androidx.browser //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/online-banking-cz/build.gradle b/online-banking-cz/build.gradle index 888b7b47f1..073afa8b7e 100644 --- a/online-banking-cz/build.gradle +++ b/online-banking-cz/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "online-banking-cz" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.onlinebankingcz' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -36,6 +36,6 @@ dependencies { api project(':action-core') api project(':online-banking-core') - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito } diff --git a/online-banking-jp/build.gradle b/online-banking-jp/build.gradle index 1ba2949c95..ca2516b26f 100644 --- a/online-banking-jp/build.gradle +++ b/online-banking-jp/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -13,11 +13,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.onlinebankingjp' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -31,6 +31,6 @@ android { dependencies { api project(':econtext') - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito } diff --git a/online-banking-pl/build.gradle b/online-banking-pl/build.gradle index 716b7ede01..b0c1350a69 100644 --- a/online-banking-pl/build.gradle +++ b/online-banking-pl/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "online-banking-pl" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.onlinebankingpl' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -37,9 +37,9 @@ dependencies { api project(':issuer-list') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests - testImplementation testLibraries.junit5 + testImplementation libs.bundles.junit } diff --git a/online-banking-sk/build.gradle b/online-banking-sk/build.gradle index 2f755d3e8b..e005e381a8 100644 --- a/online-banking-sk/build.gradle +++ b/online-banking-sk/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "online-banking-sk" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.onlinebankingsk' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -36,6 +36,6 @@ dependencies { api project(':action-core') api project(':online-banking-core') - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito } diff --git a/openbanking/build.gradle b/openbanking/build.gradle index f0dc2b4e04..b7ad88e42a 100644 --- a/openbanking/build.gradle +++ b/openbanking/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.openbanking' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -38,9 +38,9 @@ dependencies { api project(':issuer-list') // Dependencies - implementation libraries.androidx.appcompat - implementation libraries.androidx.recyclerview + implementation libs.androidx.appcompat + implementation libs.androidx.recyclerview //Tests - testImplementation testLibraries.junit5 + testImplementation libs.bundles.junit } diff --git a/paybybank/build.gradle b/paybybank/build.gradle index f9eec2e72c..e39bd2fd84 100644 --- a/paybybank/build.gradle +++ b/paybybank/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -13,11 +13,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.paybybank' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -36,13 +36,13 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/payeasy/build.gradle b/payeasy/build.gradle index 0e7fdea793..5b436e35c6 100644 --- a/payeasy/build.gradle +++ b/payeasy/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -13,11 +13,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.payeasy' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -31,6 +31,6 @@ android { dependencies { api project(':econtext') - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito } diff --git a/qr-code/build.gradle b/qr-code/build.gradle index 1ac3804f31..f7ca3fd1f1 100644 --- a/qr-code/build.gradle +++ b/qr-code/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "qr-code" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.qrcode' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -44,14 +44,14 @@ dependencies { api project(':ui-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/redirect/build.gradle b/redirect/build.gradle index 3dc705ed90..7a72b97a60 100644 --- a/redirect/build.gradle +++ b/redirect/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.redirect' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -47,8 +47,8 @@ dependencies { testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/sepa/build.gradle b/sepa/build.gradle index 820dea5ca0..fd76c289d3 100644 --- a/sepa/build.gradle +++ b/sepa/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.sepa' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -47,13 +47,13 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/sessions-core/build.gradle b/sessions-core/build.gradle index 8b4a64e7fb..e0d2ad81e7 100644 --- a/sessions-core/build.gradle +++ b/sessions-core/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "sessions-core" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.sessions.core' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -35,14 +35,11 @@ dependencies { // Checkout api project(':components-core') - // Dependencies - api libraries.kotlinCoroutines - //Tests testImplementation testFixtures(project(':test-core')) - testImplementation testLibraries.androidx.lifecycle - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito - testImplementation testLibraries.robolectric + testImplementation libs.androidx.test.lifecycle + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito + testImplementation libs.robolectric } diff --git a/settings.gradle b/settings.gradle index 05d6c3e282..2956b9a7a4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,7 @@ pluginManagement { } plugins { + // this has to be declared here directly because settings.gradle cannot reference version catalogs id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } diff --git a/seven-eleven/build.gradle b/seven-eleven/build.gradle index ba39c6a106..c105ae979e 100644 --- a/seven-eleven/build.gradle +++ b/seven-eleven/build.gradle @@ -1,7 +1,7 @@ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -13,11 +13,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.seveneleven' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -31,6 +31,6 @@ android { dependencies { api project(':econtext') - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito } diff --git a/test-core/build.gradle b/test-core/build.gradle index 178abed755..9c47be7123 100644 --- a/test-core/build.gradle +++ b/test-core/build.gradle @@ -7,19 +7,19 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android } apply from: "${rootDir}/config/gradle/codeQuality.gradle" android { namespace 'com.adyen.checkout.test' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -32,9 +32,9 @@ android { dependencies { testFixturesImplementation project(':checkout-core') - testFixturesImplementation libraries.androidx.lifecycle - testFixturesImplementation testLibraries.junit5 - testFixturesImplementation testLibraries.kotlinCoroutines + testFixturesImplementation libs.bundles.androidx.lifecycle + testFixturesImplementation libs.bundles.junit + testFixturesImplementation libs.bundles.kotlin.coroutines.test } // Disable test tasks, because this module only contains test utils. diff --git a/twint-action/build.gradle b/twint-action/build.gradle index 2c9309373c..9891e4ad78 100644 --- a/twint-action/build.gradle +++ b/twint-action/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "twint-action" @@ -20,13 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.twint.action' - compileSdkVersion compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode version_code - versionName version_name + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -42,14 +40,14 @@ dependencies { api project(':ui-core') // Dependencies - implementation libraries.twint + implementation libs.twint //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/twint/build.gradle b/twint/build.gradle index 7169456782..00dcd4742b 100644 --- a/twint/build.gradle +++ b/twint/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "twint" @@ -20,13 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.twint' - compileSdkVersion compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode version_code - versionName version_name + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -49,8 +47,8 @@ dependencies { testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/ui-core/build.gradle b/ui-core/build.gradle index 7208adf1ba..1a1b20d91c 100644 --- a/ui-core/build.gradle +++ b/ui-core/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.ui.core' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -45,18 +45,18 @@ dependencies { api project(':components-core') // Dependencies - implementation libraries.androidx.appcompat - api libraries.androidx.autofill - api libraries.androidx.constraintlayout - implementation libraries.androidx.recyclerview - api libraries.material - implementation libraries.androidx.browser + implementation libs.androidx.appcompat + api libs.androidx.autofill + api libs.androidx.constraintlayout + implementation libs.androidx.recyclerview + api libs.material + implementation libs.androidx.browser //Tests - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.robolectric - testImplementation testLibraries.mockito + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.robolectric + testImplementation libs.bundles.mockito } diff --git a/upi/build.gradle b/upi/build.gradle index d6c8943999..6292559afc 100644 --- a/upi/build.gradle +++ b/upi/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "upi" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.upi' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -42,13 +42,13 @@ dependencies { api project(':sessions-core') // Dependencies - implementation libraries.material + implementation libs.material //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.junit5 - testImplementation testLibraries.kotlinCoroutines - testImplementation testLibraries.mockito + testImplementation libs.bundles.junit + testImplementation libs.bundles.kotlin.coroutines.test + testImplementation libs.bundles.mockito } diff --git a/voucher/build.gradle b/voucher/build.gradle index 9e54bc5de6..65a102b761 100644 --- a/voucher/build.gradle +++ b/voucher/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } // Maven artifact @@ -21,11 +21,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.voucher' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -45,13 +45,13 @@ dependencies { api project(':ui-core') // Dependencies - implementation libraries.androidx.browser + implementation libs.androidx.browser //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } diff --git a/wechatpay/build.gradle b/wechatpay/build.gradle index 7452afd523..f1d00f53de 100644 --- a/wechatpay/build.gradle +++ b/wechatpay/build.gradle @@ -7,9 +7,9 @@ */ plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-parcelize' + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize } ext.mavenArtifactId = "wechatpay" @@ -20,11 +20,11 @@ apply from: "${rootDir}/config/gradle/sharedTasks.gradle" android { namespace 'com.adyen.checkout.wechatpay' - compileSdk compile_sdk_version + compileSdk libs.versions.compile.sdk.get().toInteger() defaultConfig { - minSdk min_sdk_version - targetSdk target_sdk_version + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles "consumer-rules.pro" @@ -40,14 +40,14 @@ dependencies { api project(':ui-core') // Dependencies - implementation libraries.wechat + implementation libs.wechat //Tests testImplementation testFixtures(project(':test-core')) testImplementation testFixtures(project(':components-core')) testImplementation testFixtures(project(':ui-core')) - testImplementation testLibraries.json - testImplementation testLibraries.junit5 - testImplementation testLibraries.mockito - testImplementation testLibraries.kotlinCoroutines + testImplementation libs.json + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test } From df3f8e46ab6d4d7ecc3b7b2d349443f4367e4b27 Mon Sep 17 00:00:00 2001 From: josephj Date: Tue, 15 Oct 2024 11:16:51 +0200 Subject: [PATCH 002/102] Explicitly declare compose compiler in libraries in libs.versions.toml Renovate cannot update this dependency unless it is explicitly declared in [libraries] as well even though it will be an unused entry. More info in: https://github.com/renovatebot/renovate/issues/18354 --- gradle/libs.versions.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 342b5e7584..255cf4d8ec 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -105,6 +105,8 @@ compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } compose-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "compose-viewmodel" } +# this unused dependency is needed so that renovate can update the compose compiler version. More info in: https://github.com/renovatebot/renovate/issues/18354 +compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compose-compiler" } google-pay-compose-button = { group = "com.google.pay.button", name = "compose-pay-button", version.ref = "google-pay-compose-button" } google-pay-play-services-wallet = { group = "com.google.android.gms", name = "play-services-wallet", version.ref = "play-services-wallet" } hilt = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } From c107a46c7ce27074f2ac80e9a844bd4f67b25ed8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:07:47 +0000 Subject: [PATCH 003/102] Update Kotlin --- gradle/libs.versions.toml | 10 +- gradle/verification-metadata.xml | 341 +++++++++++++++++++++++++++++++ 2 files changed, 346 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 255cf4d8ec..f616f416f2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,18 +11,18 @@ version-name = "5.7.0" # Build script android-gradle-plugin = "8.5.1" -kotlin = "1.9.24" -ksp = "1.9.24-1.0.20" +kotlin = "1.9.25" +ksp = "1.9.25-1.0.20" dokka = "1.9.20" hilt = "2.52" -compose-compiler = "1.5.14" +compose-compiler = "1.5.15" # Code quality detekt = "1.23.7" jacoco = "0.8.12" ktlint = "1.3.1" sonarqube = "5.0.0.4638" -binary-compatibility-validator = "0.16.0" +binary-compatibility-validator = "0.16.3" # Android dependencies activity = "1.9.2" @@ -30,7 +30,7 @@ annotation = "1.8.0" appcompat = "1.7.0" autofill = "1.3.0-alpha01" browser = "1.8.0" -coroutines = "1.8.1" +coroutines = "1.9.0" fragment = "1.8.3" lifecycle = "2.8.3" material = "1.12.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 868c7b76fa..fdb8946c57 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -770,6 +770,14 @@ + + + + + + + + @@ -8336,6 +8344,11 @@ + + + + + @@ -8352,6 +8365,14 @@ + + + + + + + + @@ -8376,6 +8397,14 @@ + + + + + + + + @@ -8392,6 +8421,14 @@ + + + + + + + + @@ -8408,6 +8445,14 @@ + + + + + + + + @@ -8424,6 +8469,14 @@ + + + + + + + + @@ -11994,6 +12047,14 @@ + + + + + + + + @@ -12018,6 +12079,14 @@ + + + + + + + + @@ -12073,6 +12142,14 @@ + + + + + + + + @@ -12097,6 +12174,14 @@ + + + + + + + + @@ -12121,6 +12206,14 @@ + + + + + + + + @@ -12153,6 +12246,14 @@ + + + + + + + + @@ -12193,6 +12294,14 @@ + + + + + + + + @@ -12217,6 +12326,14 @@ + + + + + + + + @@ -12249,6 +12366,14 @@ + + + + + + + + @@ -12289,6 +12414,14 @@ + + + + + + + + @@ -12313,6 +12446,14 @@ + + + + + + + + @@ -12337,6 +12478,14 @@ + + + + + + + + @@ -12361,6 +12510,14 @@ + + + + + + + + @@ -12385,6 +12542,14 @@ + + + + + + + + @@ -12409,6 +12574,14 @@ + + + + + + + + @@ -12433,6 +12606,14 @@ + + + + + + + + @@ -12457,6 +12638,14 @@ + + + + + + + + @@ -12481,6 +12670,14 @@ + + + + + + + + @@ -12513,6 +12710,14 @@ + + + + + + + + @@ -12537,6 +12742,14 @@ + + + + + + + + @@ -12561,6 +12774,14 @@ + + + + + + + + @@ -12585,6 +12806,14 @@ + + + + + + + + @@ -12694,6 +12923,14 @@ + + + + + + + + @@ -12734,6 +12971,14 @@ + + + + + + + + @@ -12758,6 +13003,14 @@ + + + + + + + + @@ -12782,6 +13035,14 @@ + + + + + + + + @@ -12806,6 +13067,14 @@ + + + + + + + + @@ -12895,7 +13164,21 @@ + + + + + + + + + + + + + + @@ -13004,6 +13287,16 @@ + + + + + + + + + + @@ -13234,6 +13527,14 @@ + + + + + + + + @@ -13258,6 +13559,14 @@ + + + + + + + + @@ -13282,6 +13591,14 @@ + + + + + + + + @@ -13297,6 +13614,11 @@ + + + + + @@ -13353,6 +13675,14 @@ + + + + + + + + @@ -13511,6 +13841,9 @@ + + + @@ -13609,6 +13942,9 @@ + + + @@ -13837,6 +14173,11 @@ + + + + + From 01804c615f596499283c93cbc22a916d5e211be8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:43:44 +0000 Subject: [PATCH 004/102] Update dependency gradle to v8.10.2 --- gradle/wrapper/gradle-wrapper.jar | Bin 43504 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 3990 zcmV;H4{7l5(*nQL0Kr1kzC=_KMxQY0|W5(lc#i zH*M1^P4B}|{x<+fkObwl)u#`$GxKKV&3pg*-y6R6txw)0qU|Clf9Uds3x{_-**c=7 z&*)~RHPM>Rw#Hi1R({;bX|7?J@w}DMF>dQQU2}9yj%iLjJ*KD6IEB2^n#gK7M~}6R zkH+)bc--JU^pV~7W=3{E*4|ZFpDpBa7;wh4_%;?XM-5ZgZNnVJ=vm!%a2CdQb?oTa z70>8rTb~M$5Tp!Se+4_OKWOB1LF+7gv~$$fGC95ToUM(I>vrd$>9|@h=O?eARj0MH zT4zo(M>`LWoYvE>pXvqG=d96D-4?VySz~=tPVNyD$XMshoTX(1ZLB5OU!I2OI{kb) zS8$B8Qm>wLT6diNnyJZC?yp{Kn67S{TCOt-!OonOK7$K)e-13U9GlnQXPAb&SJ0#3 z+vs~+4Qovv(%i8g$I#FCpCG^C4DdyQw3phJ(f#y*pvNDQCRZ~MvW<}fUs~PL=4??j zmhPyg<*I4RbTz|NHFE-DC7lf2=}-sGkE5e!RM%3ohM7_I^IF=?O{m*uUPH(V?gqyc(Rp?-Qu(3bBIL4Fz(v?=_Sh?LbK{nqZMD>#9D_hNhaV$0ef3@9V90|0u#|PUNTO>$F=qRhg1duaE z0`v~X3G{8RVT@kOa-pU+z8{JWyP6GF*u2e8eKr7a2t1fuqQy)@d|Qn(%YLZ62TWtoX@$nL}9?atE#Yw`rd(>cr0gY;dT9~^oL;u)zgHUvxc2I*b&ZkGM-iq=&(?kyO(3}=P! zRp=rErEyMT5UE9GjPHZ#T<`cnD)jyIL!8P{H@IU#`e8cAG5jMK zVyKw7--dAC;?-qEu*rMr$5@y535qZ6p(R#+fLA_)G~!wnT~~)|s`}&fA(s6xXN`9j zP#Fd3GBa#HeS{5&8p?%DKUyN^X9cYUc6vq}D_3xJ&d@=6j(6BZKPl?!k1?!`f3z&a zR4ZF60Mx7oBxLSxGuzA*Dy5n-d2K=+)6VMZh_0KetK|{e;E{8NJJ!)=_E~1uu=A=r zrn&gh)h*SFhsQJo!f+wKMIE;-EOaMSMB@aXRU(UcnJhZW^B^mgs|M9@5WF@s6B0p& zm#CTz)yiQCgURE{%hjxHcJ6G&>G9i`7MyftL!QQd5 z@RflRs?7)99?X`kHNt>W3l7YqscBpi*R2+fsgABor>KVOu(i(`03aytf2UA!&SC9v z!E}whj#^9~=XHMinFZ;6UOJjo=mmNaWkv~nC=qH9$s-8roGeyaW-E~SzZ3Gg>j zZ8}<320rg4=$`M0nxN!w(PtHUjeeU?MvYgWKZ6kkzABK;vMN0|U;X9abJleJA(xy<}5h5P(5 z{RzAFPvMnX2m0yH0Jn2Uo-p`daE|(O`YQiC#jB8;6bVIUf?SY(k$#C0`d6qT`>Xe0+0}Oj0=F&*D;PVe=Z<=0AGI<6$gYLwa#r` zm449x*fU;_+J>Mz!wa;T-wldoBB%&OEMJgtm#oaI60TSYCy7;+$5?q!zi5K`u66Wq zvg)Fx$s`V3Em{=OEY{3lmh_7|08ykS&U9w!kp@Ctuzqe1JFOGz6%i5}Kmm9>^=gih z?kRxqLA<3@e=}G4R_?phW{4DVr?`tPfyZSN@R=^;P;?!2bh~F1I|fB7P=V=9a6XU5 z<#0f>RS0O&rhc&nTRFOW7&QhevP0#>j0eq<1@D5yAlgMl5n&O9X|Vq}%RX}iNyRFF z7sX&u#6?E~bm~N|z&YikXC=I0E*8Z$v7PtWfjy)$e_Ez25fnR1Q=q1`;U!~U>|&YS zaOS8y!^ORmr2L4ik!IYR8@Dcx8MTC=(b4P6iE5CnrbI~7j7DmM8em$!da&D!6Xu)!vKPdLG z9f#)se|6=5yOCe)N6xDhPI!m81*dNe7u985zi%IVfOfJh69+#ag4ELzGne?o`eA`42K4T)h3S+s)5IT97%O>du- z0U54L8m4}rkRQ?QBfJ%DLssy^+a7Ajw;0&`NOTY4o;0-ivm9 zBz1C%nr_hQ)X)^QM6T1?=yeLkuG9Lf50(eH}`tFye;01&(p?8i+6h};VV-2B~qdxeC#=X z(JLlzy&fHkyi9Ksbcs~&r^%lh^2COldLz^H@X!s~mr9Dr6z!j+4?zkD@Ls7F8(t(f z9`U?P$Lmn*Y{K}aR4N&1N=?xtQ1%jqf1~pJyQ4SgBrEtR`j4lQuh7cqP49Em5cO=I zB(He2`iPN5M=Y0}h(IU$37ANTGx&|b-u1BYA*#dE(L-lptoOpo&th~E)_)y-`6kSH z3vvyVrcBwW^_XYReJ=JYd9OBQrzv;f2AQdZH#$Y{Y+Oa33M70XFI((fs;mB4e`<<{ ze4dv2B0V_?Ytsi>>g%qs*}oDGd5d(RNZ*6?7qNbdp7wP4T72=F&r?Ud#kZr8Ze5tB z_oNb7{G+(o2ajL$!69FW@jjPQ2a5C)m!MKKRirC$_VYIuVQCpf9rIms0GRDf)8AH${I`q^~5rjot@#3$2#zT2f`(N^P7Z;6(@EK$q*Jgif00I6*^ZGV+XB5uw*1R-@23yTw&WKD{s1;HTL;dO)%5i#`dc6b7;5@^{KU%N|A-$zsYw4)7LA{3`Zp>1 z-?K9_IE&z)dayUM)wd8K^29m-l$lFhi$zj0l!u~4;VGR6Y!?MAfBC^?QD53hy6VdD z@eUZIui}~L%#SmajaRq1J|#> z4m=o$vZ*34=ZWK2!QMNEcp2Lbc5N1q!lEDq(bz0b;WI9;e>l=CG9^n#ro`w>_0F$Q zfZ={2QyTkfByC&gy;x!r*NyXXbk=a%~~(#K?< zTke0HuF5{Q+~?@!KDXR|g+43$+;ab`^flS%miup_0OUTm=nIc%d5nLP)i308PIjl_YMF6cpQ__6&$n6it8K- z8PIjl_YMF6cpQ_!r)L8IivW`WdK8mBs6PXdjR2DYdK8nCs73=4j{uVadK8oNjwX|E wpAeHLsTu^*Y>Trk?aBtSQ(D-o$(D8Px^?ZI-PUB? z*1fv!{YdHme3Fc8%cR@*@zc5A_nq&2=R47Hp@$-JF4Fz*;SLw5}K^y>s-s;V!}b2i=5=M- zComP?ju>8Fe@=H@rlwe1l`J*6BTTo`9b$zjQ@HxrAhp0D#u?M~TxGC_!?ccCHCjt| zF*PgJf@kJB`|Ml}cmsyrAjO#Kjr^E5p29w+#>$C`Q|54BoDv$fQ9D?3n32P9LPMIzu?LjNqggOH=1@T{9bMn*u8(GI z!;MLTtFPHal^S>VcJdiYqX0VU|Rn@A}C1xOlxCribxes0~+n2 z6qDaIA2$?e`opx3_KW!rAgbpzU)gFdjAKXh|5w``#F0R|c)Y)Du0_Ihhz^S?k^pk% zP>9|pIDx)xHH^_~+aA=^$M!<8K~Hy(71nJGf6`HnjtS=4X4=Hk^O71oNia2V{HUCC zoN3RSBS?mZCLw;l4W4a+D8qc)XJS`pUJ5X-f^1ytxwr`@si$lAE?{4G|o; zO0l>`rr?;~c;{ZEFJ!!3=7=FdGJ?Q^xfNQh4A?i;IJ4}B+A?4olTK(fN++3CRBP97 ze~lG9h%oegkn)lpW-4F8o2`*WW0mZHwHez`ko@>U1_;EC_6ig|Drn@=DMV9YEUSCa zIf$kHei3(u#zm9I!Jf(4t`Vm1lltJ&lVHy(eIXE8sy9sUpmz%I_gA#8x^Zv8%w?r2 z{GdkX1SkzRIr>prRK@rqn9j2wG|rUvf6PJbbin=yy-TAXrguvzN8jL$hUrIXzr^s5 zVM?H4;eM-QeRFr06@ifV(ocvk?_)~N@1c2ien56UjWXid6W%6ievIh)>dk|rIs##^kY67ib8Kw%#-oVFaXG7$ERyA9(NSJUvWiOA5H(!{uOpcW zg&-?iqPhds%3%tFspHDqqr;A!e@B#iPQjHd=c>N1LoOEGRehVoPOdxJ>b6>yc#o#+ zl8s8!(|NMeqjsy@0x{8^j0d00SqRZjp{Kj)&4UHYGxG+z9b-)72I*&J70?+8e?p_@ z=>-(>l6z5vYlP~<2%DU02b!mA{7mS)NS_eLe=t)sm&+Pmk?asOEKlkPQ)EUvvfC=;4M&*|I!w}(@V_)eUKLA_t^%`o z0PM9LV|UKTLnk|?M3u!|f2S0?UqZsEIH9*NJS-8lzu;A6-rr-ot=dg9SASoluZUkFH$7X; zP=?kYX!K?JL-b~<#7wU;b;eS)O;@?h%sPPk{4xEBxb{!sm0AY|f9cNvx6>$3F!*0c z75H=dy8JvTyO8}g1w{$9T$p~5en}AeSLoCF>_RT9YPMpChUjl310o*$QocjbH& zbnwg#gssR#jDVN{uEi3n(PZ%PFZ|6J2 z5_rBf0-u>e4sFe0*Km49ATi7>Kn0f9!uc|rRMR1Dtt6m1LW8^>qFlo}h$@br=Rmpi z;mI&>OF64Be{dVeHI8utrh)v^wsZ0jii%x8UgZ8TC%K~@I(4E};GFW&(;WVov}3%H zH;IhRkfD^(vt^DjZz(MyHLZxv8}qzPc(%itBkBwf_fC~sDBgh<3XAv5cxxfF3<2U! z03Xe&z`is!JDHbe;mNmfkH+_LFE*I2^mdL@7(@9DfAcP6O04V-ko;Rpgp<%Cj5r8Z zd0`sXoIjV$j)--;jA6Zy^D5&5v$o^>e%>Q?9GLm{i~p^lAn!%ZtF$I~>39XVZxk0b zROh^Bk9cE0AJBLozZIEmy7xG(yHWGztvfnr0(2ro1%>zsGMS^EMu+S$r=_;9 zWwZkgf7Q7`H9sLf2Go^Xy6&h~a&%s2_T@_Csf19MntF$aVFiFkvE3_hUg(B@&Xw@YJ zpL$wNYf78=0c@!QU6_a$>CPiXT7QAGDM}7Z(0z#_ZA=fmLUj{2z7@Ypo71UDy8GHr z-&TLKf6a5WCf@Adle3VglBt4>Z>;xF}}-S~B7<(%B;Y z0QR55{z-buw>8ilNM3u6I+D$S%?)(p>=eBx-HpvZj{7c*_?K=d()*7q?93us}1dq%FAFYLsW8ZTQ_XZLh`P2*6(NgS}qGcfGXVWpwsp#Rs}IuKbk*`2}&) zI^Vsk6S&Q4@oYS?dJ`NwMVBs6f57+RxdqVub#PvMu?$=^OJy5xEl0<5SLsSRy%%a0 zi}Y#1-F3m;Ieh#Y12UgW?-R)|eX>ZuF-2cc!1>~NS|XSF-6In>zBoZg+ml!6%fk7U zw0LHcz8VQk(jOJ+Yu)|^|15ufl$KQd_1eUZZzj`aC%umU6F1&D5XVWce_wAe(qCSZ zpX-QF4e{EmEVN9~6%bR5U*UT{eMHfcUo`jw*u?4r2s_$`}U{?NjvEm(u&<>B|%mq$Q3weshxk z76<``8vh{+nX`@9CB6IE&z)I%IFjR^LH{s1p|eppv=x za(g_jLU|xjWMAn-V7th$f({|LG8zzIE0g?cyW;%Dmtv%C+0@xVxPE^ zyZzi9P%JAD6ynwHptuzP`Kox7*9h7XSMonCalv;Md0i9Vb-c*!f0ubfk?&T&T}AHh z4m8Bz{JllKcdNg?D^%a5MFQ;#1z|*}H^qHLzW)L}wp?2tY7RejtSh8<;Zw)QGJYUm z|MbTxyj*McKlStlT9I5XlSWtQGN&-LTr2XyNU+`490rg?LYLMRnz-@oKqT1hpCGqP zyRXt4=_Woj$%n5ee<3zhLF>5>`?m9a#xQH+Jk_+|RM8Vi;2*XbK- zEL6sCpaGPzP>k8f4Kh|##_imt#zJMB;ir|JrMPGW`rityK1vHXMLy18%qmMQAm4WZ zP)i30KR&5vs15)C+8dM66&$k~i|ZT;KR&5vs15)C+8dJ(sAmGPijyIz6_bsqKLSFH zlOd=TljEpH0>h4zA*dCTK&emy#FCRCs1=i^sZ9bFmXjf<6_X39E(XY)00000#N437 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e54..df97d72b8b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 15808bb94cc72202eacbe0c61b60e8338f503d12 Mon Sep 17 00:00:00 2001 From: josephj Date: Tue, 15 Oct 2024 16:45:16 +0200 Subject: [PATCH 005/102] Uncomment 3DS2 tests that were previously failing because of obfuscation COAND-1011 --- .../ui/DefaultAdyen3DS2DelegateTest.kt | 26 +++++++------------ .../ui/SharedChallengeStatusHandlerTest.kt | 7 +++-- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt index 28421c3db9..3abea32cd7 100644 --- a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt +++ b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt @@ -189,8 +189,7 @@ internal class DefaultAdyen3DS2DelegateTest( assertTrue(exceptionFlow.latestValue is ComponentException) } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `3ds2 sdk throws an exception while initializing, then an exception emitted`() = runTest { val error = InvalidInputException("test", null) threeDS2Service.initializeError = error @@ -203,8 +202,7 @@ internal class DefaultAdyen3DS2DelegateTest( assertEquals(error, exceptionFlow.latestValue.cause) } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `3ds2 sdk returns an initialization error, then details are emitted`() = runTest { val transStatus = "X" val additionalDetails = "mockAdditionalDetails" @@ -357,8 +355,7 @@ internal class DefaultAdyen3DS2DelegateTest( transaction.assertDoChallengeCalled() } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `challenge fails, then an exception is emitted`() = runTest { initializeChallengeTransaction(this).apply { shouldThrowError = true @@ -418,8 +415,7 @@ internal class DefaultAdyen3DS2DelegateTest( @DisplayName("when transaction is") inner class TransactionTest { - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `completed, then details are emitted`() = runTest { val details = JSONObject("{\"threeds2.challengeResult\":\"eyJ0cmFuc1N0YXR1cyI6InRyYW5zYWN0aW9uU3RhdHVzIn0=\"}") @@ -438,8 +434,7 @@ internal class DefaultAdyen3DS2DelegateTest( assertEquals(expected.details.toString(), detailsFlow.latestValue.details.toString()) } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `completed and creating details fails, then an error is emitted`() = runTest { val error = ComponentException("test") // We have to mock the serializer in order to throw an exception @@ -487,8 +482,7 @@ internal class DefaultAdyen3DS2DelegateTest( assertNotNull(detailsFlow.latestValue.details) } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `error, then details are emitted`() = runTest { val detailsFlow = delegate.detailsFlow.test(testScheduler) @@ -636,9 +630,8 @@ internal class DefaultAdyen3DS2DelegateTest( analyticsManager.assertLastEventEquals(expectedDisplayedEvent) } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @ParameterizedTest - // @MethodSource("com.adyen.checkout.adyen3ds2.internal.ui.DefaultAdyen3DS2DelegateTest#challengeResult") + @ParameterizedTest + @MethodSource("com.adyen.checkout.adyen3ds2.internal.ui.DefaultAdyen3DS2DelegateTest#challengeResult") fun `when challenge result is returned, then event is tracked`( challengeResult: ChallengeResult, analyticsResult: ThreeDS2Events.Result @@ -655,8 +648,7 @@ internal class DefaultAdyen3DS2DelegateTest( } } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `when details are emitted, then state is cleared`() = runTest { val savedStateHandle = SavedStateHandle().apply { set( diff --git a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/SharedChallengeStatusHandlerTest.kt b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/SharedChallengeStatusHandlerTest.kt index d3b91dd168..73c6d5e0d2 100644 --- a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/SharedChallengeStatusHandlerTest.kt +++ b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/SharedChallengeStatusHandlerTest.kt @@ -3,6 +3,7 @@ package com.adyen.checkout.adyen3ds2.internal.ui import com.adyen.threeds2.ChallengeResult import com.adyen.threeds2.ChallengeStatusHandler import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test internal class SharedChallengeStatusHandlerTest { @@ -11,8 +12,7 @@ internal class SharedChallengeStatusHandlerTest { SharedChallengeStatusHandler.reset() } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `when onCompletion is triggered, then listener is called`() { val onCompletionListener = TestOnCompletionListener() SharedChallengeStatusHandler.onCompletionListener = onCompletionListener @@ -22,8 +22,7 @@ internal class SharedChallengeStatusHandlerTest { onCompletionListener.assertOnCompletionCalled() } - // commenting this out because of failing tests, should be fixed later in collaboration with the 3DS2 team - // @Test + @Test fun `when onCompletion is triggered and no listener is set, then onCompletion is queued until a listener is set`() { val onCompletionListener = TestOnCompletionListener() SharedChallengeStatusHandler.onCompletion(ChallengeResult.Completed("test")) From e0f706e2195c38d8b325594875759c70b7a2213e Mon Sep 17 00:00:00 2001 From: josephj Date: Tue, 15 Oct 2024 16:48:54 +0200 Subject: [PATCH 006/102] Update 3DS2 SDK to version 2.2.21 It was mistakenly not updated in the migration to version catalogs COAND-1011 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f616f416f2..453de37c0c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,7 +44,7 @@ compose-hilt = "1.2.0" compose-viewmodel = "2.8.3" # Adyen dependencies -adyen3ds2 = "2.2.20" +adyen3ds2 = "2.2.21" # External dependencies cash-app-pay = "2.5.0" From 79fcf1eb20913404cbff6accfcababf54dc18f7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 08:35:33 +0000 Subject: [PATCH 007/102] Update JamesIves/github-pages-deploy-action action to v4.6.8 --- .github/workflows/publish_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml index d30b80b4ed..349da4fc96 100644 --- a/.github/workflows/publish_docs.yml +++ b/.github/workflows/publish_docs.yml @@ -38,7 +38,7 @@ jobs: # Deploy to GitHub Pages - name: Deploy GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4.6.4 + uses: JamesIves/github-pages-deploy-action@v4.6.8 with: BRANCH: gh-pages FOLDER: build/docs/ From b9ade0c3557eb4cc76a59c882bebce44b63a82cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:26:52 +0000 Subject: [PATCH 008/102] Update dependency androidx.annotation:annotation to v1.8.2 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 453de37c0c..2393322f9a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ binary-compatibility-validator = "0.16.3" # Android dependencies activity = "1.9.2" -annotation = "1.8.0" +annotation = "1.8.2" appcompat = "1.7.0" autofill = "1.3.0-alpha01" browser = "1.8.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index fdb8946c57..cf1429b7bf 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -258,6 +258,9 @@ + + + From 60fccca95b2ae4f5332ddd275aa5e362d47c33a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:58:54 +0000 Subject: [PATCH 009/102] Update dependency androidx.fragment:fragment-ktx to v1.8.4 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2393322f9a..c2f600ca7b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ appcompat = "1.7.0" autofill = "1.3.0-alpha01" browser = "1.8.0" coroutines = "1.9.0" -fragment = "1.8.3" +fragment = "1.8.4" lifecycle = "2.8.3" material = "1.12.0" recyclerview = "1.3.2" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index cf1429b7bf..411df3b71b 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -2600,6 +2600,14 @@ + + + + + + + + @@ -2640,6 +2648,14 @@ + + + + + + + + From 04301daea748fcf4f27b3711a82b80c343a3e0a0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:30:57 +0000 Subject: [PATCH 010/102] Update android.gradle.plugin to v8.7.1 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 458 +++++++++++++++++++++++++++++++ 2 files changed, 459 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c2f600ca7b..86dbba3d7c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ version-code = "1" version-name = "5.7.0" # Build script -android-gradle-plugin = "8.5.1" +android-gradle-plugin = "8.7.1" kotlin = "1.9.25" ksp = "1.9.25-1.0.20" dokka = "1.9.20" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 411df3b71b..b054a8ead6 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -2363,6 +2363,14 @@ + + + + + + + + @@ -2411,6 +2419,14 @@ + + + + + + + + @@ -2459,6 +2475,14 @@ + + + + + + + + @@ -4421,6 +4445,14 @@ + + + + + + + + @@ -4469,6 +4501,14 @@ + + + + + + + + @@ -4499,6 +4539,11 @@ + + + + + @@ -4547,6 +4592,14 @@ + + + + + + + + @@ -4577,6 +4630,11 @@ + + + + + @@ -4641,6 +4699,14 @@ + + + + + + + + @@ -4705,6 +4771,14 @@ + + + + + + + + @@ -4769,6 +4843,14 @@ + + + + + + + + @@ -4897,6 +4979,14 @@ + + + + + + + + @@ -4961,6 +5051,14 @@ + + + + + + + + @@ -5025,6 +5123,14 @@ + + + + + + + + @@ -5073,6 +5179,14 @@ + + + + + + + + @@ -5137,6 +5251,14 @@ + + + + + + + + @@ -5201,6 +5323,14 @@ + + + + + + + + @@ -5265,6 +5395,14 @@ + + + + + + + + @@ -5395,6 +5533,14 @@ + + + + + + + + @@ -5443,6 +5589,14 @@ + + + + + + + + @@ -5491,6 +5645,14 @@ + + + + + + + + @@ -5539,6 +5701,14 @@ + + + + + + + + @@ -5587,6 +5757,14 @@ + + + + + + + + @@ -5651,6 +5829,14 @@ + + + + + + + + @@ -5699,6 +5885,14 @@ + + + + + + + + @@ -5715,6 +5909,14 @@ + + + + + + + + @@ -5763,6 +5965,14 @@ + + + + + + + + @@ -5811,6 +6021,14 @@ + + + + + + + + @@ -5859,6 +6077,14 @@ + + + + + + + + @@ -5923,6 +6149,14 @@ + + + + + + + + @@ -6011,6 +6245,14 @@ + + + + + + + + @@ -6051,6 +6293,14 @@ + + + + + + + + @@ -6307,6 +6557,14 @@ + + + + + + + + @@ -6611,6 +6869,14 @@ + + + + + + + + @@ -6683,6 +6949,14 @@ + + + + + + + + @@ -6723,6 +6997,14 @@ + + + + + + + + @@ -6771,6 +7053,14 @@ + + + + + + + + @@ -6811,6 +7101,14 @@ + + + + + + + + @@ -6859,6 +7157,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -6899,6 +7221,14 @@ + + + + + + + + @@ -6947,6 +7277,14 @@ + + + + + + + + @@ -6987,6 +7325,14 @@ + + + + + + + + @@ -7035,6 +7381,14 @@ + + + + + + + + @@ -7075,6 +7429,14 @@ + + + + + + + + @@ -7123,6 +7485,14 @@ + + + + + + + + @@ -7163,6 +7533,14 @@ + + + + + + + + @@ -7203,6 +7581,14 @@ + + + + + + + + @@ -7243,6 +7629,14 @@ + + + + + + + + @@ -7291,6 +7685,14 @@ + + + + + + + + @@ -7331,6 +7733,14 @@ + + + + + + + + @@ -7379,6 +7789,14 @@ + + + + + + + + @@ -7419,6 +7837,14 @@ + + + + + + + + @@ -7467,6 +7893,14 @@ + + + + + + + + @@ -7507,6 +7941,14 @@ + + + + + + + + @@ -7555,6 +7997,14 @@ + + + + + + + + @@ -7595,6 +8045,14 @@ + + + + + + + + From 6bba6f4c8041f721610d7277abc6e0b810be763f Mon Sep 17 00:00:00 2001 From: jreij Date: Wed, 16 Oct 2024 12:37:05 +0000 Subject: [PATCH 011/102] Update verification metadata --- gradle/verification-metadata.xml | 80 ++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index b054a8ead6..c3e7309513 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4915,6 +4915,14 @@ + + + + + + + + @@ -5469,6 +5477,22 @@ + + + + + + + + + + + + + + + + @@ -6365,6 +6389,14 @@ + + + + + + + + @@ -6429,6 +6461,14 @@ + + + + + + + + @@ -6493,6 +6533,14 @@ + + + + + + + + @@ -6629,6 +6677,14 @@ + + + + + + + + @@ -6693,6 +6749,14 @@ + + + + + + + + @@ -6757,6 +6821,14 @@ + + + + + + + + @@ -6805,6 +6877,14 @@ + + + + + + + + From c2cd1b59928fd24134c3ad7ccee1b11b4acb271e Mon Sep 17 00:00:00 2001 From: josephj Date: Wed, 16 Oct 2024 16:29:45 +0200 Subject: [PATCH 012/102] Fix reading BuildConfig.CHECKOUT_VERSION from toml file COAND-977 --- config/gradle/buildConfig.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/gradle/buildConfig.gradle b/config/gradle/buildConfig.gradle index 20a0c77080..867ab90c48 100644 --- a/config/gradle/buildConfig.gradle +++ b/config/gradle/buildConfig.gradle @@ -8,7 +8,7 @@ android { defaultConfig { - buildConfigField "String", "CHECKOUT_VERSION", "\"${libs.versions.version.name}\"" + buildConfigField "String", "CHECKOUT_VERSION", "\"${libs.versions.version.name.get()}\"" } buildFeatures { From 913cdfae68d38af15198926d9b9982e74d485a9e Mon Sep 17 00:00:00 2001 From: Joseph Jreij Date: Thu, 17 Oct 2024 12:13:41 +0200 Subject: [PATCH 013/102] Replace prefill with autofill for test cards app in readme COAND-1001 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b6df76b2bc..bb6a095039 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Please let us know if you find any issues. For development and testing purposes the project is accompanied by a test app. See [here](example-app/README.md) how to set it up and run it. -To test your integration you could use [Adyen Test Cards Android][adyenTestCardsAndroid]. This will allow you to easily prefill test payment method information. +To test your integration you could use [Adyen Test Cards Android][adyenTestCardsAndroid]. This will allow you to easily autofill test payment method information. ## Support From 59a3f540a1177c8739ecd6bb735bdcb673099229 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Wed, 23 Oct 2024 11:17:38 +0400 Subject: [PATCH 014/102] Update the script to retrieve the version-name from version catalogs file COAND-977 --- scripts/version_name.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/version_name.sh b/scripts/version_name.sh index 59b533ba9b..dbcc045f40 100755 --- a/scripts/version_name.sh +++ b/scripts/version_name.sh @@ -1,8 +1,8 @@ #!/bin/bash function release_version() { - local build_file="${GITHUB_WORKSPACE}/dependencies.gradle" - local version_name_key="version_name" + local build_file="${GITHUB_WORKSPACE}/gradle/libs.versions.toml" + local version_name_key="version-name" local version_name_regex="^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}(-(alpha|beta|rc)[0-9]{2}){0,1}$" local version=$(sed -n "s/.*${version_name_key}[[:space:]]*=[[:space:]]*[\"\']\(.*\)[\"\'].*/\1/p" ${build_file}) From b7034188181c2241517e3535771a6f629af47181 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:59:21 +0200 Subject: [PATCH 015/102] Introduce DispatcherProvider --- .../data/api/SubmitFingerprintService.kt | 4 +- .../provider/Adyen3DS2ComponentProvider.kt | 4 +- .../internal/data/api/BinLookupService.kt | 4 +- .../internal/ui/DefaultCashAppPayDelegate.kt | 4 +- .../adyen/checkout/core/DispatcherProvider.kt | 57 +++++++++++++++++++ .../checkout/core/internal/ui/ImageLoader.kt | 12 ++-- .../analytics/DefaultAnalyticsManager.kt | 4 +- .../internal/data/api/AnalyticsService.kt | 4 +- .../internal/data/api/OrderStatusService.kt | 4 +- .../internal/data/api/PublicKeyService.kt | 4 +- .../internal/data/api/StatusRepository.kt | 4 +- .../internal/service/BaseDropInService.kt | 4 +- .../dropin/internal/ui/DropInViewModel.kt | 4 +- .../test/rule/IdlingDispatcherRule.kt | 14 ++--- .../data/api/NativeRedirectService.kt | 4 +- .../internal/CheckoutSessionInitializer.kt | 4 +- .../core/internal/data/api/SessionService.kt | 4 +- .../core/internal/data/api/AddressService.kt | 4 +- .../data/api/DefaultAddressRepository.kt | 4 +- .../ui/core/internal/util/ImageSaver.kt | 4 +- 20 files changed, 101 insertions(+), 50 deletions(-) create mode 100644 checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt diff --git a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/data/api/SubmitFingerprintService.kt b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/data/api/SubmitFingerprintService.kt index 104047ee34..9cfd065e39 100644 --- a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/data/api/SubmitFingerprintService.kt +++ b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/data/api/SubmitFingerprintService.kt @@ -10,15 +10,15 @@ package com.adyen.checkout.adyen3ds2.internal.data.api import com.adyen.checkout.adyen3ds2.internal.data.model.SubmitFingerprintRequest import com.adyen.checkout.adyen3ds2.internal.data.model.SubmitFingerprintResponse +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.post import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext internal class SubmitFingerprintService( private val httpClient: HttpClient, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { suspend fun submitFingerprint( diff --git a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/provider/Adyen3DS2ComponentProvider.kt b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/provider/Adyen3DS2ComponentProvider.kt index b8aed566e4..317f4aaf88 100644 --- a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/provider/Adyen3DS2ComponentProvider.kt +++ b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/provider/Adyen3DS2ComponentProvider.kt @@ -39,11 +39,11 @@ import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParam import com.adyen.checkout.components.core.internal.ui.model.DropInOverrideParams import com.adyen.checkout.components.core.internal.util.get import com.adyen.checkout.components.core.internal.util.viewModelFactory +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClientFactory import com.adyen.checkout.core.internal.util.LocaleProvider import com.adyen.checkout.ui.core.internal.DefaultRedirectHandler import com.adyen.threeds2.ThreeDS2Service -import kotlinx.coroutines.Dispatchers class Adyen3DS2ComponentProvider @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) @@ -105,7 +105,7 @@ constructor( adyen3DS2Serializer = adyen3DS2DetailsParser, redirectHandler = redirectHandler, threeDS2Service = ThreeDS2Service.INSTANCE, - coroutineDispatcher = Dispatchers.Default, + coroutineDispatcher = DispatcherProvider.Default, application = application, analyticsManager = analyticsManager, ) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/data/api/BinLookupService.kt b/card/src/main/java/com/adyen/checkout/card/internal/data/api/BinLookupService.kt index dbae165ccb..c6df098527 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/data/api/BinLookupService.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/data/api/BinLookupService.kt @@ -11,16 +11,16 @@ package com.adyen.checkout.card.internal.data.api import androidx.annotation.RestrictTo import com.adyen.checkout.card.internal.data.model.BinLookupRequest import com.adyen.checkout.card.internal.data.model.BinLookupResponse +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.post import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class BinLookupService( private val httpClient: HttpClient, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { suspend fun makeBinLookup( diff --git a/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt b/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt index e5b178176b..639a297589 100644 --- a/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt +++ b/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt @@ -38,6 +38,7 @@ import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.components.core.paymentmethod.CashAppPayPaymentMethod import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.exception.ComponentException import com.adyen.checkout.core.internal.util.adyenLog @@ -47,7 +48,6 @@ import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -65,7 +65,7 @@ constructor( private val order: OrderRequest?, override val componentParams: CashAppPayComponentParams, private val cashAppPayFactory: CashAppPayFactory, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) : CashAppPayDelegate, ButtonDelegate, CashAppPayListener { private val inputData = CashAppPayInputData() diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt b/checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt new file mode 100644 index 0000000000..090c7b96e0 --- /dev/null +++ b/checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 16/10/2024. + */ + +package com.adyen.checkout.core + +import androidx.annotation.RestrictTo +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainCoroutineDispatcher + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +object DispatcherProvider { + + private var mainFactory = { Dispatchers.Main } + val Main: MainCoroutineDispatcher get() = mainFactory() + + private var defaultFactory = { Dispatchers.Default } + val Default: CoroutineDispatcher get() = defaultFactory() + + private var ioFactory = { Dispatchers.IO } + val IO: CoroutineDispatcher get() = ioFactory() + + fun overrideMain(dispatcher: MainCoroutineDispatcher) { + mainFactory = { dispatcher } + } + + fun overrideIO(dispatcher: CoroutineDispatcher) { + ioFactory = { dispatcher } + } + + fun overrideDefault(dispatcher: CoroutineDispatcher) { + defaultFactory = { dispatcher } + } + + fun resetMain() { + mainFactory = { Dispatchers.Main } + } + + fun resetIO() { + ioFactory = { Dispatchers.IO } + } + + fun resetDefault() { + defaultFactory = { Dispatchers.Default } + } + + fun resetAll() { + resetMain() + resetIO() + resetDefault() + } +} diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/internal/ui/ImageLoader.kt b/checkout-core/src/main/java/com/adyen/checkout/core/internal/ui/ImageLoader.kt index af3994244d..23a8600ba8 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/internal/ui/ImageLoader.kt +++ b/checkout-core/src/main/java/com/adyen/checkout/core/internal/ui/ImageLoader.kt @@ -14,9 +14,9 @@ import android.content.pm.ApplicationInfo import android.graphics.Bitmap import android.graphics.BitmapFactory import androidx.annotation.RestrictTo +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.HttpException import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import okhttp3.Request @@ -43,10 +43,10 @@ class DefaultImageLoader(context: Context) : ImageLoader { url: String, onSuccess: suspend (Bitmap) -> Unit, onError: suspend (Throwable) -> Unit - ) = withContext(Dispatchers.IO) { + ) = withContext(DispatcherProvider.IO) { val cachedBitmap = cache[url] if (cachedBitmap != null) { - withContext(Dispatchers.Main) { + withContext(DispatcherProvider.Main) { onSuccess(cachedBitmap) } return@withContext @@ -72,11 +72,11 @@ class DefaultImageLoader(context: Context) : ImageLoader { cache[url] = bitmap - withContext(Dispatchers.Main) { + withContext(DispatcherProvider.Main) { onSuccess(bitmap) } } else { - withContext(Dispatchers.Main) { + withContext(DispatcherProvider.Main) { onError(HttpException(response.code, response.message, null)) } } @@ -85,7 +85,7 @@ class DefaultImageLoader(context: Context) : ImageLoader { } catch (e: CancellationException) { call.cancel() } catch (e: IOException) { - withContext(Dispatchers.Main) { + withContext(DispatcherProvider.Main) { onError(e) } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt index 29a3a89423..dcc1df5324 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt @@ -13,11 +13,11 @@ import com.adyen.checkout.components.core.internal.analytics.data.AnalyticsRepos import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParams import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParamsLevel import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.core.internal.util.runSuspendCatching import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.isActive @@ -27,7 +27,7 @@ import kotlin.time.Duration.Companion.seconds internal class DefaultAnalyticsManager( private val analyticsRepository: AnalyticsRepository, private val analyticsParams: AnalyticsParams, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) : AnalyticsManager { private var checkoutAttemptIdState: CheckoutAttemptIdState = CheckoutAttemptIdState.NotAvailable diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsService.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsService.kt index b42d84fa39..6843ce0d8e 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsService.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsService.kt @@ -12,17 +12,17 @@ import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.internal.data.model.AnalyticsSetupRequest import com.adyen.checkout.components.core.internal.data.model.AnalyticsSetupResponse import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackRequest +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.post import com.adyen.checkout.core.internal.data.model.EmptyResponse import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class AnalyticsService( private val httpClient: HttpClient, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { internal suspend fun setupAnalytics( diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/OrderStatusService.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/OrderStatusService.kt index 5fe4a1f9de..119a39c3c2 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/OrderStatusService.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/OrderStatusService.kt @@ -11,16 +11,16 @@ package com.adyen.checkout.components.core.internal.data.api import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.internal.data.model.OrderStatusRequest import com.adyen.checkout.components.core.internal.data.model.OrderStatusResponse +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.post import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class OrderStatusService( private val httpClient: HttpClient, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { internal suspend fun getOrderStatus( diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/PublicKeyService.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/PublicKeyService.kt index 15e4c1365e..6289f49408 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/PublicKeyService.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/PublicKeyService.kt @@ -10,16 +10,16 @@ package com.adyen.checkout.components.core.internal.data.api import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.internal.data.model.PublicKeyResponse +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.get import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class PublicKeyService( private val httpClient: HttpClient, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { internal suspend fun getPublicKey( diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/StatusRepository.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/StatusRepository.kt index 4850b00e36..5058f08ee9 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/StatusRepository.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/StatusRepository.kt @@ -15,10 +15,10 @@ import com.adyen.checkout.components.core.internal.data.model.StatusResponse import com.adyen.checkout.components.core.internal.util.StatusResponseUtils import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.core.internal.util.runSuspendCatching import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.cancel import kotlinx.coroutines.currentCoroutineContext @@ -51,7 +51,7 @@ class DefaultStatusRepository( private val statusService: StatusService, private val clientKey: String, private val timeSource: TimeSource = TimeSource.Monotonic, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) : StatusRepository { private var delay: Long = 0 diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt index 27fc2b8f69..acc796fe53 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/service/BaseDropInService.kt @@ -22,6 +22,7 @@ import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.dropin.AddressLookupDropInServiceResult import com.adyen.checkout.dropin.BalanceDropInServiceResult @@ -31,7 +32,6 @@ import com.adyen.checkout.dropin.DropInServiceResult import com.adyen.checkout.dropin.OrderDropInServiceResult import com.adyen.checkout.dropin.RecurringDropInServiceResult import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.Channel @@ -46,7 +46,7 @@ abstract class BaseDropInService constructor() : Service(), CoroutineScope, BaseDropInServiceInterface, BaseDropInServiceContract { private val coroutineJob: Job = Job() - final override val coroutineContext: CoroutineContext get() = Dispatchers.Main + coroutineJob + final override val coroutineContext: CoroutineContext get() = DispatcherProvider.Main + coroutineJob @Suppress("LeakingThis") private val binder = DropInBinder(this) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt index a6e513d1f2..213eb8fea7 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt @@ -31,6 +31,7 @@ import com.adyen.checkout.components.core.internal.ui.model.DropInOverrideParams import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.components.core.paymentmethod.GiftCardPaymentMethod import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.dropin.R @@ -47,7 +48,6 @@ import com.adyen.checkout.giftcard.internal.util.GiftCardBalanceUtils import com.adyen.checkout.sessions.core.internal.data.model.SessionDetails import com.adyen.checkout.sessions.core.internal.data.model.mapToModel import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.receiveAsFlow @@ -60,7 +60,7 @@ internal class DropInViewModel( internal val analyticsManager: AnalyticsManager, private val initialDropInParams: DropInParams, private val dropInConfigDataGenerator: DropInConfigDataGenerator, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) : ViewModel() { private val eventChannel: Channel = bufferedChannel() diff --git a/example-app/src/androidTest/java/com/adyen/checkout/test/rule/IdlingDispatcherRule.kt b/example-app/src/androidTest/java/com/adyen/checkout/test/rule/IdlingDispatcherRule.kt index ddfa72bcd6..5d4634465a 100644 --- a/example-app/src/androidTest/java/com/adyen/checkout/test/rule/IdlingDispatcherRule.kt +++ b/example-app/src/androidTest/java/com/adyen/checkout/test/rule/IdlingDispatcherRule.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.test.rule import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.idling.CountingIdlingResource +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.test.util.IdlingResourceDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers @@ -45,7 +46,7 @@ class IdlingDispatcherRule : TestRule { unregister(defaultIdlingResource) unregister(ioIdlingResource) } - overrideDispatchers(defaultDispatcher, ioDispatcher) + DispatcherProvider.resetAll() } } } @@ -54,14 +55,7 @@ class IdlingDispatcherRule : TestRule { default: CoroutineDispatcher, io: CoroutineDispatcher, ) { - fun setField(name: String, value: CoroutineDispatcher) { - Dispatchers::class.java.getDeclaredField(name).apply { - isAccessible = true - set(Dispatchers, value) - } - } - - setField("Default", default) - setField("IO", io) + DispatcherProvider.overrideDefault(default) + DispatcherProvider.overrideIO(io) } } diff --git a/redirect/src/main/java/com/adyen/checkout/redirect/internal/data/api/NativeRedirectService.kt b/redirect/src/main/java/com/adyen/checkout/redirect/internal/data/api/NativeRedirectService.kt index afadbb867d..088cc831cd 100644 --- a/redirect/src/main/java/com/adyen/checkout/redirect/internal/data/api/NativeRedirectService.kt +++ b/redirect/src/main/java/com/adyen/checkout/redirect/internal/data/api/NativeRedirectService.kt @@ -8,17 +8,17 @@ package com.adyen.checkout.redirect.internal.data.api +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.post import com.adyen.checkout.redirect.internal.data.model.NativeRedirectRequest import com.adyen.checkout.redirect.internal.data.model.NativeRedirectResponse import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext internal class NativeRedirectService( private val httpClient: HttpClient, - private val dispatcher: CoroutineDispatcher = Dispatchers.IO + private val dispatcher: CoroutineDispatcher = DispatcherProvider.IO ) { suspend fun makeNativeRedirect( diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/CheckoutSessionInitializer.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/CheckoutSessionInitializer.kt index 7d7ee9fb8a..ff395aaf51 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/CheckoutSessionInitializer.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/CheckoutSessionInitializer.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.sessions.core.internal import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.Order +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.Environment import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.internal.data.api.HttpClientFactory @@ -19,7 +20,6 @@ import com.adyen.checkout.sessions.core.SessionModel import com.adyen.checkout.sessions.core.internal.data.api.SessionRepository import com.adyen.checkout.sessions.core.internal.data.api.SessionService import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext internal class CheckoutSessionInitializer( @@ -27,7 +27,7 @@ internal class CheckoutSessionInitializer( private val environment: Environment, private val clientKey: String, private val order: Order?, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { private val httpClient = HttpClientFactory.getHttpClient(environment) private val sessionService = SessionService(httpClient) diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/api/SessionService.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/api/SessionService.kt index 81e04391a9..36e2b3f3c5 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/api/SessionService.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/api/SessionService.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.sessions.core.internal.data.api import androidx.annotation.RestrictTo +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.post import com.adyen.checkout.sessions.core.SessionSetupResponse @@ -26,13 +27,12 @@ import com.adyen.checkout.sessions.core.internal.data.model.SessionPaymentsReque import com.adyen.checkout.sessions.core.internal.data.model.SessionPaymentsResponse import com.adyen.checkout.sessions.core.internal.data.model.SessionSetupRequest import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class SessionService( private val httpClient: HttpClient, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { suspend fun setupSession( diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/AddressService.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/AddressService.kt index 0f8ac517f5..eb4404d8d6 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/AddressService.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/AddressService.kt @@ -9,17 +9,17 @@ package com.adyen.checkout.ui.core.internal.data.api import androidx.annotation.RestrictTo +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.data.api.HttpClient import com.adyen.checkout.core.internal.data.api.getList import com.adyen.checkout.ui.core.internal.data.model.AddressItem import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class AddressService( private val httpClient: HttpClient, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { suspend fun getCountries( shopperLocale: String diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/DefaultAddressRepository.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/DefaultAddressRepository.kt index ea70733278..aa781b6693 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/DefaultAddressRepository.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/data/api/DefaultAddressRepository.kt @@ -11,13 +11,13 @@ package com.adyen.checkout.ui.core.internal.data.api import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.core.internal.util.runSuspendCatching import com.adyen.checkout.ui.core.internal.data.model.AddressItem import com.adyen.checkout.ui.core.internal.ui.AddressSpecification import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.receiveAsFlow @@ -27,7 +27,7 @@ import java.util.Locale @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class DefaultAddressRepository( private val addressService: AddressService, - private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) : AddressRepository { private val statesChannel: Channel> = bufferedChannel() diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/ImageSaver.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/ImageSaver.kt index f6cd571e5c..111fdb6cf5 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/ImageSaver.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/ImageSaver.kt @@ -27,6 +27,7 @@ import androidx.annotation.RequiresPermission import androidx.annotation.RestrictTo import androidx.core.content.ContextCompat import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.internal.ui.PermissionHandler import com.adyen.checkout.core.internal.util.adyenLog @@ -36,7 +37,6 @@ import com.adyen.checkout.ui.core.internal.util.PermissionHandlerResult.PERMISSI import com.adyen.checkout.ui.core.internal.util.PermissionHandlerResult.PERMISSION_REQUEST_NOT_HANDLED import com.google.android.material.color.MaterialColors import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.BufferedInputStream import java.io.File @@ -49,7 +49,7 @@ import com.google.android.material.R as MaterialR @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class ImageSaver( - private val dispatcher: CoroutineDispatcher = Dispatchers.IO, + private val dispatcher: CoroutineDispatcher = DispatcherProvider.IO, ) { @Suppress("LongParameterList") From f99a25cdf86f2a63307126efc59c0a664a1e2dfa Mon Sep 17 00:00:00 2001 From: josephj Date: Tue, 8 Oct 2024 10:40:44 +0200 Subject: [PATCH 016/102] Add lint rule to prevent the use of JSONObject's optString, optBoolean, optInt, optLong and optDouble These functions are non nullable and return arbitrary default values which could cause unexpected bugs. We should use our internal extension functions that return null instead COAND-1003 --- .../adyen/checkout/lint/JSONOptFunctions.kt | 73 +++++++ .../adyen/checkout/lint/LintIssueRegistry.kt | 1 + .../checkout/lint/JSONOptFunctionsTest.kt | 193 ++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 lint/src/main/java/com/adyen/checkout/lint/JSONOptFunctions.kt create mode 100644 lint/src/test/java/com/adyen/checkout/lint/JSONOptFunctionsTest.kt diff --git a/lint/src/main/java/com/adyen/checkout/lint/JSONOptFunctions.kt b/lint/src/main/java/com/adyen/checkout/lint/JSONOptFunctions.kt new file mode 100644 index 0000000000..de8ca2af51 --- /dev/null +++ b/lint/src/main/java/com/adyen/checkout/lint/JSONOptFunctions.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by oscars on 14/8/2024. + */ + +package com.adyen.checkout.lint + +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.UCallExpression + +internal val JSON_OPT_FUNCTIONS_ISSUE = Issue.create( + id = "JSONOptFunctions", + briefDescription = "JSONObject \"opt\" functions should not be used directly", + explanation = """ + JSONObject's optString, optBoolean, optInt, optLong and optDouble functions are non nullable and return + arbitrary default values which could cause unexpected bugs. Use an internal extension function that returns + null instead. + """.trimIndent().replace(Regex("(\n*)\n"), "$1"), + implementation = Implementation(JSONOptFunctionsDetector::class.java, Scope.JAVA_FILE_SCOPE), + category = Category.CUSTOM_LINT_CHECKS, + priority = 5, + severity = Severity.ERROR, + androidSpecific = true, +) + +internal class JSONOptFunctionsDetector : Detector(), Detector.UastScanner { + + override fun getApplicableMethodNames(): List = listOf( + "optString", "optBoolean", "optInt", "optLong", "optDouble", + ) + + override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { + if (!context.evaluator.isMemberInClass(method, "org.json.JSONObject")) return + val methodName = node.methodIdentifier?.name.orEmpty() + val replacement = when (methodName) { + "optString" -> "getStringOrNull" + "optBoolean" -> "getBooleanOrNull" + "optInt" -> "getIntOrNull" + "optLong" -> "getLongOrNull" + "optDouble" -> "getDoubleOrNull" + else -> return + } + context.report( + JSON_OPT_FUNCTIONS_ISSUE, + node, + context.getLocation(node.methodIdentifier), + "JSONObject.$methodName should not be used directly. Use an internal extension function instead.", + fix() + .alternatives( + // this replacement does not compile when 2 arguments are passed to the opt functions instead of 1. + // however, it's easy for the developer to fix it manually + fix() + .replace() + .all() + .with(replacement) + .imports("com.adyen.checkout.core.internal.data.model.$replacement") + .reformat(true) + .shortenNames() + .build(), + ), + ) + } +} diff --git a/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt b/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt index 664187418c..7597f92cf5 100644 --- a/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt +++ b/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt @@ -22,5 +22,6 @@ internal class LintIssueRegistry : IssueRegistry() { NOT_ADYEN_LOG_ISSUE, OBJECT_IN_PUBLIC_SEALED_CLASS_ISSUE, TEXT_IN_LAYOUT_XML_ISSUE, + JSON_OPT_FUNCTIONS_ISSUE, ) } diff --git a/lint/src/test/java/com/adyen/checkout/lint/JSONOptFunctionsTest.kt b/lint/src/test/java/com/adyen/checkout/lint/JSONOptFunctionsTest.kt new file mode 100644 index 0000000000..eb9142d568 --- /dev/null +++ b/lint/src/test/java/com/adyen/checkout/lint/JSONOptFunctionsTest.kt @@ -0,0 +1,193 @@ +package com.adyen.checkout.lint + +import com.android.tools.lint.checks.infrastructure.LintDetectorTest.java +import com.android.tools.lint.checks.infrastructure.LintDetectorTest.kotlin +import com.android.tools.lint.checks.infrastructure.TestLintTask.lint +import org.junit.Test + +class JSONOptFunctionsTest { + + @Test + fun whenJSONObjectOptFunctionsAreUsed_thenIssueIsDetected() { + lint() + .files( + JSON_OBJECT_STUB, + kotlin( + """ + package test + + import org.json.JSONObject + + class SomeClass { + fun someFun(jsonObject: JSONObject) { + val stringWithoutFallback = jsonObject.optString("key") + val stringWithFallback = jsonObject.optString("key", "fallback") + val intWithoutFallback = jsonObject.optInt("key") + val intWithFallback = jsonObject.optInt("key", 1) + val doubleWithoutFallback = jsonObject.optDouble("key") + val doubleWithFallback = jsonObject.optDouble("key", 1.0) + val longWithoutFallback = jsonObject.optLong("key") + val longWithFallback = jsonObject.optLong("key", 1L) + val booleanWithoutFallback = jsonObject.optBoolean("key") + val booleanWithFallback = jsonObject.optBoolean("key", true) + } + } + """.trimIndent(), + ), + ) + .issues(JSON_OPT_FUNCTIONS_ISSUE) + .allowMissingSdk() + .run() + .expect( + """ +src/test/SomeClass.kt:7: Error: JSONObject.optString should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val stringWithoutFallback = jsonObject.optString("key") + ~~~~~~~~~ +src/test/SomeClass.kt:8: Error: JSONObject.optString should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val stringWithFallback = jsonObject.optString("key", "fallback") + ~~~~~~~~~ +src/test/SomeClass.kt:9: Error: JSONObject.optInt should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val intWithoutFallback = jsonObject.optInt("key") + ~~~~~~ +src/test/SomeClass.kt:10: Error: JSONObject.optInt should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val intWithFallback = jsonObject.optInt("key", 1) + ~~~~~~ +src/test/SomeClass.kt:11: Error: JSONObject.optDouble should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val doubleWithoutFallback = jsonObject.optDouble("key") + ~~~~~~~~~ +src/test/SomeClass.kt:12: Error: JSONObject.optDouble should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val doubleWithFallback = jsonObject.optDouble("key", 1.0) + ~~~~~~~~~ +src/test/SomeClass.kt:13: Error: JSONObject.optLong should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val longWithoutFallback = jsonObject.optLong("key") + ~~~~~~~ +src/test/SomeClass.kt:14: Error: JSONObject.optLong should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val longWithFallback = jsonObject.optLong("key", 1L) + ~~~~~~~ +src/test/SomeClass.kt:15: Error: JSONObject.optBoolean should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val booleanWithoutFallback = jsonObject.optBoolean("key") + ~~~~~~~~~~ +src/test/SomeClass.kt:16: Error: JSONObject.optBoolean should not be used directly. Use an internal extension function instead. [JSONOptFunctions] + val booleanWithFallback = jsonObject.optBoolean("key", true) + ~~~~~~~~~~ +10 errors, 0 warnings + """.trimIndent(), + ) + .expectFixDiffs( + """ +Fix for src/test/SomeClass.kt line 7: Replace with getStringOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getStringOrNull +@@ -7 +8 +- val stringWithoutFallback = jsonObject.optString("key") ++ val stringWithoutFallback = jsonObject.getStringOrNull("key") +Fix for src/test/SomeClass.kt line 8: Replace with getStringOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getStringOrNull +@@ -8 +9 +- val stringWithFallback = jsonObject.optString("key", "fallback") ++ val stringWithFallback = jsonObject.getStringOrNull("key", "fallback") +Fix for src/test/SomeClass.kt line 9: Replace with getIntOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getIntOrNull +@@ -9 +10 +- val intWithoutFallback = jsonObject.optInt("key") ++ val intWithoutFallback = jsonObject.getIntOrNull("key") +Fix for src/test/SomeClass.kt line 10: Replace with getIntOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getIntOrNull +@@ -10 +11 +- val intWithFallback = jsonObject.optInt("key", 1) ++ val intWithFallback = jsonObject.getIntOrNull("key", 1) +Fix for src/test/SomeClass.kt line 11: Replace with getDoubleOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getDoubleOrNull +@@ -11 +12 +- val doubleWithoutFallback = jsonObject.optDouble("key") ++ val doubleWithoutFallback = jsonObject.getDoubleOrNull("key") +Fix for src/test/SomeClass.kt line 12: Replace with getDoubleOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getDoubleOrNull +@@ -12 +13 +- val doubleWithFallback = jsonObject.optDouble("key", 1.0) ++ val doubleWithFallback = jsonObject.getDoubleOrNull("key", 1.0) +Fix for src/test/SomeClass.kt line 13: Replace with getLongOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getLongOrNull +@@ -13 +14 +- val longWithoutFallback = jsonObject.optLong("key") ++ val longWithoutFallback = jsonObject.getLongOrNull("key") +Fix for src/test/SomeClass.kt line 14: Replace with getLongOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getLongOrNull +@@ -14 +15 +- val longWithFallback = jsonObject.optLong("key", 1L) ++ val longWithFallback = jsonObject.getLongOrNull("key", 1L) +Fix for src/test/SomeClass.kt line 15: Replace with getBooleanOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getBooleanOrNull +@@ -15 +16 +- val booleanWithoutFallback = jsonObject.optBoolean("key") ++ val booleanWithoutFallback = jsonObject.getBooleanOrNull("key") +Fix for src/test/SomeClass.kt line 16: Replace with getBooleanOrNull: +@@ -3 +3 ++ import com.adyen.checkout.core.internal.data.model.getBooleanOrNull +@@ -16 +17 +- val booleanWithFallback = jsonObject.optBoolean("key", true) ++ val booleanWithFallback = jsonObject.getBooleanOrNull("key", true) + """.trimIndent(), + ) + } + + companion object { + + private val JSON_OBJECT_STUB = java( + """ + package org.json; + + public class JSONObject { + + @NonNull public String optString(@Nullable String name) { + return "stub"; + } + + @NonNull public String optString(@Nullable String name, @NonNull String fallback) { + return "stub"; + } + + public int optInt(@Nullable String name) { + return 0; + } + + public int optInt(@Nullable String name, int fallback) { + return 0; + } + + public long optLong(@Nullable String name) { + return 0L; + } + + public long optLong(@Nullable String name, long fallback) { + return 0L; + } + + public double optDouble(@Nullable String name) { + return Double.NaN; + } + + public double optDouble(@Nullable String name, double fallback) { + return Double.NaN; + } + + public boolean optBoolean(@Nullable String name) { + return false; + } + + public boolean optBoolean(@Nullable String name, boolean fallback) { + return false; + } + } + """.trimIndent(), + ) + } +} From feeffe5418e0a0290974e6039d4e67e183f9fd4a Mon Sep 17 00:00:00 2001 From: josephj Date: Tue, 8 Oct 2024 10:42:16 +0200 Subject: [PATCH 017/102] Replace JSONObject's opt functions with nullable extensions The opt functions are non nullable and return arbitrary default values which could cause unexpected bugs COAND-1003 --- .../internal/data/model/ErrorResponseBody.kt | 10 ++++---- .../adyen/checkout/components/core/Amount.kt | 3 ++- .../checkout/components/core/Installments.kt | 3 ++- .../adyen/checkout/components/core/Issuer.kt | 3 ++- .../checkout/components/core/OrderRequest.kt | 5 ++-- .../checkout/components/core/OrderResponse.kt | 9 ++++--- .../components/core/PaymentComponentData.kt | 16 ++++++------ .../checkout/components/core/action/Action.kt | 6 ++--- .../components/core/action/TwintSdkData.kt | 3 ++- .../internal/data/model/PublicKeyResponse.kt | 3 ++- .../googlepay/BillingAddressParameters.kt | 3 ++- .../googlepay/ShippingAddressParameters.kt | 3 ++- .../internal/data/model/CardParameters.kt | 13 +++++----- .../data/model/IsReadyToPayRequestModel.kt | 13 ++++++---- .../data/model/PaymentDataRequestModel.kt | 25 +++++++++++-------- .../googlepay/internal/util/GooglePayUtils.kt | 2 +- .../internal/ui/DefaultRedirectDelegate.kt | 3 ++- .../checkout/sessions/core/SessionModel.kt | 5 ++-- .../core/SessionSetupConfiguration.kt | 2 +- .../core/SessionSetupInstallmentOptions.kt | 3 ++- .../sessions/core/SessionSetupResponse.kt | 11 ++++---- .../data/model/SessionBalanceRequest.kt | 3 ++- .../data/model/SessionBalanceResponse.kt | 3 ++- .../data/model/SessionCancelOrderRequest.kt | 3 ++- .../data/model/SessionCancelOrderResponse.kt | 5 ++-- .../data/model/SessionDetailsRequest.kt | 5 ++-- .../data/model/SessionDetailsResponse.kt | 9 ++++--- .../data/model/SessionDisableTokenRequest.kt | 5 ++-- .../data/model/SessionDisableTokenResponse.kt | 3 ++- .../data/model/SessionOrderRequest.kt | 3 ++- .../data/model/SessionOrderResponse.kt | 7 +++--- .../data/model/SessionPaymentsRequest.kt | 3 ++- .../data/model/SessionPaymentsResponse.kt | 9 ++++--- .../data/model/SessionSetupRequest.kt | 3 ++- 34 files changed, 119 insertions(+), 86 deletions(-) diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/internal/data/model/ErrorResponseBody.kt b/checkout-core/src/main/java/com/adyen/checkout/core/internal/data/model/ErrorResponseBody.kt index ece6673222..93dfeda372 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/internal/data/model/ErrorResponseBody.kt +++ b/checkout-core/src/main/java/com/adyen/checkout/core/internal/data/model/ErrorResponseBody.kt @@ -51,11 +51,11 @@ data class ErrorResponseBody( override fun deserialize(jsonObject: JSONObject): ErrorResponseBody { return try { ErrorResponseBody( - status = jsonObject.optInt(STATUS), - errorCode = jsonObject.optString(ERROR_CODE), - message = jsonObject.optString(MESSAGE), - errorType = jsonObject.optString(ERROR_TYPE), - pspReference = jsonObject.optString(PSP_REFERENCE), + status = jsonObject.getIntOrNull(STATUS), + errorCode = jsonObject.getStringOrNull(ERROR_CODE), + message = jsonObject.getStringOrNull(MESSAGE), + errorType = jsonObject.getStringOrNull(ERROR_TYPE), + pspReference = jsonObject.getStringOrNull(PSP_REFERENCE), ) } catch (e: JSONException) { throw ModelSerializationException(ErrorResponseBody::class.java, e) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/Amount.kt b/components-core/src/main/java/com/adyen/checkout/components/core/Amount.kt index f92adf12c4..5dc27282ed 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/Amount.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/Amount.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.components.core import com.adyen.checkout.components.core.internal.util.EMPTY_VALUE import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getLongOrNull import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException @@ -41,7 +42,7 @@ data class Amount( override fun deserialize(jsonObject: JSONObject): Amount { return Amount( currency = jsonObject.getStringOrNull(CURRENCY), - value = jsonObject.optLong(VALUE, EMPTY_VALUE), + value = jsonObject.getLongOrNull(VALUE) ?: EMPTY_VALUE, ) } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/Installments.kt b/components-core/src/main/java/com/adyen/checkout/components/core/Installments.kt index e3428b4034..a70e87ebf1 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/Installments.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/Installments.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.components.core import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getIntOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -41,7 +42,7 @@ data class Installments( return try { Installments( plan = jsonObject.getString(PLAN), - value = jsonObject.optInt(VALUE, 1) + value = jsonObject.getIntOrNull(VALUE) ?: 1, ) } catch (e: JSONException) { throw ModelSerializationException(Installments::class.java, e) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/Issuer.kt b/components-core/src/main/java/com/adyen/checkout/components/core/Issuer.kt index 57161575fc..1f323099fb 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/Issuer.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/Issuer.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.components.core import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException @@ -44,7 +45,7 @@ data class Issuer( return Issuer( id = jsonObject.getStringOrNull(ID), name = jsonObject.getStringOrNull(NAME), - isDisabled = jsonObject.optBoolean(DISABLED, false), + isDisabled = jsonObject.getBooleanOrNull(DISABLED) ?: false, ) } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/OrderRequest.kt b/components-core/src/main/java/com/adyen/checkout/components/core/OrderRequest.kt index 734e739014..c78d7c8224 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/OrderRequest.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/OrderRequest.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.components.core import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -38,8 +39,8 @@ data class OrderRequest constructor( override fun deserialize(jsonObject: JSONObject): OrderRequest { return OrderRequest( - pspReference = jsonObject.optString(PSP_REFERENCE, ""), - orderData = jsonObject.optString(ORDER_DATA, "") + pspReference = jsonObject.getStringOrNull(PSP_REFERENCE).orEmpty(), + orderData = jsonObject.getStringOrNull(ORDER_DATA).orEmpty(), ) } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/OrderResponse.kt b/components-core/src/main/java/com/adyen/checkout/components/core/OrderResponse.kt index 7eb2b8131c..d92b40ec85 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/OrderResponse.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/OrderResponse.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.components.core import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -38,7 +39,7 @@ data class OrderResponse( putOpt(AMOUNT, ModelUtils.serializeOpt(modelObject.amount, Amount.SERIALIZER)) putOpt( REMAINING_AMOUNT, - ModelUtils.serializeOpt(modelObject.remainingAmount, Amount.SERIALIZER) + ModelUtils.serializeOpt(modelObject.remainingAmount, Amount.SERIALIZER), ) } catch (e: JSONException) { throw ModelSerializationException(OrderResponse::class.java, e) @@ -48,12 +49,12 @@ data class OrderResponse( override fun deserialize(jsonObject: JSONObject): OrderResponse { return OrderResponse( - pspReference = jsonObject.optString(PSP_REFERENCE, ""), - orderData = jsonObject.optString(ORDER_DATA, ""), + pspReference = jsonObject.getStringOrNull(PSP_REFERENCE).orEmpty(), + orderData = jsonObject.getStringOrNull(ORDER_DATA).orEmpty(), amount = ModelUtils.deserializeOpt(jsonObject.optJSONObject(AMOUNT), Amount.SERIALIZER), remainingAmount = ModelUtils.deserializeOpt( jsonObject.optJSONObject(REMAINING_AMOUNT), - Amount.SERIALIZER + Amount.SERIALIZER, ), ) } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/PaymentComponentData.kt b/components-core/src/main/java/com/adyen/checkout/components/core/PaymentComponentData.kt index aeb4b7a57a..ba6bd96a6a 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/PaymentComponentData.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/PaymentComponentData.kt @@ -12,6 +12,8 @@ import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils.deserializeOpt import com.adyen.checkout.core.internal.data.model.ModelUtils.serializeOpt +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -89,17 +91,17 @@ data class PaymentComponentData( ), order = deserializeOpt(jsonObject.optJSONObject(ORDER), OrderRequest.SERIALIZER), amount = deserializeOpt(jsonObject.optJSONObject(AMOUNT), Amount.SERIALIZER), - storePaymentMethod = jsonObject.optBoolean(STORE_PAYMENT_METHOD), - shopperReference = jsonObject.optString(SHOPPER_REFERENCE), + storePaymentMethod = jsonObject.getBooleanOrNull(STORE_PAYMENT_METHOD), + shopperReference = jsonObject.getStringOrNull(SHOPPER_REFERENCE), billingAddress = deserializeOpt(jsonObject.optJSONObject(BILLING_ADDRESS), Address.SERIALIZER), deliveryAddress = deserializeOpt(jsonObject.optJSONObject(DELIVERY_ADDRESS), Address.SERIALIZER), shopperName = deserializeOpt(jsonObject.optJSONObject(SHOPPER_NAME), ShopperName.SERIALIZER), - telephoneNumber = jsonObject.optString(TELEPHONE_NUMBER), - shopperEmail = jsonObject.optString(SHOPPER_EMAIL), - dateOfBirth = jsonObject.optString(DATE_OF_BIRTH), - socialSecurityNumber = jsonObject.optString(SOCIAL_SECURITY_NUMBER), + telephoneNumber = jsonObject.getStringOrNull(TELEPHONE_NUMBER), + shopperEmail = jsonObject.getStringOrNull(SHOPPER_EMAIL), + dateOfBirth = jsonObject.getStringOrNull(DATE_OF_BIRTH), + socialSecurityNumber = jsonObject.getStringOrNull(SOCIAL_SECURITY_NUMBER), installments = deserializeOpt(jsonObject.optJSONObject(INSTALLMENTS), Installments.SERIALIZER), - supportNativeRedirect = jsonObject.optBoolean(SUPPORT_NATIVE_REDIRECT), + supportNativeRedirect = jsonObject.getBooleanOrNull(SUPPORT_NATIVE_REDIRECT), ) } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/action/Action.kt b/components-core/src/main/java/com/adyen/checkout/components/core/action/Action.kt index 05e025517a..6d79d16f3b 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/action/Action.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/action/Action.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.components.core.action import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import org.json.JSONObject /** @@ -41,10 +42,7 @@ abstract class Action : ModelObject() { } override fun deserialize(jsonObject: JSONObject): Action { - val actionType = jsonObject.optString(TYPE) - if (actionType.isEmpty()) { - throw CheckoutException("Action type not found") - } + val actionType = jsonObject.getStringOrNull(TYPE) ?: throw CheckoutException("Action type not found") val serializer = getChildSerializer(actionType) return serializer.deserialize(jsonObject) } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/action/TwintSdkData.kt b/components-core/src/main/java/com/adyen/checkout/components/core/action/TwintSdkData.kt index b62db89c2d..547f0a6435 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/action/TwintSdkData.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/action/TwintSdkData.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.components.core.action import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -41,7 +42,7 @@ data class TwintSdkData( return try { TwintSdkData( token = jsonObject.getString(TOKEN), - isStored = jsonObject.optBoolean(IS_STORED), + isStored = jsonObject.getBooleanOrNull(IS_STORED) ?: false, ) } catch (e: JSONException) { throw ModelSerializationException(TwintSdkData::class.java, e) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/PublicKeyResponse.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/PublicKeyResponse.kt index 775e7d766f..8884c44a59 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/PublicKeyResponse.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/PublicKeyResponse.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.components.core.internal.data.model import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -38,7 +39,7 @@ internal data class PublicKeyResponse( override fun deserialize(jsonObject: JSONObject): PublicKeyResponse { return try { PublicKeyResponse( - publicKey = jsonObject.optString(PUBLIC_KEY) + publicKey = jsonObject.getStringOrNull(PUBLIC_KEY).orEmpty(), ) } catch (e: JSONException) { throw ModelSerializationException(PublicKeyResponse::class.java, e) diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/BillingAddressParameters.kt b/googlepay/src/main/java/com/adyen/checkout/googlepay/BillingAddressParameters.kt index 03ef5e2662..1673aae4de 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/BillingAddressParameters.kt +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/BillingAddressParameters.kt @@ -9,6 +9,7 @@ package com.adyen.checkout.googlepay import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException @@ -49,7 +50,7 @@ data class BillingAddressParameters( override fun deserialize(jsonObject: JSONObject) = BillingAddressParameters( format = jsonObject.getStringOrNull(FORMAT), - isPhoneNumberRequired = jsonObject.optBoolean(PHONE_NUMBER_REQUIRED), + isPhoneNumberRequired = jsonObject.getBooleanOrNull(PHONE_NUMBER_REQUIRED) ?: false, ) } } diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/ShippingAddressParameters.kt b/googlepay/src/main/java/com/adyen/checkout/googlepay/ShippingAddressParameters.kt index 133d6f2b5a..04722a1b7a 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/ShippingAddressParameters.kt +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/ShippingAddressParameters.kt @@ -11,6 +11,7 @@ import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.JsonUtils.parseOptStringList import com.adyen.checkout.core.internal.data.model.JsonUtils.serializeOptStringList import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -50,7 +51,7 @@ data class ShippingAddressParameters( override fun deserialize(jsonObject: JSONObject) = ShippingAddressParameters( allowedCountryCodes = parseOptStringList(jsonObject.optJSONArray(ALLOWED_COUNTRY_CODES)), - isPhoneNumberRequired = jsonObject.optBoolean(PHONE_NUMBER_REQUIRED), + isPhoneNumberRequired = jsonObject.getBooleanOrNull(PHONE_NUMBER_REQUIRED) ?: false, ) } } diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/CardParameters.kt b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/CardParameters.kt index cf72f8d6c2..629fb15a84 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/CardParameters.kt +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/CardParameters.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.core.internal.data.model.JsonUtils.serializeOptStringL import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils.deserializeOpt import com.adyen.checkout.core.internal.data.model.ModelUtils.serializeOpt +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull import com.adyen.checkout.googlepay.BillingAddressParameters import kotlinx.parcelize.Parcelize import org.json.JSONException @@ -51,7 +52,7 @@ internal data class CardParameters( putOpt(BILLING_ADDRESS_REQUIRED, modelObject.isBillingAddressRequired) putOpt( BILLING_ADDRESS_PARAMETERS, - serializeOpt(modelObject.billingAddressParameters, BillingAddressParameters.SERIALIZER) + serializeOpt(modelObject.billingAddressParameters, BillingAddressParameters.SERIALIZER), ) } } catch (e: JSONException) { @@ -62,13 +63,13 @@ internal data class CardParameters( override fun deserialize(jsonObject: JSONObject) = CardParameters( allowedAuthMethods = parseOptStringList(jsonObject.optJSONArray(ALLOWED_AUTH_METHODS)), allowedCardNetworks = parseOptStringList(jsonObject.optJSONArray(ALLOWED_CARD_NETWORKS)), - isAllowPrepaidCards = jsonObject.optBoolean(ALLOW_PREPAID_CARDS), - isAllowCreditCards = jsonObject.optBoolean(ALLOW_CREDIT_CARDS), - isAssuranceDetailsRequired = jsonObject.optBoolean(ASSURANCE_DETAILS_REQUIRED), - isBillingAddressRequired = jsonObject.optBoolean(BILLING_ADDRESS_REQUIRED), + isAllowPrepaidCards = jsonObject.getBooleanOrNull(ALLOW_PREPAID_CARDS) ?: false, + isAllowCreditCards = jsonObject.getBooleanOrNull(ALLOW_CREDIT_CARDS), + isAssuranceDetailsRequired = jsonObject.getBooleanOrNull(ASSURANCE_DETAILS_REQUIRED), + isBillingAddressRequired = jsonObject.getBooleanOrNull(BILLING_ADDRESS_REQUIRED) ?: false, billingAddressParameters = deserializeOpt( jsonObject.optJSONObject(BILLING_ADDRESS_PARAMETERS), - BillingAddressParameters.SERIALIZER + BillingAddressParameters.SERIALIZER, ), ) } diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/IsReadyToPayRequestModel.kt b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/IsReadyToPayRequestModel.kt index b383e211ad..c1f7bdc573 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/IsReadyToPayRequestModel.kt +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/IsReadyToPayRequestModel.kt @@ -11,6 +11,8 @@ import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils.deserializeOptList import com.adyen.checkout.core.internal.data.model.ModelUtils.serializeOptList +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull +import com.adyen.checkout.core.internal.data.model.getIntOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -38,7 +40,7 @@ internal data class IsReadyToPayRequestModel( putOpt(API_VERSION_MINOR, modelObject.apiVersionMinor) putOpt( ALLOWED_PAYMENT_METHODS, - serializeOptList(modelObject.allowedPaymentMethods, GooglePayPaymentMethodModel.SERIALIZER) + serializeOptList(modelObject.allowedPaymentMethods, GooglePayPaymentMethodModel.SERIALIZER), ) putOpt(EXISTING_PAYMENT_METHOD_REQUIRED, modelObject.isExistingPaymentMethodRequired) } @@ -48,13 +50,14 @@ internal data class IsReadyToPayRequestModel( } override fun deserialize(jsonObject: JSONObject) = IsReadyToPayRequestModel( - apiVersion = jsonObject.optInt(API_VERSION), - apiVersionMinor = jsonObject.optInt(API_VERSION_MINOR), + apiVersion = jsonObject.getIntOrNull(API_VERSION) ?: 0, + apiVersionMinor = jsonObject.getIntOrNull(API_VERSION_MINOR) ?: 0, allowedPaymentMethods = deserializeOptList( jsonObject.optJSONArray(ALLOWED_PAYMENT_METHODS), - GooglePayPaymentMethodModel.SERIALIZER + GooglePayPaymentMethodModel.SERIALIZER, ), - isExistingPaymentMethodRequired = jsonObject.optBoolean(EXISTING_PAYMENT_METHOD_REQUIRED) + isExistingPaymentMethodRequired = jsonObject.getBooleanOrNull(EXISTING_PAYMENT_METHOD_REQUIRED) + ?: false, ) } } diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/PaymentDataRequestModel.kt b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/PaymentDataRequestModel.kt index 08b74268e7..acaa06eb12 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/PaymentDataRequestModel.kt +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/data/model/PaymentDataRequestModel.kt @@ -13,6 +13,8 @@ import com.adyen.checkout.core.internal.data.model.ModelUtils.deserializeOpt import com.adyen.checkout.core.internal.data.model.ModelUtils.deserializeOptList import com.adyen.checkout.core.internal.data.model.ModelUtils.serializeOpt import com.adyen.checkout.core.internal.data.model.ModelUtils.serializeOptList +import com.adyen.checkout.core.internal.data.model.getBooleanOrNull +import com.adyen.checkout.core.internal.data.model.getIntOrNull import com.adyen.checkout.googlepay.MerchantInfo import com.adyen.checkout.googlepay.ShippingAddressParameters import kotlinx.parcelize.Parcelize @@ -51,17 +53,17 @@ internal data class PaymentDataRequestModel( putOpt(MERCHANT_INFO, serializeOpt(modelObject.merchantInfo, MerchantInfo.SERIALIZER)) putOpt( ALLOWED_PAYMENT_METHODS, - serializeOptList(modelObject.allowedPaymentMethods, GooglePayPaymentMethodModel.SERIALIZER) + serializeOptList(modelObject.allowedPaymentMethods, GooglePayPaymentMethodModel.SERIALIZER), ) putOpt( TRANSACTION_INFO, - serializeOpt(modelObject.transactionInfo, TransactionInfoModel.SERIALIZER) + serializeOpt(modelObject.transactionInfo, TransactionInfoModel.SERIALIZER), ) putOpt(EMAIL_REQUIRED, modelObject.isEmailRequired) putOpt(SHIPPING_ADDRESS_REQUIRED, modelObject.isShippingAddressRequired) putOpt( SHIPPING_ADDRESS_PARAMETERS, - serializeOpt(modelObject.shippingAddressParameters, ShippingAddressParameters.SERIALIZER) + serializeOpt(modelObject.shippingAddressParameters, ShippingAddressParameters.SERIALIZER), ) } } catch (e: JSONException) { @@ -71,25 +73,26 @@ internal data class PaymentDataRequestModel( override fun deserialize(jsonObject: JSONObject): PaymentDataRequestModel { val paymentDataRequestModel = PaymentDataRequestModel() - paymentDataRequestModel.apiVersion = jsonObject.optInt(API_VERSION) - paymentDataRequestModel.apiVersionMinor = jsonObject.optInt(API_VERSION_MINOR) + paymentDataRequestModel.apiVersion = jsonObject.getIntOrNull(API_VERSION) ?: 0 + paymentDataRequestModel.apiVersionMinor = jsonObject.getIntOrNull(API_VERSION_MINOR) ?: 0 paymentDataRequestModel.merchantInfo = deserializeOpt( jsonObject.optJSONObject(MERCHANT_INFO), - MerchantInfo.SERIALIZER + MerchantInfo.SERIALIZER, ) paymentDataRequestModel.allowedPaymentMethods = deserializeOptList( jsonObject.optJSONArray(ALLOWED_PAYMENT_METHODS), - GooglePayPaymentMethodModel.SERIALIZER + GooglePayPaymentMethodModel.SERIALIZER, ) paymentDataRequestModel.transactionInfo = deserializeOpt( jsonObject.optJSONObject(TRANSACTION_INFO), - TransactionInfoModel.SERIALIZER + TransactionInfoModel.SERIALIZER, ) - paymentDataRequestModel.isEmailRequired = jsonObject.optBoolean(EMAIL_REQUIRED) - paymentDataRequestModel.isShippingAddressRequired = jsonObject.optBoolean(SHIPPING_ADDRESS_REQUIRED) + paymentDataRequestModel.isEmailRequired = jsonObject.getBooleanOrNull(EMAIL_REQUIRED) ?: false + paymentDataRequestModel.isShippingAddressRequired = + jsonObject.getBooleanOrNull(SHIPPING_ADDRESS_REQUIRED) ?: false paymentDataRequestModel.shippingAddressParameters = deserializeOpt( jsonObject.optJSONObject(SHIPPING_ADDRESS_PARAMETERS), - ShippingAddressParameters.SERIALIZER + ShippingAddressParameters.SERIALIZER, ) return paymentDataRequestModel } diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtils.kt b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtils.kt index 64eccaa025..990cc45d51 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtils.kt +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtils.kt @@ -143,7 +143,7 @@ internal object GooglePayUtils { val tokenizationDataJson = paymentMethodDataJson.getJSONObject(TOKENIZATION_DATA) googlePayToken = tokenizationDataJson.getString(TOKEN) val infoJson = paymentMethodDataJson.optJSONObject(INFO) - if (infoJson != null && infoJson.has(CARD_NETWORK)) { + if (infoJson != null && !infoJson.isNull(CARD_NETWORK)) { googlePayCardNetwork = infoJson.getString(CARD_NETWORK) } } catch (e: JSONException) { diff --git a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt index c9b438fbd3..de0baabdc1 100644 --- a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt +++ b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt @@ -31,6 +31,7 @@ import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.exception.ComponentException import com.adyen.checkout.core.exception.HttpException import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.internal.data.model.getStringOrNull import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.redirect.internal.data.api.NativeRedirectService import com.adyen.checkout.redirect.internal.data.model.NativeRedirectRequest @@ -171,7 +172,7 @@ constructor( coroutineScope.launch { val request = NativeRedirectRequest( redirectData = nativeRedirectData, - returnQueryString = details.optString(RETURN_URL_QUERY_STRING_PARAMETER), + returnQueryString = details.getStringOrNull(RETURN_URL_QUERY_STRING_PARAMETER).orEmpty(), ) try { val response = nativeRedirectService.makeNativeRedirect(request, componentParams.clientKey) diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionModel.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionModel.kt index 18a85beb1e..50eb5b0bdb 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionModel.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionModel.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.sessions.core import com.adyen.checkout.components.core.PaymentMethodsApiResponse import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -43,8 +44,8 @@ data class SessionModel( override fun deserialize(jsonObject: JSONObject): SessionModel { return SessionModel( - id = jsonObject.optString(ID), - sessionData = jsonObject.optString(SESSION_DATA) + id = jsonObject.getStringOrNull(ID).orEmpty(), + sessionData = jsonObject.getStringOrNull(SESSION_DATA) ) } } diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupConfiguration.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupConfiguration.kt index 74cfa2f6be..f985ec6f23 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupConfiguration.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupConfiguration.kt @@ -52,7 +52,7 @@ data class SessionSetupConfiguration( return try { SessionSetupConfiguration( enableStoreDetails = jsonObject.getBooleanOrNull(ENABLE_STORE_DETAILS), - showInstallmentAmount = jsonObject.optBoolean(SHOW_INSTALLMENT_AMOUNT), + showInstallmentAmount = jsonObject.getBooleanOrNull(SHOW_INSTALLMENT_AMOUNT) ?: false, installmentOptions = jsonObject.optJSONObject(INSTALLMENT_OPTIONS) ?.jsonToMap(SessionSetupInstallmentOptions.SERIALIZER), showRemovePaymentMethodButton = jsonObject.getBooleanOrNull(SHOW_REMOVE_PAYMENT_METHOD_BUTTON), diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupInstallmentOptions.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupInstallmentOptions.kt index e7f197b4d9..69f1589663 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupInstallmentOptions.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupInstallmentOptions.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.sessions.core import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.JsonUtils import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getIntOrNull import com.adyen.checkout.core.internal.data.model.optIntList import com.adyen.checkout.core.internal.data.model.optStringList import kotlinx.parcelize.Parcelize @@ -48,7 +49,7 @@ data class SessionSetupInstallmentOptions( return try { SessionSetupInstallmentOptions( plans = jsonObject.optStringList(PLANS).orEmpty(), - preselectedValue = jsonObject.optInt(PRESELECTED_VALUE), + preselectedValue = jsonObject.getIntOrNull(PRESELECTED_VALUE), values = jsonObject.optIntList(VALUES) ) } catch (e: JSONException) { diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupResponse.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupResponse.kt index ed32a60092..2fad56cee6 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupResponse.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/SessionSetupResponse.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.components.core.PaymentMethodsApiResponse import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -70,20 +71,20 @@ data class SessionSetupResponse( override fun deserialize(jsonObject: JSONObject): SessionSetupResponse { return try { SessionSetupResponse( - id = jsonObject.optString(ID), - sessionData = jsonObject.optString(SESSION_DATA), + id = jsonObject.getStringOrNull(ID).orEmpty(), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), amount = ModelUtils.deserializeOpt(jsonObject.optJSONObject(AMOUNT), Amount.SERIALIZER), - expiresAt = jsonObject.optString(EXPIRES_AT), + expiresAt = jsonObject.getStringOrNull(EXPIRES_AT).orEmpty(), paymentMethodsApiResponse = ModelUtils.deserializeOpt( jsonObject.optJSONObject(PAYMENT_METHODS), PaymentMethodsApiResponse.SERIALIZER ), - returnUrl = jsonObject.optString(RETURN_URL), + returnUrl = jsonObject.getStringOrNull(RETURN_URL), configuration = ModelUtils.deserializeOpt( jsonObject.optJSONObject(CONFIGURATION), SessionSetupConfiguration.SERIALIZER ), - shopperLocale = jsonObject.optString(SHOPPER_LOCALE), + shopperLocale = jsonObject.getStringOrNull(SHOPPER_LOCALE), ) } catch (e: JSONException) { throw ModelSerializationException(SessionSetupResponse::class.java, e) diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceRequest.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceRequest.kt index 2b27cc96be..3652db5235 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceRequest.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceRequest.kt @@ -14,6 +14,7 @@ import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -57,7 +58,7 @@ data class SessionBalanceRequest( override fun deserialize(jsonObject: JSONObject): SessionBalanceRequest { return try { SessionBalanceRequest( - sessionData = jsonObject.optString(SESSION_DATA), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), paymentMethod = ModelUtils.deserializeOpt( jsonObject.optJSONObject(PAYMENT_METHOD), PaymentMethodDetails.SERIALIZER diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceResponse.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceResponse.kt index d64bd628b3..0a54d9e078 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceResponse.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionBalanceResponse.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -49,7 +50,7 @@ data class SessionBalanceResponse( override fun deserialize(jsonObject: JSONObject): SessionBalanceResponse { return SessionBalanceResponse( - sessionData = jsonObject.optString(SESSION_DATA), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), balance = ModelUtils.deserializeOpt(jsonObject.optJSONObject(BALANCE), Amount.SERIALIZER) ?: throw CheckoutException("Balance not found"), transactionLimit = ModelUtils.deserializeOpt( diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderRequest.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderRequest.kt index 32bf12a9bc..55199dddae 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderRequest.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderRequest.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -44,7 +45,7 @@ data class SessionCancelOrderRequest( override fun deserialize(jsonObject: JSONObject): SessionCancelOrderRequest { return try { SessionCancelOrderRequest( - sessionData = jsonObject.optString(SESSION_DATA), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), order = ModelUtils.deserializeOpt(jsonObject.optJSONObject(ORDER), OrderRequest.SERIALIZER) ) } catch (e: JSONException) { diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderResponse.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderResponse.kt index 25cb081912..639c643dce 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderResponse.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionCancelOrderResponse.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.sessions.core.internal.data.model import androidx.annotation.RestrictTo import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -40,8 +41,8 @@ data class SessionCancelOrderResponse( override fun deserialize(jsonObject: JSONObject): SessionCancelOrderResponse { return SessionCancelOrderResponse( - sessionData = jsonObject.optString(SESSION_DATA), - status = jsonObject.optString(STATUS) + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), + status = jsonObject.getStringOrNull(STATUS) ) } } diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsRequest.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsRequest.kt index 868e8b86a7..453b63a17d 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsRequest.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsRequest.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.sessions.core.internal.data.model import androidx.annotation.RestrictTo import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import com.adyen.checkout.core.internal.util.JSONObjectParceler import kotlinx.parcelize.Parcelize import kotlinx.parcelize.WriteWith @@ -47,8 +48,8 @@ data class SessionDetailsRequest( override fun deserialize(jsonObject: JSONObject): SessionDetailsRequest { return try { SessionDetailsRequest( - sessionData = jsonObject.optString(SESSION_DATA), - paymentData = jsonObject.optString(PAYMENT_DATA), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), + paymentData = jsonObject.getStringOrNull(PAYMENT_DATA), details = jsonObject.optJSONObject(DETAILS) ) } catch (e: JSONException) { diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsResponse.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsResponse.kt index 35c742e86e..e87790414a 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsResponse.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDetailsResponse.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -55,11 +56,11 @@ data class SessionDetailsResponse( override fun deserialize(jsonObject: JSONObject): SessionDetailsResponse { return SessionDetailsResponse( - sessionData = jsonObject.optString(SESSION_DATA), - status = jsonObject.optString(STATUS), - resultCode = jsonObject.optString(RESULT_CODE), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), + status = jsonObject.getStringOrNull(STATUS), + resultCode = jsonObject.getStringOrNull(RESULT_CODE), action = ModelUtils.deserializeOpt(jsonObject.optJSONObject(ACTION), Action.SERIALIZER), - sessionResult = jsonObject.optString(SESSION_RESULT), + sessionResult = jsonObject.getStringOrNull(SESSION_RESULT), order = ModelUtils.deserializeOpt(jsonObject.optJSONObject(ORDER), OrderResponse.SERIALIZER), ) } diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenRequest.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenRequest.kt index cce3a5b34b..235be2540a 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenRequest.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenRequest.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.sessions.core.internal.data.model import androidx.annotation.RestrictTo import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -41,8 +42,8 @@ data class SessionDisableTokenRequest( override fun deserialize(jsonObject: JSONObject): SessionDisableTokenRequest { return try { SessionDisableTokenRequest( - sessionData = jsonObject.optString(SESSION_DATA), - storedPaymentMethodId = jsonObject.optString(STORED_PAYMENT_METHOD_ID), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), + storedPaymentMethodId = jsonObject.getStringOrNull(STORED_PAYMENT_METHOD_ID).orEmpty(), ) } catch (e: JSONException) { throw ModelSerializationException(SessionDisableTokenRequest::class.java, e) diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenResponse.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenResponse.kt index e0fe3c37d1..51e3bcc845 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenResponse.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionDisableTokenResponse.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.sessions.core.internal.data.model import androidx.annotation.RestrictTo import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -38,7 +39,7 @@ data class SessionDisableTokenResponse( override fun deserialize(jsonObject: JSONObject): SessionDisableTokenResponse { return try { SessionDisableTokenResponse( - sessionData = jsonObject.optString(SESSION_DATA), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), ) } catch (e: JSONException) { throw ModelSerializationException(SessionDisableTokenResponse::class.java, e) diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderRequest.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderRequest.kt index c6d04dc87e..46c3993525 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderRequest.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderRequest.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.sessions.core.internal.data.model import androidx.annotation.RestrictTo import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -39,7 +40,7 @@ data class SessionOrderRequest( override fun deserialize(jsonObject: JSONObject): SessionOrderRequest { return try { SessionOrderRequest( - sessionData = jsonObject.optString(SESSION_DATA) + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), ) } catch (e: JSONException) { throw ModelSerializationException(SessionOrderRequest::class.java, e) diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderResponse.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderResponse.kt index 63f7f0ca49..08913c2b24 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderResponse.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionOrderResponse.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.sessions.core.internal.data.model import androidx.annotation.RestrictTo import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -43,9 +44,9 @@ data class SessionOrderResponse( override fun deserialize(jsonObject: JSONObject): SessionOrderResponse { return SessionOrderResponse( - sessionData = jsonObject.optString(SESSION_DATA), - orderData = jsonObject.optString(ORDER_DATA), - pspReference = jsonObject.optString(PSP_REFERENCE) + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), + orderData = jsonObject.getStringOrNull(ORDER_DATA).orEmpty(), + pspReference = jsonObject.getStringOrNull(PSP_REFERENCE).orEmpty(), ) } } diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsRequest.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsRequest.kt index 40bf1b5a22..ecabdfa241 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsRequest.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsRequest.kt @@ -14,6 +14,7 @@ import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -45,7 +46,7 @@ data class SessionPaymentsRequest( override fun deserialize(jsonObject: JSONObject): SessionPaymentsRequest { return try { SessionPaymentsRequest( - sessionData = jsonObject.optString(SESSION_DATA), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), paymentComponentData = ModelUtils.deserializeOpt( jsonObject, PaymentComponentData.SERIALIZER diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsResponse.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsResponse.kt index 88ea349dd2..5422b4fff7 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsResponse.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionPaymentsResponse.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -55,12 +56,12 @@ data class SessionPaymentsResponse( override fun deserialize(jsonObject: JSONObject): SessionPaymentsResponse { return SessionPaymentsResponse( - sessionData = jsonObject.optString(SESSION_DATA), - status = jsonObject.optString(STATUS), - resultCode = jsonObject.optString(RESULT_CODE), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), + status = jsonObject.getStringOrNull(STATUS), + resultCode = jsonObject.getStringOrNull(RESULT_CODE), action = ModelUtils.deserializeOpt(jsonObject.optJSONObject(ACTION), Action.SERIALIZER), order = ModelUtils.deserializeOpt(jsonObject.optJSONObject(ORDER), OrderResponse.SERIALIZER), - sessionResult = jsonObject.optString(SESSION_RESULT), + sessionResult = jsonObject.getStringOrNull(SESSION_RESULT), ) } } diff --git a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionSetupRequest.kt b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionSetupRequest.kt index 0cfcc692cb..b92aaea3b5 100644 --- a/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionSetupRequest.kt +++ b/sessions-core/src/main/java/com/adyen/checkout/sessions/core/internal/data/model/SessionSetupRequest.kt @@ -13,6 +13,7 @@ import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.core.internal.data.model.ModelObject import com.adyen.checkout.core.internal.data.model.ModelUtils +import com.adyen.checkout.core.internal.data.model.getStringOrNull import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject @@ -44,7 +45,7 @@ data class SessionSetupRequest( override fun deserialize(jsonObject: JSONObject): SessionSetupRequest { return try { SessionSetupRequest( - sessionData = jsonObject.optString(SESSION_DATA), + sessionData = jsonObject.getStringOrNull(SESSION_DATA).orEmpty(), order = ModelUtils.deserializeOpt(jsonObject.optJSONObject(ORDER), OrderRequest.SERIALIZER) ) } catch (e: JSONException) { From 4ac905a23ee1021472dfe272d0bdd60da0279059 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:14:47 +0000 Subject: [PATCH 018/102] Update junit5 monorepo to v5.11.3 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 67 ++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 86dbba3d7c..28bc35f8d5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -68,7 +68,7 @@ barista = "4.3.0" espresso = "3.6.1" json = "20240303" jose4j = "0.9.6" -junit-jupiter = "5.11.1" +junit-jupiter = "5.11.3" konsist = "0.16.1" lint = "31.7.0" mockito-kotlin = "5.4.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c3e7309513..e6413ae60e 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5477,18 +5477,13 @@ - - - - - - - - + + + @@ -14799,6 +14794,14 @@ + + + + + + + + @@ -14847,6 +14850,14 @@ + + + + + + + + @@ -14879,6 +14890,14 @@ + + + + + + + + @@ -14911,6 +14930,14 @@ + + + + + + + + @@ -14943,6 +14970,14 @@ + + + + + + + + @@ -14975,6 +15010,14 @@ + + + + + + + + @@ -15007,6 +15050,14 @@ + + + + + + + + From 84022a8a6c5d5448a3ff6349318b8633c3aca01a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:12:32 +0000 Subject: [PATCH 019/102] Update dependency org.sonarqube to v5.1.0.4882 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 28bc35f8d5..eb0a8c3e92 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,7 +21,7 @@ compose-compiler = "1.5.15" detekt = "1.23.7" jacoco = "0.8.12" ktlint = "1.3.1" -sonarqube = "5.0.0.4638" +sonarqube = "5.1.0.4882" binary-compatibility-validator = "0.16.3" # Android dependencies diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e6413ae60e..b2ea0ac1fa 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -15920,6 +15920,11 @@ + + + + + @@ -15954,6 +15959,14 @@ + + + + + + + + From a4e7e7a1ddc4d8bb44cfbdba965599a8742ce8f9 Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Mon, 28 Oct 2024 14:19:58 +0100 Subject: [PATCH 020/102] Replace usage of Dispatchers with DispatcherProvider This will make sure espresso tests will be aware of all async work that is happening and should fix the UI tests. --- .../example/repositories/RepositoryUtils.kt | 6 +-- .../service/ExampleAdvancedDropInService.kt | 24 ++++++--- .../example/service/ExampleDropInService.kt | 13 +++-- .../service/ExampleSessionsDropInService.kt | 8 +-- .../checkout/example/ui/bacs/BacsViewModel.kt | 17 ++++--- .../checkout/example/ui/blik/BlikViewModel.kt | 11 ++-- .../checkout/example/ui/card/CardViewModel.kt | 11 ++-- .../ui/card/SessionsCardTakenOverViewModel.kt | 8 +-- .../example/ui/giftcard/GiftCardViewModel.kt | 51 +++++++++++-------- .../ui/googlepay/GooglePayViewModel.kt | 11 ++-- .../compose/SessionsGooglePayViewModel.kt | 5 +- .../example/ui/instant/InstantViewModel.kt | 11 ++-- 12 files changed, 109 insertions(+), 67 deletions(-) diff --git a/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt b/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt index bf36721b19..0141a64236 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt @@ -9,12 +9,12 @@ package com.adyen.checkout.example.repositories import android.util.Log +import com.adyen.checkout.core.DispatcherProvider import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -@Suppress("TooGenericExceptionCaught") -internal suspend fun safeApiCall(call: suspend () -> T): T? = withContext(Dispatchers.IO) { +@Suppress("TooGenericExceptionCaught", "RestrictedApi") +internal suspend fun safeApiCall(call: suspend () -> T): T? = withContext(DispatcherProvider.IO) { return@withContext try { call() } catch (e: CancellationException) { diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt index 0b7652bed2..cfb1a46354 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt @@ -22,6 +22,7 @@ import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.dropin.AddressLookupDropInServiceResult import com.adyen.checkout.dropin.BalanceDropInServiceResult @@ -39,7 +40,6 @@ import com.adyen.checkout.example.repositories.AddressLookupRepository import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -80,6 +80,7 @@ class ExampleAdvancedDropInService : DropInService() { is AddressLookupCompletionState.Address -> { AddressLookupDropInServiceResult.LookupComplete(it.lookupAddress) } + is AddressLookupCompletionState.Error -> AddressLookupDropInServiceResult.Error( errorDialog = ErrorDialog( message = it.message, @@ -90,10 +91,11 @@ class ExampleAdvancedDropInService : DropInService() { }.launchIn(this) } + @Suppress("RestrictedApi") override fun onSubmit( state: PaymentComponentState<*>, ) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "onPaymentsCallRequested") checkPaymentState(state) @@ -139,8 +141,9 @@ class ExampleAdvancedDropInService : DropInService() { // read bundle and handle it } + @Suppress("RestrictedApi") override fun onAdditionalDetails(actionComponentData: ActionComponentData) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "onDetailsCallRequested") val actionComponentJson = ActionComponentData.SERIALIZER.serialize(actionComponentData) @@ -212,9 +215,10 @@ class ExampleAdvancedDropInService : DropInService() { return OrderResponse.SERIALIZER.deserialize(orderJSON) } + @Suppress("RestrictedApi") private fun fetchPaymentMethods(orderResponse: OrderResponse? = null) { Log.d(TAG, "fetchPaymentMethods") - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { val order = orderResponse?.let { Order( pspReference = it.pspReference, @@ -241,8 +245,9 @@ class ExampleAdvancedDropInService : DropInService() { } } + @Suppress("RestrictedApi") override fun onBalanceCheck(paymentComponentState: PaymentComponentState<*>) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "checkBalance") val amount = paymentComponentState.data.amount val paymentMethod = paymentComponentState.data.paymentMethod @@ -295,8 +300,9 @@ class ExampleAdvancedDropInService : DropInService() { } } + @Suppress("RestrictedApi") override fun onOrderRequest() { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "createOrder") val paymentRequest = createOrderRequest( @@ -326,8 +332,9 @@ class ExampleAdvancedDropInService : DropInService() { } } + @Suppress("RestrictedApi") override fun onOrderCancel(order: Order, shouldUpdatePaymentMethods: Boolean) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "cancelOrder") val orderJson = Order.SERIALIZER.serialize(order) val request = createCancelOrderRequest( @@ -364,10 +371,11 @@ class ExampleAdvancedDropInService : DropInService() { } } + @Suppress("RestrictedApi") override fun onRemoveStoredPaymentMethod( storedPaymentMethod: StoredPaymentMethod, ) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { val storedPaymentMethodId = storedPaymentMethod.id.orEmpty() val isSuccessfullyRemoved = paymentsRepository.removeStoredPaymentMethod( storedPaymentMethodId = storedPaymentMethodId, diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt index 6805bf99be..d5bcd49371 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt @@ -15,6 +15,7 @@ import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.dropin.DropInService import com.adyen.checkout.dropin.DropInServiceResult import com.adyen.checkout.dropin.ErrorDialog @@ -25,7 +26,6 @@ import com.adyen.checkout.example.extensions.toStringPretty import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.json.JSONObject import javax.inject.Inject @@ -43,10 +43,11 @@ class ExampleDropInService : DropInService() { @Inject lateinit var keyValueStorage: KeyValueStorage + @Suppress("RestrictedApi") override fun onSubmit( state: PaymentComponentState<*> ) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "onPaymentsCallRequested") checkPaymentState(state) @@ -61,7 +62,7 @@ class ExampleDropInService : DropInService() { merchantAccount = keyValueStorage.getMerchantAccount(), redirectUrl = RedirectComponent.getReturnUrl(applicationContext), threeDSMode = keyValueStorage.getThreeDSMode(), - shopperEmail = keyValueStorage.getShopperEmail() + shopperEmail = keyValueStorage.getShopperEmail(), ) Log.v(TAG, "paymentComponentJson - ${paymentComponentJson.toStringPretty()}") @@ -82,8 +83,9 @@ class ExampleDropInService : DropInService() { } } + @Suppress("RestrictedApi") override fun onAdditionalDetails(actionComponentData: ActionComponentData) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "onDetailsCallRequested") val actionComponentJson = ActionComponentData.SERIALIZER.serialize(actionComponentData) @@ -126,10 +128,11 @@ class ExampleDropInService : DropInService() { return jsonResponse.has("action") } + @Suppress("RestrictedApi") override fun onRemoveStoredPaymentMethod( storedPaymentMethod: StoredPaymentMethod, ) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { val storedPaymentMethodId = storedPaymentMethod.id.orEmpty() val isSuccessfullyRemoved = paymentsRepository.removeStoredPaymentMethod( storedPaymentMethodId = storedPaymentMethodId, diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt index e3fa9acd74..268db5b20a 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt @@ -15,6 +15,7 @@ import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.dropin.DropInServiceResult import com.adyen.checkout.dropin.ErrorDialog import com.adyen.checkout.dropin.SessionDropInService @@ -24,7 +25,6 @@ import com.adyen.checkout.example.extensions.toStringPretty import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.json.JSONObject import javax.inject.Inject @@ -38,6 +38,7 @@ class ExampleSessionsDropInService : SessionDropInService() { @Inject lateinit var keyValueStorage: KeyValueStorage + @Suppress("RestrictedApi") override fun onSubmit( state: PaymentComponentState<*>, ): Boolean { @@ -45,7 +46,7 @@ class ExampleSessionsDropInService : SessionDropInService() { state is BlikComponentState || state is CardComponentState ) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "onPaymentsCallRequested") // Check out the documentation of this method on the parent DropInService class @@ -73,11 +74,12 @@ class ExampleSessionsDropInService : SessionDropInService() { } } + @Suppress("RestrictedApi") override fun onAdditionalDetails( actionComponentData: ActionComponentData, ): Boolean { return if (isFlowTakenOver) { - launch(Dispatchers.IO) { + launch(DispatcherProvider.IO) { Log.d(TAG, "onDetailsCallRequested") val response = paymentsRepository.makeDetailsRequest( diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt index cb4e665c34..45ed525d8b 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt @@ -19,13 +19,13 @@ import com.adyen.checkout.components.core.ComponentCallback import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.R import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -57,7 +57,8 @@ internal class BacsViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - private suspend fun fetchPaymentMethods() = withContext(Dispatchers.IO) { + @Suppress("RestrictedApi") + private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { val validationError = if (keyValueStorage.getAmount().currency != CheckoutCurrency.GBP.name) { BacsViewState.Error(R.string.currency_code_error, CheckoutCurrency.GBP.name) } else if (keyValueStorage.getCountry() != Locale.UK.country) { @@ -79,7 +80,7 @@ internal class BacsViewModel @Inject constructor( countryCode = keyValueStorage.getCountry(), shopperLocale = keyValueStorage.getShopperLocale(), splitCardFundingSources = keyValueStorage.isSplitCardFundingSources(), - ) + ), ) val paymentMethod = paymentMethodResponse @@ -92,8 +93,8 @@ internal class BacsViewModel @Inject constructor( _bacsComponentDataFlow.emit( BacsComponentData( paymentMethod, - this@BacsViewModel - ) + this@BacsViewModel, + ), ) _viewState.emit(BacsViewState.ShowComponent) } @@ -115,8 +116,9 @@ internal class BacsViewModel @Inject constructor( viewModelScope.launch { _events.emit(BacsEvent.PaymentResult("Failed: ${error.errorMessage}")) } } + @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } @@ -145,7 +147,8 @@ internal class BacsViewModel @Inject constructor( val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(Dispatchers.IO) { + @Suppress("RestrictedApi") + viewModelScope.launch(DispatcherProvider.IO) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt index 257a5f117d..7a18bea928 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt @@ -20,13 +20,13 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.components.core.paymentmethod.BlikPaymentMethod +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.R import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow @@ -55,7 +55,8 @@ class BlikViewModel @Inject constructor( viewModelScope.launch { _blikViewState.emit(fetchPaymentMethods()) } } - private suspend fun fetchPaymentMethods(): BlikViewState = withContext(Dispatchers.IO) { + @Suppress("RestrictedApi") + private suspend fun fetchPaymentMethods(): BlikViewState = withContext(DispatcherProvider.IO) { if (keyValueStorage.getAmount().currency != CheckoutCurrency.PLN.name) { return@withContext BlikViewState.Error(R.string.currency_code_error, CheckoutCurrency.PLN.name) } else if (keyValueStorage.getCountry() != POLAND_COUNTRY_CODE) { @@ -70,7 +71,7 @@ class BlikViewModel @Inject constructor( countryCode = keyValueStorage.getCountry(), shopperLocale = keyValueStorage.getShopperLocale(), splitCardFundingSources = keyValueStorage.isSplitCardFundingSources(), - ) + ), ) val blikPaymentMethod = paymentMethodResponse @@ -132,13 +133,15 @@ class BlikViewModel @Inject constructor( val action = Action.SERIALIZER.deserialize(json.getJSONObject("action")) _blikViewState.value = BlikViewState.Action(action) } + else -> _events.emit(BlikEvent.PaymentResult("Finished: ${json.optString("resultCode")}")) } } ?: _events.emit(BlikEvent.PaymentResult("Failed")) } + @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 52c74d3291..80db930733 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -11,6 +11,7 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.AddressLookupCompletionState import com.adyen.checkout.example.repositories.AddressLookupRepository @@ -18,7 +19,6 @@ import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -60,7 +60,8 @@ internal class CardViewModel @Inject constructor( }.launchIn(viewModelScope) } - private suspend fun fetchPaymentMethods() = withContext(Dispatchers.IO) { + @Suppress("RestrictedApi") + private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -135,7 +136,8 @@ internal class CardViewModel @Inject constructor( val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(Dispatchers.IO) { + @Suppress("RestrictedApi") + viewModelScope.launch(DispatcherProvider.IO) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -169,8 +171,9 @@ internal class CardViewModel @Inject constructor( _events.emit(CardEvent.AdditionalAction(action)) } + @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt index c2206bbe6b..d323580ff5 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt @@ -22,6 +22,7 @@ import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.repositories.AddressLookupCompletionState @@ -38,7 +39,6 @@ import com.adyen.checkout.sessions.core.SessionComponentCallback import com.adyen.checkout.sessions.core.SessionModel import com.adyen.checkout.sessions.core.SessionPaymentResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -183,12 +183,13 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( return isFlowTakenOver } + @Suppress("RestrictedApi") private fun makePayment(data: PaymentComponentData<*>) { _cardViewState.value = CardViewState.Loading val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -222,8 +223,9 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( _events.emit(CardEvent.AdditionalAction(action)) } + @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt index a219c383e5..b223ef1f1d 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.extensions.getLogTag @@ -35,7 +36,6 @@ import com.adyen.checkout.giftcard.GiftCardComponent import com.adyen.checkout.giftcard.GiftCardComponentCallback import com.adyen.checkout.giftcard.GiftCardComponentState import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -68,7 +68,8 @@ internal class GiftCardViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - private suspend fun fetchPaymentMethods() = withContext(Dispatchers.IO) { + @Suppress("RestrictedApi") + private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -77,7 +78,7 @@ internal class GiftCardViewModel @Inject constructor( countryCode = keyValueStorage.getCountry(), shopperLocale = keyValueStorage.getShopperLocale(), splitCardFundingSources = keyValueStorage.isSplitCardFundingSources(), - ) + ), ) val giftCardPaymentMethod = paymentMethodResponse @@ -91,7 +92,7 @@ internal class GiftCardViewModel @Inject constructor( GiftCardComponentData( paymentMethod = giftCardPaymentMethod, callback = this@GiftCardViewModel, - ) + ), ) _giftCardViewStateFlow.emit(GiftCardViewState.ShowComponent) } @@ -112,8 +113,9 @@ internal class GiftCardViewModel @Inject constructor( // no ops override fun onStateChanged(state: GiftCardComponentState) = Unit + @Suppress("RestrictedApi") override fun onBalanceCheck(paymentComponentState: PaymentComponentState<*>) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { Log.d(TAG, "checkBalance") val amount = paymentComponentState.data.amount @@ -125,7 +127,7 @@ internal class GiftCardViewModel @Inject constructor( val request = createBalanceRequest( paymentMethodJson, amountJson, - keyValueStorage.getMerchantAccount() + keyValueStorage.getMerchantAccount(), ) val response = paymentsRepository.getBalance(request) @@ -145,27 +147,29 @@ internal class GiftCardViewModel @Inject constructor( _events.emit( GiftCardEvent.Balance( BalanceResult.SERIALIZER.deserialize( - jsonResponse - ) - ) + jsonResponse, + ), + ), ) } } + "NotEnoughBalance" -> { try { viewModelScope.launch { _events.emit( GiftCardEvent.Balance( BalanceResult.SERIALIZER.deserialize( - jsonResponse - ) - ) + jsonResponse, + ), + ), ) } } catch (e: ModelSerializationException) { viewModelScope.launch { _giftCardViewStateFlow.emit(GiftCardViewState.Error) } } } + else -> viewModelScope.launch { _giftCardViewStateFlow.emit(GiftCardViewState.Error) } } } else { @@ -173,13 +177,14 @@ internal class GiftCardViewModel @Inject constructor( } } + @Suppress("RestrictedApi") override fun onRequestOrder() { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { Log.d(TAG, "createOrder") val paymentRequest = createOrderRequest( keyValueStorage.getAmount(), - keyValueStorage.getMerchantAccount() + keyValueStorage.getMerchantAccount(), ) val response = paymentsRepository.createOrder(paymentRequest) @@ -196,9 +201,10 @@ internal class GiftCardViewModel @Inject constructor( _events.emit(GiftCardEvent.OrderCreated(orderResponse)) order = OrderRequest( orderData = orderResponse.orderData, - pspReference = orderResponse.pspReference + pspReference = orderResponse.pspReference, ) } + else -> viewModelScope.launch { _giftCardViewStateFlow.emit(GiftCardViewState.Error) } } } else { @@ -207,12 +213,13 @@ internal class GiftCardViewModel @Inject constructor( } } + @Suppress("RestrictedApi") private fun makePayment(data: PaymentComponentData<*>) { _giftCardViewStateFlow.value = GiftCardViewState.Loading val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -237,17 +244,20 @@ internal class GiftCardViewModel @Inject constructor( val action = Action.SERIALIZER.deserialize(json.getJSONObject("action")) handleAction(action) } + isRefusedInPartialPaymentFlow(json) -> { _events.emit(GiftCardEvent.PaymentResult("Refused in Partial Payment Flow")) } + isNonFullyPaidOrder(json) -> { order = getOrderFromResponse(json).let { Order( pspReference = it.pspReference, - orderData = it.orderData + orderData = it.orderData, ) } } + else -> _events.emit(GiftCardEvent.PaymentResult("Finished: ${json.optString("resultCode")}")) } } ?: _events.emit(GiftCardEvent.PaymentResult("Failed")) @@ -274,8 +284,9 @@ internal class GiftCardViewModel @Inject constructor( viewModelScope.launch { _events.emit(GiftCardEvent.AdditionalAction(action)) } } + @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } @@ -293,8 +304,8 @@ internal class GiftCardViewModel @Inject constructor( _events.emit( GiftCardEvent.ReloadComponent( order, - giftCardComponentData - ) + giftCardComponentData, + ), ) } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt index 6854a64c21..93d280b836 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt @@ -20,6 +20,7 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.R import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.PaymentsRepository @@ -29,7 +30,6 @@ import com.adyen.checkout.example.ui.configuration.CheckoutConfigurationProvider import com.adyen.checkout.googlepay.GooglePayComponent import com.adyen.checkout.googlepay.GooglePayComponentState import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -67,7 +67,8 @@ internal class GooglePayViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - private suspend fun fetchPaymentMethods() = withContext(Dispatchers.IO) { + @Suppress("RestrictedApi") + private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -137,8 +138,9 @@ internal class GooglePayViewModel @Inject constructor( viewModelScope.launch { _events.emit(GooglePayEvent.PaymentResult("Failed: ${error.errorMessage}")) } } + @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } @@ -167,7 +169,8 @@ internal class GooglePayViewModel @Inject constructor( val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(Dispatchers.IO) { + @Suppress("RestrictedApi") + viewModelScope.launch(DispatcherProvider.IO) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt index 07ceb78c2d..ea6a4c54ed 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt @@ -20,6 +20,7 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.repositories.PaymentsRepository @@ -37,7 +38,6 @@ import com.adyen.checkout.sessions.core.SessionComponentCallback import com.adyen.checkout.sessions.core.SessionModel import com.adyen.checkout.sessions.core.SessionPaymentResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -71,7 +71,8 @@ internal class SessionsGooglePayViewModel @Inject constructor( viewModelScope.launch { fetchSession() } } - private suspend fun fetchSession() = withContext(Dispatchers.IO) { + @Suppress("RestrictedApi") + private suspend fun fetchSession() = withContext(DispatcherProvider.IO) { val paymentMethodType = PaymentMethodTypes.GOOGLE_PAY val checkoutSession = getSession(paymentMethodType) if (checkoutSession == null) { diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt index 3c547191d5..26fd56a436 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt @@ -16,6 +16,7 @@ import com.adyen.checkout.components.core.ComponentCallback import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.PermissionHandlerCallback import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.repositories.PaymentsRepository @@ -23,7 +24,6 @@ import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest import com.adyen.checkout.instant.InstantComponentState import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -55,7 +55,8 @@ internal class InstantViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - private suspend fun fetchPaymentMethods() = withContext(Dispatchers.IO) { + @Suppress("RestrictedApi") + private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -118,11 +119,12 @@ internal class InstantViewModel @Inject constructor( permissionCallback = null } + @Suppress("RestrictedApi") private fun makePayment(data: PaymentComponentData<*>) { _instantViewState.tryEmit(InstantViewState.Loading) val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -153,8 +155,9 @@ internal class InstantViewModel @Inject constructor( } ?: _events.emit(InstantEvent.PaymentResult("Failed")) } + @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(DispatcherProvider.IO) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } From d21c072bdf112f2a1ce9b2fee6656b6ffe9129c8 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Tue, 15 Oct 2024 12:50:26 +0400 Subject: [PATCH 021/102] Create Error event type in analytics COAND-979 --- components-core/api/components-core.api | 87 ------------------- .../core/internal/analytics/AnalyticsEvent.kt | 28 ++++++ .../core/internal/analytics/ErrorEvent.kt | 43 +++++++++ .../core/internal/analytics/GenericEvents.kt | 11 +++ 4 files changed, 82 insertions(+), 87 deletions(-) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt diff --git a/components-core/api/components-core.api b/components-core/api/components-core.api index 9d27010c17..87e945e078 100644 --- a/components-core/api/components-core.api +++ b/components-core/api/components-core.api @@ -1667,93 +1667,6 @@ public abstract interface class com/adyen/checkout/components/core/internal/Paym public abstract fun isAvailable (Landroid/app/Application;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/internal/Configuration;Lcom/adyen/checkout/components/core/ComponentAvailableCallback;)V } -public final class com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info : com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent { - public fun (Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V - public synthetic fun (Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/lang/String; - public final fun component10 ()Ljava/lang/String; - public final fun component11 ()Ljava/lang/String; - public final fun component12 ()Ljava/util/Map; - public final fun component2 ()J - public final fun component3 ()Z - public final fun component4 ()Ljava/lang/String; - public final fun component5 ()Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public final fun component6 ()Ljava/lang/String; - public final fun component7 ()Ljava/lang/Boolean; - public final fun component8 ()Ljava/lang/String; - public final fun component9 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info; - public static synthetic fun copy$default (Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info;Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info; - public fun equals (Ljava/lang/Object;)Z - public final fun getBrand ()Ljava/lang/String; - public fun getComponent ()Ljava/lang/String; - public final fun getConfigData ()Ljava/util/Map; - public fun getId ()Ljava/lang/String; - public final fun getIssuer ()Ljava/lang/String; - public fun getShouldForceSend ()Z - public final fun getTarget ()Ljava/lang/String; - public fun getTimestamp ()J - public final fun getType ()Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public final fun getValidationErrorCode ()Ljava/lang/String; - public final fun getValidationErrorMessage ()Ljava/lang/String; - public fun hashCode ()I - public final fun isStoredPaymentMethod ()Ljava/lang/Boolean; - public fun toString ()Ljava/lang/String; -} - -public final class com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type : java/lang/Enum { - public static final field DISPLAYED Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static final field DOWNLOAD Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static final field FOCUS Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static final field INPUT Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static final field RENDERED Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static final field SELECTED Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static final field UNFOCUS Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static final field VALIDATION_ERROR Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public final fun getValue ()Ljava/lang/String; - public static fun valueOf (Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; - public static fun values ()[Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Info$Type; -} - -public final class com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log : com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent { - public fun (Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()J - public final fun component3 ()Z - public final fun component4 ()Ljava/lang/String; - public final fun component5 ()Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type; - public final fun component6 ()Ljava/lang/String; - public final fun component7 ()Ljava/lang/String; - public final fun component8 ()Ljava/lang/String; - public final fun component9 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log; - public static synthetic fun copy$default (Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log;Ljava/lang/String;JZLjava/lang/String;Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log; - public fun equals (Ljava/lang/Object;)Z - public fun getComponent ()Ljava/lang/String; - public fun getId ()Ljava/lang/String; - public final fun getMessage ()Ljava/lang/String; - public final fun getResult ()Ljava/lang/String; - public fun getShouldForceSend ()Z - public final fun getSubType ()Ljava/lang/String; - public final fun getTarget ()Ljava/lang/String; - public fun getTimestamp ()J - public final fun getType ()Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type : java/lang/Enum { - public static final field ACTION Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type; - public static final field SUBMIT Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type; - public static final field THREEDS2 Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public final fun getValue ()Ljava/lang/String; - public static fun valueOf (Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type; - public static fun values ()[Lcom/adyen/checkout/components/core/internal/analytics/AnalyticsEvent$Log$Type; -} - public final class com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory$Companion { } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt index 680768d24d..3b927909ff 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt @@ -20,6 +20,7 @@ sealed interface AnalyticsEvent { val shouldForceSend: Boolean val component: String + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class Info @DirectAnalyticsEventCreation constructor( override val id: String = UUID.randomUUID().toString(), override val timestamp: Long = Date().time, @@ -34,6 +35,8 @@ sealed interface AnalyticsEvent { val validationErrorMessage: String? = null, val configData: Map? = null, ) : AnalyticsEvent { + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) enum class Type(val value: String) { DISPLAYED("displayed"), DOWNLOAD("download"), @@ -46,6 +49,7 @@ sealed interface AnalyticsEvent { } } + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class Log @DirectAnalyticsEventCreation constructor( override val id: String = UUID.randomUUID().toString(), override val timestamp: Long = Date().time, @@ -57,10 +61,34 @@ sealed interface AnalyticsEvent { val target: String? = null, val message: String? = null, ) : AnalyticsEvent { + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) enum class Type(val value: String) { ACTION("action"), SUBMIT("submit"), THREEDS2("ThreeDS2"), } } + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + data class Error @DirectAnalyticsEventCreation constructor( + override val id: String = UUID.randomUUID().toString(), + override val timestamp: Long = Date().time, + override val shouldForceSend: Boolean = true, + override val component: String, + val errorType: Type? = null, + val code: String? = null, + val target: String? = null, + val message: String? = null, + ) : AnalyticsEvent { + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + enum class Type(val value: String) { + REDIRECT("Redirect"), + INTERNAL("Internal"), + THIRD_PARTY("ThirdParty"), + API_ERROR("ApiError"), + THREEDS2("ThreeDS2"), + } + } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt new file mode 100644 index 0000000000..646ed5f37c --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ararat on 14/10/2024. + */ + +package com.adyen.checkout.components.core.internal.analytics + +import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.internal.analytics.AnalyticsEvent.Error.Type + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +enum class ErrorEvent(val errorType: Type, val errorCode: String) { + + // Redirect + REDIRECT_FAILED(Type.REDIRECT, "600"), + REDIRECT_PARSE_FAILED(Type.REDIRECT, "601"), + REDIRECT_CANCELLED(Type.REDIRECT, "602"), + + // Encryption + ENCRYPTION(Type.INTERNAL, "610"), + + // Third party + THIRD_PARTY(Type.THIRD_PARTY, "611"), + + // API + API_PAYMENTS(Type.API_ERROR, "620"), + API_PAYMENTS_DETAILS(Type.API_ERROR, "621"), + API_THREEDS2(Type.API_ERROR, "622"), + API_ORDER(Type.API_ERROR, "623"), + API_PUBLIC_KEY(Type.API_ERROR, "624"), + API_NATIVE_REDIRECT(Type.API_ERROR, "625"), + + // 3DS2 + THREEDS2_TOKEN_DECODING(Type.THREEDS2, "704"), + THREEDS2_FINGERPRINT_CREATION(Type.THREEDS2, "705"), + THREEDS2_TRANSACTION_CREATION(Type.THREEDS2, "706"), + THREEDS2_TRANSACTION_MISSING(Type.THREEDS2, "707"), + THREEDS2_FINGERPRINT_HANDLING(Type.THREEDS2, "708"), + THREEDS2_CHALLENGE_HANDLING(Type.THREEDS2, "709"), +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt index 202163e236..f64388ac51 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt @@ -123,4 +123,15 @@ object GenericEvents { subType = subType, message = message, ) + + // Error events + @Suppress("Unused") // Should be removed once error events are implemented + fun error( + component: String, + event: ErrorEvent, + ) = AnalyticsEvent.Error( + component = component, + errorType = event.errorType, + code = event.errorCode, + ) } From ea7bd39a6b03c500ae2e80b23134c6a2fcbbb42d Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Tue, 15 Oct 2024 12:56:31 +0400 Subject: [PATCH 022/102] Add error event support to Analytics manager COAND-979 --- components-core/api/components-core.api | 8 ++ .../analytics/AnalyticsManagerFactory.kt | 4 + .../data/DefaultAnalyticsRepository.kt | 7 +- .../local/ErrorAnalyticsLocalDataStore.kt | 37 +++++++++ .../data/remote/AnalyticsRemoteDataStore.kt | 1 + .../remote/AnalyticsTrackRequestProvider.kt | 13 ++++ .../remote/DefaultAnalyticsRemoteDataStore.kt | 1 + .../data/model/AnalyticsTrackError.kt | 76 +++++++++++++++++++ .../data/model/AnalyticsTrackRequest.kt | 4 + .../data/DefaultAnalyticsRepositoryTest.kt | 17 ++++- .../AnalyticsTrackRequestProviderTest.kt | 25 +++++- .../internal/data/api/AnalyticsServiceTest.kt | 1 + .../data/model/AnalyticsTrackRequestTest.kt | 26 +++++++ 13 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/local/ErrorAnalyticsLocalDataStore.kt create mode 100644 components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackError.kt diff --git a/components-core/api/components-core.api b/components-core/api/components-core.api index 87e945e078..6665b06e63 100644 --- a/components-core/api/components-core.api +++ b/components-core/api/components-core.api @@ -1714,6 +1714,14 @@ public final class com/adyen/checkout/components/core/internal/data/model/Analyt public synthetic fun newArray (I)[Ljava/lang/Object; } +public final class com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackError$Creator : android/os/Parcelable$Creator { + public fun ()V + public final fun createFromParcel (Landroid/os/Parcel;)Lcom/adyen/checkout/components/core/internal/data/model/AnalyticsTrackError; + public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object; + public final fun newArray (I)[Lcom/adyen/checkout/components/core/internal/data/model/AnalyticsTrackError; + public synthetic fun newArray (I)[Ljava/lang/Object; +} + public final class com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackInfo$Creator : android/os/Parcelable$Creator { public fun ()V public final fun createFromParcel (Landroid/os/Parcel;)Lcom/adyen/checkout/components/core/internal/data/model/AnalyticsTrackInfo; diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt index 4498d7cb8c..9171ee7c03 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt @@ -12,6 +12,7 @@ import android.app.Application import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.internal.analytics.data.DefaultAnalyticsRepository +import com.adyen.checkout.components.core.internal.analytics.data.local.ErrorAnalyticsLocalDataStore import com.adyen.checkout.components.core.internal.analytics.data.local.InfoAnalyticsLocalDataStore import com.adyen.checkout.components.core.internal.analytics.data.local.LogAnalyticsLocalDataStore import com.adyen.checkout.components.core.internal.analytics.data.remote.AnalyticsTrackRequestProvider @@ -59,6 +60,7 @@ class AnalyticsManagerFactory { analyticsRepository = DefaultAnalyticsRepository( localInfoDataStore = InfoAnalyticsLocalDataStore(), localLogDataStore = LogAnalyticsLocalDataStore(), + localErrorDataStore = ErrorAnalyticsLocalDataStore(), remoteDataStore = DefaultAnalyticsRemoteDataStore( analyticsService = AnalyticsService( HttpClientFactory.getAnalyticsHttpClient(environment), @@ -66,6 +68,7 @@ class AnalyticsManagerFactory { clientKey = clientKey, infoSize = INFO_SIZE, logSize = LOG_SIZE, + errorSize = ERROR_SIZE, ), analyticsSetupProvider = DefaultAnalyticsSetupProvider( application = application, @@ -83,5 +86,6 @@ class AnalyticsManagerFactory { companion object { private const val INFO_SIZE = 50 private const val LOG_SIZE = 5 + private const val ERROR_SIZE = 5 } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt index 200a03df65..cb6a684449 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt @@ -19,6 +19,7 @@ import com.adyen.checkout.core.internal.util.adyenLog internal class DefaultAnalyticsRepository( private val localInfoDataStore: AnalyticsLocalDataStore, private val localLogDataStore: AnalyticsLocalDataStore, + private val localErrorDataStore: AnalyticsLocalDataStore, private val remoteDataStore: AnalyticsRemoteDataStore, private val analyticsSetupProvider: AnalyticsSetupProvider, private val analyticsTrackRequestProvider: AnalyticsTrackRequestProvider, @@ -33,6 +34,7 @@ internal class DefaultAnalyticsRepository( when (event) { is AnalyticsEvent.Info -> localInfoDataStore.storeEvent(event) is AnalyticsEvent.Log -> localLogDataStore.storeEvent(event) + is AnalyticsEvent.Error -> localErrorDataStore.storeEvent(event) } } @@ -41,17 +43,20 @@ internal class DefaultAnalyticsRepository( ) { val infoEvents = localInfoDataStore.fetchEvents(remoteDataStore.infoSize) val logEvents = localLogDataStore.fetchEvents(remoteDataStore.logSize) + val errorEvents = localErrorDataStore.fetchEvents(remoteDataStore.errorSize) - if (infoEvents.isEmpty() && logEvents.isEmpty()) return + if (infoEvents.isEmpty() && logEvents.isEmpty() && errorEvents.isEmpty()) return val request = analyticsTrackRequestProvider( infoList = infoEvents, logList = logEvents, + errorList = errorEvents, ) remoteDataStore.sendEvents(request, checkoutAttemptId) localInfoDataStore.removeEvents(infoEvents) localLogDataStore.removeEvents(logEvents) + localErrorDataStore.removeEvents(errorEvents) adyenLog(AdyenLogLevel.DEBUG) { "Analytics events successfully sent" } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/local/ErrorAnalyticsLocalDataStore.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/local/ErrorAnalyticsLocalDataStore.kt new file mode 100644 index 0000000000..307f2861cf --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/local/ErrorAnalyticsLocalDataStore.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ararat on 15/10/2024. + */ + +package com.adyen.checkout.components.core.internal.analytics.data.local + +import com.adyen.checkout.components.core.internal.analytics.AnalyticsEvent +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import java.util.LinkedList + +internal class ErrorAnalyticsLocalDataStore : AnalyticsLocalDataStore { + + private val list = LinkedList() + + private val mutex = Mutex() + + override suspend fun storeEvent(event: AnalyticsEvent.Error) { + mutex.withLock { + list.add(event) + } + } + + override suspend fun fetchEvents(size: Int) = mutex.withLock { + list.takeLast(size) + } + + override suspend fun removeEvents(events: List) { + mutex.withLock { + list.removeAll(events.toSet()) + } + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsRemoteDataStore.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsRemoteDataStore.kt index 9db3742a4d..74092b39b8 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsRemoteDataStore.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsRemoteDataStore.kt @@ -16,6 +16,7 @@ internal interface AnalyticsRemoteDataStore { val infoSize: Int val logSize: Int + val errorSize: Int suspend fun fetchCheckoutAttemptId(request: AnalyticsSetupRequest): AnalyticsSetupResponse diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProvider.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProvider.kt index 00a98f47e3..76d88b1e46 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProvider.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProvider.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.components.core.internal.analytics.data.remote import com.adyen.checkout.components.core.internal.analytics.AnalyticsEvent import com.adyen.checkout.components.core.internal.analytics.AnalyticsPlatformParams +import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackError import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackInfo import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackLog import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackRequest @@ -19,12 +20,14 @@ internal class AnalyticsTrackRequestProvider { operator fun invoke( infoList: List, logList: List, + errorList: List, ): AnalyticsTrackRequest { return AnalyticsTrackRequest( channel = AnalyticsPlatformParams.channel, platform = AnalyticsPlatformParams.platform, info = infoList.map { event -> event.mapToTrackEvent() }, logs = logList.map { event -> event.mapToTrackEvent() }, + errors = errorList.map { event -> event.mapToErrorEvent() }, ) } @@ -52,4 +55,14 @@ internal class AnalyticsTrackRequestProvider { message = message, result = result, ) + + private fun AnalyticsEvent.Error.mapToErrorEvent() = AnalyticsTrackError( + id = id, + timestamp = timestamp, + component = component, + errorType = errorType?.value, + code = code, + target = target, + message = message, + ) } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsRemoteDataStore.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsRemoteDataStore.kt index 969c1cae62..a5bdb99503 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsRemoteDataStore.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsRemoteDataStore.kt @@ -18,6 +18,7 @@ internal class DefaultAnalyticsRemoteDataStore( private val clientKey: String, override val infoSize: Int, override val logSize: Int, + override val errorSize: Int, ) : AnalyticsRemoteDataStore { override suspend fun fetchCheckoutAttemptId(request: AnalyticsSetupRequest): AnalyticsSetupResponse { diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackError.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackError.kt new file mode 100644 index 0000000000..14b10b06d6 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackError.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ararat on 15/10/2024. + */ + +package com.adyen.checkout.components.core.internal.data.model + +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.internal.data.model.ModelObject +import com.adyen.checkout.core.internal.data.model.getLongOrNull +import com.adyen.checkout.core.internal.data.model.getStringOrNull +import kotlinx.parcelize.Parcelize +import org.json.JSONException +import org.json.JSONObject + +@Parcelize +internal data class AnalyticsTrackError( + val id: String, + val timestamp: Long?, + val component: String?, + val errorType: String?, + val code: String?, + val target: String?, + val message: String?, +) : ModelObject() { + + companion object { + private const val ID = "id" + private const val TIMESTAMP = "timestamp" + private const val COMPONENT = "component" + private const val ERROR_TYPE = "errorType" + private const val CODE = "code" + private const val TARGET = "target" + private const val MESSAGE = "message" + + @JvmField + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: AnalyticsTrackError): JSONObject { + return try { + JSONObject().apply { + put(ID, modelObject.id) + putOpt(TIMESTAMP, modelObject.timestamp) + putOpt(COMPONENT, modelObject.component) + putOpt(ERROR_TYPE, modelObject.errorType) + putOpt(CODE, modelObject.code) + putOpt(TARGET, modelObject.target) + putOpt(MESSAGE, modelObject.message) + } + } catch (e: JSONException) { + throw ModelSerializationException(AnalyticsTrackError::class.java, e) + } + } + + override fun deserialize(jsonObject: JSONObject): AnalyticsTrackError { + return try { + with(jsonObject) { + AnalyticsTrackError( + id = getString(ID), + timestamp = getLongOrNull(TIMESTAMP), + component = getStringOrNull(COMPONENT), + errorType = getStringOrNull(ERROR_TYPE), + code = getStringOrNull(CODE), + target = getStringOrNull(TARGET), + message = getStringOrNull(MESSAGE), + ) + } + } catch (e: JSONException) { + throw ModelSerializationException(AnalyticsTrackError::class.java, e) + } + } + } + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequest.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequest.kt index fb1129a0f3..79bd800e79 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequest.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequest.kt @@ -23,12 +23,14 @@ internal data class AnalyticsTrackRequest( val platform: String?, val info: List?, val logs: List?, + val errors: List?, ) : ModelObject() { companion object { private const val CHANNEL = "channel" private const val PLATFORM = "platform" private const val INFO = "info" private const val LOGS = "logs" + private const val ERRORS = "errors" @JvmField val SERIALIZER: Serializer = object : Serializer { @@ -39,6 +41,7 @@ internal data class AnalyticsTrackRequest( putOpt(PLATFORM, modelObject.platform) putOpt(INFO, ModelUtils.serializeOptList(modelObject.info, AnalyticsTrackInfo.SERIALIZER)) putOpt(LOGS, ModelUtils.serializeOptList(modelObject.logs, AnalyticsTrackLog.SERIALIZER)) + putOpt(ERRORS, ModelUtils.serializeOptList(modelObject.errors, AnalyticsTrackError.SERIALIZER)) } } catch (e: JSONException) { throw ModelSerializationException(AnalyticsTrackRequest::class.java, e) @@ -53,6 +56,7 @@ internal data class AnalyticsTrackRequest( platform = getStringOrNull(PLATFORM), info = deserializeOptList(getJSONArray(INFO), AnalyticsTrackInfo.SERIALIZER), logs = deserializeOptList(getJSONArray(LOGS), AnalyticsTrackLog.SERIALIZER), + errors = deserializeOptList(getJSONArray(ERRORS), AnalyticsTrackError.SERIALIZER), ) } } catch (e: JSONException) { diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt index cb5378f592..8acac2c2f1 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt @@ -28,6 +28,7 @@ import org.mockito.kotlin.whenever internal class DefaultAnalyticsRepositoryTest( @Mock private val localInfoDataStore: AnalyticsLocalDataStore, @Mock private val localLogDataStore: AnalyticsLocalDataStore, + @Mock private val localErrorDataStore: AnalyticsLocalDataStore, @Mock private val remoteDataStore: AnalyticsRemoteDataStore, @Mock private val analyticsSetupProvider: AnalyticsSetupProvider, @Mock private val analyticsTrackRequestProvider: AnalyticsTrackRequestProvider, @@ -40,6 +41,7 @@ internal class DefaultAnalyticsRepositoryTest( analyticsRepository = DefaultAnalyticsRepository( localInfoDataStore = localInfoDataStore, localLogDataStore = localLogDataStore, + localErrorDataStore = localErrorDataStore, remoteDataStore = remoteDataStore, analyticsSetupProvider = analyticsSetupProvider, analyticsTrackRequestProvider = analyticsTrackRequestProvider, @@ -69,6 +71,11 @@ internal class DefaultAnalyticsRepositoryTest( analyticsRepository.storeEvent(logEvent) verify(localLogDataStore).storeEvent(logEvent) + + val errorEvent = AnalyticsEvent.Error(component = "test") + analyticsRepository.storeEvent(errorEvent) + + verify(localErrorDataStore).storeEvent(errorEvent) } @Nested @@ -79,6 +86,7 @@ internal class DefaultAnalyticsRepositoryTest( fun `there are no events stored, then sending is canceled`() = runTest { whenever(localInfoDataStore.fetchEvents(any())) doReturn emptyList() whenever(localLogDataStore.fetchEvents(any())) doReturn emptyList() + whenever(localErrorDataStore.fetchEvents(any())) doReturn emptyList() analyticsRepository.sendEvents("test") @@ -90,21 +98,25 @@ internal class DefaultAnalyticsRepositoryTest( fun `it is successful, then events are cleared from storage`() = runTest { val infoEvents = listOf(AnalyticsEvent.Info(component = "test info")) val logEvents = listOf(AnalyticsEvent.Log(component = "test log")) + val errorEvents = listOf(AnalyticsEvent.Error(component = "test error")) whenever(localInfoDataStore.fetchEvents(any())) doReturn infoEvents whenever(localLogDataStore.fetchEvents(any())) doReturn logEvents - whenever(analyticsTrackRequestProvider.invoke(any(), any())) doReturn mock() + whenever(localErrorDataStore.fetchEvents(any())) doReturn errorEvents + whenever(analyticsTrackRequestProvider.invoke(any(), any(), any())) doReturn mock() analyticsRepository.sendEvents("test") verify(localInfoDataStore).removeEvents(infoEvents) verify(localLogDataStore).removeEvents(logEvents) + verify(localErrorDataStore).removeEvents(errorEvents) } @Test fun `it fails, then events are not cleared from storage`() = runTest { whenever(localInfoDataStore.fetchEvents(any())) doReturn listOf(mock()) whenever(localLogDataStore.fetchEvents(any())) doReturn listOf(mock()) - whenever(analyticsTrackRequestProvider.invoke(any(), any())) doReturn mock() + whenever(localErrorDataStore.fetchEvents(any())) doReturn listOf(mock()) + whenever(analyticsTrackRequestProvider.invoke(any(), any(), any())) doReturn mock() whenever(remoteDataStore.sendEvents(any(), any())) doAnswer { error("test") } runCatching { @@ -113,6 +125,7 @@ internal class DefaultAnalyticsRepositoryTest( verify(localInfoDataStore, never()).removeEvents(any()) verify(localLogDataStore, never()).removeEvents(any()) + verify(localErrorDataStore, never()).removeEvents(any()) } } } diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProviderTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProviderTest.kt index a16e48b1e0..87dfe3c4c2 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProviderTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/AnalyticsTrackRequestProviderTest.kt @@ -2,6 +2,7 @@ package com.adyen.checkout.components.core.internal.analytics.data.remote import com.adyen.checkout.components.core.internal.analytics.AnalyticsEvent import com.adyen.checkout.components.core.internal.analytics.DirectAnalyticsEventCreation +import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackError import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackInfo import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackLog import com.adyen.checkout.components.core.internal.data.model.AnalyticsTrackRequest @@ -47,8 +48,19 @@ internal class AnalyticsTrackRequestProviderTest { message = null, ), ) + val errorList = listOf( + AnalyticsEvent.Error( + id = "id", + timestamp = 12345L, + component = "dropin", + errorType = AnalyticsEvent.Error.Type.INTERNAL, + code = "100", + target = null, + message = null, + ) + ) - val result = analyticsTrackRequestProvider.invoke(infoList, logList) + val result = analyticsTrackRequestProvider.invoke(infoList, logList, errorList) val expected = AnalyticsTrackRequest( channel = "android", @@ -80,6 +92,17 @@ internal class AnalyticsTrackRequestProviderTest { message = null, ), ), + errors = listOf( + AnalyticsTrackError( + id = "id", + timestamp = 12345L, + component = "dropin", + errorType = "Internal", + code = "100", + target = null, + message = null, + ) + ) ) assertEquals(expected, result) } diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsServiceTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsServiceTest.kt index 86e132c7f9..f926f6b5b4 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsServiceTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsServiceTest.kt @@ -37,6 +37,7 @@ internal class AnalyticsServiceTest( platform = "android", info = emptyList(), logs = emptyList(), + errors = emptyList() ) val checkoutAttemptId = "testtest" whenever(httpClient.post(eq("v3/analytics/$checkoutAttemptId"), any(), any(), any())) diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequestTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequestTest.kt index 412916ac55..c938baa53b 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequestTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsTrackRequestTest.kt @@ -36,11 +36,23 @@ internal class AnalyticsTrackRequestTest { message = null, ), ) + val errors = listOf( + AnalyticsTrackError( + id = "id", + timestamp = 12345L, + component = "dropin", + errorType = null, + code = null, + target = null, + message = null, + ), + ) val request = AnalyticsTrackRequest( channel = "android", platform = "android", info = info, logs = logs, + errors = errors, ) val actual = AnalyticsTrackRequest.SERIALIZER.serialize(request) @@ -50,6 +62,7 @@ internal class AnalyticsTrackRequestTest { .put("platform", "android") .put("info", ModelUtils.serializeOptList(info, AnalyticsTrackInfo.SERIALIZER)) .put("logs", ModelUtils.serializeOptList(logs, AnalyticsTrackLog.SERIALIZER)) + .put("errors", ModelUtils.serializeOptList(errors, AnalyticsTrackError.SERIALIZER)) assertEquals(expected.toString(), actual.toString()) } @@ -83,11 +96,23 @@ internal class AnalyticsTrackRequestTest { message = null, ), ) + val errors = listOf( + AnalyticsTrackError( + id = "id", + timestamp = 12345L, + component = "dropin", + errorType = null, + code = null, + target = null, + message = null, + ), + ) val response = JSONObject() .put("channel", "android") .put("platform", "android") .put("info", ModelUtils.serializeOptList(info, AnalyticsTrackInfo.SERIALIZER)) .put("logs", ModelUtils.serializeOptList(logs, AnalyticsTrackLog.SERIALIZER)) + .put("errors", ModelUtils.serializeOptList(errors, AnalyticsTrackError.SERIALIZER)) val actual = AnalyticsTrackRequest.SERIALIZER.deserialize(response) @@ -96,6 +121,7 @@ internal class AnalyticsTrackRequestTest { platform = "android", info = info, logs = logs, + errors = errors, ) assertEquals(expected, actual) From 8f82398f9d93b81c346b0435117a591e4956fd0f Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Wed, 30 Oct 2024 14:59:17 +0100 Subject: [PATCH 023/102] Simplify the check before sending events COAND-979 --- .../data/DefaultAnalyticsRepository.kt | 11 ++- .../data/DefaultAnalyticsRepositoryTest.kt | 67 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt index cb6a684449..baab712342 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepository.kt @@ -45,7 +45,7 @@ internal class DefaultAnalyticsRepository( val logEvents = localLogDataStore.fetchEvents(remoteDataStore.logSize) val errorEvents = localErrorDataStore.fetchEvents(remoteDataStore.errorSize) - if (infoEvents.isEmpty() && logEvents.isEmpty() && errorEvents.isEmpty()) return + if (!hasEventsToTrack(infoEvents, logEvents, errorEvents)) return val request = analyticsTrackRequestProvider( infoList = infoEvents, @@ -60,4 +60,13 @@ internal class DefaultAnalyticsRepository( adyenLog(AdyenLogLevel.DEBUG) { "Analytics events successfully sent" } } + + private fun hasEventsToTrack(vararg eventLists: List): Boolean { + for (events in eventLists) { + if (events.isNotEmpty()) { + return true + } + } + return false + } } diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt index 8acac2c2f1..d47eb000e5 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/DefaultAnalyticsRepositoryTest.kt @@ -14,11 +14,15 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments.arguments +import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @@ -93,6 +97,25 @@ internal class DefaultAnalyticsRepositoryTest( verify(remoteDataStore, never()).sendEvents(any(), any()) } + @ParameterizedTest + @MethodSource( + "com.adyen.checkout.components.core.internal.analytics.data.DefaultAnalyticsRepositoryTest#sendEventsSource" + ) + fun `there are events stored, then events are successfully sent`( + infoEvents: List, + logEvents: List, + errorEvents: List, + ) = runTest { + whenever(localInfoDataStore.fetchEvents(any())) doReturn infoEvents + whenever(localLogDataStore.fetchEvents(any())) doReturn logEvents + whenever(localErrorDataStore.fetchEvents(any())) doReturn errorEvents + val expectedRequest = analyticsTrackRequestProvider(infoEvents, logEvents, errorEvents) + + analyticsRepository.sendEvents("test") + + verify(remoteDataStore).sendEvents(eq(expectedRequest), any()) + } + @OptIn(DirectAnalyticsEventCreation::class) @Test fun `it is successful, then events are cleared from storage`() = runTest { @@ -128,4 +151,48 @@ internal class DefaultAnalyticsRepositoryTest( verify(localErrorDataStore, never()).removeEvents(any()) } } + + companion object { + + @OptIn(DirectAnalyticsEventCreation::class) + @JvmStatic + fun sendEventsSource() = listOf( + // infoEvents, logEvents, errorEvents + arguments( + listOf(AnalyticsEvent.Info(component = "test info")), + emptyList(), + emptyList(), + ), + arguments( + emptyList(), + listOf(AnalyticsEvent.Log(component = "test log")), + emptyList(), + ), + arguments( + emptyList(), + emptyList(), + listOf(AnalyticsEvent.Error(component = "test error")), + ), + arguments( + listOf(AnalyticsEvent.Info(component = "test info")), + listOf(AnalyticsEvent.Log(component = "test log")), + emptyList(), + ), + arguments( + listOf(AnalyticsEvent.Info(component = "test info")), + emptyList(), + listOf(AnalyticsEvent.Error(component = "test error")), + ), + arguments( + emptyList(), + listOf(AnalyticsEvent.Log(component = "test log")), + listOf(AnalyticsEvent.Error(component = "test error")), + ), + arguments( + listOf(AnalyticsEvent.Info(component = "test info")), + listOf(AnalyticsEvent.Log(component = "test log")), + listOf(AnalyticsEvent.Error(component = "test error")), + ), + ) + } } From d1dc995c44f9e71ba5de853029f4986c90b56475 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 07:10:35 +0000 Subject: [PATCH 024/102] Update lint to v31.7.1 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eb0a8c3e92..f608b2d914 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ json = "20240303" jose4j = "0.9.6" junit-jupiter = "5.11.3" konsist = "0.16.1" -lint = "31.7.0" +lint = "31.7.1" mockito-kotlin = "5.4.0" mockito = "5.12.0" robolectric = "4.13" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index b2ea0ac1fa..374a5df9ca 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6976,6 +6976,14 @@ + + + + + + + + From 44d608630aaa27c3d153ba60a7bca2c4bd6f4f0c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:03:50 +0000 Subject: [PATCH 025/102] Update mockito monorepo to v5.14.2 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f608b2d914..30b3202e8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -72,7 +72,7 @@ junit-jupiter = "5.11.3" konsist = "0.16.1" lint = "31.7.1" mockito-kotlin = "5.4.0" -mockito = "5.12.0" +mockito = "5.14.2" robolectric = "4.13" test-ext = "1.2.1" test-rules = "1.6.1" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 374a5df9ca..926760e52a 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -11511,6 +11511,14 @@ + + + + + + + + @@ -11543,6 +11551,14 @@ + + + + + + + + @@ -11567,6 +11583,14 @@ + + + + + + + + @@ -11587,6 +11611,11 @@ + + + + + @@ -15106,6 +15135,14 @@ + + + + + + + + @@ -15135,6 +15172,14 @@ + + + + + + + + @@ -15175,6 +15220,14 @@ + + + + + + + + From d6d6a31a474f9961f2c26e2bf7104ae635983517 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:37:24 +0000 Subject: [PATCH 026/102] Update dependency app.cash.turbine:turbine to v1.2.0 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 30b3202e8f..391dacc588 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -76,7 +76,7 @@ mockito = "5.14.2" robolectric = "4.13" test-ext = "1.2.1" test-rules = "1.6.1" -turbine = "1.1.0" +turbine = "1.2.0" uiautomator = "2.3.0" [libraries] diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 926760e52a..3a3a05294d 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4259,6 +4259,14 @@ + + + + + + + + @@ -4275,6 +4283,14 @@ + + + + + + + + @@ -13791,6 +13807,17 @@ + + + + + + + + + + + @@ -13896,6 +13923,11 @@ + + + + + From 0aeab407c45d6749acf1ece4bcb6d59422520f46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:08:22 +0000 Subject: [PATCH 027/102] Update dependency androidx.compose:compose-bom to v2024.10.00 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 379 +++++++++++++++++++++++++++++++ 2 files changed, 380 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 391dacc588..e772e3b4a7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ constraintlayout = "2.1.4" # Compose dependencies compose-activity = "1.9.2" -compose-bom = "2024.06.00" +compose-bom = "2024.10.00" compose-hilt = "1.2.0" compose-viewmodel = "2.8.3" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 3a3a05294d..f3e52d8322 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -299,6 +299,14 @@ + + + + + + + + @@ -540,6 +548,11 @@ + + + + + @@ -548,6 +561,14 @@ + + + + + + + + @@ -556,6 +577,11 @@ + + + + + @@ -564,6 +590,14 @@ + + + + + + + + @@ -589,6 +623,11 @@ + + + + + @@ -629,6 +668,14 @@ + + + + + + + + @@ -669,6 +716,14 @@ + + + + + + + + @@ -709,6 +764,14 @@ + + + + + + + + @@ -749,6 +812,14 @@ + + + + + + + + @@ -829,6 +900,14 @@ + + + + + + + + @@ -869,6 +948,14 @@ + + + + + + + + @@ -909,6 +996,14 @@ + + + + + + + + @@ -949,6 +1044,14 @@ + + + + + + + + @@ -974,6 +1077,11 @@ + + + + + @@ -1014,6 +1122,14 @@ + + + + + + + + @@ -1054,6 +1170,14 @@ + + + + + + + + @@ -1094,6 +1218,14 @@ + + + + + + + + @@ -1134,6 +1266,14 @@ + + + + + + + + @@ -1174,6 +1314,14 @@ + + + + + + + + @@ -1190,6 +1338,14 @@ + + + + + + + + @@ -1206,6 +1362,14 @@ + + + + + + + + @@ -1251,6 +1415,14 @@ + + + + + + + + @@ -1291,6 +1463,14 @@ + + + + + + + + @@ -1331,6 +1511,14 @@ + + + + + + + + @@ -1371,6 +1559,14 @@ + + + + + + + + @@ -1411,6 +1607,14 @@ + + + + + + + + @@ -1451,6 +1655,14 @@ + + + + + + + + @@ -1491,6 +1703,14 @@ + + + + + + + + @@ -1531,6 +1751,14 @@ + + + + + + + + @@ -1571,6 +1799,14 @@ + + + + + + + + @@ -1611,6 +1847,14 @@ + + + + + + + + @@ -1651,6 +1895,14 @@ + + + + + + + + @@ -1691,6 +1943,14 @@ + + + + + + + + @@ -1731,6 +1991,14 @@ + + + + + + + + @@ -1756,6 +2024,11 @@ + + + + + @@ -1796,6 +2069,14 @@ + + + + + + + + @@ -1821,6 +2102,11 @@ + + + + + @@ -1861,6 +2147,14 @@ + + + + + + + + @@ -1901,6 +2195,14 @@ + + + + + + + + @@ -1941,6 +2243,14 @@ + + + + + + + + @@ -1981,6 +2291,14 @@ + + + + + + + + @@ -2021,6 +2339,14 @@ + + + + + + + + @@ -2061,6 +2387,14 @@ + + + + + + + + @@ -2101,6 +2435,14 @@ + + + + + + + + @@ -2199,6 +2541,14 @@ + + + + + + + + @@ -2262,6 +2612,14 @@ + + + + + + + + @@ -2680,6 +3038,14 @@ + + + + + + + + @@ -3209,6 +3575,19 @@ + + + + + + + + + + + + + From 4e2f9bc7a0bbfaa85e83a239890aba94f2f6e160 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:28:14 +0000 Subject: [PATCH 028/102] Update gradle/actions action to v4 --- .github/workflows/assemble.yml | 2 +- .github/workflows/check_release.yml | 2 +- .github/workflows/code_analysis.yml | 4 ++-- .github/workflows/generate_dependency_graph.yml | 2 +- .github/workflows/publish_docs.yml | 2 +- .github/workflows/publish_release.yml | 2 +- .github/workflows/run_tests.yml | 4 ++-- .github/workflows/run_ui_tests.yml | 2 +- .github/workflows/sonar_cloud.yml | 2 +- .github/workflows/update_verification_metadata.yml | 2 +- .github/workflows/validate_public_api.yml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/assemble.yml b/.github/workflows/assemble.yml index 1fa221cb69..f77a41f9d0 100644 --- a/.github/workflows/assemble.yml +++ b/.github/workflows/assemble.yml @@ -18,7 +18,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false diff --git a/.github/workflows/check_release.yml b/.github/workflows/check_release.yml index 6a5daf2217..064bc97c00 100644 --- a/.github/workflows/check_release.yml +++ b/.github/workflows/check_release.yml @@ -26,7 +26,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index e48e39639b..4e5597561c 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -18,7 +18,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true @@ -42,7 +42,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true diff --git a/.github/workflows/generate_dependency_graph.yml b/.github/workflows/generate_dependency_graph.yml index b0bd3622ed..87ea93106c 100644 --- a/.github/workflows/generate_dependency_graph.yml +++ b/.github/workflows/generate_dependency_graph.yml @@ -19,7 +19,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml index 349da4fc96..734f1797a0 100644 --- a/.github/workflows/publish_docs.yml +++ b/.github/workflows/publish_docs.yml @@ -25,7 +25,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index 2eae1e7f7e..779cbe5a24 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -23,7 +23,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index be50b71e8d..344d5cf7c2 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -18,7 +18,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false @@ -42,7 +42,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false diff --git a/.github/workflows/run_ui_tests.yml b/.github/workflows/run_ui_tests.yml index 097c33556e..da7f0aa3da 100644 --- a/.github/workflows/run_ui_tests.yml +++ b/.github/workflows/run_ui_tests.yml @@ -31,7 +31,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false diff --git a/.github/workflows/sonar_cloud.yml b/.github/workflows/sonar_cloud.yml index 9d744b7798..f34166cbdd 100644 --- a/.github/workflows/sonar_cloud.yml +++ b/.github/workflows/sonar_cloud.yml @@ -20,7 +20,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true diff --git a/.github/workflows/update_verification_metadata.yml b/.github/workflows/update_verification_metadata.yml index 2ebe80d616..35df6f7f15 100644 --- a/.github/workflows/update_verification_metadata.yml +++ b/.github/workflows/update_verification_metadata.yml @@ -20,7 +20,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true diff --git a/.github/workflows/validate_public_api.yml b/.github/workflows/validate_public_api.yml index f1787c2ae3..e7b2b464fa 100644 --- a/.github/workflows/validate_public_api.yml +++ b/.github/workflows/validate_public_api.yml @@ -18,7 +18,7 @@ jobs: java-version: 17 - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: true From 7134436ca8876ce23ed67d193409123d72164f73 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:22:01 +0000 Subject: [PATCH 029/102] Update dependency androidx.annotation:annotation to v1.9.0 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e772e3b4a7..2175944b85 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ binary-compatibility-validator = "0.16.3" # Android dependencies activity = "1.9.2" -annotation = "1.8.2" +annotation = "1.9.0" appcompat = "1.7.0" autofill = "1.3.0-alpha01" browser = "1.8.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index f3e52d8322..6e08249101 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -262,6 +262,14 @@ + + + + + + + + @@ -341,6 +349,14 @@ + + + + + + + + From 32cc4661b8b7f9ab072d2646cef8a56bcd257ef9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:23:37 +0000 Subject: [PATCH 030/102] Update dependency androidx.activity:activity to v1.9.3 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2175944b85..bfc8956819 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,7 @@ sonarqube = "5.1.0.4882" binary-compatibility-validator = "0.16.3" # Android dependencies -activity = "1.9.2" +activity = "1.9.3" annotation = "1.9.0" appcompat = "1.7.0" autofill = "1.3.0-alpha01" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 6e08249101..ff60d057ec 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -100,6 +100,14 @@ + + + + + + + + @@ -124,6 +132,14 @@ + + + + + + + + @@ -177,6 +193,14 @@ + + + + + + + + @@ -3203,6 +3227,11 @@ + + + + + From f00fad4e4a6f0d0f2d450d7d7458cc118869c13a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:58:09 +0000 Subject: [PATCH 031/102] Update dependency androidx.activity:activity-compose to v1.9.3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bfc8956819..4e3a23bb05 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,7 +38,7 @@ recyclerview = "1.3.2" constraintlayout = "2.1.4" # Compose dependencies -compose-activity = "1.9.2" +compose-activity = "1.9.3" compose-bom = "2024.10.00" compose-hilt = "1.2.0" compose-viewmodel = "2.8.3" From 367f7381cd46a6aefadaca64058cc7a122ab56f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:38:33 +0000 Subject: [PATCH 032/102] Update lifecycle to v2.8.6 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 149 +++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4e3a23bb05..d533714736 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ autofill = "1.3.0-alpha01" browser = "1.8.0" coroutines = "1.9.0" fragment = "1.8.4" -lifecycle = "2.8.3" +lifecycle = "2.8.6" material = "1.12.0" recyclerview = "1.3.2" constraintlayout = "2.1.4" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index ff60d057ec..32789e85f2 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -3227,6 +3227,14 @@ + + + + + + + + @@ -3264,6 +3272,14 @@ + + + + + + + + @@ -3288,6 +3304,14 @@ + + + + + + + + @@ -3344,6 +3368,14 @@ + + + + + + + + @@ -3421,6 +3453,14 @@ + + + + + + + + @@ -3461,6 +3501,14 @@ + + + + + + + + @@ -3516,6 +3564,14 @@ + + + + + + + + @@ -3596,6 +3652,14 @@ + + + + + + + + @@ -3620,11 +3684,24 @@ + + + + + + + + + + + + + @@ -3633,6 +3710,14 @@ + + + + + + + + @@ -3697,6 +3782,14 @@ + + + + + + + + @@ -3721,6 +3814,14 @@ + + + + + + + + @@ -3815,6 +3916,17 @@ + + + + + + + + + + + @@ -3839,6 +3951,14 @@ + + + + + + + + @@ -3871,6 +3991,11 @@ + + + + + @@ -3895,6 +4020,14 @@ + + + + + + + + @@ -3959,6 +4092,14 @@ + + + + + + + + @@ -4028,6 +4169,14 @@ + + + + + + + + From 3076e6fccf409eac7b441c36546ce99a544ee3a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:04:33 +0000 Subject: [PATCH 033/102] Update dependency androidx.autofill:autofill to v1.3.0-beta01 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d533714736..3bfbe242a0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ binary-compatibility-validator = "0.16.3" activity = "1.9.3" annotation = "1.9.0" appcompat = "1.7.0" -autofill = "1.3.0-alpha01" +autofill = "1.3.0-beta01" browser = "1.8.0" coroutines = "1.9.0" fragment = "1.8.4" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 32789e85f2..85d4d197e5 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -540,6 +540,14 @@ + + + + + + + + From 4d871398d71a1c0f1fcdde9151b416b148ea7f48 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:56:09 +0000 Subject: [PATCH 034/102] Update dependency androidx.lifecycle:lifecycle-viewmodel-compose to v2.8.6 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3bfbe242a0..0a276cc256 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,7 +41,7 @@ constraintlayout = "2.1.4" compose-activity = "1.9.3" compose-bom = "2024.10.00" compose-hilt = "1.2.0" -compose-viewmodel = "2.8.3" +compose-viewmodel = "2.8.6" # Adyen dependencies adyen3ds2 = "2.2.21" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 85d4d197e5..c57a99c478 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4003,6 +4003,9 @@ + + + From d40b18dabf071e6d27e5d7aef63e9de07153df60 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:32:52 +0000 Subject: [PATCH 035/102] Update thollander/actions-comment-pull-request action to v3 --- .github/workflows/validate_public_api.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate_public_api.yml b/.github/workflows/validate_public_api.yml index e7b2b464fa..04f7982950 100644 --- a/.github/workflows/validate_public_api.yml +++ b/.github/workflows/validate_public_api.yml @@ -28,7 +28,7 @@ jobs: bash ./scripts/process_api_changes.sh - name: Comment on PR - uses: thollander/actions-comment-pull-request@v2 + uses: thollander/actions-comment-pull-request@v3 with: filePath: "${{ github.workspace }}/api_changes.md" comment_tag: api_changes From 00fb705a68c55e788b4eb98232edecd01cc3e358 Mon Sep 17 00:00:00 2001 From: josephj Date: Mon, 4 Nov 2024 17:35:09 +0100 Subject: [PATCH 036/102] Fix breaking changes caused by v3 migration --- .github/workflows/validate_public_api.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate_public_api.yml b/.github/workflows/validate_public_api.yml index 04f7982950..c89f3449a4 100644 --- a/.github/workflows/validate_public_api.yml +++ b/.github/workflows/validate_public_api.yml @@ -30,8 +30,8 @@ jobs: - name: Comment on PR uses: thollander/actions-comment-pull-request@v3 with: - filePath: "${{ github.workspace }}/api_changes.md" - comment_tag: api_changes + file-path: "${{ github.workspace }}/api_changes.md" + comment-tag: api_changes mode: recreate - name: Check if successful From 37bd155f9d3da5fee8ac8c20fc4b07ee7a6d11e8 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Tue, 5 Nov 2024 14:32:51 +0100 Subject: [PATCH 037/102] Track Closed Log event for Drop-in COAND-816 --- .../core/internal/analytics/AnalyticsEvent.kt | 1 + .../dropin/internal/analytics/DropInEvents.kt | 28 +++++++++++++++++++ .../dropin/internal/ui/DropInViewModel.kt | 5 ++++ .../dropin/internal/ui/DropInViewModelTest.kt | 14 +++++++++- 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt index 3b927909ff..654a3e2b03 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvent.kt @@ -66,6 +66,7 @@ sealed interface AnalyticsEvent { enum class Type(val value: String) { ACTION("action"), SUBMIT("submit"), + CLOSED("closed"), THREEDS2("ThreeDS2"), } } diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt new file mode 100644 index 0000000000..36e182b948 --- /dev/null +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ararat on 7/10/2024. + */ + +package com.adyen.checkout.dropin.internal.analytics + +import androidx.annotation.RestrictTo +import com.adyen.checkout.components.core.internal.analytics.AnalyticsEvent +import com.adyen.checkout.components.core.internal.analytics.DirectAnalyticsEventCreation + +private const val ANALYTICS_COMPONENT = "dropin" + +@OptIn(DirectAnalyticsEventCreation::class) +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +internal object DropInEvents { + + fun closed( + message: String? = null, + ) = AnalyticsEvent.Log( + component = ANALYTICS_COMPONENT, + type = AnalyticsEvent.Log.Type.CLOSED, + message = message, + ) +} diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt index 213eb8fea7..ba49452d0d 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt @@ -35,6 +35,7 @@ import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.dropin.R +import com.adyen.checkout.dropin.internal.analytics.DropInEvents import com.adyen.checkout.dropin.internal.ui.model.DropInActivityEvent import com.adyen.checkout.dropin.internal.ui.model.DropInDestination import com.adyen.checkout.dropin.internal.ui.model.DropInOverrideParamsFactory @@ -458,6 +459,10 @@ internal class DropInViewModel( fun cancelDropIn() { currentOrder?.let { sendCancelOrderEvent(it, true) } + + val event = DropInEvents.closed() + analyticsManager.trackEvent(event) + sendEvent(DropInActivityEvent.CancelDropIn) } diff --git a/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt b/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt index c7f82d2f3f..b98ae9eedb 100644 --- a/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt +++ b/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt @@ -11,8 +11,10 @@ import com.adyen.checkout.components.core.internal.data.api.OrderStatusRepositor import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParams import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParamsLevel import com.adyen.checkout.core.Environment +import com.adyen.checkout.dropin.internal.analytics.DropInEvents import com.adyen.checkout.dropin.internal.ui.model.DropInParams import com.adyen.checkout.test.LoggingExtension +import com.adyen.checkout.test.TestDispatcherExtension import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested @@ -28,7 +30,7 @@ import org.mockito.kotlin.doReturn import org.mockito.kotlin.whenever import java.util.Locale -@ExtendWith(MockitoExtension::class, LoggingExtension::class) +@ExtendWith(MockitoExtension::class, LoggingExtension::class, TestDispatcherExtension::class) internal class DropInViewModelTest( @Mock private val bundleHandler: DropInSavedStateHandleContainer, @Mock private val orderStatusRepository: OrderStatusRepository, @@ -98,6 +100,16 @@ internal class DropInViewModelTest( ) analyticsManager.assertLastEventEquals(expected) } + + @Test + fun `when drop-in is cancelled, then analytics event is tracked`() { + viewModel = createDropInViewModel() + + viewModel.cancelDropIn() + + val expected = DropInEvents.closed() + analyticsManager.assertLastEventEquals(expected) + } } private fun createDropInViewModel( From 4915c2fdb1e0a07dc9a92452704aeebb42a1a7b4 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Tue, 5 Nov 2024 14:33:23 +0100 Subject: [PATCH 038/102] Move rendered event for Drop-in to DropInEvents COAND-816 --- .../checkout/dropin/internal/analytics/DropInEvents.kt | 8 ++++++++ .../adyen/checkout/dropin/internal/ui/DropInViewModel.kt | 6 +----- .../checkout/dropin/internal/ui/DropInViewModelTest.kt | 4 +--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt index 36e182b948..0bd6413117 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/analytics/DropInEvents.kt @@ -11,6 +11,7 @@ package com.adyen.checkout.dropin.internal.analytics import androidx.annotation.RestrictTo import com.adyen.checkout.components.core.internal.analytics.AnalyticsEvent import com.adyen.checkout.components.core.internal.analytics.DirectAnalyticsEventCreation +import com.adyen.checkout.components.core.internal.analytics.GenericEvents private const val ANALYTICS_COMPONENT = "dropin" @@ -18,6 +19,13 @@ private const val ANALYTICS_COMPONENT = "dropin" @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) internal object DropInEvents { + fun rendered( + configData: Map? = null, + ) = GenericEvents.rendered( + component = ANALYTICS_COMPONENT, + configData = configData, + ) + fun closed( message: String? = null, ) = AnalyticsEvent.Log( diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt index ba49452d0d..2e22d9d93a 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModel.kt @@ -25,7 +25,6 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.PaymentMethodsApiResponse import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager -import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.data.api.OrderStatusRepository import com.adyen.checkout.components.core.internal.ui.model.DropInOverrideParams import com.adyen.checkout.components.core.internal.util.bufferedChannel @@ -237,8 +236,7 @@ internal class DropInViewModel( adyenLog(AdyenLogLevel.VERBOSE) { "initializeAnalytics" } analyticsManager.initialize(this, viewModelScope) - val event = GenericEvents.rendered( - component = ANALYTICS_COMPONENT, + val event = DropInEvents.rendered( configData = dropInConfigDataGenerator.generate(configuration = dropInParams), ) analyticsManager.trackEvent(event) @@ -488,8 +486,6 @@ internal class DropInViewModel( companion object { - private const val ANALYTICS_COMPONENT = "dropin" - // These payment methods are either action only or have no UI. private val SKIP_TO_SINGLE_PM_BLOCK_LIST = listOf( PaymentMethodTypes.DUIT_NOW, diff --git a/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt b/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt index b98ae9eedb..ab5f3352cc 100644 --- a/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt +++ b/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelTest.kt @@ -5,7 +5,6 @@ import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.PaymentMethodsApiResponse import com.adyen.checkout.components.core.StoredPaymentMethod -import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.data.api.OrderStatusRepository import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParams @@ -94,8 +93,7 @@ internal class DropInViewModelTest( viewModel.onCreated(false) - val expected = GenericEvents.rendered( - component = "dropin", + val expected = DropInEvents.rendered( configData = emptyMap(), ) analyticsManager.assertLastEventEquals(expected) From c55bdf43b9ba80269396078c89c7ac1b767d42f8 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 7 Nov 2024 09:56:55 +0100 Subject: [PATCH 039/102] Fix address lookup data not being correctly saved in payment component data COAND-1036 --- RELEASE_NOTES.md | 66 +---- .../ui/core/internal/util/AddressFormUtils.kt | 4 +- .../internal/util/AddressFormUtilsTest.kt | 229 ++++++++++++------ 3 files changed, 155 insertions(+), 144 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 68c09fc4c1..690b0380f7 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -8,69 +8,5 @@ [//]: # (## Deprecated) [//]: # ( - Configurations public constructor are deprecated, please use each Configuration's builder to make a Configuration object) -## New -- You can now use [Adyen Test Cards Android](https://github.com/Adyen/adyen-testcards-android) to prefill test payment method information, to test your integration more quickly. -- For Twint: - - You can now [store payment details](/docs/payment-methods/TWINT.md#optional-configurations) and [pay with stored payment details](/docs/payment-methods/TWINT.md#stored-twint-payments). -> [!WARNING] -> For Twint Components integrations, you must now use [`TwintComponent`](/docs/payment-methods/TWINT.md) instead of `InstantPaymentComponent`. -- For French meal vouchers, the following payment method types are now available: - - Up. Payment method type: **mealVoucher_FR_groupeup**. - - Natixis. Payment method type: **mealVoucher_FR_natixis**. - - Sodexo. Payment method type: **mealVoucher_FR_sodexo**. - - Learn to [configure French meal vouchers](/docs/payment-methods/FRENCH_MEAL_VOUCHER.md). -- For [API-only integrations with encrypted card details](https://docs.adyen.com/payment-methods/cards/custom-card-integration/?tab=candroid_3), you can now use the following classes to validate corresponding fields: - - | Class | Description | - |-----------------------------|------------------------------------| - | `CardNumberValidator` | Validates the card number field. | - | `CardExpiryDateValidator` | Validates the expiry date field. | - | `CardSecurityCodeValidator` | Validates the security code field. | - -- Support for the following locales: - - | Locale | Values | - |------------|-----------| - | Catalan | **ca-ES** | - | Icelandic | **is-IS** | - | Bulgarian | **bg-BG** | - | Estonian | **et-EE** | - | Latvian | **lv-LV** | - | Lithuanian | **lt-lT** | - ## Fixed -- When parsing JSON objects with explicit null values, JSON deserialization no longer returns the coerced `null` string. - -## Improved -- For UPI Intent, if the shopper selects the **Continue** button without selecting an UPI option, an error message now shows. -- For Drop-in, in the navigation bar, the accessibility of the **Back/Close** button is improved. - -## Changed -- For Drop-in, headers of preselected stored payment screen and payment methods list screen are updated. -- When you set `analyticsConfiguration = AnalyticsConfiguration(AnalyticsLevel.NONE)`, only [Drop-in/Components analytics](https://docs.adyen.com/online-payments/analytics-and-data-tracking#data-we-are-collecting) are not sent to Adyen. -- Dependency versions: - | Name | Version | - |--------------------------------------------------------------------------------------------------------|-------------------------------| - | [Adyen 3DS2](https://github.com/Adyen/adyen-3ds2-android/releases/tag/2.2.21) | **2.2.21** | - | [Cash App Pay](https://github.com/cashapp/cash-app-pay-android-sdk/releases/tag/v2.5.0) | **2.5.0** | - | [Android Gradle Plugin](https://developer.android.com/build/releases/past-releases/agp-8-5-0-release-notes#android-gradle-plugin-8.5.1) | **8.5.1** | - | [AndroidX Fragment](https://developer.android.com/jetpack/androidx/releases/fragment#1.8.3) | **1.8.3** | - | [AndroidX Activity](https://developer.android.com/jetpack/androidx/releases/activity#1.9.2) | **1.9.2** | - | [AndroidX Compose Activity](https://developer.android.com/jetpack/androidx/releases/activity#1.9.2) | **1.9.2** | - | [AndroidX Compose BOM](https://developer.android.com/develop/ui/compose/bom/bom-mapping) | **2024.06.00** | - | [AndroidX Lifecycle](https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.3) | **2.8.3** | - | [AndroidX Lifecycle ViewModel Compose](https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.3) | **2.8.3** | - | [AndroidX AppCompat](https://developer.android.com/jetpack/androidx/releases/appcompat#1.7.0) | **1.7.0** | - -## Deprecated -- The style for payment method list headers. Use the new style instead. - - | Previous | Now | - |--------------------------------------------|--------------------------------------------| - | `AdyenCheckout.TextAppearance.HeaderTitle` | `AdyenCheckout.TextAppearance.HeaderLabel` | - -- The `com.adyen.checkout.instant.ActionHandlingMethod` method. Use the new method instead. - - | Previous | Now | - |---------------------------------------------------|-----------------------------------------------------------| - | `com.adyen.checkout.instant.ActionHandlingMethod` | `com.adyen.checkout.components.core.ActionHandlingMethod` | +- Address data not being correctly saved to PaymentComponentData in Lookup mode. diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt index fdd58dc709..e336411078 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtils.kt @@ -130,7 +130,7 @@ object AddressFormUtils { */ fun makeAddressData(addressOutputData: AddressOutputData, addressFormUIState: AddressFormUIState): Address? { return when (addressFormUIState) { - AddressFormUIState.FULL_ADDRESS -> Address( + AddressFormUIState.FULL_ADDRESS, AddressFormUIState.LOOKUP -> Address( postalCode = addressOutputData.postalCode.value.ifEmpty { Address.ADDRESS_NULL_PLACEHOLDER }, street = addressOutputData.street.value.ifEmpty { Address.ADDRESS_NULL_PLACEHOLDER }, stateOrProvince = addressOutputData.stateOrProvince.value.ifEmpty { Address.ADDRESS_NULL_PLACEHOLDER }, @@ -151,7 +151,7 @@ object AddressFormUtils { country = Address.ADDRESS_COUNTRY_NULL_PLACEHOLDER, ) - else -> null + AddressFormUIState.NONE -> null } } diff --git a/ui-core/src/test/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtilsTest.kt b/ui-core/src/test/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtilsTest.kt index e08ed3be6e..f6fa40dc07 100644 --- a/ui-core/src/test/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtilsTest.kt +++ b/ui-core/src/test/java/com/adyen/checkout/ui/core/internal/util/AddressFormUtilsTest.kt @@ -8,13 +8,20 @@ package com.adyen.checkout.ui.core.internal.util +import com.adyen.checkout.components.core.Address +import com.adyen.checkout.components.core.internal.ui.model.FieldState +import com.adyen.checkout.components.core.internal.ui.model.Validation import com.adyen.checkout.ui.core.internal.data.model.AddressItem import com.adyen.checkout.ui.core.internal.ui.AddressFormUIState import com.adyen.checkout.ui.core.internal.ui.model.AddressListItem +import com.adyen.checkout.ui.core.internal.ui.model.AddressOutputData import com.adyen.checkout.ui.core.internal.ui.model.AddressParams import com.adyen.checkout.ui.core.internal.ui.model.Required import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments.arguments +import org.junit.jupiter.params.provider.MethodSource import java.util.Locale @Suppress("MaxLineLength") @@ -26,35 +33,35 @@ internal class AddressFormUtilsTest { AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) val expected = listOf( AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = true + selected = true, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) assertEquals(expected, AddressFormUtils.markAddressListItemSelected(input, "US")) } @@ -65,35 +72,35 @@ internal class AddressFormUtilsTest { AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) val expected = listOf( AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) assertEquals(expected, AddressFormUtils.markAddressListItemSelected(input)) } @@ -104,35 +111,35 @@ internal class AddressFormUtilsTest { AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) val expected = listOf( AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) assertEquals(expected, AddressFormUtils.markAddressListItemSelected(input, "TR")) } @@ -143,21 +150,21 @@ internal class AddressFormUtilsTest { val inputCountryList = listOf( AddressItem( id = "CA", - name = "Canada" + name = "Canada", ), AddressItem( id = "US", - name = "United States" + name = "United States", ), AddressItem( id = "GB", - name = "United Kingdom" - ) + name = "United Kingdom", + ), ) val expected = emptyList() assertEquals( expected, - AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList) + AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList), ) } @@ -167,21 +174,21 @@ internal class AddressFormUtilsTest { val inputCountryList = listOf( AddressItem( id = "CA", - name = "Canada" + name = "Canada", ), AddressItem( id = "US", - name = "United States" + name = "United States", ), AddressItem( id = "GB", - name = "United Kingdom" - ) + name = "United Kingdom", + ), ) val expected = emptyList() assertEquals( expected, - AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList) + AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList), ) } @@ -191,37 +198,37 @@ internal class AddressFormUtilsTest { val inputCountryList = listOf( AddressItem( id = "CA", - name = "Canada" + name = "Canada", ), AddressItem( id = "US", - name = "United States" + name = "United States", ), AddressItem( id = "GB", - name = "United Kingdom" - ) + name = "United Kingdom", + ), ) val expected = listOf( AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) assertEquals( expected, - AddressFormUtils.initializeCountryOptions(Locale.GERMANY, addressParams, inputCountryList) + AddressFormUtils.initializeCountryOptions(Locale.GERMANY, addressParams, inputCountryList), ) } @@ -231,37 +238,37 @@ internal class AddressFormUtilsTest { val inputCountryList = listOf( AddressItem( id = "CA", - name = "Canada" + name = "Canada", ), AddressItem( id = "US", - name = "United States" + name = "United States", ), AddressItem( id = "GB", - name = "United Kingdom" - ) + name = "United Kingdom", + ), ) val expected = listOf( AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = true + selected = true, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) assertEquals( expected, - AddressFormUtils.initializeCountryOptions(Locale.US, addressParams, inputCountryList) + AddressFormUtils.initializeCountryOptions(Locale.US, addressParams, inputCountryList), ) } @@ -271,37 +278,37 @@ internal class AddressFormUtilsTest { val inputCountryList = listOf( AddressItem( id = "CA", - name = "Canada" + name = "Canada", ), AddressItem( id = "US", - name = "United States" + name = "United States", ), AddressItem( id = "GB", - name = "United Kingdom" - ) + name = "United Kingdom", + ), ) val expected = listOf( AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United States", code = "US", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = true - ) + selected = true, + ), ) assertEquals( expected, - AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList) + AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList), ) } @@ -315,32 +322,32 @@ internal class AddressFormUtilsTest { val inputCountryList = listOf( AddressItem( id = "CA", - name = "Canada" + name = "Canada", ), AddressItem( id = "US", - name = "United States" + name = "United States", ), AddressItem( id = "GB", - name = "United Kingdom" - ) + name = "United Kingdom", + ), ) val expected = listOf( AddressListItem( name = "Canada", code = "CA", - selected = false + selected = false, ), AddressListItem( name = "United Kingdom", code = "GB", - selected = false - ) + selected = false, + ), ) assertEquals( expected, - AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList) + AddressFormUtils.initializeCountryOptions(Locale.getDefault(), addressParams, inputCountryList), ) } @@ -349,33 +356,33 @@ internal class AddressFormUtilsTest { val input = listOf( AddressItem( id = "AL", - name = "Alabama" + name = "Alabama", ), AddressItem( id = "MA", - name = "Massachusetts" + name = "Massachusetts", ), AddressItem( id = "NY", - name = "New York" - ) + name = "New York", + ), ) val expected = listOf( AddressListItem( code = "AL", name = "Alabama", - selected = false + selected = false, ), AddressListItem( code = "MA", name = "Massachusetts", - selected = false + selected = false, ), AddressListItem( code = "NY", name = "New York", - selected = false - ) + selected = false, + ), ) assertEquals(expected, AddressFormUtils.initializeStateOptions(input)) } @@ -421,4 +428,72 @@ internal class AddressFormUtilsTest { val apartmentSuite = "3b" assertEquals("3b", AddressFormUtils.makeHouseNumberOrName(houseNumber, apartmentSuite)) } + + @ParameterizedTest + @MethodSource("makeAddressDataSource") + fun `when makeAddressData is called it returns the correct Address object`( + addressOutputData: AddressOutputData, + addressFormUIState: AddressFormUIState, + expectedAddress: Address?, + ) { + val actual = AddressFormUtils.makeAddressData(addressOutputData, addressFormUIState) + assertEquals(expectedAddress, actual) + } + + companion object { + private val TEST_ADDRESS_OUTPUT_DATA = AddressOutputData( + postalCode = FieldState("postalCode", Validation.Valid), + houseNumberOrName = FieldState("houseNumberOrName", Validation.Valid), + apartmentSuite = FieldState("", Validation.Valid), + street = FieldState("street", Validation.Valid), + city = FieldState("city", Validation.Valid), + stateOrProvince = FieldState("stateOrProvince", Validation.Valid), + country = FieldState("country", Validation.Valid), + isOptional = false, + countryOptions = emptyList(), + stateOptions = emptyList(), + ) + + @JvmStatic + fun makeAddressDataSource() = listOf( + // addressOutputData, addressFormUIState, expected Address object + arguments(TEST_ADDRESS_OUTPUT_DATA, AddressFormUIState.NONE, null), + arguments( + TEST_ADDRESS_OUTPUT_DATA, + AddressFormUIState.POSTAL_CODE, + Address( + postalCode = "postalCode", + street = Address.ADDRESS_NULL_PLACEHOLDER, + stateOrProvince = Address.ADDRESS_NULL_PLACEHOLDER, + houseNumberOrName = Address.ADDRESS_NULL_PLACEHOLDER, + city = Address.ADDRESS_NULL_PLACEHOLDER, + country = Address.ADDRESS_COUNTRY_NULL_PLACEHOLDER, + ), + ), + arguments( + TEST_ADDRESS_OUTPUT_DATA, + AddressFormUIState.FULL_ADDRESS, + Address( + postalCode = "postalCode", + street = "street", + stateOrProvince = "stateOrProvince", + houseNumberOrName = "houseNumberOrName", + city = "city", + country = "country", + ), + ), + arguments( + TEST_ADDRESS_OUTPUT_DATA, + AddressFormUIState.LOOKUP, + Address( + postalCode = "postalCode", + street = "street", + stateOrProvince = "stateOrProvince", + houseNumberOrName = "houseNumberOrName", + city = "city", + country = "country", + ), + ), + ) + } } From 53ae6939f6ef4ce77b651079189aeb4c76632dcc Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:54:35 +0100 Subject: [PATCH 040/102] Track encryption related errors COAND-1008 --- .../checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt | 4 ++++ .../adyen/checkout/card/internal/ui/DefaultCardDelegate.kt | 4 ++++ .../com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt | 4 ++++ .../checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt index 5532b95b4e..66cd77a89c 100644 --- a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt +++ b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt @@ -21,6 +21,7 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.PaymentComponentEvent import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.data.api.PublicKeyRepository import com.adyen.checkout.components.core.internal.ui.model.AddressInputModel @@ -313,6 +314,9 @@ internal class DefaultACHDirectDebitDelegate( return ACHDirectDebitComponentState(paymentComponentData, isInputValid = true, isReady = true) } catch (e: EncryptionException) { + val event = GenericEvents.error(paymentMethod.type.orEmpty(), ErrorEvent.ENCRYPTION) + analyticsManager.trackEvent(event) + exceptionChannel.trySend(e) return ACHDirectDebitComponentState( data = PaymentComponentData(null, null, null), diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index ebe8424217..f39b9e47c8 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -43,6 +43,7 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.PaymentComponentEvent import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.data.api.PublicKeyRepository import com.adyen.checkout.components.core.internal.ui.model.AddressInputModel @@ -461,6 +462,9 @@ class DefaultCardDelegate( cardEncryptor.encryptFields(unencryptedCardBuilder.build(), publicKey) } catch (e: EncryptionException) { + val event = GenericEvents.error(paymentMethod.type.orEmpty(), ErrorEvent.ENCRYPTION) + analyticsManager.trackEvent(event) + exceptionChannel.trySend(e) return CardComponentState( diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt index 805a974aa4..b8d89601de 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/StoredCardDelegate.kt @@ -30,6 +30,7 @@ import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.internal.PaymentComponentEvent import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.data.api.PublicKeyRepository import com.adyen.checkout.components.core.internal.ui.model.AddressInputModel @@ -294,6 +295,9 @@ internal class StoredCardDelegate( cardEncryptor.encryptFields(unencryptedCardBuilder.build(), publicKey) } catch (e: EncryptionException) { + val event = GenericEvents.error(storedPaymentMethod.type.orEmpty(), ErrorEvent.ENCRYPTION) + analyticsManager.trackEvent(event) + exceptionChannel.trySend(e) return CardComponentState( data = PaymentComponentData(null, null, null), diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt index dd6ae91f49..313fa52e35 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt @@ -21,6 +21,7 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.PaymentComponentEvent import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.data.api.PublicKeyRepository import com.adyen.checkout.components.core.internal.ui.model.FieldState @@ -282,6 +283,9 @@ class DefaultGiftCardDelegate( cardEncryptor.encryptFields(unencryptedCard, publicKey) } catch (e: EncryptionException) { + val event = GenericEvents.error(paymentMethod.type.orEmpty(), ErrorEvent.ENCRYPTION) + analyticsManager.trackEvent(event) + exceptionChannel.trySend(e) null } From f8cacda23a6b8d825e0ebc69862ca982a3d2285e Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:55:23 +0100 Subject: [PATCH 041/102] Remove suppress annotation from GenericEvents.error function COAND-1008 --- .../checkout/components/core/internal/analytics/GenericEvents.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt index f64388ac51..226dd931db 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt @@ -125,7 +125,6 @@ object GenericEvents { ) // Error events - @Suppress("Unused") // Should be removed once error events are implemented fun error( component: String, event: ErrorEvent, From 02d8fb4b791e6266306230d323d3705d2d7b3fc6 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:27:57 +0100 Subject: [PATCH 042/102] Add tests for tracking encryption analytics events COAND-1008 --- .../ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt | 6 +++++- .../checkout/card/internal/ui/DefaultCardDelegateTest.kt | 6 +++++- .../checkout/card/internal/ui/StoredCardDelegateTest.kt | 8 ++++++-- .../giftcard/internal/ui/DefaultGiftCardDelegateTest.kt | 6 +++++- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt index 4db5fa8cdd..01eafac788 100644 --- a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt +++ b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt @@ -22,6 +22,7 @@ import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.data.api.PublicKeyRepository @@ -334,7 +335,7 @@ internal class DefaultACHDirectDebitDelegateTest( } @Test - fun `encryption fails, then component state should be invalid`() = runTest { + fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = runTest { genericEncryptor.shouldThrowException = true delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) @@ -356,6 +357,9 @@ internal class DefaultACHDirectDebitDelegateTest( val componentState = delegate.componentStateFlow.first() + val expectedEvent = GenericEvents.error(TEST_PAYMENT_METHOD_TYPE, ErrorEvent.ENCRYPTION) + analyticsManager.assertLastEventEquals(expectedEvent) + assertFalse(componentState.isValid) } diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index 56377fbae0..6c08efc7ac 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -43,6 +43,7 @@ import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.data.api.PublicKeyRepository @@ -694,7 +695,7 @@ internal class DefaultCardDelegateTest( } @Test - fun `encryption fails, then component state should be invalid`() = runTest { + fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = runTest { cardEncryptor.shouldThrowException = true delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) @@ -704,6 +705,9 @@ internal class DefaultCardDelegateTest( val componentState = expectMostRecentItem() + val expectedEvent = GenericEvents.error(PaymentMethodTypes.SCHEME, ErrorEvent.ENCRYPTION) + analyticsManager.assertLastEventEquals(expectedEvent) + assertTrue(componentState.isReady) assertFalse(componentState.isInputValid) assertNull(componentState.lastFourDigits) diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt index b34d642cdd..46f13ffb7f 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/StoredCardDelegateTest.kt @@ -33,6 +33,7 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.data.api.PublicKeyRepository @@ -265,16 +266,19 @@ internal class StoredCardDelegateTest( } @Test - fun `encryption fails, then component state should be invalid`() = runTest { + fun `encryption fails, then component state should be invalid and analytics error event is tracked `() = runTest { cardEncryptor.shouldThrowException = true delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) delegate.componentStateFlow.test { - delegate.updateInputData { /* Empty to trigger an update */ } + delegate.updateComponentState(createOutputData()) val componentState = expectMostRecentItem() + val expectedEvent = GenericEvents.error(CardPaymentMethod.PAYMENT_METHOD_TYPE, ErrorEvent.ENCRYPTION) + analyticsManager.assertLastEventEquals(expectedEvent) + assertTrue(componentState.isReady) assertFalse(componentState.isInputValid) assertNull(componentState.lastFourDigits) diff --git a/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt b/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt index e04c673e5a..66da89942a 100644 --- a/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt +++ b/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt @@ -15,6 +15,7 @@ import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.OrderResponse import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.internal.PaymentObserverRepository +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.data.api.TestPublicKeyRepository @@ -126,7 +127,7 @@ internal class DefaultGiftCardDelegateTest( } @Test - fun `encryption fails, then component state should be invalid`() = runTest { + fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = runTest { cardEncryptor.shouldThrowException = true delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) @@ -136,6 +137,9 @@ internal class DefaultGiftCardDelegateTest( val componentState = expectMostRecentItem() + val expectedEvent = GenericEvents.error(TEST_PAYMENT_METHOD_TYPE, ErrorEvent.ENCRYPTION) + analyticsManager.assertLastEventEquals(expectedEvent) + assertTrue(componentState.isReady) assertFalse(componentState.isInputValid) assertEquals(null, componentState.lastFourDigits) From 797f6502280b250804f0e112c89b5637b129c223 Mon Sep 17 00:00:00 2001 From: josephj Date: Fri, 8 Nov 2024 17:15:32 +0100 Subject: [PATCH 043/102] Remove incorrect Singleton annotation in AddressLookupRepository --- .../checkout/example/repositories/AddressLookupRepository.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt b/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt index 2e1aa1ef71..6529343eb2 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt @@ -25,9 +25,7 @@ import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import javax.inject.Inject -import javax.inject.Singleton -@Singleton class AddressLookupRepository @Inject constructor( assetManager: AssetManager ) { From 52b17780963b89408088a9a72319c73bc7cd0f94 Mon Sep 17 00:00:00 2001 From: josephj Date: Fri, 8 Nov 2024 17:35:04 +0100 Subject: [PATCH 044/102] Remove state flow from AddressLookupRepository to make sure onAddressLookupCompleted always produces a result --- ...te.kt => AddressLookupCompletionResult.kt} | 6 ++-- .../repositories/AddressLookupRepository.kt | 17 +++------- .../service/ExampleAdvancedDropInService.kt | 33 +++++++++---------- .../checkout/example/ui/card/CardViewModel.kt | 20 ++++------- .../ui/card/SessionsCardTakenOverViewModel.kt | 19 +++++------ .../example/ui/card/SessionsCardViewModel.kt | 19 +++++------ 6 files changed, 45 insertions(+), 69 deletions(-) rename example-app/src/main/java/com/adyen/checkout/example/repositories/{AddressLookupCompletionState.kt => AddressLookupCompletionResult.kt} (79%) diff --git a/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupCompletionState.kt b/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupCompletionResult.kt similarity index 79% rename from example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupCompletionState.kt rename to example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupCompletionResult.kt index 2013aae472..7f943c5b91 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupCompletionState.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupCompletionResult.kt @@ -10,7 +10,7 @@ package com.adyen.checkout.example.repositories import com.adyen.checkout.components.core.LookupAddress -sealed class AddressLookupCompletionState { - data class Error(val message: String = "Something went wrong") : AddressLookupCompletionState() - data class Address(val lookupAddress: LookupAddress) : AddressLookupCompletionState() +sealed class AddressLookupCompletionResult { + data class Error(val message: String = "Something went wrong") : AddressLookupCompletionResult() + data class Address(val lookupAddress: LookupAddress) : AddressLookupCompletionResult() } diff --git a/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt b/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt index 6529343eb2..9a89d1931f 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/repositories/AddressLookupRepository.kt @@ -19,11 +19,9 @@ import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach import javax.inject.Inject class AddressLookupRepository @Inject constructor( @@ -49,21 +47,16 @@ class AddressLookupRepository @Inject constructor( queryAddressLookupOptions(query) } - private val _addressLookupCompletionFlow: MutableStateFlow = MutableStateFlow(null) - val addressLookupCompletionFlow: Flow = _addressLookupCompletionFlow - .asStateFlow() - .onEach { delay(ADDRESS_LOOKUP_COMPLETION_DELAY) } - .filterNotNull() - fun onQuery(query: String) { addressLookupQueryFlow.tryEmit(query) } - fun onAddressLookupCompleted(lookupAddress: LookupAddress) { - if (lookupAddress.id == ADDRESS_LOOKUP_ERROR_ITEM_ID) { - _addressLookupCompletionFlow.tryEmit(AddressLookupCompletionState.Error()) + suspend fun onAddressLookupCompleted(lookupAddress: LookupAddress): AddressLookupCompletionResult { + delay(ADDRESS_LOOKUP_COMPLETION_DELAY) + return if (lookupAddress.id == ADDRESS_LOOKUP_ERROR_ITEM_ID) { + AddressLookupCompletionResult.Error() } else { - _addressLookupCompletionFlow.tryEmit(AddressLookupCompletionState.Address(lookupAddress)) + AddressLookupCompletionResult.Address(lookupAddress) } } diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt index cfb1a46354..1c7e359f9f 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt @@ -35,7 +35,7 @@ import com.adyen.checkout.dropin.RecurringDropInServiceResult import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.extensions.toStringPretty -import com.adyen.checkout.example.repositories.AddressLookupCompletionState +import com.adyen.checkout.example.repositories.AddressLookupCompletionResult import com.adyen.checkout.example.repositories.AddressLookupRepository import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.redirect.RedirectComponent @@ -73,22 +73,6 @@ class ExampleAdvancedDropInService : DropInService() { .onEach { options -> sendAddressLookupResult(AddressLookupDropInServiceResult.LookupResult(options)) }.launchIn(this) - - addressLookupRepository.addressLookupCompletionFlow - .onEach { - val result = when (it) { - is AddressLookupCompletionState.Address -> { - AddressLookupDropInServiceResult.LookupComplete(it.lookupAddress) - } - - is AddressLookupCompletionState.Error -> AddressLookupDropInServiceResult.Error( - errorDialog = ErrorDialog( - message = it.message, - ), - ) - } - sendAddressLookupResult(result) - }.launchIn(this) } @Suppress("RestrictedApi") @@ -419,7 +403,20 @@ class ExampleAdvancedDropInService : DropInService() { override fun onAddressLookupCompletion(lookupAddress: LookupAddress): Boolean { Log.d(TAG, "On address lookup query completion: $lookupAddress") - addressLookupRepository.onAddressLookupCompleted(lookupAddress) + launch { + val lookupResult = when (val result = addressLookupRepository.onAddressLookupCompleted(lookupAddress)) { + is AddressLookupCompletionResult.Address -> { + AddressLookupDropInServiceResult.LookupComplete(result.lookupAddress) + } + + is AddressLookupCompletionResult.Error -> AddressLookupDropInServiceResult.Error( + errorDialog = ErrorDialog( + message = result.message, + ), + ) + } + sendAddressLookupResult(lookupResult) + } return true } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 80db930733..8fc7404dc4 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -13,7 +13,7 @@ import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage -import com.adyen.checkout.example.repositories.AddressLookupCompletionState +import com.adyen.checkout.example.repositories.AddressLookupCompletionResult import com.adyen.checkout.example.repositories.AddressLookupRepository import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest @@ -54,10 +54,6 @@ internal class CardViewModel @Inject constructor( .onEach { options -> _events.emit(CardEvent.AddressLookup(options)) }.launchIn(viewModelScope) - addressLookupRepository.addressLookupCompletionFlow - .onEach { - onAddressCompleted(it) - }.launchIn(viewModelScope) } @Suppress("RestrictedApi") @@ -107,21 +103,17 @@ internal class CardViewModel @Inject constructor( } fun onAddressLookupCompletion(lookupAddress: LookupAddress) { - addressLookupRepository.onAddressLookupCompleted(lookupAddress) - } - - private fun onAddressCompleted(addressLookupCompletionState: AddressLookupCompletionState) { viewModelScope.launch { - when (addressLookupCompletionState) { - is AddressLookupCompletionState.Address -> _events.emit( + when (val lookupResult = addressLookupRepository.onAddressLookupCompleted(lookupAddress)) { + is AddressLookupCompletionResult.Address -> _events.emit( CardEvent.AddressLookupCompleted( - addressLookupCompletionState.lookupAddress, + lookupResult.lookupAddress, ), ) - is AddressLookupCompletionState.Error -> _events.emit( + is AddressLookupCompletionResult.Error -> _events.emit( CardEvent.AddressLookupError( - addressLookupCompletionState.message, + lookupResult.message, ), ) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt index d323580ff5..2d99c29244 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt @@ -25,7 +25,7 @@ import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.extensions.getLogTag -import com.adyen.checkout.example.repositories.AddressLookupCompletionState +import com.adyen.checkout.example.repositories.AddressLookupCompletionResult import com.adyen.checkout.example.repositories.AddressLookupRepository import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest @@ -84,15 +84,6 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( .onEach { options -> _events.emit(CardEvent.AddressLookup(options)) }.launchIn(viewModelScope) - - addressLookupRepository.addressLookupCompletionFlow - .onEach { - val event = when (it) { - is AddressLookupCompletionState.Address -> CardEvent.AddressLookupCompleted(it.lookupAddress) - is AddressLookupCompletionState.Error -> CardEvent.AddressLookupError(it.message) - } - _events.emit(event) - }.launchIn(viewModelScope) } private suspend fun launchComponent() { @@ -247,7 +238,13 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( } fun onAddressLookupCompletion(lookupAddress: LookupAddress) { - addressLookupRepository.onAddressLookupCompleted(lookupAddress) + viewModelScope.launch { + val event = when (val lookupResult = addressLookupRepository.onAddressLookupCompleted(lookupAddress)) { + is AddressLookupCompletionResult.Address -> CardEvent.AddressLookupCompleted(lookupResult.lookupAddress) + is AddressLookupCompletionResult.Error -> CardEvent.AddressLookupError(lookupResult.message) + } + _events.emit(event) + } } companion object { diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardViewModel.kt index 703a0832ae..b6a22aa8f1 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardViewModel.kt @@ -23,7 +23,7 @@ import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.core.exception.CancellationException import com.adyen.checkout.example.data.storage.KeyValueStorage import com.adyen.checkout.example.extensions.getLogTag -import com.adyen.checkout.example.repositories.AddressLookupCompletionState +import com.adyen.checkout.example.repositories.AddressLookupCompletionResult import com.adyen.checkout.example.repositories.AddressLookupRepository import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.getSessionRequest @@ -70,15 +70,6 @@ internal class SessionsCardViewModel @Inject constructor( it.copy(addressLookupOptions = options) } }.launchIn(viewModelScope) - - addressLookupRepository.addressLookupCompletionFlow - .onEach { - val result = when (it) { - is AddressLookupCompletionState.Address -> AddressLookupResult.Completed(it.lookupAddress) - is AddressLookupCompletionState.Error -> AddressLookupResult.Error(it.message) - } - updateUiState { it.copy(addressLookupResult = result) } - }.launchIn(viewModelScope) } private suspend fun launchComponent() { @@ -193,7 +184,13 @@ internal class SessionsCardViewModel @Inject constructor( } override fun onLookupCompletion(lookupAddress: LookupAddress): Boolean { - addressLookupRepository.onAddressLookupCompleted(lookupAddress) + viewModelScope.launch { + val result = when (val lookupResult = addressLookupRepository.onAddressLookupCompleted(lookupAddress)) { + is AddressLookupCompletionResult.Address -> AddressLookupResult.Completed(lookupResult.lookupAddress) + is AddressLookupCompletionResult.Error -> AddressLookupResult.Error(lookupResult.message) + } + updateUiState { it.copy(addressLookupResult = result) } + } return true } From e4e2138113161291f5985bac90e8835b7f5d5927 Mon Sep 17 00:00:00 2001 From: josephj Date: Fri, 8 Nov 2024 17:39:26 +0100 Subject: [PATCH 045/102] Remove onLookupCompletion override in CardActivity to allow testing this scenario --- .../com/adyen/checkout/example/ui/card/CardActivity.kt | 7 +------ .../com/adyen/checkout/example/ui/card/CardViewModel.kt | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt index 6d1f1d23ca..cfecf43845 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardActivity.kt @@ -159,17 +159,12 @@ class CardActivity : AppCompatActivity(), AddressLookupCallback { cardComponent?.setAddressLookupResult(AddressLookupResult.Error(message)) } + // onLookupCompletion is not implemented intentionally to allow testing this scenario override fun onQueryChanged(query: String) { Log.d(TAG, "On address lookup query changed: $query") cardViewModel.onAddressLookupQueryChanged(query) } - override fun onLookupCompletion(lookupAddress: LookupAddress): Boolean { - Log.d(TAG, "on lookup completed $lookupAddress") - cardViewModel.onAddressLookupCompletion(lookupAddress) - return true - } - override fun onBackPressed() { if (cardComponent?.handleBackPress() == true) return super.onBackPressed() diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 8fc7404dc4..1670b5a611 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -102,6 +102,7 @@ internal class CardViewModel @Inject constructor( addressLookupRepository.onQuery(query) } + // intentionally not called, check comment in CardActivity fun onAddressLookupCompletion(lookupAddress: LookupAddress) { viewModelScope.launch { when (val lookupResult = addressLookupRepository.onAddressLookupCompleted(lookupAddress)) { From 433048e9a765095ef06c57c46f7492be7691cfd8 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:59:28 +0100 Subject: [PATCH 046/102] Fix address lookup view not retaining correct input state COAND-1032 --- .../adyen/checkout/card/internal/ui/DefaultCardDelegate.kt | 4 ++-- .../adyen/checkout/card/internal/ui/model/CardInputData.kt | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index f39b9e47c8..4476ff257a 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -169,7 +169,7 @@ class DefaultCardDelegate( addressLookupDelegate.addressLookupSubmitFlow .onEach { _viewFlow.tryEmit(CardComponentViewType.DefaultCardView) - inputData.address = it + inputData.address.set(it) updateOutputData() } .launchIn(coroutineScope) @@ -495,8 +495,8 @@ class DefaultCardDelegate( } override fun startAddressLookup() { - _viewFlow.tryEmit(CardComponentViewType.AddressLookup) addressLookupDelegate.initialize(coroutineScope, inputData.address) + _viewFlow.tryEmit(CardComponentViewType.AddressLookup) } override fun handleBackPress(): Boolean { diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt index ea2b796679..63a5be0672 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/model/CardInputData.kt @@ -13,7 +13,6 @@ import com.adyen.checkout.components.core.internal.ui.model.AddressInputModel import com.adyen.checkout.components.core.internal.ui.model.InputData import com.adyen.checkout.core.internal.ui.model.EMPTY_DATE import com.adyen.checkout.core.ui.model.ExpiryDate -import com.adyen.checkout.ui.core.internal.ui.model.AddressLookupInputData @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class CardInputData( @@ -25,7 +24,6 @@ data class CardInputData( var kcpBirthDateOrTaxNumber: String = "", var kcpCardPassword: String = "", var postalCode: String = "", - var addressLookupInputData: AddressLookupInputData = AddressLookupInputData(), var address: AddressInputModel = AddressInputModel(), var isStorePaymentMethodSwitchChecked: Boolean = false, var selectedCardIndex: Int = -1, From fddfade87e964de7ca67f403aeff5dca74a78ccf Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:59:28 +0100 Subject: [PATCH 047/102] Fix address lookup view not retaining correct input state COAND-1032 --- RELEASE_NOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 690b0380f7..0ce2691229 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,3 +10,4 @@ ## Fixed - Address data not being correctly saved to PaymentComponentData in Lookup mode. +- Manually edited fields in address form in Lookup mode no longer lose their state on starting Lookup mode. From de4b411fdae5678faaf7f5d1ba9da7c4ea195e3c Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 12 Nov 2024 13:11:24 +0100 Subject: [PATCH 048/102] Update release notes --- RELEASE_NOTES.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 0ce2691229..efe3a28d75 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -9,5 +9,6 @@ [//]: # ( - Configurations public constructor are deprecated, please use each Configuration's builder to make a Configuration object) ## Fixed -- Address data not being correctly saved to PaymentComponentData in Lookup mode. -- Manually edited fields in address form in Lookup mode no longer lose their state on starting Lookup mode. +- For the Address Lookup functionality: + - Address data is now correctly saved to `PaymentComponentData`. + - Address fields that were edited manually no longer lose their state when starting Lookup mode. From 5b4f3f22088af14d2a890b434f315b4ba61d662f Mon Sep 17 00:00:00 2001 From: josephj Date: Wed, 13 Nov 2024 11:49:55 +0100 Subject: [PATCH 049/102] Bump version to 5.7.1 --- README.md | 10 +++++----- example-app/build.gradle | 4 ++-- gradle/libs.versions.toml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bb6a095039..0d07faac90 100644 --- a/README.md +++ b/README.md @@ -31,23 +31,23 @@ Import the corresponding module in your `build.gradle` file. For Drop-in: ```groovy -implementation "com.adyen.checkout:drop-in-compose:5.7.0" +implementation "com.adyen.checkout:drop-in-compose:5.7.1" ``` For the Credit Card component: ```groovy -implementation "com.adyen.checkout:card:5.7.0" -implementation "com.adyen.checkout:components-compose:5.7.0" +implementation "com.adyen.checkout:card:5.7.1" +implementation "com.adyen.checkout:components-compose:5.7.1" ``` ### Without Jetpack Compose For Drop-in: ```groovy -implementation "com.adyen.checkout:drop-in:5.7.0" +implementation "com.adyen.checkout:drop-in:5.7.1" ``` For the Credit Card component: ```groovy -implementation "com.adyen.checkout:card:5.7.0" +implementation "com.adyen.checkout:card:5.7.1" ``` The library is available on [Maven Central][mavenRepo]. diff --git a/example-app/build.gradle b/example-app/build.gradle index b0492f1442..0f5696cc91 100644 --- a/example-app/build.gradle +++ b/example-app/build.gradle @@ -71,8 +71,8 @@ dependencies { // Checkout implementation project(':drop-in') implementation project(':components-compose') -// implementation "com.adyen.checkout:drop-in:5.7.0" -// implementation "com.adyen.checkout:components-compose:5.7.0" +// implementation "com.adyen.checkout:drop-in:5.7.1" +// implementation "com.adyen.checkout:components-compose:5.7.1" // Dependencies implementation libs.bundles.kotlin.coroutines diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0a276cc256..af4dad09be 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ min-sdk = "21" # App version, only used for example app, no need to increment version-code = "1" # The version-name format is "major.minor.patch(-(alpha|beta|rc)[0-9]{2}){0,1}" (e.g. 3.0.0, 3.1.1-alpha04 or 3.1.4-rc01 etc). -version-name = "5.7.0" +version-name = "5.7.1" # Build script android-gradle-plugin = "8.7.1" From deedfaf0ed22e1f75b9bc2d4616b80cd1fcd57dc Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Mon, 11 Nov 2024 16:38:55 +0100 Subject: [PATCH 050/102] Add lint rule that prevents Dispatchers usage COAND-1020 --- .../adyen/checkout/lint/LintIssueRegistry.kt | 3 +- .../checkout/lint/NotDispatcherProvider.kt | 58 +++++++++++ .../lint/NotDispatcherProviderTest.kt | 95 +++++++++++++++++++ 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 lint/src/main/java/com/adyen/checkout/lint/NotDispatcherProvider.kt create mode 100644 lint/src/test/java/com/adyen/checkout/lint/NotDispatcherProviderTest.kt diff --git a/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt b/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt index 7597f92cf5..837af8aa34 100644 --- a/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt +++ b/lint/src/main/java/com/adyen/checkout/lint/LintIssueRegistry.kt @@ -19,9 +19,10 @@ internal class LintIssueRegistry : IssueRegistry() { override val issues: List = listOf( CONTEXT_GET_STRING_ISSUE, + JSON_OPT_FUNCTIONS_ISSUE, NOT_ADYEN_LOG_ISSUE, + NOT_DISPATCHER_PROVIDER_ISSUE, OBJECT_IN_PUBLIC_SEALED_CLASS_ISSUE, TEXT_IN_LAYOUT_XML_ISSUE, - JSON_OPT_FUNCTIONS_ISSUE, ) } diff --git a/lint/src/main/java/com/adyen/checkout/lint/NotDispatcherProvider.kt b/lint/src/main/java/com/adyen/checkout/lint/NotDispatcherProvider.kt new file mode 100644 index 0000000000..73359cdd29 --- /dev/null +++ b/lint/src/main/java/com/adyen/checkout/lint/NotDispatcherProvider.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by oscars on 8/11/2024. + */ + +package com.adyen.checkout.lint + +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import com.intellij.psi.PsiElement +import org.jetbrains.uast.UReferenceExpression +import org.jetbrains.uast.getQualifiedName + +internal val NOT_DISPATCHER_PROVIDER_ISSUE = Issue.create( + id = "NotDispatcherProvider", + briefDescription = "Dispatchers used instead of DispatcherProvider", + explanation = "DispatcherProvider should be used, so we can override dispatchers for testing purposes.", + implementation = Implementation(NotDispatcherProvider::class.java, Scope.JAVA_FILE_SCOPE), + category = Category.CUSTOM_LINT_CHECKS, + priority = 7, + severity = Severity.ERROR, +) + +internal class NotDispatcherProvider : Detector(), SourceCodeScanner { + + override fun getApplicableReferenceNames() = listOf( + "Dispatchers", + ) + + override fun visitReference(context: JavaContext, reference: UReferenceExpression, referenced: PsiElement) { + if (reference.getQualifiedName() == "kotlinx.coroutines.Dispatchers") { + context.report( + NOT_DISPATCHER_PROVIDER_ISSUE, + reference, + context.getLocation(reference), + "Dispatchers used instead of DispatcherProvider", + fix().alternatives( + fix() + .replace() + .with("DispatcherProvider") + .imports("com.adyen.checkout.core.DispatcherProvider") + .reformat(true) + .shortenNames() + .build(), + ), + ) + } + } +} diff --git a/lint/src/test/java/com/adyen/checkout/lint/NotDispatcherProviderTest.kt b/lint/src/test/java/com/adyen/checkout/lint/NotDispatcherProviderTest.kt new file mode 100644 index 0000000000..a4575ecb9b --- /dev/null +++ b/lint/src/test/java/com/adyen/checkout/lint/NotDispatcherProviderTest.kt @@ -0,0 +1,95 @@ +package com.adyen.checkout.lint + +import com.android.tools.lint.checks.infrastructure.LintDetectorTest.kotlin +import com.android.tools.lint.checks.infrastructure.TestLintTask.lint +import org.junit.Test + +internal class NotDispatcherProviderTest { + + @Test + fun whenDispatchersIsUsed_thenIssueIsDetected() { + lint() + .files( + DISPATCHERS_STUB, + DISPATCHER_PROVIDER_STUB, + kotlin( + """ + package test + + import kotlinx.coroutines.Dispatchers + import kotlinx.coroutines.CoroutineDispatcher + import com.adyen.checkout.core.DispatcherProvider + + class Test( + private val dispatcher: CoroutineDispatcher = Dispatchers.IO + ) { + + fun test() = withContext(Dispatchers.Default) { + withContext(DispatcherProvider.Main) {} + } + } + """, + ).indented(), + ) + .issues(NOT_DISPATCHER_PROVIDER_ISSUE) + .allowMissingSdk() + .allowDuplicates() + .run() + .expect( + """ + src/test/Test.kt:8: Error: Dispatchers used instead of DispatcherProvider [NotDispatcherProvider] + private val dispatcher: CoroutineDispatcher = Dispatchers.IO + ~~~~~~~~~~~ + src/test/Test.kt:11: Error: Dispatchers used instead of DispatcherProvider [NotDispatcherProvider] + fun test() = withContext(Dispatchers.Default) { + ~~~~~~~~~~~ + 2 errors, 0 warnings + """, + ) + .expectFixDiffs( + """ + Fix for src/test/Test.kt line 8: Replace with DispatcherProvider: + @@ -8 +8 + - private val dispatcher: CoroutineDispatcher = Dispatchers.IO + + private val dispatcher: CoroutineDispatcher = DispatcherProvider.IO + Fix for src/test/Test.kt line 11: Replace with DispatcherProvider: + @@ -11 +11 + - fun test() = withContext(Dispatchers.Default) { + + fun test() = withContext(DispatcherProvider.Default) { + """, + ) + } + + companion object { + + private val DISPATCHERS_STUB = kotlin( + """ + package kotlinx.coroutines + + object Dispatchers { + val Main = CoroutineDispatcher() + val Default = CoroutineDispatcher() + val IO = CoroutineDispatcher() + } + + open class CoroutineDispatcher + + fun withContext(dispatcher: CoroutineDispatcher, block: () -> Unit) { + block() + } + """, + ).indented() + + private val DISPATCHER_PROVIDER_STUB = kotlin( + """ + package com.adyen.checkout.core + + object DispatcherProvider { + val Main = CoroutineDispatcher() + val Default = CoroutineDispatcher() + val IO = CoroutineDispatcher() + } + """, + ).indented() + } +} From 454a597927766d55d2746f0041573fd425012ff0 Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Wed, 13 Nov 2024 15:39:16 +0100 Subject: [PATCH 051/102] Suppress NotDispatcherProvider rule in DispatcherProvider COAND-1020 --- .../src/main/java/com/adyen/checkout/core/DispatcherProvider.kt | 1 + .../java/com/adyen/checkout/test/TestDispatcherExtension.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt b/checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt index 090c7b96e0..44ebbcab28 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt +++ b/checkout-core/src/main/java/com/adyen/checkout/core/DispatcherProvider.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.MainCoroutineDispatcher +@Suppress("NotDispatcherProvider") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) object DispatcherProvider { diff --git a/test-core/src/testFixtures/java/com/adyen/checkout/test/TestDispatcherExtension.kt b/test-core/src/testFixtures/java/com/adyen/checkout/test/TestDispatcherExtension.kt index 8df09af10a..8d04084825 100644 --- a/test-core/src/testFixtures/java/com/adyen/checkout/test/TestDispatcherExtension.kt +++ b/test-core/src/testFixtures/java/com/adyen/checkout/test/TestDispatcherExtension.kt @@ -21,6 +21,7 @@ import org.junit.jupiter.api.extension.ExtensionContext * JUnit 5 extension that replaces [Dispatchers.Main] with a test dispatcher. This gives control over how the dispatcher * executes it's work. */ +@Suppress("NotDispatcherProvider") @OptIn(ExperimentalCoroutinesApi::class) class TestDispatcherExtension : BeforeEachCallback, AfterEachCallback { From f6748f3e0f59ea5d9dbad12d18697e0b757e4f20 Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Thu, 14 Nov 2024 15:38:00 +0100 Subject: [PATCH 052/102] Centralize IO dispatcher usage in example app --- .../extensions/DispatcherExtensions.kt | 15 ++++++++++++ .../example/repositories/RepositoryUtils.kt | 6 ++--- .../service/ExampleAdvancedDropInService.kt | 23 +++++++------------ .../example/service/ExampleDropInService.kt | 11 ++++----- .../service/ExampleSessionsDropInService.kt | 8 +++---- .../checkout/example/ui/bacs/BacsViewModel.kt | 11 ++++----- .../checkout/example/ui/blik/BlikViewModel.kt | 8 +++---- .../checkout/example/ui/card/CardViewModel.kt | 11 ++++----- .../ui/card/SessionsCardTakenOverViewModel.kt | 10 +++----- .../example/ui/giftcard/GiftCardViewModel.kt | 17 +++++--------- .../ui/googlepay/GooglePayViewModel.kt | 11 ++++----- .../compose/SessionsGooglePayViewModel.kt | 5 ++-- .../example/ui/instant/InstantViewModel.kt | 11 ++++----- 13 files changed, 63 insertions(+), 84 deletions(-) create mode 100644 example-app/src/main/java/com/adyen/checkout/example/extensions/DispatcherExtensions.kt diff --git a/example-app/src/main/java/com/adyen/checkout/example/extensions/DispatcherExtensions.kt b/example-app/src/main/java/com/adyen/checkout/example/extensions/DispatcherExtensions.kt new file mode 100644 index 0000000000..8848b42ac0 --- /dev/null +++ b/example-app/src/main/java/com/adyen/checkout/example/extensions/DispatcherExtensions.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by oscars on 14/11/2024. + */ + +package com.adyen.checkout.example.extensions + +import com.adyen.checkout.core.DispatcherProvider +import kotlinx.coroutines.CoroutineDispatcher + +@Suppress("RestrictedApi") +val IODispatcher: CoroutineDispatcher get() = DispatcherProvider.IO diff --git a/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt b/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt index 0141a64236..d15abc2a0a 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/repositories/RepositoryUtils.kt @@ -9,12 +9,12 @@ package com.adyen.checkout.example.repositories import android.util.Log -import com.adyen.checkout.core.DispatcherProvider +import com.adyen.checkout.example.extensions.IODispatcher import kotlinx.coroutines.CancellationException import kotlinx.coroutines.withContext -@Suppress("TooGenericExceptionCaught", "RestrictedApi") -internal suspend fun safeApiCall(call: suspend () -> T): T? = withContext(DispatcherProvider.IO) { +@Suppress("TooGenericExceptionCaught") +internal suspend fun safeApiCall(call: suspend () -> T): T? = withContext(IODispatcher) { return@withContext try { call() } catch (e: CancellationException) { diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt index 1c7e359f9f..e12f1f2754 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleAdvancedDropInService.kt @@ -22,7 +22,6 @@ import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.dropin.AddressLookupDropInServiceResult import com.adyen.checkout.dropin.BalanceDropInServiceResult @@ -33,6 +32,7 @@ import com.adyen.checkout.dropin.FinishedDialog import com.adyen.checkout.dropin.OrderDropInServiceResult import com.adyen.checkout.dropin.RecurringDropInServiceResult import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.extensions.toStringPretty import com.adyen.checkout.example.repositories.AddressLookupCompletionResult @@ -75,11 +75,10 @@ class ExampleAdvancedDropInService : DropInService() { }.launchIn(this) } - @Suppress("RestrictedApi") override fun onSubmit( state: PaymentComponentState<*>, ) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "onPaymentsCallRequested") checkPaymentState(state) @@ -125,9 +124,8 @@ class ExampleAdvancedDropInService : DropInService() { // read bundle and handle it } - @Suppress("RestrictedApi") override fun onAdditionalDetails(actionComponentData: ActionComponentData) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "onDetailsCallRequested") val actionComponentJson = ActionComponentData.SERIALIZER.serialize(actionComponentData) @@ -199,10 +197,9 @@ class ExampleAdvancedDropInService : DropInService() { return OrderResponse.SERIALIZER.deserialize(orderJSON) } - @Suppress("RestrictedApi") private fun fetchPaymentMethods(orderResponse: OrderResponse? = null) { Log.d(TAG, "fetchPaymentMethods") - launch(DispatcherProvider.IO) { + launch(IODispatcher) { val order = orderResponse?.let { Order( pspReference = it.pspReference, @@ -229,9 +226,8 @@ class ExampleAdvancedDropInService : DropInService() { } } - @Suppress("RestrictedApi") override fun onBalanceCheck(paymentComponentState: PaymentComponentState<*>) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "checkBalance") val amount = paymentComponentState.data.amount val paymentMethod = paymentComponentState.data.paymentMethod @@ -284,9 +280,8 @@ class ExampleAdvancedDropInService : DropInService() { } } - @Suppress("RestrictedApi") override fun onOrderRequest() { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "createOrder") val paymentRequest = createOrderRequest( @@ -316,9 +311,8 @@ class ExampleAdvancedDropInService : DropInService() { } } - @Suppress("RestrictedApi") override fun onOrderCancel(order: Order, shouldUpdatePaymentMethods: Boolean) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "cancelOrder") val orderJson = Order.SERIALIZER.serialize(order) val request = createCancelOrderRequest( @@ -355,11 +349,10 @@ class ExampleAdvancedDropInService : DropInService() { } } - @Suppress("RestrictedApi") override fun onRemoveStoredPaymentMethod( storedPaymentMethod: StoredPaymentMethod, ) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { val storedPaymentMethodId = storedPaymentMethod.id.orEmpty() val isSuccessfullyRemoved = paymentsRepository.removeStoredPaymentMethod( storedPaymentMethodId = storedPaymentMethodId, diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt index d5bcd49371..c29433b795 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleDropInService.kt @@ -15,12 +15,12 @@ import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.StoredPaymentMethod import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.dropin.DropInService import com.adyen.checkout.dropin.DropInServiceResult import com.adyen.checkout.dropin.ErrorDialog import com.adyen.checkout.dropin.RecurringDropInServiceResult import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.extensions.toStringPretty import com.adyen.checkout.example.repositories.PaymentsRepository @@ -43,11 +43,10 @@ class ExampleDropInService : DropInService() { @Inject lateinit var keyValueStorage: KeyValueStorage - @Suppress("RestrictedApi") override fun onSubmit( state: PaymentComponentState<*> ) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "onPaymentsCallRequested") checkPaymentState(state) @@ -83,9 +82,8 @@ class ExampleDropInService : DropInService() { } } - @Suppress("RestrictedApi") override fun onAdditionalDetails(actionComponentData: ActionComponentData) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "onDetailsCallRequested") val actionComponentJson = ActionComponentData.SERIALIZER.serialize(actionComponentData) @@ -128,11 +126,10 @@ class ExampleDropInService : DropInService() { return jsonResponse.has("action") } - @Suppress("RestrictedApi") override fun onRemoveStoredPaymentMethod( storedPaymentMethod: StoredPaymentMethod, ) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { val storedPaymentMethodId = storedPaymentMethod.id.orEmpty() val isSuccessfullyRemoved = paymentsRepository.removeStoredPaymentMethod( storedPaymentMethodId = storedPaymentMethodId, diff --git a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt index 268db5b20a..922214b7a7 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/service/ExampleSessionsDropInService.kt @@ -15,11 +15,11 @@ import com.adyen.checkout.components.core.ActionComponentData import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.dropin.DropInServiceResult import com.adyen.checkout.dropin.ErrorDialog import com.adyen.checkout.dropin.SessionDropInService import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.extensions.toStringPretty import com.adyen.checkout.example.repositories.PaymentsRepository @@ -38,7 +38,6 @@ class ExampleSessionsDropInService : SessionDropInService() { @Inject lateinit var keyValueStorage: KeyValueStorage - @Suppress("RestrictedApi") override fun onSubmit( state: PaymentComponentState<*>, ): Boolean { @@ -46,7 +45,7 @@ class ExampleSessionsDropInService : SessionDropInService() { state is BlikComponentState || state is CardComponentState ) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "onPaymentsCallRequested") // Check out the documentation of this method on the parent DropInService class @@ -74,12 +73,11 @@ class ExampleSessionsDropInService : SessionDropInService() { } } - @Suppress("RestrictedApi") override fun onAdditionalDetails( actionComponentData: ActionComponentData, ): Boolean { return if (isFlowTakenOver) { - launch(DispatcherProvider.IO) { + launch(IODispatcher) { Log.d(TAG, "onDetailsCallRequested") val response = paymentsRepository.makeDetailsRequest( diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt index 45ed525d8b..f6e6f5132b 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/bacs/BacsViewModel.kt @@ -19,9 +19,9 @@ import com.adyen.checkout.components.core.ComponentCallback import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.R import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest @@ -57,8 +57,7 @@ internal class BacsViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - @Suppress("RestrictedApi") - private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { + private suspend fun fetchPaymentMethods() = withContext(IODispatcher) { val validationError = if (keyValueStorage.getAmount().currency != CheckoutCurrency.GBP.name) { BacsViewState.Error(R.string.currency_code_error, CheckoutCurrency.GBP.name) } else if (keyValueStorage.getCountry() != Locale.UK.country) { @@ -116,9 +115,8 @@ internal class BacsViewModel @Inject constructor( viewModelScope.launch { _events.emit(BacsEvent.PaymentResult("Failed: ${error.errorMessage}")) } } - @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } @@ -147,8 +145,7 @@ internal class BacsViewModel @Inject constructor( val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - @Suppress("RestrictedApi") - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt index 7a18bea928..31931f3a41 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/blik/BlikViewModel.kt @@ -20,9 +20,9 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.components.core.paymentmethod.BlikPaymentMethod -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.R import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest @@ -55,8 +55,7 @@ class BlikViewModel @Inject constructor( viewModelScope.launch { _blikViewState.emit(fetchPaymentMethods()) } } - @Suppress("RestrictedApi") - private suspend fun fetchPaymentMethods(): BlikViewState = withContext(DispatcherProvider.IO) { + private suspend fun fetchPaymentMethods(): BlikViewState = withContext(IODispatcher) { if (keyValueStorage.getAmount().currency != CheckoutCurrency.PLN.name) { return@withContext BlikViewState.Error(R.string.currency_code_error, CheckoutCurrency.PLN.name) } else if (keyValueStorage.getCountry() != POLAND_COUNTRY_CODE) { @@ -139,9 +138,8 @@ class BlikViewModel @Inject constructor( } ?: _events.emit(BlikEvent.PaymentResult("Failed")) } - @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt index 1670b5a611..4ab7b48b2e 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/CardViewModel.kt @@ -11,8 +11,8 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.repositories.AddressLookupCompletionResult import com.adyen.checkout.example.repositories.AddressLookupRepository import com.adyen.checkout.example.repositories.PaymentsRepository @@ -56,8 +56,7 @@ internal class CardViewModel @Inject constructor( }.launchIn(viewModelScope) } - @Suppress("RestrictedApi") - private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { + private suspend fun fetchPaymentMethods() = withContext(IODispatcher) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -129,8 +128,7 @@ internal class CardViewModel @Inject constructor( val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - @Suppress("RestrictedApi") - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -164,9 +162,8 @@ internal class CardViewModel @Inject constructor( _events.emit(CardEvent.AdditionalAction(action)) } - @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt index 2d99c29244..7a2dd336e5 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/card/SessionsCardTakenOverViewModel.kt @@ -22,8 +22,8 @@ import com.adyen.checkout.components.core.LookupAddress import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.repositories.AddressLookupCompletionResult import com.adyen.checkout.example.repositories.AddressLookupRepository @@ -39,7 +39,6 @@ import com.adyen.checkout.sessions.core.SessionComponentCallback import com.adyen.checkout.sessions.core.SessionModel import com.adyen.checkout.sessions.core.SessionPaymentResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -50,7 +49,6 @@ import kotlinx.coroutines.launch import org.json.JSONObject import javax.inject.Inject -@OptIn(FlowPreview::class) @Suppress("TooManyFunctions") @HiltViewModel internal class SessionsCardTakenOverViewModel @Inject constructor( @@ -174,13 +172,12 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( return isFlowTakenOver } - @Suppress("RestrictedApi") private fun makePayment(data: PaymentComponentData<*>) { _cardViewState.value = CardViewState.Loading val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -214,9 +211,8 @@ internal class SessionsCardTakenOverViewModel @Inject constructor( _events.emit(CardEvent.AdditionalAction(action)) } - @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt index b223ef1f1d..453aefb500 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/giftcard/GiftCardViewModel.kt @@ -23,9 +23,9 @@ import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentComponentState import com.adyen.checkout.components.core.action.Action import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.exception.ModelSerializationException import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createBalanceRequest @@ -68,8 +68,7 @@ internal class GiftCardViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - @Suppress("RestrictedApi") - private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { + private suspend fun fetchPaymentMethods() = withContext(IODispatcher) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -113,9 +112,8 @@ internal class GiftCardViewModel @Inject constructor( // no ops override fun onStateChanged(state: GiftCardComponentState) = Unit - @Suppress("RestrictedApi") override fun onBalanceCheck(paymentComponentState: PaymentComponentState<*>) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { Log.d(TAG, "checkBalance") val amount = paymentComponentState.data.amount @@ -177,9 +175,8 @@ internal class GiftCardViewModel @Inject constructor( } } - @Suppress("RestrictedApi") override fun onRequestOrder() { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { Log.d(TAG, "createOrder") val paymentRequest = createOrderRequest( @@ -213,13 +210,12 @@ internal class GiftCardViewModel @Inject constructor( } } - @Suppress("RestrictedApi") private fun makePayment(data: PaymentComponentData<*>) { _giftCardViewStateFlow.value = GiftCardViewState.Loading val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -284,9 +280,8 @@ internal class GiftCardViewModel @Inject constructor( viewModelScope.launch { _events.emit(GiftCardEvent.AdditionalAction(action)) } } - @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt index 93d280b836..c4d3be339c 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/GooglePayViewModel.kt @@ -20,9 +20,9 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.R import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest @@ -67,8 +67,7 @@ internal class GooglePayViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - @Suppress("RestrictedApi") - private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { + private suspend fun fetchPaymentMethods() = withContext(IODispatcher) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -138,9 +137,8 @@ internal class GooglePayViewModel @Inject constructor( viewModelScope.launch { _events.emit(GooglePayEvent.PaymentResult("Failed: ${error.errorMessage}")) } } - @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } @@ -169,8 +167,7 @@ internal class GooglePayViewModel @Inject constructor( val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - @Suppress("RestrictedApi") - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt index ea6a4c54ed..3939f75ef3 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/googlepay/compose/SessionsGooglePayViewModel.kt @@ -20,8 +20,8 @@ import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.extensions.getLogTag import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.getSessionRequest @@ -71,8 +71,7 @@ internal class SessionsGooglePayViewModel @Inject constructor( viewModelScope.launch { fetchSession() } } - @Suppress("RestrictedApi") - private suspend fun fetchSession() = withContext(DispatcherProvider.IO) { + private suspend fun fetchSession() = withContext(IODispatcher) { val paymentMethodType = PaymentMethodTypes.GOOGLE_PAY val checkoutSession = getSession(paymentMethodType) if (checkoutSession == null) { diff --git a/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt b/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt index 26fd56a436..feed4869bb 100644 --- a/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt +++ b/example-app/src/main/java/com/adyen/checkout/example/ui/instant/InstantViewModel.kt @@ -16,9 +16,9 @@ import com.adyen.checkout.components.core.ComponentCallback import com.adyen.checkout.components.core.ComponentError import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.core.DispatcherProvider import com.adyen.checkout.core.PermissionHandlerCallback import com.adyen.checkout.example.data.storage.KeyValueStorage +import com.adyen.checkout.example.extensions.IODispatcher import com.adyen.checkout.example.repositories.PaymentsRepository import com.adyen.checkout.example.service.createPaymentRequest import com.adyen.checkout.example.service.getPaymentMethodRequest @@ -55,8 +55,7 @@ internal class InstantViewModel @Inject constructor( viewModelScope.launch { fetchPaymentMethods() } } - @Suppress("RestrictedApi") - private suspend fun fetchPaymentMethods() = withContext(DispatcherProvider.IO) { + private suspend fun fetchPaymentMethods() = withContext(IODispatcher) { val paymentMethodResponse = paymentsRepository.getPaymentMethods( getPaymentMethodRequest( merchantAccount = keyValueStorage.getMerchantAccount(), @@ -119,12 +118,11 @@ internal class InstantViewModel @Inject constructor( permissionCallback = null } - @Suppress("RestrictedApi") private fun makePayment(data: PaymentComponentData<*>) { _instantViewState.tryEmit(InstantViewState.Loading) val paymentComponentData = PaymentComponentData.SERIALIZER.serialize(data) - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val paymentRequest = createPaymentRequest( paymentComponentData = paymentComponentData, shopperReference = keyValueStorage.getShopperReference(), @@ -155,9 +153,8 @@ internal class InstantViewModel @Inject constructor( } ?: _events.emit(InstantEvent.PaymentResult("Failed")) } - @Suppress("RestrictedApi") private fun sendPaymentDetails(actionComponentData: ActionComponentData) { - viewModelScope.launch(DispatcherProvider.IO) { + viewModelScope.launch(IODispatcher) { val json = ActionComponentData.SERIALIZER.serialize(actionComponentData) handlePaymentResponse(paymentsRepository.makeDetailsRequest(json)) } From 45f01767d2faf09183639cfe71538e45fe01b32b Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Wed, 30 Oct 2024 16:29:31 +0100 Subject: [PATCH 053/102] Rename analytics param level from None to Initial COAND-1029 --- .../ui/model/Adyen3DS2ComponentParamsMapperTest.kt | 2 +- .../model/ACHDirectDebitComponentParamsMapperTest.kt | 2 +- .../ui/model/BcmcComponentParamsMapperTest.kt | 2 +- .../ui/model/BoletoComponentParamsMapperTest.kt | 2 +- .../ui/model/CardComponentParamsMapperTest.kt | 2 +- .../ui/model/CashAppPayComponentParamsMapperTest.kt | 2 +- .../internal/analytics/DefaultAnalyticsManager.kt | 2 +- .../core/internal/ui/model/AnalyticsParams.kt | 4 ++-- .../analytics/DefaultAnalyticsManagerTest.kt | 12 ++++++------ .../ui/model/ButtonComponentParamsMapperTest.kt | 2 +- .../ui/model/GenericComponentParamsMapperTest.kt | 2 +- .../internal/ui/model/DropInParamsMapperTest.kt | 2 +- .../ui/model/GiftCardComponentParamsMapperTest.kt | 2 +- .../ui/model/GooglePayComponentParamsMapperTest.kt | 2 +- .../googlepay/internal/util/GooglePayUtilsTest.kt | 2 +- .../ui/model/IssuerListComponentParamsMapperTest.kt | 2 +- .../model/MealVoucherFRComponentParamsMapperTest.kt | 2 +- .../ui/model/TwintComponentParamsMapperTest.kt | 2 +- 18 files changed, 24 insertions(+), 24 deletions(-) diff --git a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/model/Adyen3DS2ComponentParamsMapperTest.kt b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/model/Adyen3DS2ComponentParamsMapperTest.kt index 545255bf63..a293237036 100644 --- a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/model/Adyen3DS2ComponentParamsMapperTest.kt +++ b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/model/Adyen3DS2ComponentParamsMapperTest.kt @@ -91,7 +91,7 @@ internal class Adyen3DS2ComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "CAD", diff --git a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitComponentParamsMapperTest.kt b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitComponentParamsMapperTest.kt index 632e32b591..1637d2f924 100644 --- a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitComponentParamsMapperTest.kt +++ b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/model/ACHDirectDebitComponentParamsMapperTest.kt @@ -88,7 +88,7 @@ internal class ACHDirectDebitComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "EUR", diff --git a/bcmc/src/test/java/com/adyen/checkout/bcmc/internal/ui/model/BcmcComponentParamsMapperTest.kt b/bcmc/src/test/java/com/adyen/checkout/bcmc/internal/ui/model/BcmcComponentParamsMapperTest.kt index d8013b7595..9605275b19 100644 --- a/bcmc/src/test/java/com/adyen/checkout/bcmc/internal/ui/model/BcmcComponentParamsMapperTest.kt +++ b/bcmc/src/test/java/com/adyen/checkout/bcmc/internal/ui/model/BcmcComponentParamsMapperTest.kt @@ -108,7 +108,7 @@ internal class BcmcComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "CAD", diff --git a/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/model/BoletoComponentParamsMapperTest.kt b/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/model/BoletoComponentParamsMapperTest.kt index 07a38106f9..21259686ce 100644 --- a/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/model/BoletoComponentParamsMapperTest.kt +++ b/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/model/BoletoComponentParamsMapperTest.kt @@ -90,7 +90,7 @@ internal class BoletoComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "EUR", diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapperTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapperTest.kt index fdb2308693..be398aa9d9 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapperTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/model/CardComponentParamsMapperTest.kt @@ -163,7 +163,7 @@ internal class CardComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "EUR", diff --git a/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/model/CashAppPayComponentParamsMapperTest.kt b/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/model/CashAppPayComponentParamsMapperTest.kt index 7a6634e458..58386c6f0e 100644 --- a/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/model/CashAppPayComponentParamsMapperTest.kt +++ b/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/model/CashAppPayComponentParamsMapperTest.kt @@ -136,7 +136,7 @@ internal class CashAppPayComponentParamsMapperTest { environment = Environment.EUROPE, cashAppPayEnvironment = CashAppPayEnvironment.PRODUCTION, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "EUR", diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt index dcc1df5324..73af88f932 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManager.kt @@ -125,7 +125,7 @@ internal class DefaultAnalyticsManager( CheckoutAttemptIdState.NotAvailable -> CHECKOUT_ATTEMPT_ID_NOT_FETCHED } - private fun cannotSendEvents() = analyticsParams.level.priority <= AnalyticsParamsLevel.NONE.priority + private fun cannotSendEvents() = analyticsParams.level.priority <= AnalyticsParamsLevel.INITIAL.priority override fun clear(owner: Any) { if (ownerReference != owner::class.qualifiedName) { diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt index 8214b77f58..6ffd722f0f 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt @@ -26,7 +26,7 @@ data class AnalyticsParams( @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) enum class AnalyticsParamsLevel(val priority: Int) { - NONE(1), + INITIAL(1), ALL(2), } @@ -34,6 +34,6 @@ private fun getLevel(analyticsConfiguration: AnalyticsConfiguration?): Analytics return when (analyticsConfiguration?.level) { null -> AnalyticsParamsLevel.ALL // default is ALL AnalyticsLevel.ALL -> AnalyticsParamsLevel.ALL - AnalyticsLevel.NONE -> AnalyticsParamsLevel.NONE + AnalyticsLevel.NONE -> AnalyticsParamsLevel.INITIAL } } diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManagerTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManagerTest.kt index 545e00290f..8472b99395 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManagerTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/DefaultAnalyticsManagerTest.kt @@ -59,8 +59,8 @@ internal class DefaultAnalyticsManagerTest( } @Test - fun `sending events is disabled, then checkoutAttemptId is still set`() = runTest { - analyticsManager = createAnalyticsManager(AnalyticsParamsLevel.NONE) + fun `analytics level is initial, then checkoutAttemptId is still set`() = runTest { + analyticsManager = createAnalyticsManager(AnalyticsParamsLevel.INITIAL) whenever(analyticsRepository.fetchCheckoutAttemptId()) doReturn "test value" analyticsManager.initialize(this@InitializeTest, this) @@ -95,8 +95,8 @@ internal class DefaultAnalyticsManagerTest( inner class TrackEventTest { @Test - fun `sending events is disabled, then events should not be stored`() = runTest { - analyticsManager = createAnalyticsManager(AnalyticsParamsLevel.NONE) + fun `analytics level is initial, then events should not be stored`() = runTest { + analyticsManager = createAnalyticsManager(AnalyticsParamsLevel.INITIAL) analyticsManager.initialize(this@TrackEventTest, this) analyticsManager.trackEvent(GenericEvents.rendered("dropin", false)) @@ -140,8 +140,8 @@ internal class DefaultAnalyticsManagerTest( inner class SendEventTest { @Test - fun `sending events is disabled, then events are not sent`() = runTest { - analyticsManager = createAnalyticsManager(AnalyticsParamsLevel.NONE) + fun `analytics level is initial, then events are not sent`() = runTest { + analyticsManager = createAnalyticsManager(AnalyticsParamsLevel.INITIAL) analyticsManager.initialize(this@SendEventTest, this) val event = AnalyticsEvent.Info( component = "test", diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/ButtonComponentParamsMapperTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/ButtonComponentParamsMapperTest.kt index dc725315d8..484e09f7b3 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/ButtonComponentParamsMapperTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/ButtonComponentParamsMapperTest.kt @@ -66,7 +66,7 @@ internal class ButtonComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "USD", diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/GenericComponentParamsMapperTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/GenericComponentParamsMapperTest.kt index bce1246f83..3e001c7e36 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/GenericComponentParamsMapperTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/ui/model/GenericComponentParamsMapperTest.kt @@ -66,7 +66,7 @@ internal class GenericComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "CAD", diff --git a/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/model/DropInParamsMapperTest.kt b/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/model/DropInParamsMapperTest.kt index 7181f45c37..61c3764f7a 100644 --- a/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/model/DropInParamsMapperTest.kt +++ b/drop-in/src/test/java/com/adyen/checkout/dropin/internal/ui/model/DropInParamsMapperTest.kt @@ -97,7 +97,7 @@ internal class DropInParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), amount = Amount( currency = "EUR", value = 49_00L, diff --git a/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/model/GiftCardComponentParamsMapperTest.kt b/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/model/GiftCardComponentParamsMapperTest.kt index 3d8e531dbf..92d0aafc10 100644 --- a/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/model/GiftCardComponentParamsMapperTest.kt +++ b/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/model/GiftCardComponentParamsMapperTest.kt @@ -67,7 +67,7 @@ internal class GiftCardComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "CAD", diff --git a/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/model/GooglePayComponentParamsMapperTest.kt b/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/model/GooglePayComponentParamsMapperTest.kt index 244d2b9558..6eda610890 100644 --- a/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/model/GooglePayComponentParamsMapperTest.kt +++ b/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/model/GooglePayComponentParamsMapperTest.kt @@ -166,7 +166,7 @@ internal class GooglePayComponentParamsMapperTest { environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, googlePayEnvironment = WalletConstants.ENVIRONMENT_PRODUCTION, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "CAD", diff --git a/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtilsTest.kt b/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtilsTest.kt index a5f45707d4..8d33d0ccf6 100644 --- a/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtilsTest.kt +++ b/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/util/GooglePayUtilsTest.kt @@ -273,7 +273,7 @@ internal class GooglePayUtilsTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = "CLIENT_KEY_CUSTOM", - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, "CLIENT_KEY_CUSTOM"), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, "CLIENT_KEY_CUSTOM"), isCreatedByDropIn = true, amount = Amount("EUR", 13_37), ), diff --git a/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/model/IssuerListComponentParamsMapperTest.kt b/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/model/IssuerListComponentParamsMapperTest.kt index 35b4ea78c5..eb61d32752 100644 --- a/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/model/IssuerListComponentParamsMapperTest.kt +++ b/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/model/IssuerListComponentParamsMapperTest.kt @@ -118,7 +118,7 @@ internal class IssuerListComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, viewType = IssuerListViewType.SPINNER_VIEW, hideIssuerLogos = true, diff --git a/meal-voucher-fr/src/test/java/com/adyen/checkout/mealvoucherfr/internal/ui/model/MealVoucherFRComponentParamsMapperTest.kt b/meal-voucher-fr/src/test/java/com/adyen/checkout/mealvoucherfr/internal/ui/model/MealVoucherFRComponentParamsMapperTest.kt index bb814e8a8c..6a8f13fe13 100644 --- a/meal-voucher-fr/src/test/java/com/adyen/checkout/mealvoucherfr/internal/ui/model/MealVoucherFRComponentParamsMapperTest.kt +++ b/meal-voucher-fr/src/test/java/com/adyen/checkout/mealvoucherfr/internal/ui/model/MealVoucherFRComponentParamsMapperTest.kt @@ -77,7 +77,7 @@ internal class MealVoucherFRComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "DKK", diff --git a/twint/src/test/java/com/adyen/checkout/twint/internal/ui/model/TwintComponentParamsMapperTest.kt b/twint/src/test/java/com/adyen/checkout/twint/internal/ui/model/TwintComponentParamsMapperTest.kt index 10eaae2f80..a534b667a2 100644 --- a/twint/src/test/java/com/adyen/checkout/twint/internal/ui/model/TwintComponentParamsMapperTest.kt +++ b/twint/src/test/java/com/adyen/checkout/twint/internal/ui/model/TwintComponentParamsMapperTest.kt @@ -107,7 +107,7 @@ internal class TwintComponentParamsMapperTest { shopperLocale = Locale.GERMAN, environment = Environment.EUROPE, clientKey = TEST_CLIENT_KEY_2, - analyticsParams = AnalyticsParams(AnalyticsParamsLevel.NONE, TEST_CLIENT_KEY_2), + analyticsParams = AnalyticsParams(AnalyticsParamsLevel.INITIAL, TEST_CLIENT_KEY_2), isCreatedByDropIn = true, amount = Amount( currency = "EUR", From ed3a0bf2509c70851acc9d8dadd9b0886070e713 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Wed, 30 Oct 2024 16:30:17 +0100 Subject: [PATCH 054/102] Fix read parcelable classLoader type COAND-1029 --- .../com/adyen/checkout/components/core/CheckoutConfiguration.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/CheckoutConfiguration.kt b/components-core/src/main/java/com/adyen/checkout/components/core/CheckoutConfiguration.kt index 551b38a8fd..fa2a13810a 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/CheckoutConfiguration.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/CheckoutConfiguration.kt @@ -89,7 +89,7 @@ class CheckoutConfiguration( environment = requireNotNull(parcel.readParcelable(Environment::class.java.classLoader)), clientKey = requireNotNull(parcel.readString()), amount = parcel.readParcelable(Amount::class.java.classLoader), - analyticsConfiguration = parcel.readParcelable(Amount::class.java.classLoader), + analyticsConfiguration = parcel.readParcelable(AnalyticsConfiguration::class.java.classLoader), ) { val size = parcel.readInt() From 103e987c8a90f479658e8b53d1e95234304deb1f Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 31 Oct 2024 11:03:25 +0100 Subject: [PATCH 055/102] Send level as part of the initial analytics request COAND-1029 --- .../analytics/AnalyticsManagerFactory.kt | 1 + .../remote/DefaultAnalyticsSetupProvider.kt | 12 ++++++ .../data/model/AnalyticsSetupRequest.kt | 4 ++ .../DefaultAnalyticsSetupProviderTest.kt | 41 +++++++++++++++++++ .../data/model/AnalyticsSetupRequestTest.kt | 4 ++ 5 files changed, 62 insertions(+) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt index 9171ee7c03..fb701287ba 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsManagerFactory.kt @@ -74,6 +74,7 @@ class AnalyticsManagerFactory { application = application, shopperLocale = shopperLocale, isCreatedByDropIn = isCreatedByDropIn, + analyticsLevel = analyticsParams.level, amount = amount, source = source, sessionId = sessionId, diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProvider.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProvider.kt index 50473beac8..a5d0927923 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProvider.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProvider.kt @@ -14,12 +14,15 @@ import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.internal.analytics.AnalyticsPlatformParams import com.adyen.checkout.components.core.internal.analytics.AnalyticsSource import com.adyen.checkout.components.core.internal.data.model.AnalyticsSetupRequest +import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParamsLevel import java.util.Locale +@Suppress("LongParameterList") internal class DefaultAnalyticsSetupProvider( private val application: Application, private val shopperLocale: Locale, private val isCreatedByDropIn: Boolean, + private val analyticsLevel: AnalyticsParamsLevel, private val amount: Amount?, private val source: AnalyticsSource, private val sessionId: String?, @@ -33,6 +36,7 @@ internal class DefaultAnalyticsSetupProvider( locale = shopperLocale.toLanguageTag(), component = getComponentQueryParameter(source), flavor = getFlavorQueryParameter(isCreatedByDropIn), + level = getLevelQueryParameter(analyticsLevel), deviceBrand = Build.BRAND, deviceModel = Build.MODEL, referrer = application.packageName, @@ -57,8 +61,16 @@ internal class DefaultAnalyticsSetupProvider( is AnalyticsSource.PaymentComponent -> source.paymentMethodType } + private fun getLevelQueryParameter(analyticsParamsLevel: AnalyticsParamsLevel) = when (analyticsParamsLevel) { + AnalyticsParamsLevel.INITIAL -> ANALYTICS_LEVEL_INITIAL + AnalyticsParamsLevel.ALL -> ANALYTICS_LEVEL_ALL + } + companion object { private const val DROP_IN = "dropin" private const val COMPONENTS = "components" + + private const val ANALYTICS_LEVEL_INITIAL = "initial" + private const val ANALYTICS_LEVEL_ALL = "all" } } diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequest.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequest.kt index cfedef7b1d..b5e62c5ef4 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequest.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequest.kt @@ -29,6 +29,7 @@ internal data class AnalyticsSetupRequest( val locale: String?, val component: String?, val flavor: String?, + val level: String?, val deviceBrand: String?, val deviceModel: String?, val referrer: String?, @@ -47,6 +48,7 @@ internal data class AnalyticsSetupRequest( private const val LOCALE = "locale" private const val COMPONENT = "component" private const val FLAVOR = "flavor" + private const val LEVEL = "level" private const val DEVICE_BRAND = "deviceBrand" private const val DEVICE_MODEL = "deviceModel" private const val REFERRER = "referrer" @@ -68,6 +70,7 @@ internal data class AnalyticsSetupRequest( putOpt(LOCALE, modelObject.locale) putOpt(COMPONENT, modelObject.component) putOpt(FLAVOR, modelObject.flavor) + putOpt(LEVEL, modelObject.level) putOpt(DEVICE_BRAND, modelObject.deviceBrand) putOpt(DEVICE_MODEL, modelObject.deviceModel) putOpt(REFERRER, modelObject.referrer) @@ -93,6 +96,7 @@ internal data class AnalyticsSetupRequest( locale = getStringOrNull(LOCALE), component = getStringOrNull(COMPONENT), flavor = getStringOrNull(FLAVOR), + level = getStringOrNull(LEVEL), deviceBrand = getStringOrNull(DEVICE_BRAND), deviceModel = getStringOrNull(DEVICE_MODEL), referrer = getStringOrNull(REFERRER), diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProviderTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProviderTest.kt index 4ce23be7e7..e793cbb8ea 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProviderTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/analytics/data/remote/DefaultAnalyticsSetupProviderTest.kt @@ -8,6 +8,7 @@ import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.internal.analytics.AnalyticsPlatformParams import com.adyen.checkout.components.core.internal.analytics.AnalyticsSource import com.adyen.checkout.components.core.internal.data.model.AnalyticsSetupRequest +import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParamsLevel import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.mockito.kotlin.doReturn @@ -25,6 +26,7 @@ internal class DefaultAnalyticsSetupProviderTest { application = createMockApplication(), shopperLocale = Locale.US, isCreatedByDropIn = false, + analyticsLevel = AnalyticsParamsLevel.INITIAL, amount = Amount("USD", 123), source = AnalyticsSource.PaymentComponent("scheme"), sessionId = "sessionId", @@ -39,6 +41,7 @@ internal class DefaultAnalyticsSetupProviderTest { locale = Locale.US.toLanguageTag(), component = "scheme", flavor = "components", + level = "initial", deviceBrand = Build.BRAND, deviceModel = Build.MODEL, referrer = "com.adyen.checkout", @@ -58,6 +61,7 @@ internal class DefaultAnalyticsSetupProviderTest { application = createMockApplication(), shopperLocale = Locale.US, isCreatedByDropIn = true, + analyticsLevel = AnalyticsParamsLevel.INITIAL, amount = Amount("USD", 123), source = AnalyticsSource.PaymentComponent("scheme"), sessionId = "sessionId", @@ -74,6 +78,7 @@ internal class DefaultAnalyticsSetupProviderTest { application = createMockApplication(), shopperLocale = Locale.US, isCreatedByDropIn = false, + analyticsLevel = AnalyticsParamsLevel.INITIAL, amount = Amount("USD", 123), source = AnalyticsSource.PaymentComponent("scheme"), sessionId = "sessionId", @@ -90,6 +95,7 @@ internal class DefaultAnalyticsSetupProviderTest { application = createMockApplication(), shopperLocale = Locale.US, isCreatedByDropIn = true, + analyticsLevel = AnalyticsParamsLevel.INITIAL, amount = Amount("USD", 123), source = AnalyticsSource.DropIn(listOf()), sessionId = "sessionId", @@ -106,6 +112,7 @@ internal class DefaultAnalyticsSetupProviderTest { application = createMockApplication(), shopperLocale = Locale.US, isCreatedByDropIn = true, + analyticsLevel = AnalyticsParamsLevel.INITIAL, amount = Amount("USD", 123), source = AnalyticsSource.PaymentComponent("scheme"), sessionId = "sessionId", @@ -116,6 +123,40 @@ internal class DefaultAnalyticsSetupProviderTest { assertEquals("scheme", result.component) } + @Test + fun `when analytics params level is initial, then level should be initial`() { + analyticsSetupProvider = DefaultAnalyticsSetupProvider( + application = createMockApplication(), + shopperLocale = Locale.US, + isCreatedByDropIn = false, + analyticsLevel = AnalyticsParamsLevel.INITIAL, + amount = Amount("USD", 123), + source = AnalyticsSource.PaymentComponent("scheme"), + sessionId = "sessionId", + ) + + val result = analyticsSetupProvider.provide() + + assertEquals("initial", result.level) + } + + @Test + fun `when analytics params level is all, then level should be all`() { + analyticsSetupProvider = DefaultAnalyticsSetupProvider( + application = createMockApplication(), + shopperLocale = Locale.US, + isCreatedByDropIn = false, + analyticsLevel = AnalyticsParamsLevel.ALL, + amount = Amount("USD", 123), + source = AnalyticsSource.PaymentComponent("scheme"), + sessionId = "sessionId", + ) + + val result = analyticsSetupProvider.provide() + + assertEquals("all", result.level) + } + private fun createMockApplication(): Application { val application = mock() val resources = mock() diff --git a/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequestTest.kt b/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequestTest.kt index b533f02035..25da8403f1 100644 --- a/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequestTest.kt +++ b/components-core/src/test/java/com/adyen/checkout/components/core/internal/data/model/AnalyticsSetupRequestTest.kt @@ -17,6 +17,7 @@ internal class AnalyticsSetupRequestTest { locale = "en-US", component = "dropin", flavor = "dropin", + level = "all", deviceBrand = "Google", deviceModel = "Pixel", referrer = "unknown", @@ -37,6 +38,7 @@ internal class AnalyticsSetupRequestTest { .put("locale", "en-US") .put("component", "dropin") .put("flavor", "dropin") + .put("level", "all") .put("deviceBrand", "Google") .put("deviceModel", "Pixel") .put("referrer", "unknown") @@ -59,6 +61,7 @@ internal class AnalyticsSetupRequestTest { .put("locale", "en-US") .put("component", "dropin") .put("flavor", "dropin") + .put("level", "all") .put("deviceBrand", "Google") .put("deviceModel", "Pixel") .put("referrer", "unknown") @@ -78,6 +81,7 @@ internal class AnalyticsSetupRequestTest { locale = "en-US", component = "dropin", flavor = "dropin", + level = "all", deviceBrand = "Google", deviceModel = "Pixel", referrer = "unknown", From 88f697269ef97d4000db320265544a57624e7741 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 7 Nov 2024 15:26:30 +0100 Subject: [PATCH 056/102] Add target to error events COAND-1006 --- .../components/core/internal/analytics/GenericEvents.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt index 226dd931db..d6d3c4d561 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt @@ -128,9 +128,11 @@ object GenericEvents { fun error( component: String, event: ErrorEvent, + target: String? = null, ) = AnalyticsEvent.Error( component = component, errorType = event.errorType, code = event.errorCode, + target = target, ) } From 7b9fe18ee536fb7c605ef5e902b0eb67dfff13b5 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 7 Nov 2024 15:26:49 +0100 Subject: [PATCH 057/102] Track redirect failed event COAND-1006 --- .../internal/ui/DefaultRedirectDelegate.kt | 7 +++++++ .../internal/ui/DefaultRedirectDelegateTest.kt | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt index de0baabdc1..c5f3ef6314 100644 --- a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt +++ b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.components.core.internal.PaymentDataRepository import com.adyen.checkout.components.core.internal.SavedStateHandleContainer import com.adyen.checkout.components.core.internal.SavedStateHandleProperty import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.ui.model.GenericComponentParams import com.adyen.checkout.components.core.internal.util.bufferedChannel @@ -139,6 +140,12 @@ constructor( // PaymentComponentState for actions. redirectHandler.launchUriRedirect(activity, url) } catch (ex: CheckoutException) { + val event = GenericEvents.error( + component = action?.paymentMethodType.orEmpty(), + event = ErrorEvent.REDIRECT_FAILED + ) + analyticsManager?.trackEvent(event) + emitError(ex) } } diff --git a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt index 0cb1c80fa4..4a085015e5 100644 --- a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt +++ b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt @@ -17,6 +17,7 @@ import com.adyen.checkout.components.core.action.ActionTypes import com.adyen.checkout.components.core.action.RedirectAction import com.adyen.checkout.components.core.internal.ActionObserverRepository import com.adyen.checkout.components.core.internal.PaymentDataRepository +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParamsMapper @@ -199,6 +200,23 @@ internal class DefaultRedirectDelegateTest( ) analyticsManager.assertLastEventEquals(expectedEvent) } + + @Test + fun `when handleAction called and redirect fails, then an event is tracked`() = runTest { + val action = RedirectAction( + paymentMethodType = TEST_PAYMENT_METHOD_TYPE, + type = TEST_ACTION_TYPE, + ) + redirectHandler.exception = ComponentException("Failed to launch redirect.") + + delegate.handleAction(action, Activity()) + + val expectedEvent = GenericEvents.error( + component = TEST_PAYMENT_METHOD_TYPE, + event = ErrorEvent.REDIRECT_FAILED, + ) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test From 0b7532c0b338ebf4c0fc53ac0de24ee19ab54a3d Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 7 Nov 2024 15:27:01 +0100 Subject: [PATCH 058/102] Track redirect parse failed event COAND-1006 --- .../internal/ui/DefaultRedirectDelegate.kt | 6 ++++++ .../ui/DefaultRedirectDelegateTest.kt | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt index c5f3ef6314..227fc4cb85 100644 --- a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt +++ b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt @@ -164,6 +164,12 @@ constructor( } } } catch (ex: CheckoutException) { + val event = GenericEvents.error( + component = action?.paymentMethodType.orEmpty(), + event = ErrorEvent.REDIRECT_PARSE_FAILED + ) + analyticsManager?.trackEvent(event) + emitError(ex) } } diff --git a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt index 4a085015e5..8643e3c165 100644 --- a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt +++ b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt @@ -217,6 +217,25 @@ internal class DefaultRedirectDelegateTest( ) analyticsManager.assertLastEventEquals(expectedEvent) } + + @Test + fun `when handleIntent called and parsing redirect result fails, then an event is tracked`() = runTest { + val action = RedirectAction( + paymentMethodType = TEST_PAYMENT_METHOD_TYPE, + type = TEST_ACTION_TYPE, + ) + + delegate.handleAction(action, Activity()) + redirectHandler.exception = ComponentException("Failed to parse redirect result.") + + delegate.handleIntent(Intent()) + + val expectedEvent = GenericEvents.error( + component = TEST_PAYMENT_METHOD_TYPE, + event = ErrorEvent.REDIRECT_PARSE_FAILED, + ) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test From 692e0586df0a15c9176f52d04aa9a586d7af9851 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Thu, 7 Nov 2024 15:27:18 +0100 Subject: [PATCH 059/102] Track redirect cancelled event COAND-1006 --- .../internal/ui/DefaultRedirectDelegate.kt | 9 +++++++++ .../ui/DefaultRedirectDelegateTest.kt | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt index 227fc4cb85..061b4b2ef0 100644 --- a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt +++ b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt @@ -28,6 +28,7 @@ import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.ui.model.GenericComponentParams import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.exception.CancellationException import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.exception.ComponentException import com.adyen.checkout.core.exception.HttpException @@ -200,6 +201,14 @@ constructor( } override fun onError(e: CheckoutException) { + if (e is CancellationException) { + val event = GenericEvents.error( + component = action?.paymentMethodType.orEmpty(), + event = ErrorEvent.REDIRECT_CANCELLED + ) + analyticsManager?.trackEvent(event) + } + emitError(e) } diff --git a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt index 8643e3c165..d57fa4bede 100644 --- a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt +++ b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManage import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParamsMapper import com.adyen.checkout.components.core.internal.ui.model.GenericComponentParamsMapper import com.adyen.checkout.core.Environment +import com.adyen.checkout.core.exception.CancellationException import com.adyen.checkout.core.exception.ComponentException import com.adyen.checkout.core.exception.HttpException import com.adyen.checkout.core.exception.ModelSerializationException @@ -236,6 +237,24 @@ internal class DefaultRedirectDelegateTest( ) analyticsManager.assertLastEventEquals(expectedEvent) } + + @Test + fun `when redirect is cancelled with CancellationException, then an event is tracked`() = runTest { + val action = RedirectAction( + paymentMethodType = TEST_PAYMENT_METHOD_TYPE, + type = TEST_ACTION_TYPE, + ) + delegate.handleAction(action, Activity()) + + val exception = CancellationException("Redirect flow cancelled.") + delegate.onError(exception) + + val expectedEvent = GenericEvents.error( + component = TEST_PAYMENT_METHOD_TYPE, + event = ErrorEvent.REDIRECT_CANCELLED, + ) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test From 608f48c2a396b0cd66af45f7bc73e03e4da71107 Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Tue, 19 Nov 2024 15:11:35 +0100 Subject: [PATCH 060/102] Fix NPE when pressing back and postal code is focussed in address lookup COAND-1040 --- .../core/internal/ui/view/AddressFormInput.kt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt index fd18ec36f3..897b23f7fc 100644 --- a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/AddressFormInput.kt @@ -52,13 +52,13 @@ class AddressFormInput @JvmOverloads constructor( private var countryAdapter: SimpleTextListAdapter = SimpleTextListAdapter(context) private var statesAdapter: SimpleTextListAdapter = SimpleTextListAdapter(context) - private val textViewHeader: TextView + private val textViewHeader: TextView? get() = rootView.findViewById(R.id.textView_header) - private val formContainer: LinearLayout + private val formContainer: LinearLayout? get() = rootView.findViewById(R.id.linearLayout_formContainer) - private val autoCompleteTextViewCountry: AutoCompleteTextView + private val autoCompleteTextViewCountry: AutoCompleteTextView? get() = rootView.findViewById(R.id.autoCompleteTextView_country) private val autoCompleteTextViewState: AutoCompleteTextView? @@ -74,7 +74,7 @@ class AddressFormInput @JvmOverloads constructor( get() = rootView.findViewById(R.id.editText_apartmentSuite) private val editTextPostalCode: AdyenTextInputEditText? - get() = formContainer.findViewById(R.id.editText_postalCode) + get() = formContainer?.findViewById(R.id.editText_postalCode) private val editTextCity: AdyenTextInputEditText? get() = rootView.findViewById(R.id.editText_city) @@ -95,7 +95,7 @@ class AddressFormInput @JvmOverloads constructor( get() = rootView.findViewById(R.id.textInputLayout_apartmentSuite) private val textInputLayoutPostalCode: TextInputLayout? - get() = formContainer.findViewById(R.id.textInputLayout_postalCode) + get() = formContainer?.findViewById(R.id.textInputLayout_postalCode) private val textInputLayoutCity: TextInputLayout? get() = rootView.findViewById(R.id.textInputLayout_city) @@ -111,7 +111,7 @@ class AddressFormInput @JvmOverloads constructor( layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) LayoutInflater.from(context).inflate(R.layout.address_form_input, this, true) - autoCompleteTextViewCountry.apply { + autoCompleteTextViewCountry?.apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setAutofillHints(HintConstants.AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY) } @@ -218,7 +218,7 @@ class AddressFormInput @JvmOverloads constructor( val selectedSpecification = AddressSpecification.fromString(selectedCountry?.code) if (selectedSpecification != currentSpec || currentSelected != selectedCountry) { currentSpec = selectedSpecification - autoCompleteTextViewCountry.setText(selectedCountry?.name) + autoCompleteTextViewCountry?.setText(selectedCountry?.name) populateFormFields(selectedSpecification) } } @@ -246,7 +246,7 @@ class AddressFormInput @JvmOverloads constructor( } val hadFocus = hasFocus() - formContainer.removeAllViews() + formContainer?.removeAllViews() LayoutInflater.from(context).inflate(layoutResId, formContainer, true) initForm(specification) if (hadFocus) requestFocus() @@ -293,7 +293,7 @@ class AddressFormInput @JvmOverloads constructor( } private fun initHeader() { - textViewHeader.setLocalizedTextFromStyle( + textViewHeader?.setLocalizedTextFromStyle( R.style.AdyenCheckout_AddressForm_HeaderTextAppearance, localizedContext, ) @@ -304,7 +304,8 @@ class AddressFormInput @JvmOverloads constructor( styleResId, localizedContext, ) - autoCompleteTextViewCountry.setText(delegate.addressOutputData.countryOptions.firstOrNull { it.selected }?.name) + val text = delegate.addressOutputData.countryOptions.firstOrNull { it.selected }?.name + autoCompleteTextViewCountry?.setText(text) } private fun initStreetInput(styleResId: Int?) { From 6a22388da3cba598dc510f3fbe2e93b039c2e901 Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Tue, 19 Nov 2024 15:14:28 +0100 Subject: [PATCH 061/102] Add release note COAND-1040 --- RELEASE_NOTES.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index efe3a28d75..9b64a15369 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -9,6 +9,4 @@ [//]: # ( - Configurations public constructor are deprecated, please use each Configuration's builder to make a Configuration object) ## Fixed -- For the Address Lookup functionality: - - Address data is now correctly saved to `PaymentComponentData`. - - Address fields that were edited manually no longer lose their state when starting Lookup mode. +- For the Address Lookup functionality, when the postal/zip code field is focused and the user presses back, then it no longer crashes. From a92213ff0be61cc19edf1a4096e295ad6e865420 Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Tue, 19 Nov 2024 16:53:17 +0100 Subject: [PATCH 062/102] Immediately add the loading dialog to the fragment manager This makes sure we are able to always find the loading dialog when we want to dismiss it. Solving an issue where the loading fragment would be presented on top of the error dialog. COAND-984 --- .../com/adyen/checkout/dropin/internal/ui/DropInActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt index 609b6b8783..50cb225f52 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt @@ -627,7 +627,7 @@ internal class DropInActivity : val loadingDialog = getFragmentByTag(LOADING_FRAGMENT_TAG) if (showLoading) { if (loadingDialog == null && !supportFragmentManager.isDestroyed) { - LoadingDialogFragment.newInstance().show(supportFragmentManager, LOADING_FRAGMENT_TAG) + LoadingDialogFragment.newInstance().showNow(supportFragmentManager, LOADING_FRAGMENT_TAG) } } else { loadingDialog?.dismiss() From 036ce791123d93c0dda9fb22454fea92ef459979 Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Tue, 19 Nov 2024 16:58:42 +0100 Subject: [PATCH 063/102] Remove unused progress spinner in gift card bottom sheet COAND-984 --- .../src/main/res/layout/fragment_giftcard_component.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drop-in/src/main/res/layout/fragment_giftcard_component.xml b/drop-in/src/main/res/layout/fragment_giftcard_component.xml index bd3403d871..57ce4e2e3b 100644 --- a/drop-in/src/main/res/layout/fragment_giftcard_component.xml +++ b/drop-in/src/main/res/layout/fragment_giftcard_component.xml @@ -31,14 +31,6 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> - - From 6d2c779403595176b6c8f925d1e8f14f497b962e Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Tue, 19 Nov 2024 17:01:59 +0100 Subject: [PATCH 064/102] Make sure loading state is dismissed before handling result COAND-984 --- .../checkout/dropin/internal/ui/DropInActivity.kt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt index 50cb225f52..676b2749db 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInActivity.kt @@ -277,8 +277,6 @@ internal class DropInActivity : private fun errorDialogDismissed(reason: String, terminateDropIn: Boolean) { if (terminateDropIn) { terminateWithError(reason) - } else { - setLoading(false) } } @@ -384,6 +382,7 @@ internal class DropInActivity : private fun handleDropInServiceResult(dropInServiceResult: BaseDropInServiceResult) { adyenLog(AdyenLogLevel.DEBUG) { "handleDropInServiceResult - ${dropInServiceResult::class.simpleName}" } dropInViewModel.isWaitingResult = false + setLoading(false) when (dropInServiceResult) { is DropInServiceResult -> handleDropInServiceResult(dropInServiceResult) is BalanceDropInServiceResult -> handleDropInServiceResult(dropInServiceResult) @@ -457,10 +456,10 @@ internal class DropInActivity : dropInServiceResult.errorDialog?.let { errorDialog -> val errorMessage = errorDialog.message ?: getString(R.string.unknown_error) showError(errorDialog.title, errorMessage, reason, dropInServiceResult.dismissDropIn) - } ?: if (dropInServiceResult.dismissDropIn) { - terminateWithError(reason) - } else { - setLoading(false) + } ?: run { + if (dropInServiceResult.dismissDropIn) { + terminateWithError(reason) + } } } @@ -480,7 +479,6 @@ internal class DropInActivity : handleAction(action) return } - setLoading(false) hideAllScreens() val actionFragment = ActionComponentDialogFragment.newInstance(action, dropInViewModel.checkoutConfiguration) actionFragment.show(supportFragmentManager, ACTION_FRAGMENT_TAG) @@ -654,7 +652,6 @@ internal class DropInActivity : private fun handleGiftCardFullPayment(fullPayment: GiftCardBalanceResult.FullPayment) { adyenLog(AdyenLogLevel.DEBUG) { "handleGiftCardFullPayment" } - setLoading(false) showGiftCardPaymentConfirmationDialog(fullPayment.data) } @@ -679,7 +676,6 @@ internal class DropInActivity : } private fun handleRemovePaymentMethodResult(id: String) { - setLoading(false) dropInViewModel.removeStoredPaymentMethodWithId(id) val preselectedStoredPaymentMethodFragment = From 3a703361c40f51285a8076c84a8592bbb5024d7d Mon Sep 17 00:00:00 2001 From: Oscar Spruit Date: Wed, 20 Nov 2024 10:35:21 +0100 Subject: [PATCH 065/102] Add release note COAND-984 --- RELEASE_NOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9b64a15369..f44abb0afc 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,3 +10,4 @@ ## Fixed - For the Address Lookup functionality, when the postal/zip code field is focused and the user presses back, then it no longer crashes. +- For drop-in, in some edge-cases the loading state would be shown on top of an error dialog. This is fixed now. From 6e3c00bf10b751d26e304e4a4354105c0494bafb Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Tue, 26 Nov 2024 13:09:40 +0100 Subject: [PATCH 066/102] Remove tracking redirect error event when user closes redirect COAND-1006 --- .../core/internal/analytics/ErrorEvent.kt | 1 - .../internal/ui/DefaultRedirectDelegate.kt | 13 ++----------- .../ui/DefaultRedirectDelegateTest.kt | 19 ------------------- 3 files changed, 2 insertions(+), 31 deletions(-) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt index 646ed5f37c..8832aa083c 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/ErrorEvent.kt @@ -17,7 +17,6 @@ enum class ErrorEvent(val errorType: Type, val errorCode: String) { // Redirect REDIRECT_FAILED(Type.REDIRECT, "600"), REDIRECT_PARSE_FAILED(Type.REDIRECT, "601"), - REDIRECT_CANCELLED(Type.REDIRECT, "602"), // Encryption ENCRYPTION(Type.INTERNAL, "610"), diff --git a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt index 061b4b2ef0..cbb0ace41b 100644 --- a/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt +++ b/redirect/src/main/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegate.kt @@ -28,7 +28,6 @@ import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.ui.model.GenericComponentParams import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.core.AdyenLogLevel -import com.adyen.checkout.core.exception.CancellationException import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.exception.ComponentException import com.adyen.checkout.core.exception.HttpException @@ -143,7 +142,7 @@ constructor( } catch (ex: CheckoutException) { val event = GenericEvents.error( component = action?.paymentMethodType.orEmpty(), - event = ErrorEvent.REDIRECT_FAILED + event = ErrorEvent.REDIRECT_FAILED, ) analyticsManager?.trackEvent(event) @@ -167,7 +166,7 @@ constructor( } catch (ex: CheckoutException) { val event = GenericEvents.error( component = action?.paymentMethodType.orEmpty(), - event = ErrorEvent.REDIRECT_PARSE_FAILED + event = ErrorEvent.REDIRECT_PARSE_FAILED, ) analyticsManager?.trackEvent(event) @@ -201,14 +200,6 @@ constructor( } override fun onError(e: CheckoutException) { - if (e is CancellationException) { - val event = GenericEvents.error( - component = action?.paymentMethodType.orEmpty(), - event = ErrorEvent.REDIRECT_CANCELLED - ) - analyticsManager?.trackEvent(event) - } - emitError(e) } diff --git a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt index d57fa4bede..8643e3c165 100644 --- a/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt +++ b/redirect/src/test/java/com/adyen/checkout/redirect/internal/ui/DefaultRedirectDelegateTest.kt @@ -23,7 +23,6 @@ import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManage import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParamsMapper import com.adyen.checkout.components.core.internal.ui.model.GenericComponentParamsMapper import com.adyen.checkout.core.Environment -import com.adyen.checkout.core.exception.CancellationException import com.adyen.checkout.core.exception.ComponentException import com.adyen.checkout.core.exception.HttpException import com.adyen.checkout.core.exception.ModelSerializationException @@ -237,24 +236,6 @@ internal class DefaultRedirectDelegateTest( ) analyticsManager.assertLastEventEquals(expectedEvent) } - - @Test - fun `when redirect is cancelled with CancellationException, then an event is tracked`() = runTest { - val action = RedirectAction( - paymentMethodType = TEST_PAYMENT_METHOD_TYPE, - type = TEST_ACTION_TYPE, - ) - delegate.handleAction(action, Activity()) - - val exception = CancellationException("Redirect flow cancelled.") - delegate.onError(exception) - - val expectedEvent = GenericEvents.error( - component = TEST_PAYMENT_METHOD_TYPE, - event = ErrorEvent.REDIRECT_CANCELLED, - ) - analyticsManager.assertLastEventEquals(expectedEvent) - } } @Test From 805d5faf04c2b9b99b722ba33b2c5a74cf477ce0 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Mon, 11 Nov 2024 11:27:55 +0100 Subject: [PATCH 067/102] Track third party error event for Twint COAND-1009 --- .../internal/ui/DefaultTwintActionDelegate.kt | 11 +++++ .../ui/DefaultTwintActionDelegateTest.kt | 40 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/twint-action/src/main/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegate.kt b/twint-action/src/main/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegate.kt index 4bfceb628b..a23a0fe3e5 100644 --- a/twint-action/src/main/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegate.kt +++ b/twint-action/src/main/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegate.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.components.core.internal.PaymentDataRepository import com.adyen.checkout.components.core.internal.SavedStateHandleContainer import com.adyen.checkout.components.core.internal.SavedStateHandleProperty import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.data.api.StatusRepository import com.adyen.checkout.components.core.internal.data.model.StatusResponse @@ -163,10 +164,12 @@ internal class DefaultTwintActionDelegate( } TwintPayResult.TW_B_ERROR -> { + trackThirdPartyErrorEvent() onError(ComponentException("Twint encountered an error.")) } TwintPayResult.TW_B_APP_NOT_INSTALLED -> { + trackThirdPartyErrorEvent() onError(ComponentException("Twint app not installed.")) } } @@ -220,6 +223,14 @@ internal class DefaultTwintActionDelegate( ) } + private fun trackThirdPartyErrorEvent() { + val event = GenericEvents.error( + component = action?.paymentMethodType.orEmpty(), + event = ErrorEvent.THIRD_PARTY, + ) + analyticsManager?.trackEvent(event) + } + override fun onError(e: CheckoutException) { emitError(e) } diff --git a/twint-action/src/test/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegateTest.kt b/twint-action/src/test/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegateTest.kt index f70203e4a8..560c0db394 100644 --- a/twint-action/src/test/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegateTest.kt +++ b/twint-action/src/test/java/com/adyen/checkout/twint/action/internal/ui/DefaultTwintActionDelegateTest.kt @@ -21,6 +21,7 @@ import com.adyen.checkout.components.core.action.TwintSdkData import com.adyen.checkout.components.core.action.WeChatPaySdkData import com.adyen.checkout.components.core.internal.ActionObserverRepository import com.adyen.checkout.components.core.internal.PaymentDataRepository +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.data.api.TestStatusRepository @@ -287,6 +288,32 @@ internal class DefaultTwintActionDelegateTest { ) analyticsManager.assertLastEventEquals(expectedEvent) } + + @ParameterizedTest + @MethodSource( + "com.adyen.checkout.twint.action.internal.ui.DefaultTwintActionDelegateTest#handleTwintResultErrorEvents", + ) + fun `when handling twint result, then event is tracked`( + result: TwintPayResult, + errorEvent: ErrorEvent + ) = runTest { + delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) + val action = SdkAction( + paymentMethodType = TEST_PAYMENT_METHOD_TYPE, + type = TEST_ACTION_TYPE, + paymentData = TEST_PAYMENT_DATA, + sdkData = TwintSdkData("token", false), + ) + delegate.handleAction(action, Activity()) + + delegate.handleTwintResult(result) + + val expectedEvent = GenericEvents.error( + component = TEST_PAYMENT_METHOD_TYPE, + event = errorEvent, + ) + analyticsManager.assertLastEventEquals(expectedEvent) + } } private fun createDelegate( @@ -347,6 +374,19 @@ internal class DefaultTwintActionDelegateTest { TwintTestResult.Error("Twint app not installed."), ), ) + + @JvmStatic + fun handleTwintResultErrorEvents() = listOf( + // result, errorEvent + arguments( + TwintPayResult.TW_B_ERROR, + ErrorEvent.THIRD_PARTY, + ), + arguments( + TwintPayResult.TW_B_APP_NOT_INSTALLED, + ErrorEvent.THIRD_PARTY, + ), + ) } sealed class TwintTestResult { From 4b2ad0abba4575d82861bc9ea6cbc33d5a71f8fa Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Mon, 11 Nov 2024 12:07:29 +0100 Subject: [PATCH 068/102] Track third party error event for WeChat COAND-1009 --- .../internal/ui/DefaultWeChatDelegate.kt | 10 ++++++++++ .../internal/ui/DefaultWeChatDelegateTest.kt | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/wechatpay/src/main/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegate.kt b/wechatpay/src/main/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegate.kt index 6353ab54da..91ddf717a0 100644 --- a/wechatpay/src/main/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegate.kt +++ b/wechatpay/src/main/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegate.kt @@ -23,6 +23,7 @@ import com.adyen.checkout.components.core.internal.PaymentDataRepository import com.adyen.checkout.components.core.internal.SavedStateHandleContainer import com.adyen.checkout.components.core.internal.SavedStateHandleProperty import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.ui.model.GenericComponentParams import com.adyen.checkout.components.core.internal.util.bufferedChannel @@ -169,6 +170,7 @@ constructor( val isWeChatNotInitiated = !initiateWeChatPayRedirect(sdkData, activityName) if (isWeChatNotInitiated) { + trackThirdPartyErrorEvent() emitError(ComponentException("Failed to initialize WeChat app")) } } @@ -187,6 +189,14 @@ constructor( ) } + private fun trackThirdPartyErrorEvent() { + val event = GenericEvents.error( + component = action?.paymentMethodType.orEmpty(), + event = ErrorEvent.THIRD_PARTY, + ) + analyticsManager?.trackEvent(event) + } + override fun onError(e: CheckoutException) { emitError(e) } diff --git a/wechatpay/src/test/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegateTest.kt b/wechatpay/src/test/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegateTest.kt index c717529aa5..8d94abc1b7 100644 --- a/wechatpay/src/test/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegateTest.kt +++ b/wechatpay/src/test/java/com/adyen/checkout/wechatpay/internal/ui/DefaultWeChatDelegateTest.kt @@ -17,6 +17,7 @@ import com.adyen.checkout.components.core.action.SdkAction import com.adyen.checkout.components.core.action.WeChatPaySdkData import com.adyen.checkout.components.core.internal.ActionObserverRepository import com.adyen.checkout.components.core.internal.PaymentDataRepository +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParamsMapper @@ -170,6 +171,25 @@ internal class DefaultWeChatDelegateTest( component = TEST_PAYMENT_METHOD_TYPE, subType = TEST_ACTION_TYPE, ) + analyticsManager.assertHasEventEquals(expectedEvent) + } + + @Test + fun `when handleAction is called and sending a request to WeChat fails, then an error is tracked`() { + whenever(iwxApi.sendReq(any())) doReturn false + val action = SdkAction( + paymentMethodType = TEST_PAYMENT_METHOD_TYPE, + type = TEST_ACTION_TYPE, + paymentData = TEST_PAYMENT_DATA, + sdkData = WeChatPaySdkData(), + ) + + delegate.handleAction(action, Activity()) + + val expectedEvent = GenericEvents.error( + component = TEST_PAYMENT_METHOD_TYPE, + event = ErrorEvent.THIRD_PARTY, + ) analyticsManager.assertLastEventEquals(expectedEvent) } } From 341adfdf606cb88c3ae068232451560f1bc3d22f Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Mon, 11 Nov 2024 12:42:06 +0100 Subject: [PATCH 069/102] Track third party error event for CashAppPay COAND-1009 --- .../internal/ui/DefaultCashAppPayDelegate.kt | 10 ++++++++++ .../internal/ui/DefaultCashAppPayDelegateTest.kt | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt b/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt index 639a297589..ef655a1c0e 100644 --- a/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt +++ b/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt @@ -34,6 +34,7 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.PaymentComponentEvent import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.components.core.paymentmethod.CashAppPayPaymentMethod @@ -284,6 +285,7 @@ constructor( } is CashAppPayState.CashAppPayExceptionState -> { + trackThirdPartyErrorEvent() exceptionChannel.trySend( ComponentException("Cash App Pay has encountered an error", newState.exception), ) @@ -311,6 +313,14 @@ constructor( ) } + private fun trackThirdPartyErrorEvent() { + val event = GenericEvents.error( + component = getPaymentMethodType(), + event = ErrorEvent.THIRD_PARTY, + ) + analyticsManager.trackEvent(event) + } + override fun isConfirmationRequired(): Boolean = _viewFlow.value is ButtonComponentViewType && componentParams.showStorePaymentField diff --git a/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt b/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt index f009258f17..43296b23f5 100644 --- a/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt +++ b/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt @@ -35,6 +35,7 @@ import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.internal.PaymentObserverRepository +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParamsMapper @@ -532,6 +533,20 @@ internal class DefaultCashAppPayDelegateTest( analyticsManager.assertLastEventNotEquals(expectedEvent) } + @Test + fun `when state is exception, then an error is tracked`() = runTest { + delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) + val exception = RuntimeException("Stub!") + + delegate.cashAppPayStateDidChange(CashAppPayState.CashAppPayExceptionState(exception)) + + val expectedEvent = GenericEvents.error( + component = TEST_PAYMENT_METHOD_TYPE, + event = ErrorEvent.THIRD_PARTY + ) + analyticsManager.assertLastEventEquals(expectedEvent) + } + @Test fun `when delegate is cleared then analytics manager is cleared`() { delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) From a9e34b5472ae7da900f7f58f162417f50e13bbe0 Mon Sep 17 00:00:00 2001 From: Ararat Mnatsakanyan Date: Wed, 20 Nov 2024 13:26:22 +0100 Subject: [PATCH 070/102] Track third party error event for Google Pay COAND-1009 --- .../internal/ui/DefaultGooglePayDelegate.kt | 12 ++++++++++++ .../internal/ui/DefaultGooglePayDelegateTest.kt | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegate.kt b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegate.kt index af2b87eb71..cf9ceb154d 100644 --- a/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegate.kt +++ b/googlepay/src/main/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegate.kt @@ -19,6 +19,7 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.PaymentComponentEvent import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.util.bufferedChannel import com.adyen.checkout.core.AdyenLogLevel @@ -149,6 +150,7 @@ internal class DefaultGooglePayDelegate( when (resultCode) { Activity.RESULT_OK -> { if (data == null) { + trackThirdPartyErrorEvent() exceptionChannel.trySend(ComponentException("Result data is null")) return } @@ -161,6 +163,8 @@ internal class DefaultGooglePayDelegate( } AutoResolveHelper.RESULT_ERROR -> { + trackThirdPartyErrorEvent() + val status = AutoResolveHelper.getStatusFromIntent(data) val statusMessage: String = status?.let { ": ${it.statusMessage}" }.orEmpty() exceptionChannel.trySend(ComponentException("GooglePay returned an error$statusMessage")) @@ -170,6 +174,14 @@ internal class DefaultGooglePayDelegate( } } + private fun trackThirdPartyErrorEvent() { + val event = GenericEvents.error( + component = getPaymentMethodType(), + event = ErrorEvent.THIRD_PARTY, + ) + analyticsManager.trackEvent(event) + } + override fun getGooglePayButtonParameters(): GooglePayButtonParameters { val allowedPaymentMethodsList = GooglePayUtils.getAllowedPaymentMethods(componentParams) val allowedPaymentMethods = ModelUtils.serializeOptList( diff --git a/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegateTest.kt b/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegateTest.kt index b44f4b74be..5c26c122da 100644 --- a/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegateTest.kt +++ b/googlepay/src/test/java/com/adyen/checkout/googlepay/internal/ui/DefaultGooglePayDelegateTest.kt @@ -8,6 +8,7 @@ package com.adyen.checkout.googlepay.internal.ui +import android.app.Activity import app.cash.turbine.test import com.adyen.checkout.components.core.Amount import com.adyen.checkout.components.core.CheckoutConfiguration @@ -15,6 +16,7 @@ import com.adyen.checkout.components.core.Configuration import com.adyen.checkout.components.core.OrderRequest import com.adyen.checkout.components.core.PaymentMethod import com.adyen.checkout.components.core.internal.PaymentObserverRepository +import com.adyen.checkout.components.core.internal.analytics.ErrorEvent import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.analytics.TestAnalyticsManager import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParamsMapper @@ -185,6 +187,17 @@ internal class DefaultGooglePayDelegateTest { analyticsManager.assertIsCleared() } + + @Test + fun `when activity result is OK and data is null, then error event is tracked`() { + delegate.handleActivityResult(Activity.RESULT_OK, data = null) + + val expectedEvent = GenericEvents.error( + component = TEST_PAYMENT_METHOD_TYPE, + event = ErrorEvent.THIRD_PARTY, + ) + analyticsManager.assertLastEventEquals(expectedEvent) + } } private fun createCheckoutConfiguration( From 9f2486429ae289660a173fcc5c2c729b13a28a3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 13:55:19 +0000 Subject: [PATCH 071/102] Update dependency com.pinterest.ktlint:ktlint-cli to v1.4.1 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 282 +++++++++++++++++++++++++++++++ 2 files changed, 283 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index af4dad09be..11842d038c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ compose-compiler = "1.5.15" # Code quality detekt = "1.23.7" jacoco = "0.8.12" -ktlint = "1.3.1" +ktlint = "1.4.1" sonarqube = "5.1.0.4882" binary-compatibility-validator = "0.16.3" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c57a99c478..862565b682 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -8840,6 +8840,24 @@ + + + + + + + + + + + + + + + + + + @@ -8856,6 +8874,14 @@ + + + + + + + + @@ -8866,6 +8892,11 @@ + + + + + @@ -8882,6 +8913,14 @@ + + + + + + + + @@ -8892,6 +8931,24 @@ + + + + + + + + + + + + + + + + + + @@ -8908,6 +8965,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10099,6 +10203,14 @@ + + + + + + + + @@ -10123,6 +10235,14 @@ + + + + + + + + @@ -10147,6 +10267,14 @@ + + + + + + + + @@ -10171,6 +10299,14 @@ + + + + + + + + @@ -10195,6 +10331,14 @@ + + + + + + + + @@ -10219,6 +10363,14 @@ + + + + + + + + @@ -10243,6 +10395,14 @@ + + + + + + + + @@ -10267,6 +10427,14 @@ + + + + + + + + @@ -10291,6 +10459,14 @@ + + + + + + + + @@ -10315,6 +10491,14 @@ + + + + + + + + @@ -10347,6 +10531,14 @@ + + + + + + + + @@ -10379,6 +10571,14 @@ + + + + + + + + @@ -10403,6 +10603,14 @@ + + + + + + + + @@ -10435,6 +10643,14 @@ + + + + + + + + @@ -10467,6 +10683,14 @@ + + + + + + + + @@ -11106,6 +11330,11 @@ + + + + + @@ -11138,6 +11367,14 @@ + + + + + + + + @@ -11238,6 +11475,14 @@ + + + + + + + + @@ -12638,11 +12883,24 @@ + + + + + + + + + + + + + @@ -13459,6 +13717,14 @@ + + + + + + + + @@ -13579,6 +13845,14 @@ + + + + + + + + @@ -14136,6 +14410,14 @@ + + + + + + + + From 062b6d7509b491ec4d254dd44cc41af1d102bbf5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:44:02 +0000 Subject: [PATCH 072/102] Update lint to v31.7.2 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 184 +++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 11842d038c..0214eb61e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ json = "20240303" jose4j = "0.9.6" junit-jupiter = "5.11.3" konsist = "0.16.1" -lint = "31.7.1" +lint = "31.7.2" mockito-kotlin = "5.4.0" mockito = "5.14.2" robolectric = "4.13" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 862565b682..ff4c837af8 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5307,6 +5307,14 @@ + + + + + + + + @@ -5379,6 +5387,14 @@ + + + + + + + + @@ -5451,6 +5467,14 @@ + + + + + + + + @@ -5523,6 +5547,14 @@ + + + + + + + + @@ -5595,6 +5627,14 @@ + + + + + + + + @@ -5667,6 +5707,14 @@ + + + + + + + + @@ -5739,6 +5787,14 @@ + + + + + + + + @@ -5867,6 +5923,14 @@ + + + + + + + + @@ -5939,6 +6003,14 @@ + + + + + + + + @@ -6011,6 +6083,14 @@ + + + + + + + + @@ -6160,6 +6240,14 @@ + + + + + + + + @@ -6456,6 +6544,14 @@ + + + + + + + + @@ -6776,6 +6872,14 @@ + + + + + + + + @@ -6872,6 +6976,14 @@ + + + + + + + + @@ -6992,6 +7104,14 @@ + + + + + + + + @@ -7064,6 +7184,14 @@ + + + + + + + + @@ -7136,6 +7264,14 @@ + + + + + + + + @@ -7208,6 +7344,14 @@ + + + + + + + + @@ -7280,6 +7424,14 @@ + + + + + + + + @@ -7352,6 +7504,14 @@ + + + + + + + + @@ -7424,6 +7584,14 @@ + + + + + + + + @@ -7552,6 +7720,14 @@ + + + + + + + + @@ -7584,6 +7760,14 @@ + + + + + + + + From 08a652911182bd8a30105f99692cce375d7a81bb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:37:26 +0000 Subject: [PATCH 073/102] Update JamesIves/github-pages-deploy-action action to v4.6.9 --- .github/workflows/publish_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml index 734f1797a0..eacb82dc5f 100644 --- a/.github/workflows/publish_docs.yml +++ b/.github/workflows/publish_docs.yml @@ -38,7 +38,7 @@ jobs: # Deploy to GitHub Pages - name: Deploy GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4.6.8 + uses: JamesIves/github-pages-deploy-action@v4.6.9 with: BRANCH: gh-pages FOLDER: build/docs/ From efd0746080940e619f0c750cd7f349a60dbc80c7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:02:49 +0000 Subject: [PATCH 074/102] Update dependency androidx.annotation:annotation to v1.9.1 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0214eb61e3..278ae211b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ binary-compatibility-validator = "0.16.3" # Android dependencies activity = "1.9.3" -annotation = "1.9.0" +annotation = "1.9.1" appcompat = "1.7.0" autofill = "1.3.0-beta01" browser = "1.8.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index ff4c837af8..a08d2d8cd6 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -294,6 +294,14 @@ + + + + + + + + @@ -381,6 +389,14 @@ + + + + + + + + From e4b007946b1e7f58f82c937bb68ac48dd6046dac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:34:47 +0000 Subject: [PATCH 075/102] Update dependency androidx.fragment:fragment-ktx to v1.8.5 --- gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 278ae211b8..fec10de749 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ appcompat = "1.7.0" autofill = "1.3.0-beta01" browser = "1.8.0" coroutines = "1.9.0" -fragment = "1.8.4" +fragment = "1.8.5" lifecycle = "2.8.6" material = "1.12.0" recyclerview = "1.3.2" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index a08d2d8cd6..4d7e16d399 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -3054,6 +3054,14 @@ + + + + + + + + @@ -3102,6 +3110,14 @@ + + + + + + + + From 33439dc45d91f1b044f957cb97c92279382bd0f0 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:41:40 +0200 Subject: [PATCH 076/102] Create paybybank-us module COAND-974 --- paybybank-us/.gitignore | 1 + paybybank-us/api/paybybank-us.api | 8 ++++ paybybank-us/build.gradle | 47 +++++++++++++++++++++++ paybybank-us/consumer-rules.pro | 0 paybybank-us/proguard-rules.pro | 21 ++++++++++ paybybank-us/src/main/AndroidManifest.xml | 10 +++++ settings.gradle | 1 + 7 files changed, 88 insertions(+) create mode 100644 paybybank-us/.gitignore create mode 100644 paybybank-us/api/paybybank-us.api create mode 100644 paybybank-us/build.gradle create mode 100644 paybybank-us/consumer-rules.pro create mode 100644 paybybank-us/proguard-rules.pro create mode 100644 paybybank-us/src/main/AndroidManifest.xml diff --git a/paybybank-us/.gitignore b/paybybank-us/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/paybybank-us/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/paybybank-us/api/paybybank-us.api b/paybybank-us/api/paybybank-us.api new file mode 100644 index 0000000000..67eed6465a --- /dev/null +++ b/paybybank-us/api/paybybank-us.api @@ -0,0 +1,8 @@ +public final class com/adyen/checkout/paybybankus/BuildConfig { + public static final field BUILD_TYPE Ljava/lang/String; + public static final field CHECKOUT_VERSION Ljava/lang/String; + public static final field DEBUG Z + public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String; + public fun ()V +} + diff --git a/paybybank-us/build.gradle b/paybybank-us/build.gradle new file mode 100644 index 0000000000..69ec3c7a70 --- /dev/null +++ b/paybybank-us/build.gradle @@ -0,0 +1,47 @@ +plugins { + alias libs.plugins.android.library + alias libs.plugins.kotlin.android + alias libs.plugins.kotlin.parcelize +} + +// Maven artifact +ext.mavenArtifactId = "paybybank-us" +ext.mavenArtifactName = "Adyen Pay by Bank US component" +ext.mavenArtifactDescription = "Adyen Checkout Pay by Bank US component client for Adyen's Checkout API." + +apply from: "${rootDir}/config/gradle/sharedTasks.gradle" + +android { + namespace 'com.adyen.checkout.paybybankus' + compileSdk libs.versions.compile.sdk.get().toInteger() + + defaultConfig { + minSdk libs.versions.min.sdk.get().toInteger() + targetSdk libs.versions.target.sdk.get().toInteger() + + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + consumerProguardFiles "consumer-rules.pro" + } + + buildFeatures { + viewBinding true + } +} + +dependencies { + // Checkout + api project(':action-core') + api project(':components-core') + api project(':sessions-core') + + // Dependencies + implementation libs.material + + //Tests + testImplementation testFixtures(project(':test-core')) + testImplementation testFixtures(project(':components-core')) + testImplementation testFixtures(project(':ui-core')) + testImplementation libs.bundles.junit + testImplementation libs.bundles.mockito + testImplementation libs.bundles.kotlin.coroutines.test +} diff --git a/paybybank-us/consumer-rules.pro b/paybybank-us/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/paybybank-us/proguard-rules.pro b/paybybank-us/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/paybybank-us/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/paybybank-us/src/main/AndroidManifest.xml b/paybybank-us/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..1ebae297b7 --- /dev/null +++ b/paybybank-us/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + diff --git a/settings.gradle b/settings.gradle index 2956b9a7a4..402a603586 100644 --- a/settings.gradle +++ b/settings.gradle @@ -58,6 +58,7 @@ include ':3ds2', ':online-banking-sk', ':openbanking', ':paybybank', + ':paybybank-us', ':payeasy', ':qr-code', ':redirect', From 0bd9e3d376c2c90863e0af9b8249f66ad4ac2e5d Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:02:07 +0200 Subject: [PATCH 077/102] Create paybybank-us component files COAND-974 --- paybybank-us/api/paybybank-us.api | 39 +++++++++++++++++++ .../paybybankus/PayByBankUSComponent.kt | 13 +++++++ .../paybybankus/PayByBankUSComponentState.kt | 13 +++++++ .../paybybankus/PayByBankUSConfiguration.kt | 13 +++++++ .../internal/DefaultPayByBankUSDelegate.kt | 13 +++++++ .../internal/PayByBankUSDelegate.kt | 13 +++++++ .../internal/PayByBankUSViewProvider.kt | 13 +++++++ .../provider/PayByBankUSComponentProvider.kt | 13 +++++++ .../internal/ui/model/PayByBankUSInputData.kt | 13 +++++++ .../ui/model/PayByBankUSOutputData.kt | 13 +++++++ .../internal/ui/view/PayByBankUSView.kt | 13 +++++++ 11 files changed, 169 insertions(+) create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt diff --git a/paybybank-us/api/paybybank-us.api b/paybybank-us/api/paybybank-us.api index 67eed6465a..b04c5d7eab 100644 --- a/paybybank-us/api/paybybank-us.api +++ b/paybybank-us/api/paybybank-us.api @@ -6,3 +6,42 @@ public final class com/adyen/checkout/paybybankus/BuildConfig { public fun ()V } +public final class com/adyen/checkout/paybybankus/PayByBankUSComponent { + public fun ()V +} + +public final class com/adyen/checkout/paybybankus/PayByBankUSComponentState { + public fun ()V +} + +public final class com/adyen/checkout/paybybankus/PayByBankUSConfiguration { + public fun ()V +} + +public final class com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate { + public fun ()V +} + +public abstract interface class com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate { +} + +public final class com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider { + public fun ()V +} + +public final class com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider { + public fun ()V +} + +public final class com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData { + public fun ()V +} + +public final class com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData { + public fun ()V +} + +public final class com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView { + public fun ()V +} + diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt new file mode 100644 index 0000000000..6a4518cfbb --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus + +class PayByBankUSComponent { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt new file mode 100644 index 0000000000..78cf31085f --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus + +class PayByBankUSComponentState { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt new file mode 100644 index 0000000000..fcf6782e2a --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus + +class PayByBankUSConfiguration { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt new file mode 100644 index 0000000000..2e8042bc31 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus.internal + +class DefaultPayByBankUSDelegate { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt new file mode 100644 index 0000000000..07c671a860 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus.internal + +interface PayByBankUSDelegate { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt new file mode 100644 index 0000000000..ee5985ea84 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus.internal + +class PayByBankUSViewProvider { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt new file mode 100644 index 0000000000..baddb855e7 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus.internal.provider + +class PayByBankUSComponentProvider { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt new file mode 100644 index 0000000000..2b06c0ec71 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus.internal.ui.model + +class PayByBankUSInputData { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt new file mode 100644 index 0000000000..87399d1534 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus.internal.ui.model + +class PayByBankUSOutputData { + // TODO implement +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt new file mode 100644 index 0000000000..7111f948a4 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.paybybankus.internal.ui.view + +class PayByBankUSView { + // TODO implement +} From 9d512ced159404ef6af4580829aad0407c3c23c4 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:25:43 +0200 Subject: [PATCH 078/102] Implement PayByBankUSConfiguration COAND-974 --- components-core/api/components-core.api | 1 + .../components/core/PaymentMethodTypes.kt | 1 + paybybank-us/api/paybybank-us.api | 29 ++++- .../paybybankus/PayByBankUSConfiguration.kt | 104 +++++++++++++++++- 4 files changed, 132 insertions(+), 3 deletions(-) diff --git a/components-core/api/components-core.api b/components-core/api/components-core.api index 6665b06e63..b076b2388e 100644 --- a/components-core/api/components-core.api +++ b/components-core/api/components-core.api @@ -915,6 +915,7 @@ public final class com/adyen/checkout/components/core/PaymentMethodTypes { public static final field OPEN_BANKING Ljava/lang/String; public static final field OXXO Ljava/lang/String; public static final field PAY_BY_BANK Ljava/lang/String; + public static final field PAY_BY_BANK_US Ljava/lang/String; public static final field PAY_NOW Ljava/lang/String; public static final field PIX Ljava/lang/String; public static final field PROMPT_PAY Ljava/lang/String; diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt b/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt index 2daa2a4101..7e9dc9d75c 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/PaymentMethodTypes.kt @@ -48,6 +48,7 @@ object PaymentMethodTypes { const val ONLINE_BANKING_SK = "onlineBanking_SK" const val OPEN_BANKING = "openbanking_UK" const val PAY_BY_BANK = "paybybank" + const val PAY_BY_BANK_US = "paybybank_AIS_DD" const val SCHEME = "scheme" const val SEPA = "sepadirectdebit" const val TWINT = "twint" diff --git a/paybybank-us/api/paybybank-us.api b/paybybank-us/api/paybybank-us.api index b04c5d7eab..71e69477d7 100644 --- a/paybybank-us/api/paybybank-us.api +++ b/paybybank-us/api/paybybank-us.api @@ -14,8 +14,35 @@ public final class com/adyen/checkout/paybybankus/PayByBankUSComponentState { public fun ()V } -public final class com/adyen/checkout/paybybankus/PayByBankUSConfiguration { +public final class com/adyen/checkout/paybybankus/PayByBankUSConfiguration : com/adyen/checkout/components/core/internal/Configuration { + public static final field CREATOR Landroid/os/Parcelable$Creator; + public synthetic fun (Ljava/util/Locale;Lcom/adyen/checkout/core/Environment;Ljava/lang/String;Lcom/adyen/checkout/components/core/AnalyticsConfiguration;Lcom/adyen/checkout/components/core/Amount;Lcom/adyen/checkout/action/core/GenericActionConfiguration;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun describeContents ()I + public fun getAmount ()Lcom/adyen/checkout/components/core/Amount; + public fun getAnalyticsConfiguration ()Lcom/adyen/checkout/components/core/AnalyticsConfiguration; + public fun getClientKey ()Ljava/lang/String; + public fun getEnvironment ()Lcom/adyen/checkout/core/Environment; + public fun getShopperLocale ()Ljava/util/Locale; + public fun writeToParcel (Landroid/os/Parcel;I)V +} + +public final class com/adyen/checkout/paybybankus/PayByBankUSConfiguration$Builder : com/adyen/checkout/action/core/internal/ActionHandlingPaymentMethodConfigurationBuilder { + public fun (Lcom/adyen/checkout/core/Environment;Ljava/lang/String;)V + public fun (Ljava/util/Locale;Lcom/adyen/checkout/core/Environment;Ljava/lang/String;)V + public synthetic fun buildInternal ()Lcom/adyen/checkout/components/core/internal/Configuration; +} + +public final class com/adyen/checkout/paybybankus/PayByBankUSConfiguration$Creator : android/os/Parcelable$Creator { public fun ()V + public final fun createFromParcel (Landroid/os/Parcel;)Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration; + public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object; + public final fun newArray (I)[Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration; + public synthetic fun newArray (I)[Ljava/lang/Object; +} + +public final class com/adyen/checkout/paybybankus/PayByBankUSConfigurationKt { + public static final fun payByBankUS (Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lkotlin/jvm/functions/Function1;)Lcom/adyen/checkout/components/core/CheckoutConfiguration; + public static synthetic fun payByBankUS$default (Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/adyen/checkout/components/core/CheckoutConfiguration; } public final class com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate { diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt index fcf6782e2a..a5830a2f08 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSConfiguration.kt @@ -8,6 +8,106 @@ package com.adyen.checkout.paybybankus -class PayByBankUSConfiguration { - // TODO implement +import com.adyen.checkout.action.core.GenericActionConfiguration +import com.adyen.checkout.action.core.internal.ActionHandlingPaymentMethodConfigurationBuilder +import com.adyen.checkout.components.core.Amount +import com.adyen.checkout.components.core.AnalyticsConfiguration +import com.adyen.checkout.components.core.CheckoutConfiguration +import com.adyen.checkout.components.core.PaymentMethodTypes +import com.adyen.checkout.components.core.internal.Configuration +import com.adyen.checkout.components.core.internal.util.CheckoutConfigurationMarker +import com.adyen.checkout.core.Environment +import kotlinx.parcelize.Parcelize +import java.util.Locale + +/** + * Configuration class for the [PayByBankUSComponent]. + */ +@Parcelize +class PayByBankUSConfiguration private constructor( + override val shopperLocale: Locale?, + override val environment: Environment, + override val clientKey: String, + override val analyticsConfiguration: AnalyticsConfiguration?, + override val amount: Amount?, + internal val genericActionConfiguration: GenericActionConfiguration, +) : Configuration { + + class Builder : ActionHandlingPaymentMethodConfigurationBuilder { + + /** + * Initialize a configuration builder with the required fields. + * + * The shopper locale will match the value passed to the API with the sessions flow, or the primary user locale + * on the device otherwise. Check out the + * [Sessions API documentation](https://docs.adyen.com/api-explorer/Checkout/latest/post/sessions) on how to set + * this value. + * + * @param environment The [Environment] to be used for internal network calls from the SDK to Adyen. + * @param clientKey Your Client Key used for internal network calls from the SDK to Adyen. + */ + constructor(environment: Environment, clientKey: String) : super( + environment, + clientKey, + ) + + /** + * Initialize a configuration builder with the required fields and a shopper locale. + * + * @param shopperLocale The [Locale] of the shopper. + * @param environment The [Environment] to be used for internal network calls from the SDK to Adyen. + * @param clientKey Your Client Key used for internal network calls from the SDK to Adyen. + */ + constructor( + shopperLocale: Locale, + environment: Environment, + clientKey: String + ) : super(shopperLocale, environment, clientKey) + + override fun buildInternal(): PayByBankUSConfiguration { + return PayByBankUSConfiguration( + shopperLocale = shopperLocale, + environment = environment, + clientKey = clientKey, + analyticsConfiguration = analyticsConfiguration, + amount = amount, + genericActionConfiguration = genericActionConfigurationBuilder.build(), + ) + } + } +} + +fun CheckoutConfiguration.payByBankUS( + configuration: @CheckoutConfigurationMarker PayByBankUSConfiguration.Builder.() -> Unit = {} +): CheckoutConfiguration { + val config = PayByBankUSConfiguration.Builder(environment, clientKey) + .apply { + shopperLocale?.let { setShopperLocale(it) } + amount?.let { setAmount(it) } + analyticsConfiguration?.let { setAnalyticsConfiguration(it) } + } + .apply(configuration) + .build() + addConfiguration(PaymentMethodTypes.PAY_BY_BANK_US, config) + return this +} + +internal fun CheckoutConfiguration.getPayByBankUSConfiguration(): PayByBankUSConfiguration? { + return getConfiguration(PaymentMethodTypes.PAY_BY_BANK_US) +} + +internal fun PayByBankUSConfiguration.toCheckoutConfiguration(): CheckoutConfiguration { + return CheckoutConfiguration( + shopperLocale = shopperLocale, + environment = environment, + clientKey = clientKey, + amount = amount, + analyticsConfiguration = analyticsConfiguration, + ) { + addConfiguration(PaymentMethodTypes.PAY_BY_BANK_US, this@toCheckoutConfiguration) + + genericActionConfiguration.getAllConfigurations().forEach { + addActionConfiguration(it) + } + } } From 00a34439a5b0d9ff81864e2754f65d0ebb979216 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:30:40 +0200 Subject: [PATCH 079/102] Add PayByBankUSConfigurationTest COAND-974 --- .../PayByBankUSConfigurationTest.kt | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 paybybank-us/src/test/java/com/adyen/checkout/paybybankus/PayByBankUSConfigurationTest.kt diff --git a/paybybank-us/src/test/java/com/adyen/checkout/paybybankus/PayByBankUSConfigurationTest.kt b/paybybank-us/src/test/java/com/adyen/checkout/paybybankus/PayByBankUSConfigurationTest.kt new file mode 100644 index 0000000000..b9bd8e6453 --- /dev/null +++ b/paybybank-us/src/test/java/com/adyen/checkout/paybybankus/PayByBankUSConfigurationTest.kt @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 24/10/2024. + */ + +package com.adyen.checkout.paybybankus + +import com.adyen.checkout.components.core.Amount +import com.adyen.checkout.components.core.AnalyticsConfiguration +import com.adyen.checkout.components.core.AnalyticsLevel +import com.adyen.checkout.components.core.CheckoutConfiguration +import com.adyen.checkout.core.Environment +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import java.util.Locale + +class PayByBankUSConfigurationTest { + + @Test + fun `when creating the configuration through CheckoutConfiguration, then it should be the same as when the builder is used`() { + val checkoutConfiguration = CheckoutConfiguration( + shopperLocale = Locale.US, + environment = Environment.TEST, + clientKey = TEST_CLIENT_KEY, + amount = Amount("EUR", 123L), + analyticsConfiguration = AnalyticsConfiguration(AnalyticsLevel.ALL), + ) { + payByBankUS() + } + + val actual = checkoutConfiguration.getPayByBankUSConfiguration() + + val expected = PayByBankUSConfiguration.Builder( + shopperLocale = Locale.US, + environment = Environment.TEST, + clientKey = TEST_CLIENT_KEY, + ) + .setAmount(Amount("EUR", 123L)) + .setAnalyticsConfiguration(AnalyticsConfiguration(AnalyticsLevel.ALL)) + .build() + + assertEquals(expected.shopperLocale, actual?.shopperLocale) + assertEquals(expected.environment, actual?.environment) + assertEquals(expected.clientKey, actual?.clientKey) + assertEquals(expected.amount, actual?.amount) + assertEquals(expected.analyticsConfiguration, actual?.analyticsConfiguration) + } + + @Test + fun `when the configuration is mapped to CheckoutConfiguration, then CheckoutConfiguration is created correctly`() { + val config = PayByBankUSConfiguration.Builder( + shopperLocale = Locale.US, + environment = Environment.TEST, + clientKey = TEST_CLIENT_KEY, + ) + .setAmount(Amount("EUR", 123L)) + .setAnalyticsConfiguration(AnalyticsConfiguration(AnalyticsLevel.ALL)) + .build() + + val actual = config.toCheckoutConfiguration() + + val expected = CheckoutConfiguration( + shopperLocale = Locale.US, + environment = Environment.TEST, + clientKey = TEST_CLIENT_KEY, + amount = Amount("EUR", 123L), + analyticsConfiguration = AnalyticsConfiguration(AnalyticsLevel.ALL), + ) + + assertEquals(expected.shopperLocale, actual.shopperLocale) + assertEquals(expected.environment, actual.environment) + assertEquals(expected.clientKey, actual.clientKey) + assertEquals(expected.amount, actual.amount) + assertEquals(expected.analyticsConfiguration, actual.analyticsConfiguration) + + val actualPayConfig = actual.getPayByBankUSConfiguration() + assertEquals(config.shopperLocale, actualPayConfig?.shopperLocale) + assertEquals(config.environment, actualPayConfig?.environment) + assertEquals(config.clientKey, actualPayConfig?.clientKey) + assertEquals(config.amount, actualPayConfig?.amount) + assertEquals(config.analyticsConfiguration, actualPayConfig?.analyticsConfiguration) + } + + companion object { + private const val TEST_CLIENT_KEY = "test_qwertyuiopasdfghjklzxcvbnmqwerty" + } +} From 3e75f74d9a1070d915a57831ec91327f52cbbbae Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:40:34 +0200 Subject: [PATCH 080/102] Implement paybybank-us component, delegate and component state classes COAND-974 --- components-core/api/components-core.api | 24 ++++++ .../paymentmethod/PayByBankUSPaymentMethod.kt | 46 +++++++++++ .../paymentmethod/PaymentMethodDetails.kt | 1 + paybybank-us/api/paybybank-us.api | 47 ++++++----- .../paybybankus/PayByBankUSComponent.kt | 67 ++++++++++++++- .../paybybankus/PayByBankUSComponentState.kt | 15 +++- .../internal/DefaultPayByBankUSDelegate.kt | 82 ++++++++++++++++++- .../internal/PayByBankUSDelegate.kt | 18 +++- .../internal/ui/model/PayByBankUSInputData.kt | 13 --- .../ui/model/PayByBankUSOutputData.kt | 13 --- 10 files changed, 272 insertions(+), 54 deletions(-) create mode 100644 components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod.kt delete mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt delete mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt diff --git a/components-core/api/components-core.api b/components-core/api/components-core.api index b076b2388e..eab7506ae8 100644 --- a/components-core/api/components-core.api +++ b/components-core/api/components-core.api @@ -2687,6 +2687,30 @@ public final class com/adyen/checkout/components/core/paymentmethod/PayByBankPay public synthetic fun newArray (I)[Ljava/lang/Object; } +public final class com/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod : com/adyen/checkout/components/core/paymentmethod/PaymentMethodDetails { + public static final field CREATOR Landroid/os/Parcelable$Creator; + public static final field Companion Lcom/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod$Companion; + public static final field SERIALIZER Lcom/adyen/checkout/core/internal/data/model/ModelObject$Serializer; + public fun (Ljava/lang/String;Ljava/lang/String;)V + public fun describeContents ()I + public fun getCheckoutAttemptId ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public fun setCheckoutAttemptId (Ljava/lang/String;)V + public fun setType (Ljava/lang/String;)V + public fun writeToParcel (Landroid/os/Parcel;I)V +} + +public final class com/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod$Companion { +} + +public final class com/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod$Creator : android/os/Parcelable$Creator { + public fun ()V + public final fun createFromParcel (Landroid/os/Parcel;)Lcom/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod; + public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object; + public final fun newArray (I)[Lcom/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod; + public synthetic fun newArray (I)[Ljava/lang/Object; +} + public final class com/adyen/checkout/components/core/paymentmethod/PayEasyPaymentMethod : com/adyen/checkout/components/core/paymentmethod/EContextPaymentMethod { public static final field CREATOR Landroid/os/Parcelable$Creator; public static final field Companion Lcom/adyen/checkout/components/core/paymentmethod/PayEasyPaymentMethod$Companion; diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod.kt b/components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod.kt new file mode 100644 index 0000000000..ee363814c7 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PayByBankUSPaymentMethod.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 21/10/2024. + */ + +package com.adyen.checkout.components.core.paymentmethod + +import com.adyen.checkout.core.exception.ModelSerializationException +import com.adyen.checkout.core.internal.data.model.getStringOrNull +import kotlinx.parcelize.Parcelize +import org.json.JSONException +import org.json.JSONObject + +@Parcelize +class PayByBankUSPaymentMethod( + override var type: String?, + override var checkoutAttemptId: String?, +) : PaymentMethodDetails() { + + companion object { + + @JvmField + val SERIALIZER: Serializer = object : Serializer { + override fun serialize(modelObject: PayByBankUSPaymentMethod): JSONObject { + return try { + JSONObject().apply { + putOpt(TYPE, modelObject.type) + putOpt(CHECKOUT_ATTEMPT_ID, modelObject.checkoutAttemptId) + } + } catch (e: JSONException) { + throw ModelSerializationException(PayByBankUSPaymentMethod::class.java, e) + } + } + + override fun deserialize(jsonObject: JSONObject): PayByBankUSPaymentMethod { + return PayByBankUSPaymentMethod( + type = jsonObject.getStringOrNull(TYPE), + checkoutAttemptId = jsonObject.getStringOrNull(CHECKOUT_ATTEMPT_ID), + ) + } + } + } +} diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PaymentMethodDetails.kt b/components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PaymentMethodDetails.kt index 4fd527ee0b..378f809ad0 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PaymentMethodDetails.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/paymentmethod/PaymentMethodDetails.kt @@ -79,6 +79,7 @@ abstract class PaymentMethodDetails : ModelObject() { OnlineBankingSKPaymentMethod.PAYMENT_METHOD_TYPE -> OnlineBankingSKPaymentMethod.SERIALIZER OpenBankingPaymentMethod.PAYMENT_METHOD_TYPE -> OpenBankingPaymentMethod.SERIALIZER PayByBankPaymentMethod.PAYMENT_METHOD_TYPE -> PayByBankPaymentMethod.SERIALIZER + PaymentMethodTypes.PAY_BY_BANK_US -> PayByBankUSPaymentMethod.SERIALIZER PayEasyPaymentMethod.PAYMENT_METHOD_TYPE -> PayEasyPaymentMethod.SERIALIZER PaymentMethodTypes.GOOGLE_PAY, PaymentMethodTypes.GOOGLE_PAY_LEGACY -> GooglePayPaymentMethod.SERIALIZER diff --git a/paybybank-us/api/paybybank-us.api b/paybybank-us/api/paybybank-us.api index 71e69477d7..e42b0db140 100644 --- a/paybybank-us/api/paybybank-us.api +++ b/paybybank-us/api/paybybank-us.api @@ -6,12 +6,36 @@ public final class com/adyen/checkout/paybybankus/BuildConfig { public fun ()V } -public final class com/adyen/checkout/paybybankus/PayByBankUSComponent { - public fun ()V +public final class com/adyen/checkout/paybybankus/PayByBankUSComponent : androidx/lifecycle/ViewModel, com/adyen/checkout/action/core/internal/ActionHandlingComponent, com/adyen/checkout/components/core/internal/PaymentComponent, com/adyen/checkout/ui/core/internal/ui/ViewableComponent { + public static final field Companion Lcom/adyen/checkout/paybybankus/PayByBankUSComponent$Companion; + public static final field PAYMENT_METHOD_TYPES Ljava/util/List; + public static final field PROVIDER Lcom/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider; + public fun canHandleAction (Lcom/adyen/checkout/components/core/action/Action;)Z + public fun getDelegate ()Lcom/adyen/checkout/components/core/internal/ui/ComponentDelegate; + public fun getViewFlow ()Lkotlinx/coroutines/flow/Flow; + public fun handleAction (Lcom/adyen/checkout/components/core/action/Action;Landroid/app/Activity;)V + public fun handleIntent (Landroid/content/Intent;)V + public fun setInteractionBlocked (Z)V + public fun setOnRedirectListener (Lkotlin/jvm/functions/Function0;)V } -public final class com/adyen/checkout/paybybankus/PayByBankUSComponentState { - public fun ()V +public final class com/adyen/checkout/paybybankus/PayByBankUSComponent$Companion { +} + +public final class com/adyen/checkout/paybybankus/PayByBankUSComponentState : com/adyen/checkout/components/core/PaymentComponentState { + public fun (Lcom/adyen/checkout/components/core/PaymentComponentData;ZZ)V + public final fun component1 ()Lcom/adyen/checkout/components/core/PaymentComponentData; + public final fun component2 ()Z + public final fun component3 ()Z + public final fun copy (Lcom/adyen/checkout/components/core/PaymentComponentData;ZZ)Lcom/adyen/checkout/paybybankus/PayByBankUSComponentState; + public static synthetic fun copy$default (Lcom/adyen/checkout/paybybankus/PayByBankUSComponentState;Lcom/adyen/checkout/components/core/PaymentComponentData;ZZILjava/lang/Object;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponentState; + public fun equals (Ljava/lang/Object;)Z + public fun getData ()Lcom/adyen/checkout/components/core/PaymentComponentData; + public fun hashCode ()I + public fun isInputValid ()Z + public fun isReady ()Z + public fun isValid ()Z + public fun toString ()Ljava/lang/String; } public final class com/adyen/checkout/paybybankus/PayByBankUSConfiguration : com/adyen/checkout/components/core/internal/Configuration { @@ -45,13 +69,6 @@ public final class com/adyen/checkout/paybybankus/PayByBankUSConfigurationKt { public static synthetic fun payByBankUS$default (Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/adyen/checkout/components/core/CheckoutConfiguration; } -public final class com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate { - public fun ()V -} - -public abstract interface class com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate { -} - public final class com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider { public fun ()V } @@ -60,14 +77,6 @@ public final class com/adyen/checkout/paybybankus/internal/provider/PayByBankUSC public fun ()V } -public final class com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData { - public fun ()V -} - -public final class com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData { - public fun ()V -} - public final class com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView { public fun ()V } diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt index 6a4518cfbb..d847d39773 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt @@ -8,6 +8,69 @@ package com.adyen.checkout.paybybankus -class PayByBankUSComponent { - // TODO implement +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ViewModel +import com.adyen.checkout.action.core.internal.ActionHandlingComponent +import com.adyen.checkout.action.core.internal.DefaultActionHandlingComponent +import com.adyen.checkout.action.core.internal.ui.GenericActionDelegate +import com.adyen.checkout.components.core.PaymentMethodTypes +import com.adyen.checkout.components.core.internal.ComponentEventHandler +import com.adyen.checkout.components.core.internal.PaymentComponent +import com.adyen.checkout.components.core.internal.PaymentComponentEvent +import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.paybybankus.internal.PayByBankUSDelegate +import com.adyen.checkout.paybybankus.internal.provider.PayByBankUSComponentProvider +import com.adyen.checkout.ui.core.internal.ui.ComponentViewType +import com.adyen.checkout.ui.core.internal.ui.ViewableComponent +import kotlinx.coroutines.flow.Flow + +/** + * A [PaymentComponent] that supports the [PaymentMethodTypes.PAY_BY_BANK_US] payment method. + */ +// TODO remove the suppress annotation after complete implementation +@Suppress("UnusedPrivateProperty", "UnusedParameter") +class PayByBankUSComponent internal constructor( + private val payByBankUSDelegate: PayByBankUSDelegate, + private val genericActionDelegate: GenericActionDelegate, + private val actionHandlingComponent: DefaultActionHandlingComponent, + internal val componentEventHandler: ComponentEventHandler, +) : ViewModel(), + PaymentComponent, + ViewableComponent, + ActionHandlingComponent by actionHandlingComponent { + + override val delegate: ComponentDelegate + get() = TODO("Not yet implemented") + + override val viewFlow: Flow + get() = TODO("Not yet implemented") + + internal fun observe( + lifecycleOwner: LifecycleOwner, + callback: (PaymentComponentEvent) -> Unit + ) { + TODO("Not yet implemented") + } + + internal fun removeObserver() { + TODO("Not yet implemented") + } + + override fun setInteractionBlocked(isInteractionBlocked: Boolean) { + TODO("Not yet implemented") + } + + override fun onCleared() { + super.onCleared() + TODO("Not yet implemented") + } + + companion object { + + @JvmField + val PROVIDER = PayByBankUSComponentProvider() + + @JvmField + val PAYMENT_METHOD_TYPES = listOf(PaymentMethodTypes.PAY_BY_BANK_US) + } } diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt index 78cf31085f..45c1550bf3 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponentState.kt @@ -8,6 +8,15 @@ package com.adyen.checkout.paybybankus -class PayByBankUSComponentState { - // TODO implement -} +import com.adyen.checkout.components.core.PaymentComponentData +import com.adyen.checkout.components.core.PaymentComponentState +import com.adyen.checkout.components.core.paymentmethod.PayByBankUSPaymentMethod + +/** + * Represents the state of [PayByBankUSComponent]. + */ +data class PayByBankUSComponentState( + override val data: PaymentComponentData, + override val isInputValid: Boolean, + override val isReady: Boolean +) : PaymentComponentState diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt index 2e8042bc31..fd5fa6d4ee 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt @@ -8,6 +8,84 @@ package com.adyen.checkout.paybybankus.internal -class DefaultPayByBankUSDelegate { - // TODO implement +import androidx.lifecycle.LifecycleOwner +import com.adyen.checkout.components.core.Order +import com.adyen.checkout.components.core.PaymentMethod +import com.adyen.checkout.components.core.internal.PaymentComponentEvent +import com.adyen.checkout.components.core.internal.PaymentObserverRepository +import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.ui.model.ButtonComponentParams +import com.adyen.checkout.paybybankus.PayByBankUSComponentState +import com.adyen.checkout.ui.core.internal.ui.ComponentViewType +import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent +import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState +import com.adyen.checkout.ui.core.internal.ui.SubmitHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow + +// TODO remove the suppress annotation after complete implementation +@Suppress("UnusedPrivateProperty", "UnusedParameter") +internal class DefaultPayByBankUSDelegate( + private val observerRepository: PaymentObserverRepository, + private val paymentMethod: PaymentMethod, + private val order: Order?, + override val componentParams: ButtonComponentParams, + private val analyticsManager: AnalyticsManager, + private val submitHandler: SubmitHandler, +) : PayByBankUSDelegate { + + override val componentStateFlow: Flow + get() = TODO("Not yet implemented") + + override val viewFlow: Flow + get() = TODO("Not yet implemented") + + override val submitFlow: Flow + get() = TODO("Not yet implemented") + + override val uiStateFlow: Flow + get() = TODO("Not yet implemented") + + override val uiEventFlow: Flow + get() = TODO("Not yet implemented") + + override fun initialize(coroutineScope: CoroutineScope) { + TODO("Not yet implemented") + } + + override fun observe( + lifecycleOwner: LifecycleOwner, + coroutineScope: CoroutineScope, + callback: (PaymentComponentEvent) -> Unit + ) { + TODO("Not yet implemented") + } + + override fun removeObserver() { + TODO("Not yet implemented") + } + + override fun getPaymentMethodType(): String { + TODO("Not yet implemented") + } + + override fun onSubmit() { + TODO("Not yet implemented") + } + + override fun isConfirmationRequired(): Boolean { + TODO("Not yet implemented") + } + + override fun shouldShowSubmitButton(): Boolean { + TODO("Not yet implemented") + } + + override fun setInteractionBlocked(isInteractionBlocked: Boolean) { + TODO("Not yet implemented") + } + + override fun onCleared() { + TODO("Not yet implemented") + } } diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt index 07c671a860..91120c31ee 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt @@ -8,6 +8,20 @@ package com.adyen.checkout.paybybankus.internal -interface PayByBankUSDelegate { - // TODO implement +import com.adyen.checkout.components.core.internal.ui.PaymentComponentDelegate +import com.adyen.checkout.paybybankus.PayByBankUSComponentState +import com.adyen.checkout.ui.core.internal.ui.ButtonDelegate +import com.adyen.checkout.ui.core.internal.ui.UIStateDelegate +import com.adyen.checkout.ui.core.internal.ui.ViewProvidingDelegate +import kotlinx.coroutines.flow.Flow + +internal interface PayByBankUSDelegate : + PaymentComponentDelegate, + ViewProvidingDelegate, + ButtonDelegate, + UIStateDelegate { + + val componentStateFlow: Flow + + fun setInteractionBlocked(isInteractionBlocked: Boolean) } diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt deleted file mode 100644 index 2b06c0ec71..0000000000 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSInputData.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2024 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - * - * Created by ozgur on 21/10/2024. - */ - -package com.adyen.checkout.paybybankus.internal.ui.model - -class PayByBankUSInputData { - // TODO implement -} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt deleted file mode 100644 index 87399d1534..0000000000 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2024 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - * - * Created by ozgur on 21/10/2024. - */ - -package com.adyen.checkout.paybybankus.internal.ui.model - -class PayByBankUSOutputData { - // TODO implement -} From 7fca1dfc3223f3af0e6486af7735854b7ba2926c Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:15:00 +0100 Subject: [PATCH 081/102] Implement PayByBankUSComponentProvider COAND-974 --- paybybank-us/api/paybybank-us.api | 32 ++- .../provider/PayByBankUSComponentProvider.kt | 268 +++++++++++++++++- 2 files changed, 296 insertions(+), 4 deletions(-) diff --git a/paybybank-us/api/paybybank-us.api b/paybybank-us/api/paybybank-us.api index e42b0db140..3ac16f012c 100644 --- a/paybybank-us/api/paybybank-us.api +++ b/paybybank-us/api/paybybank-us.api @@ -73,8 +73,36 @@ public final class com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvid public fun ()V } -public final class com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider { - public fun ()V +public final class com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider : com/adyen/checkout/components/core/internal/provider/PaymentComponentProvider, com/adyen/checkout/sessions/core/internal/provider/SessionPaymentComponentProvider { + public synthetic fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/internal/Configuration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/internal/Configuration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/activity/ComponentActivity;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/internal/Configuration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/internal/Configuration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/fragment/app/Fragment;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Landroid/app/Application;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Landroid/app/Application;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/internal/Configuration;Landroid/app/Application;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration;Landroid/app/Application;Lcom/adyen/checkout/components/core/ComponentCallback;Lcom/adyen/checkout/components/core/OrderRequest;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Landroid/app/Application;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/CheckoutConfiguration;Landroid/app/Application;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public synthetic fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/components/core/internal/Configuration;Landroid/app/Application;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/components/core/internal/PaymentComponent; + public fun get (Landroidx/savedstate/SavedStateRegistryOwner;Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/LifecycleOwner;Lcom/adyen/checkout/sessions/core/CheckoutSession;Lcom/adyen/checkout/components/core/PaymentMethod;Lcom/adyen/checkout/paybybankus/PayByBankUSConfiguration;Landroid/app/Application;Lcom/adyen/checkout/sessions/core/SessionComponentCallback;Ljava/lang/String;)Lcom/adyen/checkout/paybybankus/PayByBankUSComponent; + public fun isPaymentMethodSupported (Lcom/adyen/checkout/components/core/PaymentMethod;)Z } public final class com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView { diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt index baddb855e7..a9dc0c261f 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider.kt @@ -8,6 +8,270 @@ package com.adyen.checkout.paybybankus.internal.provider -class PayByBankUSComponentProvider { - // TODO implement +import android.app.Application +import androidx.annotation.RestrictTo +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelStoreOwner +import androidx.savedstate.SavedStateRegistryOwner +import com.adyen.checkout.action.core.internal.DefaultActionHandlingComponent +import com.adyen.checkout.action.core.internal.provider.GenericActionComponentProvider +import com.adyen.checkout.components.core.CheckoutConfiguration +import com.adyen.checkout.components.core.ComponentCallback +import com.adyen.checkout.components.core.Order +import com.adyen.checkout.components.core.PaymentMethod +import com.adyen.checkout.components.core.internal.DefaultComponentEventHandler +import com.adyen.checkout.components.core.internal.PaymentObserverRepository +import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.AnalyticsManagerFactory +import com.adyen.checkout.components.core.internal.analytics.AnalyticsSource +import com.adyen.checkout.components.core.internal.provider.PaymentComponentProvider +import com.adyen.checkout.components.core.internal.ui.model.ButtonComponentParamsMapper +import com.adyen.checkout.components.core.internal.ui.model.CommonComponentParamsMapper +import com.adyen.checkout.components.core.internal.ui.model.DropInOverrideParams +import com.adyen.checkout.components.core.internal.util.get +import com.adyen.checkout.components.core.internal.util.viewModelFactory +import com.adyen.checkout.core.exception.ComponentException +import com.adyen.checkout.core.internal.data.api.HttpClientFactory +import com.adyen.checkout.core.internal.util.LocaleProvider +import com.adyen.checkout.paybybankus.PayByBankUSComponent +import com.adyen.checkout.paybybankus.PayByBankUSComponentState +import com.adyen.checkout.paybybankus.PayByBankUSConfiguration +import com.adyen.checkout.paybybankus.getPayByBankUSConfiguration +import com.adyen.checkout.paybybankus.internal.DefaultPayByBankUSDelegate +import com.adyen.checkout.paybybankus.toCheckoutConfiguration +import com.adyen.checkout.sessions.core.CheckoutSession +import com.adyen.checkout.sessions.core.SessionComponentCallback +import com.adyen.checkout.sessions.core.internal.SessionComponentEventHandler +import com.adyen.checkout.sessions.core.internal.SessionInteractor +import com.adyen.checkout.sessions.core.internal.SessionSavedStateHandleContainer +import com.adyen.checkout.sessions.core.internal.data.api.SessionRepository +import com.adyen.checkout.sessions.core.internal.data.api.SessionService +import com.adyen.checkout.sessions.core.internal.provider.SessionPaymentComponentProvider +import com.adyen.checkout.sessions.core.internal.ui.model.SessionParamsFactory +import com.adyen.checkout.ui.core.internal.ui.SubmitHandler + +class PayByBankUSComponentProvider +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +constructor( + private val dropInOverrideParams: DropInOverrideParams? = null, + private val analyticsManager: AnalyticsManager? = null, + private val localeProvider: LocaleProvider = LocaleProvider(), +) : + PaymentComponentProvider< + PayByBankUSComponent, + PayByBankUSConfiguration, + PayByBankUSComponentState, + ComponentCallback, + >, + SessionPaymentComponentProvider< + PayByBankUSComponent, + PayByBankUSConfiguration, + PayByBankUSComponentState, + SessionComponentCallback, + > { + + override fun get( + savedStateRegistryOwner: SavedStateRegistryOwner, + viewModelStoreOwner: ViewModelStoreOwner, + lifecycleOwner: LifecycleOwner, + paymentMethod: PaymentMethod, + checkoutConfiguration: CheckoutConfiguration, + application: Application, + componentCallback: ComponentCallback, + order: Order?, + key: String? + ): PayByBankUSComponent { + assertSupported(paymentMethod) + + val genericFactory = viewModelFactory(savedStateRegistryOwner, null) { savedStateHandle -> + val componentParams = + ButtonComponentParamsMapper(CommonComponentParamsMapper()).mapToParams( + checkoutConfiguration = checkoutConfiguration, + deviceLocale = localeProvider.getLocale(application), + dropInOverrideParams = dropInOverrideParams, + componentSessionParams = null, + componentConfiguration = checkoutConfiguration.getPayByBankUSConfiguration(), + ) + + val analyticsManager = analyticsManager ?: AnalyticsManagerFactory().provide( + componentParams = componentParams, + application = application, + source = AnalyticsSource.PaymentComponent(paymentMethod.type.orEmpty()), + sessionId = null, + ) + + val payByBankUSDelegate = DefaultPayByBankUSDelegate( + observerRepository = PaymentObserverRepository(), + paymentMethod = paymentMethod, + order = order, + componentParams = componentParams, + analyticsManager = analyticsManager, + submitHandler = SubmitHandler(savedStateHandle), + ) + + val genericActionDelegate = + GenericActionComponentProvider(analyticsManager, dropInOverrideParams).getDelegate( + checkoutConfiguration = checkoutConfiguration, + savedStateHandle = savedStateHandle, + application = application, + ) + + PayByBankUSComponent( + payByBankUSDelegate = payByBankUSDelegate, + genericActionDelegate = genericActionDelegate, + actionHandlingComponent = DefaultActionHandlingComponent( + genericActionDelegate, + payByBankUSDelegate, + ), + componentEventHandler = DefaultComponentEventHandler(), + ) + } + + return ViewModelProvider(viewModelStoreOwner, genericFactory)[key, PayByBankUSComponent::class.java] + .also { component -> + component.observe(lifecycleOwner) { + component.componentEventHandler.onPaymentComponentEvent(it, componentCallback) + } + } + } + + override fun get( + savedStateRegistryOwner: SavedStateRegistryOwner, + viewModelStoreOwner: ViewModelStoreOwner, + lifecycleOwner: LifecycleOwner, + paymentMethod: PaymentMethod, + configuration: PayByBankUSConfiguration, + application: Application, + componentCallback: ComponentCallback, + order: Order?, + key: String? + ): PayByBankUSComponent { + return get( + savedStateRegistryOwner = savedStateRegistryOwner, + viewModelStoreOwner = viewModelStoreOwner, + lifecycleOwner = lifecycleOwner, + paymentMethod = paymentMethod, + checkoutConfiguration = configuration.toCheckoutConfiguration(), + application = application, + componentCallback = componentCallback, + order = order, + key = key, + ) + } + + @Suppress("LongMethod") + override fun get( + savedStateRegistryOwner: SavedStateRegistryOwner, + viewModelStoreOwner: ViewModelStoreOwner, + lifecycleOwner: LifecycleOwner, + checkoutSession: CheckoutSession, + paymentMethod: PaymentMethod, + checkoutConfiguration: CheckoutConfiguration, + application: Application, + componentCallback: SessionComponentCallback, + key: String? + ): PayByBankUSComponent { + assertSupported(paymentMethod) + + val genericFactory = viewModelFactory(savedStateRegistryOwner, null) { savedStateHandle -> + val componentParams = ButtonComponentParamsMapper(CommonComponentParamsMapper()).mapToParams( + checkoutConfiguration = checkoutConfiguration, + deviceLocale = localeProvider.getLocale(application), + dropInOverrideParams = dropInOverrideParams, + componentSessionParams = SessionParamsFactory.create(checkoutSession), + componentConfiguration = checkoutConfiguration.getPayByBankUSConfiguration(), + ) + + val httpClient = HttpClientFactory.getHttpClient(componentParams.environment) + + val analyticsManager = analyticsManager ?: AnalyticsManagerFactory().provide( + componentParams = componentParams, + application = application, + source = AnalyticsSource.PaymentComponent(paymentMethod.type.orEmpty()), + sessionId = checkoutSession.sessionSetupResponse.id, + ) + + val payByBankDelegate = DefaultPayByBankUSDelegate( + observerRepository = PaymentObserverRepository(), + paymentMethod = paymentMethod, + order = checkoutSession.order, + componentParams = componentParams, + analyticsManager = analyticsManager, + submitHandler = SubmitHandler(savedStateHandle), + ) + + val genericActionDelegate = + GenericActionComponentProvider(analyticsManager, dropInOverrideParams).getDelegate( + checkoutConfiguration = checkoutConfiguration, + savedStateHandle = savedStateHandle, + application = application, + ) + + val sessionSavedStateHandleContainer = SessionSavedStateHandleContainer( + savedStateHandle = savedStateHandle, + checkoutSession = checkoutSession, + ) + val sessionInteractor = SessionInteractor( + sessionRepository = SessionRepository( + sessionService = SessionService(httpClient), + clientKey = componentParams.clientKey, + ), + sessionModel = sessionSavedStateHandleContainer.getSessionModel(), + isFlowTakenOver = sessionSavedStateHandleContainer.isFlowTakenOver ?: false, + ) + val sessionComponentEventHandler = SessionComponentEventHandler( + sessionInteractor = sessionInteractor, + sessionSavedStateHandleContainer = sessionSavedStateHandleContainer, + ) + + PayByBankUSComponent( + payByBankUSDelegate = payByBankDelegate, + genericActionDelegate = genericActionDelegate, + actionHandlingComponent = DefaultActionHandlingComponent(genericActionDelegate, payByBankDelegate), + componentEventHandler = sessionComponentEventHandler, + ) + } + + return ViewModelProvider(viewModelStoreOwner, genericFactory)[key, PayByBankUSComponent::class.java] + .also { component -> + component.observe(lifecycleOwner) { + component.componentEventHandler.onPaymentComponentEvent(it, componentCallback) + } + } + } + + override fun get( + savedStateRegistryOwner: SavedStateRegistryOwner, + viewModelStoreOwner: ViewModelStoreOwner, + lifecycleOwner: LifecycleOwner, + checkoutSession: CheckoutSession, + paymentMethod: PaymentMethod, + configuration: PayByBankUSConfiguration, + application: Application, + componentCallback: SessionComponentCallback, + key: String? + ): PayByBankUSComponent { + return get( + savedStateRegistryOwner = savedStateRegistryOwner, + viewModelStoreOwner = viewModelStoreOwner, + lifecycleOwner = lifecycleOwner, + checkoutSession = checkoutSession, + paymentMethod = paymentMethod, + checkoutConfiguration = configuration.toCheckoutConfiguration(), + application = application, + componentCallback = componentCallback, + key = key, + ) + } + + private fun assertSupported(paymentMethod: PaymentMethod) { + if (!isPaymentMethodSupported(paymentMethod)) { + throw ComponentException("Unsupported payment method ${paymentMethod.type}") + } + } + + override fun isPaymentMethodSupported(paymentMethod: PaymentMethod): Boolean { + return PayByBankUSComponent.PAYMENT_METHOD_TYPES.contains(paymentMethod.type) + } } From be47252b9df32f1e7472f791b292983021a5507d Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:43:55 +0100 Subject: [PATCH 082/102] Implement PayByBankUSComponent COAND-974 --- .../paybybankus/PayByBankUSComponent.kt | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt index d847d39773..f5bde79afd 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/PayByBankUSComponent.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.paybybankus import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.adyen.checkout.action.core.internal.ActionHandlingComponent import com.adyen.checkout.action.core.internal.DefaultActionHandlingComponent import com.adyen.checkout.action.core.internal.ui.GenericActionDelegate @@ -17,11 +18,15 @@ import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.ComponentEventHandler import com.adyen.checkout.components.core.internal.PaymentComponent import com.adyen.checkout.components.core.internal.PaymentComponentEvent +import com.adyen.checkout.components.core.internal.toActionCallback import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.paybybankus.internal.PayByBankUSDelegate import com.adyen.checkout.paybybankus.internal.provider.PayByBankUSComponentProvider import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.ViewableComponent +import com.adyen.checkout.ui.core.internal.util.mergeViewFlows import kotlinx.coroutines.flow.Flow /** @@ -39,30 +44,43 @@ class PayByBankUSComponent internal constructor( ViewableComponent, ActionHandlingComponent by actionHandlingComponent { - override val delegate: ComponentDelegate - get() = TODO("Not yet implemented") + override val delegate: ComponentDelegate get() = actionHandlingComponent.activeDelegate - override val viewFlow: Flow - get() = TODO("Not yet implemented") + override val viewFlow: Flow = mergeViewFlows( + viewModelScope, + payByBankUSDelegate.viewFlow, + genericActionDelegate.viewFlow, + ) + + init { + payByBankUSDelegate.initialize(viewModelScope) + genericActionDelegate.initialize(viewModelScope) + componentEventHandler.initialize(viewModelScope) + } internal fun observe( lifecycleOwner: LifecycleOwner, callback: (PaymentComponentEvent) -> Unit ) { - TODO("Not yet implemented") + payByBankUSDelegate.observe(lifecycleOwner, viewModelScope, callback) + genericActionDelegate.observe(lifecycleOwner, viewModelScope, callback.toActionCallback()) } internal fun removeObserver() { - TODO("Not yet implemented") + payByBankUSDelegate.removeObserver() + genericActionDelegate.removeObserver() } override fun setInteractionBlocked(isInteractionBlocked: Boolean) { - TODO("Not yet implemented") + (delegate as? PayByBankUSDelegate)?.setInteractionBlocked(isInteractionBlocked) + ?: adyenLog(AdyenLogLevel.ERROR) { "Payment component is not interactable, ignoring." } } override fun onCleared() { super.onCleared() - TODO("Not yet implemented") + payByBankUSDelegate.onCleared() + genericActionDelegate.onCleared() + componentEventHandler.onCleared() } companion object { From ab1518ca93dd6206575ec00d4281fe86287cd707 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:36:34 +0100 Subject: [PATCH 083/102] Implement DefaultPayByBankUSDelegate COAND-974 --- .../internal/DefaultPayByBankUSDelegate.kt | 91 +++++++++++++------ 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt index fd5fa6d4ee..d51824db30 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt @@ -10,21 +10,28 @@ package com.adyen.checkout.paybybankus.internal import androidx.lifecycle.LifecycleOwner import com.adyen.checkout.components.core.Order +import com.adyen.checkout.components.core.PaymentComponentData import com.adyen.checkout.components.core.PaymentMethod +import com.adyen.checkout.components.core.PaymentMethodTypes import com.adyen.checkout.components.core.internal.PaymentComponentEvent import com.adyen.checkout.components.core.internal.PaymentObserverRepository import com.adyen.checkout.components.core.internal.analytics.AnalyticsManager +import com.adyen.checkout.components.core.internal.analytics.GenericEvents import com.adyen.checkout.components.core.internal.ui.model.ButtonComponentParams +import com.adyen.checkout.components.core.paymentmethod.PayByBankUSPaymentMethod +import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.paybybankus.PayByBankUSComponentState +import com.adyen.checkout.ui.core.internal.ui.ButtonComponentViewType import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow -// TODO remove the suppress annotation after complete implementation -@Suppress("UnusedPrivateProperty", "UnusedParameter") +@Suppress("TooManyFunctions") internal class DefaultPayByBankUSDelegate( private val observerRepository: PaymentObserverRepository, private val paymentMethod: PaymentMethod, @@ -34,23 +41,28 @@ internal class DefaultPayByBankUSDelegate( private val submitHandler: SubmitHandler, ) : PayByBankUSDelegate { - override val componentStateFlow: Flow - get() = TODO("Not yet implemented") + private val _componentStateFlow = MutableStateFlow(createComponentState()) + override val componentStateFlow: Flow = _componentStateFlow - override val viewFlow: Flow - get() = TODO("Not yet implemented") + // TODO push pay by bank us view after implementing view provider and view + private val _viewFlow: MutableStateFlow = MutableStateFlow(null) + override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow - get() = TODO("Not yet implemented") + override val submitFlow: Flow = submitHandler.submitFlow + override val uiStateFlow: Flow = submitHandler.uiStateFlow + override val uiEventFlow: Flow = submitHandler.uiEventFlow - override val uiStateFlow: Flow - get() = TODO("Not yet implemented") + override fun initialize(coroutineScope: CoroutineScope) { + submitHandler.initialize(coroutineScope, componentStateFlow) + initializeAnalytics(coroutineScope) + } - override val uiEventFlow: Flow - get() = TODO("Not yet implemented") + private fun initializeAnalytics(coroutineScope: CoroutineScope) { + adyenLog(AdyenLogLevel.VERBOSE) { "initializeAnalytics" } + analyticsManager.initialize(this, coroutineScope) - override fun initialize(coroutineScope: CoroutineScope) { - TODO("Not yet implemented") + val event = GenericEvents.rendered(paymentMethod.type.orEmpty()) + analyticsManager.trackEvent(event) } override fun observe( @@ -58,34 +70,59 @@ internal class DefaultPayByBankUSDelegate( coroutineScope: CoroutineScope, callback: (PaymentComponentEvent) -> Unit ) { - TODO("Not yet implemented") + observerRepository.addObservers( + stateFlow = componentStateFlow, + exceptionFlow = null, + submitFlow = submitFlow, + lifecycleOwner = lifecycleOwner, + coroutineScope = coroutineScope, + callback = callback, + ) } override fun removeObserver() { - TODO("Not yet implemented") + observerRepository.removeObservers() } - override fun getPaymentMethodType(): String { - TODO("Not yet implemented") + override fun getPaymentMethodType(): String = paymentMethod.type ?: PaymentMethodTypes.UNKNOWN + + private fun createComponentState(): PayByBankUSComponentState { + val payByBankUsPaymentMethod = PayByBankUSPaymentMethod( + type = getPaymentMethodType(), + checkoutAttemptId = analyticsManager.getCheckoutAttemptId(), + ) + + val paymentComponentData = PaymentComponentData( + paymentMethod = payByBankUsPaymentMethod, + order = order, + amount = componentParams.amount, + ) + + return PayByBankUSComponentState( + data = paymentComponentData, + isInputValid = true, + isReady = true, + ) } override fun onSubmit() { - TODO("Not yet implemented") - } + val event = GenericEvents.submit(paymentMethod.type.orEmpty()) + analyticsManager.trackEvent(event) - override fun isConfirmationRequired(): Boolean { - TODO("Not yet implemented") + val state = _componentStateFlow.value + submitHandler.onSubmit(state = state) } - override fun shouldShowSubmitButton(): Boolean { - TODO("Not yet implemented") - } + override fun isConfirmationRequired(): Boolean = _viewFlow.value is ButtonComponentViewType + + override fun shouldShowSubmitButton(): Boolean = isConfirmationRequired() && componentParams.isSubmitButtonVisible override fun setInteractionBlocked(isInteractionBlocked: Boolean) { - TODO("Not yet implemented") + submitHandler.setInteractionBlocked(isInteractionBlocked) } override fun onCleared() { - TODO("Not yet implemented") + removeObserver() + analyticsManager.clear(this) } } From 3bc8c1eacea94eb2a71f9bc5310e0ffa8a172879 Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:39:52 +0100 Subject: [PATCH 084/102] Implement ui for PayByBankUSComponent COAND-974 --- paybybank-us/api/paybybank-us.api | 15 +-- .../internal/DefaultPayByBankUSDelegate.kt | 28 ++++- .../internal/PayByBankUSDelegate.kt | 5 + .../internal/PayByBankUSViewProvider.kt | 22 +++- .../internal/ui/model/PayByBankUSBrandLogo.kt | 16 +++ .../ui/model/PayByBankUSOutputData.kt | 18 ++++ .../internal/ui/view/PayByBankUSView.kt | 87 ++++++++++++++- .../main/res/layout/pay_by_bank_us_view.xml | 53 ++++++++++ .../main/res/template/values/strings.xml.tt | 17 +++ .../src/main/res/values-ar/strings.xml | 15 +++ .../src/main/res/values-bg-rBG/strings.xml | 15 +++ .../src/main/res/values-ca-rES/strings.xml | 15 +++ .../src/main/res/values-cs-rCZ/strings.xml | 15 +++ .../src/main/res/values-da-rDK/strings.xml | 15 +++ .../src/main/res/values-de-rDE/strings.xml | 15 +++ .../src/main/res/values-el-rGR/strings.xml | 15 +++ .../src/main/res/values-es-rES/strings.xml | 15 +++ .../src/main/res/values-et-rEE/strings.xml | 15 +++ .../src/main/res/values-fi-rFI/strings.xml | 15 +++ .../src/main/res/values-fr-rFR/strings.xml | 15 +++ .../src/main/res/values-hr-rHR/strings.xml | 15 +++ .../src/main/res/values-hu-rHU/strings.xml | 15 +++ .../src/main/res/values-is-rIS/strings.xml | 15 +++ .../src/main/res/values-it-rIT/strings.xml | 15 +++ .../src/main/res/values-ja-rJP/strings.xml | 15 +++ .../src/main/res/values-ko-rKR/strings.xml | 15 +++ .../src/main/res/values-lt-rLT/strings.xml | 15 +++ .../src/main/res/values-lv-rLV/strings.xml | 15 +++ .../src/main/res/values-nb-rNO/strings.xml | 15 +++ .../src/main/res/values-nl-rNL/strings.xml | 15 +++ .../src/main/res/values-pl-rPL/strings.xml | 15 +++ .../src/main/res/values-pt-rBR/strings.xml | 15 +++ .../src/main/res/values-pt-rPT/strings.xml | 15 +++ .../src/main/res/values-ro-rRO/strings.xml | 15 +++ .../src/main/res/values-ru-rRU/strings.xml | 15 +++ .../src/main/res/values-sk-rSK/strings.xml | 15 +++ .../src/main/res/values-sl-rSI/strings.xml | 15 +++ .../src/main/res/values-sv-rSE/strings.xml | 15 +++ .../src/main/res/values-zh-rCN/strings.xml | 15 +++ .../src/main/res/values-zh-rTW/strings.xml | 15 +++ paybybank-us/src/main/res/values/strings.xml | 17 +++ paybybank-us/src/main/res/values/styles.xml | 54 ++++++++++ .../ui/core/internal/ui/model/LogoTextItem.kt | 41 +++++++ .../core/internal/ui/view/LogoTextAdapter.kt | 100 ++++++++++++++++++ .../src/main/res/layout/logo_view_holder.xml | 20 ++++ .../src/main/res/layout/text_view_holder.xml | 17 +++ ui-core/src/main/res/values/dimens.xml | 3 + ui-core/src/main/res/values/styles.xml | 12 +++ 48 files changed, 978 insertions(+), 12 deletions(-) create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSBrandLogo.kt create mode 100644 paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt create mode 100644 paybybank-us/src/main/res/layout/pay_by_bank_us_view.xml create mode 100644 paybybank-us/src/main/res/template/values/strings.xml.tt create mode 100644 paybybank-us/src/main/res/values-ar/strings.xml create mode 100644 paybybank-us/src/main/res/values-bg-rBG/strings.xml create mode 100644 paybybank-us/src/main/res/values-ca-rES/strings.xml create mode 100644 paybybank-us/src/main/res/values-cs-rCZ/strings.xml create mode 100644 paybybank-us/src/main/res/values-da-rDK/strings.xml create mode 100644 paybybank-us/src/main/res/values-de-rDE/strings.xml create mode 100644 paybybank-us/src/main/res/values-el-rGR/strings.xml create mode 100644 paybybank-us/src/main/res/values-es-rES/strings.xml create mode 100644 paybybank-us/src/main/res/values-et-rEE/strings.xml create mode 100644 paybybank-us/src/main/res/values-fi-rFI/strings.xml create mode 100644 paybybank-us/src/main/res/values-fr-rFR/strings.xml create mode 100644 paybybank-us/src/main/res/values-hr-rHR/strings.xml create mode 100644 paybybank-us/src/main/res/values-hu-rHU/strings.xml create mode 100644 paybybank-us/src/main/res/values-is-rIS/strings.xml create mode 100644 paybybank-us/src/main/res/values-it-rIT/strings.xml create mode 100644 paybybank-us/src/main/res/values-ja-rJP/strings.xml create mode 100644 paybybank-us/src/main/res/values-ko-rKR/strings.xml create mode 100644 paybybank-us/src/main/res/values-lt-rLT/strings.xml create mode 100644 paybybank-us/src/main/res/values-lv-rLV/strings.xml create mode 100644 paybybank-us/src/main/res/values-nb-rNO/strings.xml create mode 100644 paybybank-us/src/main/res/values-nl-rNL/strings.xml create mode 100644 paybybank-us/src/main/res/values-pl-rPL/strings.xml create mode 100644 paybybank-us/src/main/res/values-pt-rBR/strings.xml create mode 100644 paybybank-us/src/main/res/values-pt-rPT/strings.xml create mode 100644 paybybank-us/src/main/res/values-ro-rRO/strings.xml create mode 100644 paybybank-us/src/main/res/values-ru-rRU/strings.xml create mode 100644 paybybank-us/src/main/res/values-sk-rSK/strings.xml create mode 100644 paybybank-us/src/main/res/values-sl-rSI/strings.xml create mode 100644 paybybank-us/src/main/res/values-sv-rSE/strings.xml create mode 100644 paybybank-us/src/main/res/values-zh-rCN/strings.xml create mode 100644 paybybank-us/src/main/res/values-zh-rTW/strings.xml create mode 100644 paybybank-us/src/main/res/values/strings.xml create mode 100644 paybybank-us/src/main/res/values/styles.xml create mode 100644 ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LogoTextItem.kt create mode 100644 ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/LogoTextAdapter.kt create mode 100644 ui-core/src/main/res/layout/logo_view_holder.xml create mode 100644 ui-core/src/main/res/layout/text_view_holder.xml diff --git a/paybybank-us/api/paybybank-us.api b/paybybank-us/api/paybybank-us.api index 3ac16f012c..33a016c516 100644 --- a/paybybank-us/api/paybybank-us.api +++ b/paybybank-us/api/paybybank-us.api @@ -69,8 +69,15 @@ public final class com/adyen/checkout/paybybankus/PayByBankUSConfigurationKt { public static synthetic fun payByBankUS$default (Lcom/adyen/checkout/components/core/CheckoutConfiguration;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/adyen/checkout/components/core/CheckoutConfiguration; } -public final class com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider { - public fun ()V +public final class com/adyen/checkout/paybybankus/databinding/PayByBankUsViewBinding : androidx/viewbinding/ViewBinding { + public final field imageViewLogo Landroid/widget/ImageView; + public final field recyclerViewBrandList Landroidx/recyclerview/widget/RecyclerView; + public final field textViewDisclaimerBody Landroid/widget/TextView; + public final field textViewDisclaimerHeader Landroid/widget/TextView; + public final field textViewTitle Landroid/widget/TextView; + public static fun bind (Landroid/view/View;)Lcom/adyen/checkout/paybybankus/databinding/PayByBankUsViewBinding; + public fun getRoot ()Landroid/view/View; + public static fun inflate (Landroid/view/LayoutInflater;Landroid/view/ViewGroup;)Lcom/adyen/checkout/paybybankus/databinding/PayByBankUsViewBinding; } public final class com/adyen/checkout/paybybankus/internal/provider/PayByBankUSComponentProvider : com/adyen/checkout/components/core/internal/provider/PaymentComponentProvider, com/adyen/checkout/sessions/core/internal/provider/SessionPaymentComponentProvider { @@ -105,7 +112,3 @@ public final class com/adyen/checkout/paybybankus/internal/provider/PayByBankUSC public fun isPaymentMethodSupported (Lcom/adyen/checkout/components/core/PaymentMethod;)Z } -public final class com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView { - public fun ()V -} - diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt index d51824db30..8e22138ca2 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/DefaultPayByBankUSDelegate.kt @@ -22,11 +22,17 @@ import com.adyen.checkout.components.core.paymentmethod.PayByBankUSPaymentMethod import com.adyen.checkout.core.AdyenLogLevel import com.adyen.checkout.core.internal.util.adyenLog import com.adyen.checkout.paybybankus.PayByBankUSComponentState +import com.adyen.checkout.paybybankus.R +import com.adyen.checkout.paybybankus.internal.ui.model.PayByBankUSBrandLogo +import com.adyen.checkout.paybybankus.internal.ui.model.PayByBankUSOutputData import com.adyen.checkout.ui.core.internal.ui.ButtonComponentViewType import com.adyen.checkout.ui.core.internal.ui.ComponentViewType import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIEvent import com.adyen.checkout.ui.core.internal.ui.PaymentComponentUIState import com.adyen.checkout.ui.core.internal.ui.SubmitHandler +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem.LogoItem +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem.TextItem import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -41,11 +47,15 @@ internal class DefaultPayByBankUSDelegate( private val submitHandler: SubmitHandler, ) : PayByBankUSDelegate { + private val _outputDataFlow = MutableStateFlow(createOutputData()) + override val outputDataFlow: Flow = _outputDataFlow + + override val outputData: PayByBankUSOutputData = _outputDataFlow.value + private val _componentStateFlow = MutableStateFlow(createComponentState()) override val componentStateFlow: Flow = _componentStateFlow - // TODO push pay by bank us view after implementing view provider and view - private val _viewFlow: MutableStateFlow = MutableStateFlow(null) + private val _viewFlow: MutableStateFlow = MutableStateFlow(PayByBankUSComponentViewType) override val viewFlow: Flow = _viewFlow override val submitFlow: Flow = submitHandler.submitFlow @@ -86,6 +96,10 @@ internal class DefaultPayByBankUSDelegate( override fun getPaymentMethodType(): String = paymentMethod.type ?: PaymentMethodTypes.UNKNOWN + private fun createOutputData() = PayByBankUSOutputData( + brandList = getBrandList() + ) + private fun createComponentState(): PayByBankUSComponentState { val payByBankUsPaymentMethod = PayByBankUSPaymentMethod( type = getPaymentMethodType(), @@ -125,4 +139,14 @@ internal class DefaultPayByBankUSDelegate( removeObserver() analyticsManager.clear(this) } + + private fun getBrandList(): List { + return listOf( + LogoItem(PayByBankUSBrandLogo.US_1.path, componentParams.environment), + LogoItem(PayByBankUSBrandLogo.US_2.path, componentParams.environment), + LogoItem(PayByBankUSBrandLogo.US_3.path, componentParams.environment), + LogoItem(PayByBankUSBrandLogo.US_4.path, componentParams.environment), + TextItem(R.string.checkout_pay_by_bank_us_more), + ) + } } diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt index 91120c31ee..b6cc70c191 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSDelegate.kt @@ -10,6 +10,7 @@ package com.adyen.checkout.paybybankus.internal import com.adyen.checkout.components.core.internal.ui.PaymentComponentDelegate import com.adyen.checkout.paybybankus.PayByBankUSComponentState +import com.adyen.checkout.paybybankus.internal.ui.model.PayByBankUSOutputData import com.adyen.checkout.ui.core.internal.ui.ButtonDelegate import com.adyen.checkout.ui.core.internal.ui.UIStateDelegate import com.adyen.checkout.ui.core.internal.ui.ViewProvidingDelegate @@ -21,6 +22,10 @@ internal interface PayByBankUSDelegate : ButtonDelegate, UIStateDelegate { + val outputData: PayByBankUSOutputData + + val outputDataFlow: Flow + val componentStateFlow: Flow fun setInteractionBlocked(isInteractionBlocked: Boolean) diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt index ee5985ea84..031f7e0402 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/PayByBankUSViewProvider.kt @@ -8,6 +8,24 @@ package com.adyen.checkout.paybybankus.internal -class PayByBankUSViewProvider { - // TODO implement +import android.content.Context +import com.adyen.checkout.paybybankus.R +import com.adyen.checkout.paybybankus.internal.ui.view.PayByBankUSView +import com.adyen.checkout.ui.core.internal.ui.ButtonComponentViewType +import com.adyen.checkout.ui.core.internal.ui.ComponentView +import com.adyen.checkout.ui.core.internal.ui.ComponentViewType +import com.adyen.checkout.ui.core.internal.ui.ViewProvider + +internal object PayByBankUSViewProvider : ViewProvider { + override fun getView(viewType: ComponentViewType, context: Context): ComponentView { + return when (viewType) { + PayByBankUSComponentViewType -> PayByBankUSView(context) + else -> throw IllegalArgumentException("Unsupported view type") + } + } +} + +internal object PayByBankUSComponentViewType : ButtonComponentViewType { + override val viewProvider: ViewProvider = PayByBankUSViewProvider + override val buttonTextResId: Int = R.string.checkout_pay_by_bank_us_submit } diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSBrandLogo.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSBrandLogo.kt new file mode 100644 index 0000000000..f8033c8797 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSBrandLogo.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 1/11/2024. + */ + +package com.adyen.checkout.paybybankus.internal.ui.model + +internal enum class PayByBankUSBrandLogo(val path: String) { + US_1("US-1"), + US_2("US-2"), + US_3("US-3"), + US_4("US-4"), +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt new file mode 100644 index 0000000000..0cc3d03834 --- /dev/null +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/model/PayByBankUSOutputData.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 5/11/2024. + */ + +package com.adyen.checkout.paybybankus.internal.ui.model + +import com.adyen.checkout.components.core.internal.ui.model.OutputData +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem + +internal data class PayByBankUSOutputData( + val brandList: List +) : OutputData { + override val isValid: Boolean = true +} diff --git a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt index 7111f948a4..23c6df693b 100644 --- a/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt +++ b/paybybank-us/src/main/java/com/adyen/checkout/paybybankus/internal/ui/view/PayByBankUSView.kt @@ -8,6 +8,89 @@ package com.adyen.checkout.paybybankus.internal.ui.view -class PayByBankUSView { - // TODO implement +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.LinearLayout +import com.adyen.checkout.components.core.internal.ui.ComponentDelegate +import com.adyen.checkout.paybybankus.R +import com.adyen.checkout.paybybankus.databinding.PayByBankUsViewBinding +import com.adyen.checkout.paybybankus.internal.PayByBankUSDelegate +import com.adyen.checkout.ui.core.internal.ui.ComponentView +import com.adyen.checkout.ui.core.internal.ui.loadLogo +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem +import com.adyen.checkout.ui.core.internal.ui.view.LogoTextAdapter +import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle +import kotlinx.coroutines.CoroutineScope +import com.adyen.checkout.ui.core.R as UiCoreR + +internal class PayByBankUSView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr), ComponentView { + + private val binding: PayByBankUsViewBinding = PayByBankUsViewBinding.inflate(LayoutInflater.from(context), this) + + private lateinit var localizedContext: Context + + private lateinit var delegate: PayByBankUSDelegate + + private var logoTextAdapter: LogoTextAdapter? = null + + init { + orientation = VERTICAL + val padding = resources.getDimension(UiCoreR.dimen.standard_margin).toInt() + setPadding(0, padding, 0, 0) + } + + override fun initView(delegate: ComponentDelegate, coroutineScope: CoroutineScope, localizedContext: Context) { + require(delegate is PayByBankUSDelegate) { "Unsupported delegate type" } + this.delegate = delegate + + this.localizedContext = localizedContext + initLocalizedStrings(localizedContext) + + initPayByBankUSLogo() + initBrandList(delegate.outputData.brandList) + } + + private fun initLocalizedStrings(localizedContext: Context) { + binding.textViewTitle.setLocalizedTextFromStyle( + R.style.AdyenCheckout_PayByBankUS_Title, + localizedContext, + ) + + binding.textViewDisclaimerHeader.setLocalizedTextFromStyle( + R.style.AdyenCheckout_PayByBankUS_DisclaimerHeader, + localizedContext, + ) + + binding.textViewDisclaimerBody.setLocalizedTextFromStyle( + R.style.AdyenCheckout_PayByBankUS_DisclaimerBody, + localizedContext, + ) + } + + private fun initPayByBankUSLogo() { + binding.imageViewLogo.loadLogo( + delegate.componentParams.environment, + delegate.getPaymentMethodType(), + ) + } + + private fun initBrandList(brands: List) { + if (logoTextAdapter == null) { + logoTextAdapter = LogoTextAdapter(localizedContext) + binding.recyclerViewBrandList.adapter = logoTextAdapter + } + logoTextAdapter?.submitList(brands) + } + + override fun highlightValidationErrors() { + // no validation + } + + override fun getView(): View = this } diff --git a/paybybank-us/src/main/res/layout/pay_by_bank_us_view.xml b/paybybank-us/src/main/res/layout/pay_by_bank_us_view.xml new file mode 100644 index 0000000000..3247729172 --- /dev/null +++ b/paybybank-us/src/main/res/layout/pay_by_bank_us_view.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + diff --git a/paybybank-us/src/main/res/template/values/strings.xml.tt b/paybybank-us/src/main/res/template/values/strings.xml.tt new file mode 100644 index 0000000000..0b3991f8de --- /dev/null +++ b/paybybank-us/src/main/res/template/values/strings.xml.tt @@ -0,0 +1,17 @@ + + + + + %%payByBankAISDD.disclaimer.header%% + %%payByBankAISDD.disclaimer.body%% + %%payByBankAISDD.submit%% + %%payByBankAISDD.more%% + + Pay by Bank + diff --git a/paybybank-us/src/main/res/values-ar/strings.xml b/paybybank-us/src/main/res/values-ar/strings.xml new file mode 100644 index 0000000000..a404c47720 --- /dev/null +++ b/paybybank-us/src/main/res/values-ar/strings.xml @@ -0,0 +1,15 @@ + + + + + استخدم خدمة Pay by Bank للدفع الفوري من خلال أي حساب مصرفي. + من خلال ربط حسابك البنكي، أنت بذلك تمنحنا تفويضًا بخصم مدفوعات المبالغ المستحقة من حسابك البنكي، وذلك مقابل استخدام خدماتنا و/أو شراء منتجاتنا. ويستمر العمل بهذا التفويض إلى أن يتم إلغاؤه. + المضي قُدمًا والدفع عن طريق البنك + + المزيد + diff --git a/paybybank-us/src/main/res/values-bg-rBG/strings.xml b/paybybank-us/src/main/res/values-bg-rBG/strings.xml new file mode 100644 index 0000000000..3504f42d12 --- /dev/null +++ b/paybybank-us/src/main/res/values-bg-rBG/strings.xml @@ -0,0 +1,15 @@ + + + + + Използвайте Pay by Bank, за да платите незабавно от всяка банкова сметка. + Като свържете банковата си сметка, Вие разрешавате дебитиране на сметката Ви за всяка сума, дължима за употреба на нашите услуги и/или закупуване на нашите продукти, докато това разрешение не бъде оттеглено. + Продължете към Pay by Bank + + още + diff --git a/paybybank-us/src/main/res/values-ca-rES/strings.xml b/paybybank-us/src/main/res/values-ca-rES/strings.xml new file mode 100644 index 0000000000..a9b0c1f6c5 --- /dev/null +++ b/paybybank-us/src/main/res/values-ca-rES/strings.xml @@ -0,0 +1,15 @@ + + + + + Utilitzeu el pagament per banc per pagar a l\'instant des de qualsevol compte bancari. + En connectar el vostre compte bancari, esteu autoritzant càrrecs a aquest compte per qualsevol import degut per l\'ús dels nostres serveis o la compra dels nostres productes, fins que es revoqui aquesta autorització. + Continua a pagament per banc + + més + diff --git a/paybybank-us/src/main/res/values-cs-rCZ/strings.xml b/paybybank-us/src/main/res/values-cs-rCZ/strings.xml new file mode 100644 index 0000000000..c16af8ee53 --- /dev/null +++ b/paybybank-us/src/main/res/values-cs-rCZ/strings.xml @@ -0,0 +1,15 @@ + + + + + Použijte Pay by Bank k okamžité platbě z jakéhokoli bankovního účtu. + Připojením svého bankovního účtu vyjadřujete souhlas s tím, aby z účtu byly strženy všechny dlužné částky za využívání našich služeb a nákup našich produktů, a to až do odvolání tohoto souhlasu. + Pokračovat v platbě přes banku + + více + diff --git a/paybybank-us/src/main/res/values-da-rDK/strings.xml b/paybybank-us/src/main/res/values-da-rDK/strings.xml new file mode 100644 index 0000000000..61fad6141f --- /dev/null +++ b/paybybank-us/src/main/res/values-da-rDK/strings.xml @@ -0,0 +1,15 @@ + + + + + Brug Pay by Bank til at betale med det samme fra enhver bankkonto. + Ved at tilknytte din bankkonto tillader du debiteringer på din konto for ethvert skyldigt beløb for brug af vores tjenester og/eller køb af vores produkter, indtil denne tilladelse tilbagekaldes. + Fortsæt via Pay by Bank + + mere + diff --git a/paybybank-us/src/main/res/values-de-rDE/strings.xml b/paybybank-us/src/main/res/values-de-rDE/strings.xml new file mode 100644 index 0000000000..3d19dbfcb9 --- /dev/null +++ b/paybybank-us/src/main/res/values-de-rDE/strings.xml @@ -0,0 +1,15 @@ + + + + + Verwenden Sie Pay by Bank, um sofort von jedem Bankkonto zu bezahlen. + Durch die Verbindung Ihres Bankkontos autorisieren Sie bis auf Widerruf Abbuchungen von Ihrem Konto für alle Beträge, die für die Nutzung unserer Dienste und/oder den Kauf unserer Produkte geschuldet werden. + Weiter zu Pay by Bank + + mehr + diff --git a/paybybank-us/src/main/res/values-el-rGR/strings.xml b/paybybank-us/src/main/res/values-el-rGR/strings.xml new file mode 100644 index 0000000000..5c3634d2d0 --- /dev/null +++ b/paybybank-us/src/main/res/values-el-rGR/strings.xml @@ -0,0 +1,15 @@ + + + + + Χρησιμοποιήστε το Pay by Bank για άμεση πληρωμή από οποιονδήποτε τραπεζικό λογαριασμό. + Συνδέοντας τον τραπεζικό λογαριασμό σας, εξουσιοδοτείτε χρεώσεις στον λογαριασμό σας για οποιοδήποτε ποσό οφείλεται για τη χρήση των υπηρεσιών μας ή/και την αγορά των προϊόντων μας, έως ότου ανακληθεί αυτή η εξουσιοδότηση. + Συνεχίστε να πληρώνετε μέσω τράπεζας + + περισσότερα + diff --git a/paybybank-us/src/main/res/values-es-rES/strings.xml b/paybybank-us/src/main/res/values-es-rES/strings.xml new file mode 100644 index 0000000000..ca82557432 --- /dev/null +++ b/paybybank-us/src/main/res/values-es-rES/strings.xml @@ -0,0 +1,15 @@ + + + + + Utilice la opción de pago bancario para pagar al instante desde cualquier cuenta bancaria. + Al conectar su cuenta bancaria, autoriza los cargos en su cuenta de cualquier importe que deba pagar por el uso de nuestros servicios o la compra de nuestros productos hasta que se revoque esta autorización. + Continúe para pagar a través del banco + + más + diff --git a/paybybank-us/src/main/res/values-et-rEE/strings.xml b/paybybank-us/src/main/res/values-et-rEE/strings.xml new file mode 100644 index 0000000000..1d94c1d136 --- /dev/null +++ b/paybybank-us/src/main/res/values-et-rEE/strings.xml @@ -0,0 +1,15 @@ + + + + + Kasutage pangamakset, et maksta koheselt mis tahes pangakontoga. + Pangakonto sidumisega annate loa debiteerida oma kontolt meie teenuste kasutamise ja/või meie toodete ostmise eest mis tahes võlgnetavad summad kuni selle loa tühistamiseni. + Jätkake pangaga maksmist + + veel + diff --git a/paybybank-us/src/main/res/values-fi-rFI/strings.xml b/paybybank-us/src/main/res/values-fi-rFI/strings.xml new file mode 100644 index 0000000000..11c10f1c11 --- /dev/null +++ b/paybybank-us/src/main/res/values-fi-rFI/strings.xml @@ -0,0 +1,15 @@ + + + + + Pankkimaksutoiminnolla voit maksaa heti miltä tahansa pankkitililtä. + Kun yhdistät pankkitilisi, annat luvan veloittaa tililtäsi kaikki palveluidemme käytöstä ja/tai tuotteidemme ostamisesta aiheutuvat kulut. Tämä valtuutus on voimassa siihen saakka, kunnes peruutat sen. + Jatka pankkimaksuun + + lisää + diff --git a/paybybank-us/src/main/res/values-fr-rFR/strings.xml b/paybybank-us/src/main/res/values-fr-rFR/strings.xml new file mode 100644 index 0000000000..9cb1f080e6 --- /dev/null +++ b/paybybank-us/src/main/res/values-fr-rFR/strings.xml @@ -0,0 +1,15 @@ + + + + + Utilisez Pay by Bank pour payer instantanément depuis n\'importe quel compte bancaire. + En connectant votre compte bancaire, vous autorisez le débit de tous les montants dus pour l\'utilisation de nos services et l\'achat de nos produits, jusqu\'à révocation de votre autorisation. + Continuer vers Pay by Bank + + de détails + diff --git a/paybybank-us/src/main/res/values-hr-rHR/strings.xml b/paybybank-us/src/main/res/values-hr-rHR/strings.xml new file mode 100644 index 0000000000..af29fcce99 --- /dev/null +++ b/paybybank-us/src/main/res/values-hr-rHR/strings.xml @@ -0,0 +1,15 @@ + + + + + Koristite Pay by Bank za trenutačno plaćanje s bilo kojeg bankovnog računa. + Povezivanjem svog bankovnog računa autorizirate zaduženja na svoj račun za bilo koji iznos koji se duguje za upotrebu naših usluga i/ili kupnju naših proizvoda, sve dok se autorizacija ne opozove. + Nastavite s plaćanjem putem banke + + više + diff --git a/paybybank-us/src/main/res/values-hu-rHU/strings.xml b/paybybank-us/src/main/res/values-hu-rHU/strings.xml new file mode 100644 index 0000000000..c0649d520f --- /dev/null +++ b/paybybank-us/src/main/res/values-hu-rHU/strings.xml @@ -0,0 +1,15 @@ + + + + + Ha bankszámláról szeretne azonnal fizetni, használja a Fizetés bankkal lehetőséget. + Bankszámlája csatlakoztatásával engedélyezi, hogy a szolgáltatásaink használatáért és/vagy termékeink megvásárlásáért levonandó összeget a számlájára terheljük egészen addig, amíg ezt az engedélyt vissza nem vonja. + Tovább a Fizetés bankkal lehetőségre + + továbbiak + diff --git a/paybybank-us/src/main/res/values-is-rIS/strings.xml b/paybybank-us/src/main/res/values-is-rIS/strings.xml new file mode 100644 index 0000000000..82b4d8786d --- /dev/null +++ b/paybybank-us/src/main/res/values-is-rIS/strings.xml @@ -0,0 +1,15 @@ + + + + + Notaðu Pay by Bank til að greiða strax af hvaða bankareikningi sem er. + Með því að tengja bankareikninginn þinn heimilar þú skuldfærslu af reikningnum þínum fyrir hvaða upphæð sem þú skuldar vegna notkunar á þjónustu okkar og/eða kaupum á vörum okkar, þar til þessi heimild er afturkölluð. + Fara í Pay by Bank + + meira + diff --git a/paybybank-us/src/main/res/values-it-rIT/strings.xml b/paybybank-us/src/main/res/values-it-rIT/strings.xml new file mode 100644 index 0000000000..c1577da253 --- /dev/null +++ b/paybybank-us/src/main/res/values-it-rIT/strings.xml @@ -0,0 +1,15 @@ + + + + + Utilizza Pay by Bank per pagare istantaneamente da qualsiasi conto bancario. + Collegando il tuo conto bancario, autorizzi l\'addebito su di esso di qualsiasi importo dovuto per l\'utilizzo dei nostri servizi e/o l\'acquisto dei nostri prodotti, fino alla revoca di tale autorizzazione. + Continua su Pay by Bank + + altro + diff --git a/paybybank-us/src/main/res/values-ja-rJP/strings.xml b/paybybank-us/src/main/res/values-ja-rJP/strings.xml new file mode 100644 index 0000000000..7e44d16d54 --- /dev/null +++ b/paybybank-us/src/main/res/values-ja-rJP/strings.xml @@ -0,0 +1,15 @@ + + + + + Pay by Bankを使用すると、どの銀行口座からでも即座に支払いができます。 + 銀行口座を接続することで、お客様は、この承認が取り消されるまで、当社のサービスの利用および/または当社製品の購入のために支払うべき金額をお客様の口座から引き落とすことを承認したことになります。 + Pay by Bankに進む + + 詳細を確認 + diff --git a/paybybank-us/src/main/res/values-ko-rKR/strings.xml b/paybybank-us/src/main/res/values-ko-rKR/strings.xml new file mode 100644 index 0000000000..05875300ae --- /dev/null +++ b/paybybank-us/src/main/res/values-ko-rKR/strings.xml @@ -0,0 +1,15 @@ + + + + + Pay by Bank를 사용하면 어떤 은행 계좌에서든 즉시 결제할 수 있습니다. + 은행 계좌를 연결함으로써, 이 승인이 취소될 때까지 당사의 서비스 이용 및/또는 제품 구매에 대해 지불해야 할 모든 금액이 귀하의 계좌에서 인출되는 것을 승인하게 됩니다. + Pay by Bank로 계속 진행 + + 더 보기 + diff --git a/paybybank-us/src/main/res/values-lt-rLT/strings.xml b/paybybank-us/src/main/res/values-lt-rLT/strings.xml new file mode 100644 index 0000000000..d44a95f9d5 --- /dev/null +++ b/paybybank-us/src/main/res/values-lt-rLT/strings.xml @@ -0,0 +1,15 @@ + + + + + Naudokitės „Pay by Bank“ ir akimirksniu atsiskaitykite iš bet kurios banko sąskaitos. + Prijungdami savo banko sąskaitą sutinkate, kad iš jos būtų nurašomos visos mokėtinos sumos už naudojimąsi mūsų paslaugomis ir (arba) už mūsų produktų pirkimą, kol šis leidimas bus atšauktas. + Toliau eiti į „Pay by Bank“ + + daugiau + diff --git a/paybybank-us/src/main/res/values-lv-rLV/strings.xml b/paybybank-us/src/main/res/values-lv-rLV/strings.xml new file mode 100644 index 0000000000..6faa2fe7a9 --- /dev/null +++ b/paybybank-us/src/main/res/values-lv-rLV/strings.xml @@ -0,0 +1,15 @@ + + + + + Izmantojiet Pay by Bank pakalpojumu, lai nekavējoties norēķinātos no jebkura bankas konta. + Pievienojot bankas kontu, jūs atļaujat debetēt no sava konta jebkuru summu, kas maksājama par mūsu pakalpojumu izmantošanu un/vai mūsu produktu iegādi, līdz brīdim, kad šī atļauja tiek atsaukta. + Turpināt maksāt ar bankas starpniecību + + vairāk + diff --git a/paybybank-us/src/main/res/values-nb-rNO/strings.xml b/paybybank-us/src/main/res/values-nb-rNO/strings.xml new file mode 100644 index 0000000000..32991c89cc --- /dev/null +++ b/paybybank-us/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,15 @@ + + + + + Bruk Pay by Bank for å betale umiddelbart fra en hvilken som helst bankkonto. + Ved å koble til bankkontoen din autoriserer du debiteringer av kontoen for ethvert beløp du skylder for din bruk av våre tjenester og/eller kjøp av våre produkter, inntil denne autorisasjonen blir trukket tilbake. + Fortsett for å bruke Pay by Bank + + mer + diff --git a/paybybank-us/src/main/res/values-nl-rNL/strings.xml b/paybybank-us/src/main/res/values-nl-rNL/strings.xml new file mode 100644 index 0000000000..59e280657e --- /dev/null +++ b/paybybank-us/src/main/res/values-nl-rNL/strings.xml @@ -0,0 +1,15 @@ + + + + + Gebruik Pay by Bank om direct vanaf elke bankrekening te betalen. + Door uw bankrekening te koppelen, machtigt u afschrijvingen van uw rekening voor elk bedrag dat u verschuldigd bent voor het gebruik van onze diensten en/of de aankoop van onze producten, totdat deze machtiging wordt ingetrokken. + Doorgaan met betalen via de bank + + meer + diff --git a/paybybank-us/src/main/res/values-pl-rPL/strings.xml b/paybybank-us/src/main/res/values-pl-rPL/strings.xml new file mode 100644 index 0000000000..18d130599d --- /dev/null +++ b/paybybank-us/src/main/res/values-pl-rPL/strings.xml @@ -0,0 +1,15 @@ + + + + + Użyj Pay by Bank, aby zapłacić natychmiast z dowolnego konta bankowego. + Podłączając swoje konto bankowe, zezwalasz na obciążanie swojego konta wszelkimi kwotami należnymi za korzystanie z naszych usług i/lub zakup naszych produktów, do czasu odwołania tego upoważnienia. + Kontynuuj płatność przez bank + + więcej + diff --git a/paybybank-us/src/main/res/values-pt-rBR/strings.xml b/paybybank-us/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000..6f43ca47a3 --- /dev/null +++ b/paybybank-us/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,15 @@ + + + + + Use o Pay by Bank para pagar instantaneamente de qualquer conta bancária. + Ao conectar sua conta bancária, você autoriza débitos dessa conta de qualquer valor devido pelo uso de nossos serviços e/ou compra de nossos produtos até que esta autorização seja revogada. + Continuar para o Pay by Bank + + mais + diff --git a/paybybank-us/src/main/res/values-pt-rPT/strings.xml b/paybybank-us/src/main/res/values-pt-rPT/strings.xml new file mode 100644 index 0000000000..1922fb23c6 --- /dev/null +++ b/paybybank-us/src/main/res/values-pt-rPT/strings.xml @@ -0,0 +1,15 @@ + + + + + Utilize Pagamento por banco para pagar instantaneamente com qualquer conta bancária. + Ao conectar a sua conta bancária, você autoriza débitos na sua conta de qualquer valor devido pela utilização dos nossos serviços e/ou compra dos nossos produtos, até que esta autorização seja revogada. + Continuar para pagamento por banco + + mais + diff --git a/paybybank-us/src/main/res/values-ro-rRO/strings.xml b/paybybank-us/src/main/res/values-ro-rRO/strings.xml new file mode 100644 index 0000000000..1b961ab863 --- /dev/null +++ b/paybybank-us/src/main/res/values-ro-rRO/strings.xml @@ -0,0 +1,15 @@ + + + + + Utilizați Plată prin bancă pentru a plăti instantaneu din orice cont bancar. + Prin conectarea contului dvs. bancar, autorizați debitarea din contul dvs. a oricărei sume datorate cu privire la utilizarea serviciilor noastre și/sau achiziționarea produselor noastre, până la revocarea acestei autorizații. + Continuați către plata prin bancă + + mai multe + diff --git a/paybybank-us/src/main/res/values-ru-rRU/strings.xml b/paybybank-us/src/main/res/values-ru-rRU/strings.xml new file mode 100644 index 0000000000..14a4645260 --- /dev/null +++ b/paybybank-us/src/main/res/values-ru-rRU/strings.xml @@ -0,0 +1,15 @@ + + + + + Для моментальной оплаты с любого банковского счета воспользуйтесь приложением Pay by Bank. + Привязывая банковский счет, вы тем самым даете разрешение на списание с него средств за пользование нашими услугами и/или покупку нашей продукции. Данное разрешение продействует до тех пор, пока оно не будет отозвано. + Продолжить оплату через банк + + иное + diff --git a/paybybank-us/src/main/res/values-sk-rSK/strings.xml b/paybybank-us/src/main/res/values-sk-rSK/strings.xml new file mode 100644 index 0000000000..43c2c01d9c --- /dev/null +++ b/paybybank-us/src/main/res/values-sk-rSK/strings.xml @@ -0,0 +1,15 @@ + + + + + Používajte Pay by Bank na okamžitú platbu z akéhokoľvek bankového účtu. + Pripojením svojho bankového účtu dávate súhlas na odpísanie akejkoľvek dlžnej sumy z vášho účtu za používanie našich služieb a/alebo nákup našich produktov, a to až do odvolania tohto súhlasu. + Pokračovať v platbe bankou + + ďalšie + diff --git a/paybybank-us/src/main/res/values-sl-rSI/strings.xml b/paybybank-us/src/main/res/values-sl-rSI/strings.xml new file mode 100644 index 0000000000..55d025202e --- /dev/null +++ b/paybybank-us/src/main/res/values-sl-rSI/strings.xml @@ -0,0 +1,15 @@ + + + + + Uporabite Pay by Bank za takojšnje plačilo s katerega koli bančnega računa. + S povezavo svojega bančnega računa dovoljujete bremenitev računa za vse zneske, ki jih dolgujete za uporabo naših storitev in/ali nakup naših izdelkov, dokler tega dovoljenja ne prekličete. + Nadaljuj na storitev Pay by Bank + + več + diff --git a/paybybank-us/src/main/res/values-sv-rSE/strings.xml b/paybybank-us/src/main/res/values-sv-rSE/strings.xml new file mode 100644 index 0000000000..4ddc034f87 --- /dev/null +++ b/paybybank-us/src/main/res/values-sv-rSE/strings.xml @@ -0,0 +1,15 @@ + + + + + Använd Pay by Bank och betala direkt från vilket bankkonto som helst. + Genom att ansluta ditt bankkonto godkänner du att ditt konto debiteras eventuella belopp som du är skyldig för användning av våra tjänster och/eller köp av våra produkter, tills detta godkännande återkallas. + Fortsätt att betala via bank + + mer + diff --git a/paybybank-us/src/main/res/values-zh-rCN/strings.xml b/paybybank-us/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..785ec04c8b --- /dev/null +++ b/paybybank-us/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,15 @@ + + + + + 使用 Pay by Bank 从任何银行账户即时付款。 + 关联您的银行账户,即表示您授权从您的账户中扣除因使用我们的服务和/或购买我们的产品而需支付的任何金额,直至该授权被撤销。 + 继续使用 Pay by Bank + + 更多 + diff --git a/paybybank-us/src/main/res/values-zh-rTW/strings.xml b/paybybank-us/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..b18ef9ebee --- /dev/null +++ b/paybybank-us/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,15 @@ + + + + + 運用銀行支付方式透過任何銀行帳戶立即付款。 + 連結您的銀行帳戶即表示您授權我們可以在您享有我們的服務和/或購買我們的產品時,向您的帳戶扣款對應的費用,直到授權被撤銷為止。 + 繼續透過銀行付款 + + 更多 + diff --git a/paybybank-us/src/main/res/values/strings.xml b/paybybank-us/src/main/res/values/strings.xml new file mode 100644 index 0000000000..0c9b005318 --- /dev/null +++ b/paybybank-us/src/main/res/values/strings.xml @@ -0,0 +1,17 @@ + + + + + Use Pay by Bank to pay instantly from any bank account. + By connecting your bank account you are authorizing debits to your account for any amount owed for use of our services and/or purchase of our products, until this authorization is revoked. + Continue to Pay by Bank + + more + + Pay by Bank + diff --git a/paybybank-us/src/main/res/values/styles.xml b/paybybank-us/src/main/res/values/styles.xml new file mode 100644 index 0000000000..d246193776 --- /dev/null +++ b/paybybank-us/src/main/res/values/styles.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LogoTextItem.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LogoTextItem.kt new file mode 100644 index 0000000000..9e23eb69b3 --- /dev/null +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/model/LogoTextItem.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 29/10/2024. + */ + +package com.adyen.checkout.ui.core.internal.ui.model + +import androidx.annotation.RestrictTo +import androidx.annotation.StringRes +import com.adyen.checkout.core.Environment + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +sealed interface LogoTextItem { + fun getViewType(): LogoTextItemViewType + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + data class LogoItem( + val logoPath: String, + // We need the environment to load the logo + val environment: Environment, + ) : LogoTextItem { + override fun getViewType() = LogoTextItemViewType.Logo + } + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + data class TextItem( + @StringRes + val textResId: Int, + ) : LogoTextItem { + override fun getViewType() = LogoTextItemViewType.Text + } + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + enum class LogoTextItemViewType(val type: Int) { + Logo(0), + Text(1) + } +} diff --git a/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/LogoTextAdapter.kt b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/LogoTextAdapter.kt new file mode 100644 index 0000000000..26d6a161b4 --- /dev/null +++ b/ui-core/src/main/java/com/adyen/checkout/ui/core/internal/ui/view/LogoTextAdapter.kt @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 29/10/2024. + */ + +package com.adyen.checkout.ui.core.internal.ui.view + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.RestrictTo +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.adyen.checkout.core.exception.CheckoutException +import com.adyen.checkout.ui.core.databinding.LogoViewHolderBinding +import com.adyen.checkout.ui.core.databinding.TextViewHolderBinding +import com.adyen.checkout.ui.core.internal.ui.loadLogo +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem.LogoItem +import com.adyen.checkout.ui.core.internal.ui.model.LogoTextItem.TextItem + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +class LogoTextAdapter(private val localizedContext: Context) : + ListAdapter(LogoTextItemDiffCallback) { + + override fun getItemViewType(position: Int): Int { + return currentList[position].getViewType().type + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val inflater = LayoutInflater.from(parent.context) + return when (viewType) { + LogoTextItem.LogoTextItemViewType.Logo.type -> { + LogoViewHolder( + LogoViewHolderBinding.inflate(inflater, parent, false), + ) + } + + LogoTextItem.LogoTextItemViewType.Text.type -> { + TextViewHolder( + TextViewHolderBinding.inflate(inflater, parent, false), + localizedContext, + ) + } + + else -> throw CheckoutException("Unexpected viewType on onCreateViewHolder - $viewType") + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + val item = currentList[position] + when (holder) { + is LogoViewHolder -> holder.bind(item as LogoItem) + is TextViewHolder -> holder.bind(item as TextItem) + } + } + + internal class LogoViewHolder( + private val binding: LogoViewHolderBinding + ) : RecyclerView.ViewHolder(binding.root) { + fun bind(item: LogoItem) { + binding.imageViewBrandLogo.loadLogo( + environment = item.environment, + txVariant = item.logoPath, + ) + } + } + + internal class TextViewHolder( + private val binding: TextViewHolderBinding, + private val localizedContext: Context + ) : RecyclerView.ViewHolder(binding.root) { + fun bind(item: TextItem) { + binding.textView.text = localizedContext.getString(item.textResId) + } + } + + internal object LogoTextItemDiffCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: LogoTextItem, newItem: LogoTextItem): Boolean { + return when (oldItem) { + is LogoItem -> { + oldItem.logoPath == (newItem as? LogoItem)?.logoPath + } + + is TextItem -> { + oldItem.textResId == (newItem as? TextItem)?.textResId + } + } + } + + override fun areContentsTheSame(oldItem: LogoTextItem, newItem: LogoTextItem): Boolean { + return oldItem == newItem + } + } +} diff --git a/ui-core/src/main/res/layout/logo_view_holder.xml b/ui-core/src/main/res/layout/logo_view_holder.xml new file mode 100644 index 0000000000..c59a3e6176 --- /dev/null +++ b/ui-core/src/main/res/layout/logo_view_holder.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/ui-core/src/main/res/layout/text_view_holder.xml b/ui-core/src/main/res/layout/text_view_holder.xml new file mode 100644 index 0000000000..7edfe7a7c0 --- /dev/null +++ b/ui-core/src/main/res/layout/text_view_holder.xml @@ -0,0 +1,17 @@ + + + + diff --git a/ui-core/src/main/res/values/dimens.xml b/ui-core/src/main/res/values/dimens.xml index fcfa517936..12445116be 100644 --- a/ui-core/src/main/res/values/dimens.xml +++ b/ui-core/src/main/res/values/dimens.xml @@ -22,6 +22,9 @@ 80dp 52dp + 24dp + 16dp + 82dp 55dp diff --git a/ui-core/src/main/res/values/styles.xml b/ui-core/src/main/res/values/styles.xml index 9596fdc49a..fe3053e36e 100644 --- a/ui-core/src/main/res/values/styles.xml +++ b/ui-core/src/main/res/values/styles.xml @@ -43,6 +43,11 @@ 14sp + + + +