├── .gitignore
├── .idea
└── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── release
│ └── output-metadata.json
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ └── ru
│ │ └── cloudpayments
│ │ └── demo
│ │ ├── Constants.kt
│ │ ├── api
│ │ └── PayApi.kt
│ │ ├── base
│ │ ├── BaseActivity.kt
│ │ ├── BaseAdapter.kt
│ │ └── BaseListActivity.kt
│ │ ├── googlepay
│ │ ├── ConstantsGPay.kt
│ │ └── PaymentsUtil.kt
│ │ ├── managers
│ │ └── CartManager.kt
│ │ ├── models
│ │ └── Product.kt
│ │ ├── screens
│ │ ├── checkout
│ │ │ └── CheckoutActivity.kt
│ │ └── main
│ │ │ └── MainActivity.kt
│ │ └── support
│ │ ├── CardIOScanner.kt
│ │ ├── Constants.kt
│ │ └── SideSpaceItemDecoration.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable-xxhdpi
│ ├── logo.png
│ ├── product.png
│ └── splash_logo.png
│ ├── drawable
│ ├── googlepay_button_content.xml
│ ├── googlepay_button_overlay.xml
│ ├── ic_credit_card_black_24dp.xml
│ ├── ic_date_range_black_24dp.xml
│ ├── ic_email_white_24dp.xml
│ ├── ic_launcher_foreground.xml
│ ├── ic_lock_black_24dp.xml
│ ├── ic_person_black_24dp.xml
│ ├── ic_phone_white_24dp.xml
│ ├── ic_shopping_cart_white_24dp.xml
│ └── splashscreen_bg.xml
│ ├── layout
│ ├── activity_checkout.xml
│ ├── activity_main.xml
│ ├── googlepay_button.xml
│ └── toolbar.xml
│ ├── menu
│ └── main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── ic_launcher_background.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── sdk
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── ru
│ │ └── cloudpayments
│ │ └── sdk
│ │ ├── Constants.kt
│ │ ├── api
│ │ ├── AuthenticationInterceptor.kt
│ │ ├── CloudpaymentsApi.kt
│ │ ├── CloudpaymentsApiService.kt
│ │ └── models
│ │ │ ├── CardCryptogramPacket.kt
│ │ │ ├── CloudpaymentsBinInfoResponse.kt
│ │ │ ├── CloudpaymentsGetTinkoffPayQrLinkResponse.kt
│ │ │ ├── CloudpaymentsMerchantConfigurationResponse.kt
│ │ │ ├── CloudpaymentsPublicKeyResponse.kt
│ │ │ ├── CloudpaymentsThreeDsResponse.kt
│ │ │ ├── CloudpaymentsTinkoffPayQrLinkTransaction.kt
│ │ │ ├── CloudpaymentsTransaction.kt
│ │ │ ├── CloudpaymentsTransactionError.kt
│ │ │ ├── CloudpaymentsTransactionResponse.kt
│ │ │ ├── PaymentDataPayer.kt
│ │ │ ├── PaymentRequestBody.kt
│ │ │ ├── QrLinkStatusWait.kt
│ │ │ ├── QrLinkStatusWaitBody.kt
│ │ │ ├── QrLinkStatusWaitResponse.kt
│ │ │ ├── ThreeDsMdData.kt
│ │ │ ├── ThreeDsRequestBody.kt
│ │ │ └── TinkoffPayQrLinkBody.kt
│ │ ├── card
│ │ ├── Card.kt
│ │ └── CardType.kt
│ │ ├── configuration
│ │ ├── CloudPaymentsIntentSender.kt
│ │ ├── CloudpaymentsSDK.kt
│ │ ├── PaymentConfiguration.kt
│ │ └── PaymentData.kt
│ │ ├── dagger2
│ │ └── CloudpaymentsModule.kt
│ │ ├── models
│ │ ├── ApiError.kt
│ │ ├── Currency.kt
│ │ ├── PayParams.kt
│ │ └── Transaction.kt
│ │ ├── scanner
│ │ ├── CardData.kt
│ │ └── CardScanner.kt
│ │ ├── ui
│ │ ├── PaymentActivity.kt
│ │ └── dialogs
│ │ │ ├── PaymentCardFragment.kt
│ │ │ ├── PaymentOptionsFragment.kt
│ │ │ ├── PaymentProcessFragment.kt
│ │ │ ├── ThreeDsDialogFragment.kt
│ │ │ └── base
│ │ │ ├── BasePaymentBottomSheetFragment.kt
│ │ │ ├── BasePaymentDialogFragment.kt
│ │ │ ├── BaseVMBottomSheetFragment.kt
│ │ │ └── BaseVMDialogFragment.kt
│ │ ├── util
│ │ ├── Constants.kt
│ │ ├── Extensions.kt
│ │ ├── GooglePayHandler.kt
│ │ ├── HexPacketHelper.kt
│ │ ├── InjectorUtils.kt
│ │ ├── PublicKey.kt
│ │ └── Tools.kt
│ │ └── viewmodel
│ │ ├── BaseViewModel.kt
│ │ ├── BaseViewState.kt
│ │ ├── PaymentCardViewModel.kt
│ │ ├── PaymentOptionsViewModel.kt
│ │ ├── PaymentProcessViewModel.kt
│ │ └── PaymentProcessViewModelFactory.kt
│ └── res
│ ├── anim
│ ├── cpsdk_fade_in.xml
│ ├── cpsdk_fade_out.xml
│ ├── cpsdk_slide_in.xml
│ └── cpsdk_slide_out.xml
│ ├── color
│ └── cpsdk_color_edittext.xml
│ ├── drawable-hdpi
│ ├── cpsdk_button_tinkoff_pay.png
│ ├── cpsdk_ic_checkbox_checked.png
│ ├── cpsdk_ic_checkbox_unchecked.png
│ ├── cpsdk_ic_failure.png
│ ├── cpsdk_ic_progress.png
│ ├── cpsdk_ic_ps_jcb.png
│ ├── cpsdk_ic_ps_mir.png
│ ├── cpsdk_ic_success.png
│ ├── drag_handle.png
│ └── ic_required_email.png
│ ├── drawable-mdpi
│ ├── cpsdk_button_tinkoff_pay.png
│ ├── cpsdk_ic_checkbox_unchecked.png
│ ├── cpsdk_ic_failure.png
│ ├── cpsdk_ic_progress.png
│ ├── cpsdk_ic_ps_jcb.png
│ ├── cpsdk_ic_ps_mir.png
│ ├── cpsdk_ic_success.png
│ ├── drag_handle.png
│ └── ic_required_email.png
│ ├── drawable-v21
│ └── cpsdk_bg_button_gp.xml
│ ├── drawable-xhdpi
│ ├── cpsdk_button_tinkoff_pay.png
│ ├── cpsdk_ic_checkbox_checked.png
│ ├── cpsdk_ic_checkbox_unchecked.png
│ ├── cpsdk_ic_failure.png
│ ├── cpsdk_ic_progress.png
│ ├── cpsdk_ic_ps_jcb.png
│ ├── cpsdk_ic_ps_mir.png
│ ├── cpsdk_ic_success.png
│ ├── drag_handle.png
│ └── ic_required_email.png
│ ├── drawable-xxhdpi
│ ├── cpsdk_button_tinkoff_pay.png
│ ├── cpsdk_ic_checkbox_checked.png
│ ├── cpsdk_ic_checkbox_unchecked.png
│ ├── cpsdk_ic_failure.png
│ ├── cpsdk_ic_progress.png
│ ├── cpsdk_ic_ps_jcb.png
│ ├── cpsdk_ic_ps_mir.png
│ ├── cpsdk_ic_success.png
│ ├── drag_handle.png
│ └── ic_required_email.png
│ ├── drawable-xxxhdpi
│ ├── cpsdk_button_tinkoff_pay.png
│ ├── cpsdk_ic_checkbox_checked.png
│ ├── cpsdk_ic_checkbox_unchecked.png
│ ├── cpsdk_ic_failure.png
│ ├── cpsdk_ic_progress.png
│ ├── cpsdk_ic_ps_jcb.png
│ ├── cpsdk_ic_ps_mir.png
│ ├── cpsdk_ic_success.png
│ ├── drag_handle.png
│ └── ic_required_email.png
│ ├── drawable
│ ├── cpsdk_bg_button_close.xml
│ ├── cpsdk_bg_button_gp.xml
│ ├── cpsdk_bg_button_gp_black.xml
│ ├── cpsdk_bg_edit_text.xml
│ ├── cpsdk_bg_edit_text_error.xml
│ ├── cpsdk_bg_edit_text_focused.xml
│ ├── cpsdk_bg_edit_text_selector.xml
│ ├── cpsdk_bg_edit_text_selector_error.xml
│ ├── cpsdk_bg_popup.xml
│ ├── cpsdk_bg_rounded_black_button.xml
│ ├── cpsdk_bg_rounded_blue_button.xml
│ ├── cpsdk_bg_rounded_bottom_sheet.xml
│ ├── cpsdk_bg_rounded_dialog.xml
│ ├── cpsdk_bg_rounded_dialog_inset.xml
│ ├── cpsdk_bg_rounded_white_button_with_border.xml
│ ├── cpsdk_edit_text_underline.xml
│ ├── cpsdk_edit_text_underline_error.xml
│ ├── cpsdk_googlepay_button_content.xml
│ ├── cpsdk_googlepay_button_overlay.xml
│ ├── cpsdk_ic_blue_circle.xml
│ ├── cpsdk_ic_checkbox_selector.xml
│ ├── cpsdk_ic_close.xml
│ ├── cpsdk_ic_ps_amex.xml
│ ├── cpsdk_ic_ps_maestro.xml
│ ├── cpsdk_ic_ps_mastercard.xml
│ ├── cpsdk_ic_ps_troy.xml
│ ├── cpsdk_ic_ps_visa.xml
│ ├── cpsdk_ic_save_card_popup.xml
│ ├── cpsdk_ic_scan.xml
│ ├── cpsdk_ic_secured.xml
│ └── cpsdk_secured_logo.xml
│ ├── font
│ ├── rubik.xml
│ ├── rubik_black.ttf
│ ├── rubik_black_italic.ttf
│ ├── rubik_bold.ttf
│ ├── rubik_bold_italic.ttf
│ ├── rubik_italic.ttf
│ ├── rubik_light.ttf
│ ├── rubik_light_italic.ttf
│ ├── rubik_medium.ttf
│ ├── rubik_medium_italic.ttf
│ ├── rubik_regular.ttf
│ └── sf_pro_text_regular.ttf
│ ├── layout
│ ├── activity_cpsdk_payment.xml
│ ├── dialog_cpsdk_payment_card.xml
│ ├── dialog_cpsdk_payment_options.xml
│ ├── dialog_cpsdk_payment_process.xml
│ ├── dialog_cpsdk_three_ds.xml
│ ├── googlepay_button.xml
│ └── popup_cpsdk_save_card_info.xml
│ ├── values-v21
│ └── styles.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/androidstudio
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=androidstudio
3 |
4 | ### AndroidStudio ###
5 | # Covers files to be ignored for android development using Android Studio.
6 |
7 | # Built application files
8 | *.apk
9 | *.ap_
10 | *.aab
11 |
12 | # Files for the ART/Dalvik VM
13 | *.dex
14 |
15 | # Java class files
16 | *.class
17 |
18 | # Generated files
19 | bin/
20 | gen/
21 | out/
22 |
23 | # Gradle files
24 | .gradle
25 | .gradle/
26 | build/
27 |
28 | # Signing files
29 | .signing/
30 |
31 | # Local configuration file (sdk path, etc)
32 | local.properties
33 |
34 | # Proguard folder generated by Eclipse
35 | proguard/
36 |
37 | # Log Files
38 | *.log
39 |
40 | # Android Studio
41 | /*/build/
42 | /*/local.properties
43 | /*/out
44 | /*/*/build
45 | /*/*/production
46 | captures/
47 | .navigation/
48 | *.ipr
49 | *~
50 | *.swp
51 |
52 | # Keystore files
53 | *.jks
54 | *.keystore
55 |
56 | # Google Services (e.g. APIs or Firebase)
57 | # google-services.json
58 |
59 | # Android Patch
60 | gen-external-apklibs
61 |
62 | # External native build folder generated in Android Studio 2.2 and later
63 | .externalNativeBuild
64 |
65 | # NDK
66 | obj/
67 |
68 | # IntelliJ IDEA
69 | *.iml
70 | *.iws
71 | /out/
72 |
73 | # User-specific configurations
74 | .idea/caches/
75 | .idea/libraries/
76 | .idea/shelf/
77 | .idea/workspace.xml
78 | .idea/tasks.xml
79 | .idea/.name
80 | .idea/compiler.xml
81 | .idea/copyright/profiles_settings.xml
82 | .idea/encodings.xml
83 | .idea/misc.xml
84 | .idea/modules.xml
85 | .idea/scopes/scope_settings.xml
86 | .idea/dictionaries
87 | .idea/vcs.xml
88 | .idea/jsLibraryMappings.xml
89 | .idea/datasources.xml
90 | .idea/dataSources.ids
91 | .idea/sqlDataSources.xml
92 | .idea/dynamic.xml
93 | .idea/uiDesigner.xml
94 | .idea/assetWizardSettings.xml
95 | .idea/gradle.xml
96 | .idea/jarRepositories.xml
97 | .idea/navEditor.xml
98 |
99 | # OS-specific files
100 | .DS_Store
101 | .DS_Store?
102 | ._*
103 | .Spotlight-V100
104 | .Trashes
105 | ehthumbs.db
106 | Thumbs.db
107 |
108 | # Legacy Eclipse project files
109 | .classpath
110 | .project
111 | .cproject
112 | .settings/
113 |
114 | # Mobile Tools for Java (J2ME)
115 | .mtj.tmp/
116 |
117 | # Package Files #
118 | *.war
119 | *.ear
120 |
121 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
122 | hs_err_pid*
123 |
124 | ## Plugin-specific files:
125 |
126 | # mpeltonen/sbt-idea plugin
127 | .idea_modules/
128 |
129 | # JIRA plugin
130 | atlassian-ide-plugin.xml
131 |
132 | # Mongo Explorer plugin
133 | .idea/mongoSettings.xml
134 |
135 | # Crashlytics plugin (for Android Studio and IntelliJ)
136 | com_crashlytics_export_strings.xml
137 | crashlytics.properties
138 | crashlytics-build.properties
139 | fabric.properties
140 |
141 | ### AndroidStudio Patch ###
142 |
143 | !/gradle/wrapper/gradle-wrapper.jar
144 |
145 | # End of https://www.toptal.com/developers/gitignore/api/androidstudio
146 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | xmlns:android
22 |
23 | ^$
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | xmlns:.*
33 |
34 | ^$
35 |
36 |
37 | BY_NAME
38 |
39 |
40 |
41 |
42 |
43 |
44 | .*:id
45 |
46 | http://schemas.android.com/apk/res/android
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | .*:name
56 |
57 | http://schemas.android.com/apk/res/android
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | name
67 |
68 | ^$
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | style
78 |
79 | ^$
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | .*
89 |
90 | ^$
91 |
92 |
93 | BY_NAME
94 |
95 |
96 |
97 |
98 |
99 |
100 | .*
101 |
102 | http://schemas.android.com/apk/res/android
103 |
104 |
105 | ANDROID_ATTRIBUTE_ORDER
106 |
107 |
108 |
109 |
110 |
111 |
112 | .*
113 |
114 | .*
115 |
116 |
117 | BY_NAME
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-parcelize'
5 | id 'kotlin-kapt'
6 | }
7 |
8 |
9 | android {
10 | compileSdkVersion 33
11 |
12 | defaultConfig {
13 | applicationId "ru.cloudpayments.demo"
14 | minSdkVersion 23
15 | targetSdkVersion 33
16 | versionCode 1
17 | versionName "1.0"
18 | multiDexEnabled true
19 | manifestPlaceholders = [
20 | YANDEX_CLIENT_ID: "e7a80db136b0488fb420c8232531fa81"
21 | ]
22 |
23 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
24 | }
25 |
26 | viewBinding {
27 | enabled = true
28 | }
29 |
30 | buildTypes {
31 | debug {
32 | debuggable true
33 | minifyEnabled true
34 | shrinkResources false
35 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
36 | }
37 | release {
38 | debuggable false
39 | minifyEnabled true
40 | shrinkResources true
41 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
42 | }
43 |
44 | applicationVariants.all { variant ->
45 | variant.outputs.all { output ->
46 | def sh = ""
47 | if (!variant.buildType.isDebuggable()) {
48 | sh = getGitShortName()
49 | }
50 | def branch = getGitCurrentBranch()
51 | outputFileName = "${variant.name}-${variant.versionName}(${defaultConfig.versionCode})${sh}_[${branch}].apk"
52 | }
53 | }
54 | }
55 |
56 |
57 | compileOptions {
58 | sourceCompatibility JavaVersion.VERSION_17
59 | targetCompatibility JavaVersion.VERSION_17
60 | }
61 |
62 | kotlinOptions {
63 | jvmTarget = JavaVersion.VERSION_17.toString()
64 | }
65 | namespace 'ru.cloudpayments.demo'
66 | }
67 |
68 | def getGitShortName() {
69 | def stdout = new ByteArrayOutputStream()
70 |
71 | try {
72 | exec {
73 | commandLine 'git', 'rev-parse', '--short', 'HEAD'
74 | standardOutput = stdout
75 | }
76 | } catch (Exception ignored) {
77 |
78 | }
79 |
80 | return stdout.toString().trim()
81 | }
82 |
83 | def getGitCurrentBranch() {
84 | def stdout = new ByteArrayOutputStream()
85 |
86 | try {
87 | exec {
88 | commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
89 | standardOutput = stdout
90 | }
91 | } catch (Exception ignored) {
92 |
93 | }
94 |
95 | return stdout.toString().trim()
96 | }
97 |
98 | dependencies {
99 | implementation fileTree(dir: "libs", include: ["*.jar"])
100 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
101 | implementation 'androidx.core:core-ktx:1.9.0'
102 | implementation 'androidx.appcompat:appcompat:1.6.1'
103 |
104 | implementation 'com.google.android.material:material:1.8.0'
105 | implementation 'androidx.cardview:cardview:1.0.0'
106 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
107 | implementation 'androidx.fragment:fragment-ktx:1.5.7'
108 | implementation 'androidx.arch.core:core-runtime:2.2.0'
109 |
110 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
111 |
112 | // material dialogs
113 | implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
114 |
115 | implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
116 | implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
117 | implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
118 | implementation "com.squareup.okhttp3:okhttp:$okHttp3Version"
119 | implementation "com.squareup.okhttp3:logging-interceptor:$okHttp3Version"
120 |
121 | implementation 'ru.tinkoff.decoro:decoro:1.5.0'
122 |
123 | // rxkotlin
124 | implementation 'io.reactivex.rxjava2:rxkotlin:2.1.0'
125 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
126 | implementation "com.jakewharton.rxbinding2:rxbinding-kotlin:$rxBindingVersion"
127 |
128 | implementation 'com.google.android.gms:play-services-wallet:19.1.0'
129 |
130 | //Multidex support
131 | implementation 'androidx.multidex:multidex:2.0.1'
132 |
133 | // dagger2
134 | implementation "com.google.dagger:dagger:$dagger2Version"
135 | implementation "com.google.dagger:dagger-android:$dagger2Version"
136 | implementation "com.google.dagger:dagger-android-support:$dagger2Version"
137 | kapt "com.google.dagger:dagger-compiler:$dagger2Version"
138 | kapt "com.google.dagger:dagger-android-processor:$dagger2Version"
139 |
140 | // image loading and caching
141 | implementation 'com.github.bumptech.glide:glide:4.11.0'
142 |
143 | //card io scanner
144 | implementation 'io.card:android-sdk:5.5.0'
145 |
146 | implementation project(path: ':sdk')
147 | //implementation 'com.github.cloudpayments:CloudPayments-SDK-Android:1.1.3'
148 | }
149 |
150 | ext {
151 | retrofitVersion = '2.5.0'
152 | okHttp3Version = '3.8.0'
153 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | # com.squareup.retrofit2
24 | -dontwarn javax.annotation.**
25 | -dontwarn retrofit2.**
26 | -keep, includedescriptorclasses class retrofit2.** { *; }
27 | -keepattributes Signature
28 | -keepattributes Exceptions
29 | -keepclasseswithmembers class * {
30 | @retrofit2.http.* ;
31 | }
32 |
33 | # com.squareup.okhttp3
34 | -keepattributes Signature
35 | -keepattributes *Annotation*
36 | -keep, includedescriptorclasses class okhttp3.** { *; }
37 | -keep interface okhttp3.** { *; }
38 | -dontwarn okhttp3.**
39 | -keep class okhttp3.internal.platform.** { *; }
40 | -dontwarn okhttp3.internal.platform.**
41 | -dontnote okhttp3.internal.platform.**
42 |
43 | # com.google.gson
44 | -keep class com.google.gson.internal.** { *; }
45 | -dontwarn com.google.gson.internal.**
46 | -dontnote com.google.gson.internal.**
47 |
48 | # ru.cloudpayments.sdk
49 | -keep class ru.cloudpayments.demo.** { *; }
50 | -dontwarn ru.cloudpayments.demo.**
51 | -dontnote ru.cloudpayments.demo.**
52 |
53 |
54 | # Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
55 | # EnclosingMethod is required to use InnerClasses.
56 | -keepattributes Signature, InnerClasses, EnclosingMethod
57 |
58 | # Retrofit does reflection on method and parameter annotations.
59 | -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
60 |
61 | # Keep annotation default values (e.g., retrofit2.http.Field.encoded).
62 | -keepattributes AnnotationDefault
63 |
64 | # Retain service method parameters when optimizing.
65 | -keepclassmembers,allowshrinking,allowobfuscation interface * {
66 | @retrofit2.http.* ;
67 | }
68 |
69 | # Ignore annotation used for build tooling.
70 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
71 |
72 | # Ignore JSR 305 annotations for embedding nullability information.
73 | -dontwarn javax.annotation.**
74 |
75 | # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
76 | -dontwarn kotlin.Unit
77 |
78 | # Top-level functions that can only be used by Kotlin.
79 | -dontwarn retrofit2.KotlinExtensions
80 | -dontwarn retrofit2.KotlinExtensions$*
81 |
82 | # With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
83 | # and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
84 | -if interface * { @retrofit2.http.* ; }
85 | -keep,allowobfuscation interface <1>
86 |
87 | # Keep inherited services.
88 | -if interface * { @retrofit2.http.* ; }
89 | -keep,allowobfuscation interface * extends <1>
90 |
91 | # With R8 full mode generic signatures are stripped for classes that are not
92 | # kept. Suspend functions are wrapped in continuations where the type argument
93 | # is used.
94 | -keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
95 |
96 | # R8 full mode strips generic signatures from return types if not kept.
97 | -if interface * { @retrofit2.http.* public *** *(...); }
98 | -keep,allowoptimization,allowshrinking,allowobfuscation class <3>
99 |
100 |
101 | # JSR 305 annotations are for embedding nullability information.
102 | -dontwarn javax.annotation.**
103 |
104 | # A resource is loaded with a relative path so the package of this class must be preserved.
105 | -adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz
106 |
107 | # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
108 | -dontwarn org.codehaus.mojo.animal_sniffer.*
109 |
110 | # OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
111 | -dontwarn okhttp3.internal.platform.**
112 | -dontwarn org.conscrypt.**
113 | -dontwarn org.bouncycastle.**
114 | -dontwarn org.openjsse.**
--------------------------------------------------------------------------------
/app/release/output-metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "artifactType": {
4 | "type": "APK",
5 | "kind": "Directory"
6 | },
7 | "applicationId": "ru.cloudpayments.demo",
8 | "variantName": "release",
9 | "elements": [
10 | {
11 | "type": "SINGLE",
12 | "filters": [],
13 | "versionCode": 1,
14 | "versionName": "1.0",
15 | "outputFile": "release-1.0(1)f762b6f_[master].apk"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/Constants.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo
2 |
3 | class Constants {
4 | companion object {
5 | const val merchantPublicId = "test_api_00000000000000000000002"
6 | }
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/api/PayApi.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.api
2 |
3 | import io.reactivex.Observable
4 | import ru.cloudpayments.sdk.api.models.*
5 | import ru.cloudpayments.sdk.configuration.CloudpaymentsSDK
6 | import ru.cloudpayments.demo.Constants
7 |
8 | class PayApi {
9 | companion object {
10 | private val api = CloudpaymentsSDK.createApi(Constants.merchantPublicId)
11 |
12 | fun charge(cardCryptogramPacket: String, cardHolderName: String?, amount: Int): Observable {
13 | // Параметры см. в PaymentRequestBody
14 | val body = PaymentRequestBody(amount = amount.toString(),
15 | currency = "RUB",
16 | ipAddress = "",
17 | name = cardHolderName.orEmpty(),
18 | cryptogram = cardCryptogramPacket)
19 | return api.charge(body)
20 | .toObservable()
21 | .flatMap(CloudpaymentsTransactionResponse::handleError)
22 | .map { it.transaction }
23 | }
24 |
25 | fun auth(cardCryptogramPacket: String, cardHolderName: String?, amount: Int): Observable {
26 | // Параметры см. в PaymentRequestBody
27 | val body = PaymentRequestBody(amount = amount.toString(),
28 | currency = "RUB",
29 | ipAddress = "",
30 | name = cardHolderName.orEmpty(),
31 | cryptogram = cardCryptogramPacket)
32 | return api.auth(body)
33 | .toObservable()
34 | .flatMap(CloudpaymentsTransactionResponse::handleError)
35 | .map { it.transaction }
36 | }
37 |
38 | fun postThreeDs(transactionId: String, threeDsCallbackId: String, paRes: String): Observable {
39 | return api.postThreeDs(transactionId, threeDsCallbackId, paRes)
40 | .toObservable()
41 | }
42 |
43 | fun getBinInfo(firstSixDigits: String): Observable {
44 | return api.getBinInfo(firstSixDigits)
45 | .toObservable()
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.base
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.view.MenuItem
6 | import android.widget.Toast
7 | import androidx.annotation.StringRes
8 | import androidx.appcompat.app.AppCompatActivity
9 | import com.afollestad.materialdialogs.MaterialDialog
10 | import io.reactivex.disposables.CompositeDisposable
11 | import ru.cloudpayments.sdk.api.models.CloudpaymentsTransactionError
12 | import ru.cloudpayments.demo.R
13 | import ru.cloudpayments.demo.databinding.ToolbarBinding
14 | import java.net.UnknownHostException
15 | import java.util.*
16 |
17 | abstract class BaseActivity : AppCompatActivity() {
18 | protected val TAG = "TAG_" + javaClass.simpleName.toUpperCase(Locale.getDefault())
19 | protected var compositeDisposable = CompositeDisposable()
20 | private var loadingDialog: MaterialDialog? = null
21 | protected abstract val layoutId: Int
22 |
23 |
24 | override fun onCreate(savedInstanceState: Bundle?) {
25 | super.onCreate(savedInstanceState)
26 | val toolbar = ToolbarBinding.inflate(layoutInflater).root
27 | setSupportActionBar(toolbar)
28 | supportActionBar?.setDisplayHomeAsUpEnabled(true)
29 | initLoadingDialog()
30 | }
31 |
32 | private fun initLoadingDialog() {
33 | loadingDialog = MaterialDialog.Builder(this)
34 | .progress(true, 0)
35 | .title(R.string.dialog_loading_title)
36 | .content(R.string.dialog_loading_content)
37 | .cancelable(false)
38 | .build()
39 | }
40 |
41 |
42 | /*@Override
43 | public void onDestroy() {
44 | super.onDestroy();
45 | compositeSubscription.unsubscribe();
46 | }*/
47 |
48 | fun showLoading() {
49 | if (loadingDialog?.isShowing == true) {
50 | return
51 | }
52 | loadingDialog?.show()
53 | }
54 |
55 | fun hideLoading() {
56 | if (loadingDialog?.isShowing != true) {
57 | return
58 | }
59 | loadingDialog?.dismiss()
60 | }
61 |
62 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
63 | when (item.itemId) {
64 | android.R.id.home -> {
65 | onBackPressed()
66 | return true
67 | }
68 | }
69 | return super.onOptionsItemSelected(item)
70 | }
71 |
72 | fun showToast(@StringRes resId: Int) {
73 | showToast(getString(resId))
74 | }
75 |
76 | fun showToast(message: String?) {
77 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
78 | }
79 |
80 | fun log(message: String?) {
81 | Log.d(TAG, message.orEmpty())
82 | }
83 |
84 | fun handleError(throwable: Throwable, vararg ignoreClasses: Class<*>?) {
85 | if (ignoreClasses.isNotEmpty()) {
86 | val classList = listOf(*ignoreClasses)
87 | if (classList.contains(throwable.javaClass)) {
88 | return
89 | }
90 | }
91 | when (throwable) {
92 | is CloudpaymentsTransactionError -> {
93 | val message: String = throwable.message
94 | showToast(message)
95 | }
96 | is UnknownHostException -> showToast(R.string.common_no_internet_connection)
97 | else -> showToast(throwable.message)
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/base/BaseAdapter.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.base
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 |
5 | abstract class BaseAdapter : RecyclerView.Adapter()
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/base/BaseListActivity.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.base
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 |
5 | abstract class BaseListActivity?> : BaseActivity() {
6 | protected var adapter: T? = null
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/googlepay/ConstantsGPay.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.googlepay
2 |
3 | import android.util.Pair
4 | import com.google.android.gms.wallet.WalletConstants
5 | import ru.cloudpayments.demo.support.Constants
6 | import java.util.*
7 |
8 | object ConstantsGPay {
9 | // This file contains several constants you must edit before proceeding. Once you're done,
10 | // remove this static block and run the sample.
11 | // Before you start, please take a look at PaymentsUtil.java to see where the constants are used
12 | // and to potentially remove ones not relevant to your integration.
13 | // Required changes:
14 | // 1. Update SUPPORTED_NETWORKS and SUPPORTED_METHODS if required (consult your processor if
15 | // unsure).
16 | // 2. Update CURRENCY_CODE to the currency you use.
17 | // 3. Update SHIPPING_SUPPORTED_COUNTRIES to list the countries where you currently ship. If
18 | // this is not applicable to your app, remove the relevant bits from PaymentsUtil.java.
19 | // 4. If you're integrating with your processor / gateway directly, update
20 | // GATEWAY_TOKENIZATION_NAME and GATEWAY_TOKENIZATION_PARAMETERS per the instructions they
21 | // provided. You don't need to update DIRECT_TOKENIZATION_PUBLIC_KEY.
22 | // 5. If you're using direct integration, please consult the documentation to learn about
23 | // next steps.
24 | // Changing this to ENVIRONMENT_PRODUCTION will make the API return real card information.
25 | // Please refer to the documentation to read about the required steps needed to enable
26 | // ENVIRONMENT_PRODUCTION.
27 | const val PAYMENTS_ENVIRONMENT = WalletConstants.ENVIRONMENT_TEST
28 |
29 | // The allowed networks to be requested from the API. If the user has cards from networks not
30 | // specified here in their account, these will not be offered for them to choose in the popup.
31 | val SUPPORTED_NETWORKS = Arrays.asList(
32 | WalletConstants.CARD_NETWORK_VISA,
33 | WalletConstants.CARD_NETWORK_MASTERCARD
34 | )
35 | val SUPPORTED_METHODS =
36 | Arrays.asList( // PAYMENT_METHOD_CARD returns to any card the user has stored in their Google Account.
37 | WalletConstants.PAYMENT_METHOD_CARD, // PAYMENT_METHOD_TOKENIZED_CARD refers to cards added to Android Pay, assuming Android
38 | // Pay is installed.
39 | // Please keep in mind cards may exist in Android Pay without being added to the Google
40 | // Account.
41 | WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD
42 | )
43 |
44 | // Required by the API, but not visible to the user.
45 | const val CURRENCY_CODE = "RUB"
46 |
47 | // The name of your payment processor / gateway. Please refer to their documentation for
48 | // more information.
49 | const val GATEWAY_TOKENIZATION_NAME = "cloudpayments"
50 |
51 | // Custom parameters required by the processor / gateway.
52 | // In many cases, your processor / gateway will only require a gatewayMerchantId.
53 | // Please refer to your processor's documentation for more information. The number of parameters
54 | // required and their names vary depending on the processor.
55 | val GATEWAY_TOKENIZATION_PARAMETERS = Arrays.asList(
56 | Pair.create("gatewayMerchantId", Constants.MERCHANT_PUBLIC_ID)
57 | )
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/managers/CartManager.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.managers
2 |
3 | import ru.cloudpayments.demo.models.Product
4 | import kotlin.collections.ArrayList
5 |
6 | class CartManager private constructor() {
7 | private var products: ArrayList = arrayListOf()
8 |
9 | fun clear() {
10 | products.clear()
11 | }
12 |
13 | fun getProducts() = products
14 |
15 | fun setProducts(products: ArrayList?) {
16 | this.products = ArrayList(products.orEmpty())
17 | }
18 |
19 | fun addProduct(product: Product) {
20 | products.add(product)
21 | }
22 |
23 | companion object {
24 | private var instance: CartManager? = null
25 | @Synchronized fun getInstance(): CartManager? {
26 | if (instance == null) {
27 | synchronized(CartManager::class.java) { instance = CartManager() }
28 | }
29 | return instance
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/models/Product.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 | import ru.cloudpayments.demo.R
5 |
6 | data class Product(
7 | @SerializedName("id") val id: String = "1",
8 | @SerializedName("name") val name: String = "Букет \"Нежность\"",
9 | @SerializedName("price") val price: String = "1",
10 | @SerializedName("image") val image: Int = R.drawable.product)
11 |
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/screens/main/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.screens.main
2 |
3 | import android.os.Bundle
4 | import android.widget.Toast
5 | import ru.cloudpayments.demo.R
6 | import ru.cloudpayments.demo.base.BaseActivity
7 | import ru.cloudpayments.demo.databinding.ActivityMainBinding
8 | import ru.cloudpayments.demo.support.CardIOScanner
9 | import ru.cloudpayments.sdk.api.models.PaymentDataPayer
10 | import ru.cloudpayments.sdk.configuration.CloudpaymentsSDK
11 | import ru.cloudpayments.sdk.configuration.PaymentConfiguration
12 | import ru.cloudpayments.sdk.configuration.PaymentData
13 |
14 | class MainActivity : BaseActivity() {
15 |
16 | private val cpSdkLauncher = CloudpaymentsSDK.getInstance().launcher(this, result = {
17 | if (it.status != null) {
18 | if (it.status == CloudpaymentsSDK.TransactionStatus.Succeeded) {
19 | Toast.makeText(this, "Успешно! Транзакция №${it.transactionId}", Toast.LENGTH_SHORT).show()
20 | } else {
21 | if (it.reasonCode != 0) {
22 | Toast.makeText(this, "Ошибка! Транзакция №${it.transactionId}. Код ошибки ${it.reasonCode}", Toast.LENGTH_SHORT).show()
23 | } else {
24 | Toast.makeText(this, "Ошибка! Транзакция №${it.transactionId}.", Toast.LENGTH_SHORT).show()
25 | }
26 | }
27 | }
28 | })
29 |
30 | override val layoutId = R.layout.activity_main
31 |
32 | private lateinit var binding: ActivityMainBinding
33 |
34 | override fun onCreate(savedInstanceState: Bundle?) {
35 | super.onCreate(savedInstanceState)
36 |
37 | binding = ActivityMainBinding.inflate(layoutInflater)
38 | val view = binding.root
39 | setContentView(view)
40 |
41 | binding.buttonRunTop.setOnClickListener {
42 | runCpSdk()
43 | }
44 |
45 | binding.buttonRun.setOnClickListener {
46 | runCpSdk()
47 | }
48 | }
49 |
50 | private fun runCpSdk() {
51 |
52 | val apiUrl = binding.editApiUrl.text.toString()
53 | val publicId = binding.editPublicId.text.toString()
54 | val amount = binding.editAmount.text.toString()
55 | val currency = binding.editCurrency.text.toString()
56 | val invoiceId = binding.editInvoiceId.text.toString()
57 | val description = binding.editDescription.text.toString()
58 | val accountId = binding.editAccountId.text.toString()
59 | val email = binding.editEmail.text.toString()
60 |
61 | val payerFirstName = binding.editPayerFirstName.text.toString()
62 | val payerLastName = binding.editPayerLastName.text.toString()
63 | val payerMiddleName = binding.editPayerMiddleName.text.toString()
64 | val payerBirthDay = binding.editPayerBirth.text.toString()
65 | val payerAddress = binding.editPayerAddress.text.toString()
66 | val payerStreet = binding.editPayerStreet.text.toString()
67 | val payerCity = binding.editPayerCity.text.toString()
68 | val payerCountry = binding.editPayerCountry.text.toString()
69 | val payerPhone = binding.editPayerPhone.text.toString()
70 | val payerPostcode = binding.editPayerPostcode.text.toString()
71 |
72 | val jsonData = binding.editJsonData.text.toString()
73 | val isDualMessagePayment = binding.checkboxDualMessagePayment.isChecked
74 |
75 | var payer = PaymentDataPayer()
76 | payer.firstName = payerFirstName
77 | payer.lastName = payerLastName
78 | payer.middleName = payerMiddleName
79 | payer.birthDay = payerBirthDay
80 | payer.address = payerAddress
81 | payer.street = payerStreet
82 | payer.city = payerCity
83 | payer.country = payerCountry
84 | payer.phone = payerPhone
85 | payer.postcode = payerPostcode
86 |
87 | val paymentData = PaymentData(
88 | amount = amount,
89 | currency = currency,
90 | invoiceId = invoiceId,
91 | description = description,
92 | accountId = accountId,
93 | email = email,
94 | payer = payer,
95 | jsonData = jsonData
96 | )
97 |
98 | val configuration = PaymentConfiguration(
99 | publicId = publicId,
100 | paymentData = paymentData,
101 | scanner = CardIOScanner(),
102 | requireEmail = false,
103 | useDualMessagePayment = isDualMessagePayment,
104 | disableGPay = false,
105 | disableYandexPay = false,
106 | yandexPayMerchantID = "",
107 | apiUrl = apiUrl
108 | )
109 | cpSdkLauncher.launch(configuration)
110 | }
111 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/support/CardIOScanner.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.support
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import io.card.payment.CardIOActivity
6 | import io.card.payment.CreditCard
7 | import kotlinx.android.parcel.Parcelize
8 | import ru.cloudpayments.sdk.scanner.CardData
9 | import ru.cloudpayments.sdk.scanner.CardScanner
10 |
11 |
12 | @Parcelize
13 | class CardIOScanner: CardScanner() {
14 | override fun getScannerIntent(context: Context) =
15 | Intent(context, CardIOActivity::class.java).apply {
16 | putExtra(CardIOActivity.EXTRA_REQUIRE_EXPIRY, true)
17 | }
18 |
19 | override fun getCardDataFromIntent(data: Intent) =
20 | if (data.hasExtra(CardIOActivity.EXTRA_SCAN_RESULT)) {
21 | val scanResult = data.getParcelableExtra(CardIOActivity.EXTRA_SCAN_RESULT) as? CreditCard
22 | val month = (scanResult?.expiryMonth ?: 0).toString().padStart(2, '0')
23 | val yearString = scanResult?.expiryYear?.toString() ?: "00"
24 | val year = if (yearString.length > 2) {
25 | yearString.substring(yearString.lastIndex - 1)
26 | } else {
27 | yearString.padStart(2, '0')
28 | }
29 | val cardData = CardData(scanResult?.cardNumber, month, year, scanResult?.cardholderName)
30 | cardData
31 | } else {
32 | null
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/support/Constants.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.support
2 |
3 | object Constants {
4 | const val CONSUMER_KEY = "ck_ddb320b48b89a170248545eb3bb8e822365aa917"
5 | const val CONSUMER_SECRET = "cs_35ad6d0cf8e6b149e66968efdad87112ca2bc2d3"
6 | const val MERCHANT_PUBLIC_ID = "test_api_00000000000000000000002" // Test host
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/ru/cloudpayments/demo/support/SideSpaceItemDecoration.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.demo.support
2 |
3 | import android.content.Context
4 | import android.graphics.Rect
5 | import android.view.View
6 | import androidx.recyclerview.widget.RecyclerView
7 | import androidx.recyclerview.widget.RecyclerView.ItemDecoration
8 |
9 | class SideSpaceItemDecoration(context: Context, spacing: Int, private val spanCount: Int, private val includeEdge: Boolean) : ItemDecoration() {
10 | private val spacingInDP: Float = spacing * context.resources.displayMetrics.density
11 |
12 | override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
13 | val position = parent.getChildAdapterPosition(view)
14 | val column = position % spanCount
15 | if (includeEdge) {
16 | outRect.left = (spacingInDP - column * spacingInDP / spanCount).toInt()
17 | outRect.right = ((column + 1) * spacingInDP / spanCount).toInt()
18 | if (position < spanCount) {
19 | outRect.top = spacingInDP.toInt()
20 | }
21 | outRect.bottom = spacingInDP.toInt()
22 | } else {
23 | outRect.left = (column * spacingInDP / spanCount).toInt()
24 | outRect.right = (spacingInDP - (column + 1) * spacingInDP / spanCount).toInt()
25 | if (position >= spanCount) {
26 | outRect.top = spacingInDP.toInt()
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/drawable-xxhdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/product.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/drawable-xxhdpi/product.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/splash_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/drawable-xxhdpi/splash_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/googlepay_button_content.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
24 |
30 |
36 |
42 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/googlepay_button_overlay.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_credit_card_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_date_range_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_email_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_lock_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_phone_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shopping_cart_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splashscreen_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
7 |
8 |
9 |
10 |
11 | -
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/googlepay_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
15 |
22 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6494DA
4 | #393861
5 | #6494DA
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 | 16dp
21 |
22 | 5dp
23 | 10dp
24 | 30dp
25 |
26 | 300dp
27 | 48sp
28 | 200dp
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CloudPayments Demo
3 |
4 | My Online Store
5 | Unfortunately, Pay with Google is not available on this phone.
6 | Checking if Pay with Google is available...
7 | Successfully received payment data for %s!
8 |
9 | Оплатить через Google
10 |
11 |
12 | Загрузка данных
13 | Пожалуйста, подождите…
14 | Для этого действия необходима авторизация
15 | Сервер недоступен
16 |
17 |
18 | Отсутствует соединение с интернетом
19 |
20 |
21 | CloudPayments
22 | Посмотрите, как выглядят платежи через CloudPayments для покупателей в мобильном приложении. Выберите товары, которые нужно приобрести. Товары не настоящие, платежи тоже — деньги тратить не придется.
23 | В корзину
24 | +7 495 374-78-60
25 | sales@cloudpayments.ru
26 | Выберите приложение
27 | Ваша корзина пуста добавьте один или несколько товаров чтобы продолжить.
28 | Товар добавлен в корзину.
29 | Руб.
30 |
31 | Одностадийная оплата
32 | Двухстадийная оплата
33 |
34 |
35 |
36 | Корзина
37 | Итого:
38 | Итого: %s Руб.
39 | Перейти к оплате
40 |
41 |
42 | Оплата
43 | Так выглядят платежи через CloudPayments для покупателей в мобильном приложении. Платеж тестовый — деньги тратить не придется.
44 | Всего к оплате:
45 | Всего к оплате: %s Руб.
46 | Номер карты
47 | MM/YY
48 | CVC
49 | Владелец карты
50 | Оплатить
51 |
52 |
53 | ВНИМАНИЕ!\nВ режиме PRODUCTION с вашей банковской карты будет списан 1 рубль!
54 | Вы можете провести оплату введя данные банковской карты или используя Google Pay если этот сервис доступен на Вашем устройстве
55 | Срок действия в формате: MMYY
56 | Имя владельца
57 | CVV код
58 | Оплатить
59 | или
60 |
61 | Номер карты некорректен
62 | Срок действитя некорректен либо истек
63 | Некорректный CVC код
64 |
65 | Невозможно создать криптограмму проверьте данные карты
66 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
15 |
16 |
23 |
24 |
30 |
31 |
35 |
36 |
43 |
44 |
50 |
51 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '8.0.0' apply false
4 | id 'com.android.library' version '8.0.0' apply false
5 | id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
6 | }
7 |
8 | task clean(type: Delete) {
9 | delete rootProject.buildDir
10 | }
11 |
12 | ext {
13 | kotlin_version = "1.7.20"
14 | retrofitVersion = '2.9.0'
15 | okHttp3Version = '4.5.0'
16 | rxBindingVersion = '2.2.0'
17 | dagger2Version = '2.45'
18 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 | org.gradle.unsafe.configuration-cache = true
23 | android.defaults.buildfeatures.buildconfig = true
24 | android.nonTransitiveRClass = false
25 | android.nonFinalResIds = false
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Aug 01 11:57:48 YEKT 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Fri Jan 22 15:32:23 YEKT 2021
8 | sdk.dir=/Users/a.ignatov/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/sdk/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/sdk/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-parcelize'
5 | id 'kotlin-kapt'
6 | }
7 |
8 | android {
9 | compileSdkVersion 33
10 |
11 | defaultConfig {
12 | minSdkVersion 23
13 | targetSdkVersion 33
14 | multiDexEnabled false
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | viewBinding {
21 | enabled = true
22 | }
23 |
24 | buildTypes {
25 | debug {
26 | minifyEnabled true
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | consumerProguardFiles 'proguard-rules.pro'
29 | }
30 | release {
31 | minifyEnabled true
32 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
33 | consumerProguardFiles 'proguard-rules.pro'
34 | }
35 | }
36 |
37 | compileOptions {
38 | sourceCompatibility JavaVersion.VERSION_17
39 | targetCompatibility JavaVersion.VERSION_17
40 | }
41 |
42 | kotlinOptions {
43 | jvmTarget = JavaVersion.VERSION_17.toString()
44 | }
45 | namespace 'ru.cloudpayments.sdk'
46 | }
47 |
48 | dependencies {
49 | implementation fileTree(dir: "libs", include: ["*.jar"])
50 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
51 | implementation 'androidx.core:core-ktx:1.9.0'
52 | implementation 'androidx.appcompat:appcompat:1.6.1'
53 |
54 | implementation 'com.google.android.material:material:1.8.0'
55 | implementation 'androidx.cardview:cardview:1.0.0'
56 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
57 | implementation 'androidx.fragment:fragment-ktx:1.5.7'
58 | implementation 'androidx.arch.core:core-runtime:2.2.0'
59 |
60 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
61 |
62 | implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
63 | implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
64 | implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
65 | implementation "com.squareup.okhttp3:okhttp:$okHttp3Version"
66 | implementation "com.squareup.okhttp3:logging-interceptor:$okHttp3Version"
67 |
68 | implementation 'ru.tinkoff.decoro:decoro:1.5.0'
69 |
70 | implementation 'org.jsoup:jsoup:1.13.1'
71 |
72 | // rxkotlin
73 | implementation 'io.reactivex.rxjava2:rxkotlin:2.1.0'
74 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
75 | implementation "com.jakewharton.rxbinding2:rxbinding-kotlin:$rxBindingVersion"
76 |
77 | implementation 'com.google.android.gms:play-services-wallet:19.1.0'
78 |
79 | //Multidex support
80 | implementation 'androidx.multidex:multidex:2.0.1'
81 |
82 | // dagger2
83 | implementation "com.google.dagger:dagger:$dagger2Version"
84 | implementation "com.google.dagger:dagger-android:$dagger2Version"
85 | implementation "com.google.dagger:dagger-android-support:$dagger2Version"
86 | kapt "com.google.dagger:dagger-compiler:$dagger2Version"
87 | kapt "com.google.dagger:dagger-android-processor:$dagger2Version"
88 |
89 | //rx google-play-services
90 | implementation 'io.ashdavies.rx.rxtasks:rx-tasks:2.2.0'
91 |
92 | // yandex pay
93 | implementation 'com.yandex.pay:core:0.2.2'
94 | }
--------------------------------------------------------------------------------
/sdk/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/consumer-rules.pro
--------------------------------------------------------------------------------
/sdk/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | # com.squareup.retrofit2
24 | -dontwarn javax.annotation.**
25 | -dontwarn retrofit2.**
26 | -keep, includedescriptorclasses class retrofit2.** { *; }
27 | -keepattributes Signature
28 | -keepattributes Exceptions
29 | -keepclasseswithmembers class * {
30 | @retrofit2.http.* ;
31 | }
32 |
33 | # com.squareup.okhttp3
34 | -keepattributes Signature
35 | -keepattributes *Annotation*
36 | -keep, includedescriptorclasses class okhttp3.** { *; }
37 | -keep interface okhttp3.** { *; }
38 | -dontwarn okhttp3.**
39 | -keep class okhttp3.internal.platform.** { *; }
40 | -dontwarn okhttp3.internal.platform.**
41 | -dontnote okhttp3.internal.platform.**
42 |
43 | # com.google.gson
44 | -keep class com.google.gson.internal.** { *; }
45 | -dontwarn com.google.gson.internal.**
46 | -dontnote com.google.gson.internal.**
47 |
48 | # ru.cloudpayments.sdk
49 | -keep class ru.cloudpayments.sdk.** { *; }
50 | -dontwarn ru.cloudpayments.sdk.**
51 | -dontnote ru.cloudpayments.sdk.**
52 |
53 |
54 | # Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
55 | # EnclosingMethod is required to use InnerClasses.
56 | -keepattributes Signature, InnerClasses, EnclosingMethod
57 |
58 | # Retrofit does reflection on method and parameter annotations.
59 | -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
60 |
61 | # Keep annotation default values (e.g., retrofit2.http.Field.encoded).
62 | -keepattributes AnnotationDefault
63 |
64 | # Retain service method parameters when optimizing.
65 | -keepclassmembers,allowshrinking,allowobfuscation interface * {
66 | @retrofit2.http.* ;
67 | }
68 |
69 | # Ignore annotation used for build tooling.
70 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
71 |
72 | # Ignore JSR 305 annotations for embedding nullability information.
73 | -dontwarn javax.annotation.**
74 |
75 | # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
76 | -dontwarn kotlin.Unit
77 |
78 | # Top-level functions that can only be used by Kotlin.
79 | -dontwarn retrofit2.KotlinExtensions
80 | -dontwarn retrofit2.KotlinExtensions$*
81 |
82 | # With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
83 | # and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
84 | -if interface * { @retrofit2.http.* ; }
85 | -keep,allowobfuscation interface <1>
86 |
87 | # Keep inherited services.
88 | -if interface * { @retrofit2.http.* ; }
89 | -keep,allowobfuscation interface * extends <1>
90 |
91 | # With R8 full mode generic signatures are stripped for classes that are not
92 | # kept. Suspend functions are wrapped in continuations where the type argument
93 | # is used.
94 | -keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
95 |
96 | # R8 full mode strips generic signatures from return types if not kept.
97 | -if interface * { @retrofit2.http.* public *** *(...); }
98 | -keep,allowoptimization,allowshrinking,allowobfuscation class <3>
99 |
100 |
101 | # JSR 305 annotations are for embedding nullability information.
102 | -dontwarn javax.annotation.**
103 |
104 | # A resource is loaded with a relative path so the package of this class must be preserved.
105 | -adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz
106 |
107 | # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
108 | -dontwarn org.codehaus.mojo.animal_sniffer.*
109 |
110 | # OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
111 | -dontwarn okhttp3.internal.platform.**
112 | -dontwarn org.conscrypt.**
113 | -dontwarn org.bouncycastle.**
114 | -dontwarn org.openjsse.**
--------------------------------------------------------------------------------
/sdk/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/Constants.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk
2 |
3 | class Constants {
4 | companion object {
5 | const val baseApiUrl = "https://api.cloudpayments.ru/"
6 | }
7 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/AuthenticationInterceptor.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api
2 |
3 | import okhttp3.HttpUrl
4 | import okhttp3.Interceptor
5 | import okhttp3.Request
6 | import okhttp3.Response
7 | import java.io.IOException
8 |
9 | class AuthenticationInterceptor (private val publicId: String) : Interceptor {
10 |
11 | @Throws(IOException::class)
12 | override fun intercept(chain: Interceptor.Chain): Response {
13 | val original: Request = chain.request()
14 | val originalHttpUrl: HttpUrl = original.url
15 |
16 | val builder = originalHttpUrl.newBuilder()
17 | builder.addQueryParameter("publicId", publicId)
18 |
19 | val url = builder.build()
20 |
21 | val requestBuilder: Request.Builder = original.newBuilder()
22 | .url(url)
23 |
24 | val request: Request = requestBuilder.build()
25 | return chain.proceed(request)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/CloudpaymentsApi.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api
2 |
3 | import android.net.Uri
4 | import com.google.gson.Gson
5 | import io.reactivex.Single
6 | import io.reactivex.schedulers.Schedulers
7 | import retrofit2.HttpException
8 | import ru.cloudpayments.sdk.api.models.*
9 | import java.net.URLDecoder
10 | import javax.inject.Inject
11 |
12 | class CloudpaymentsApi @Inject constructor(private val apiService: CloudpaymentsApiService) {
13 | companion object {
14 | private const val THREE_DS_SUCCESS_URL = "https://api.cloudpayments.ru/threeds/success"
15 | private const val THREE_DS_FAIL_URL = "https://api.cloudpayments.ru/threeds/fail"
16 | }
17 |
18 | fun getPublicKey(): Single {
19 | return apiService.getPublicKey()
20 | .subscribeOn(Schedulers.io())
21 | }
22 |
23 | fun getMerchantConfiguration(publicId: String): Single {
24 | return apiService.getMerchantConfiguration(publicId)
25 | .subscribeOn(Schedulers.io())
26 | }
27 |
28 | fun charge(requestBody: PaymentRequestBody): Single {
29 | return apiService.charge(requestBody)
30 | .subscribeOn(Schedulers.io())
31 | }
32 |
33 | fun auth(requestBody: PaymentRequestBody): Single {
34 | return apiService.auth(requestBody)
35 | .subscribeOn(Schedulers.io())
36 | }
37 |
38 | fun postThreeDs(transactionId: String, threeDsCallbackId: String, paRes: String): Single {
39 | val md = ThreeDsMdData(transactionId = transactionId, threeDsCallbackId = threeDsCallbackId, successURL = THREE_DS_SUCCESS_URL, failURL = THREE_DS_FAIL_URL)
40 | val mdString = Gson().toJson(md)
41 | return apiService.postThreeDs(ThreeDsRequestBody(md = mdString, paRes = paRes))
42 | .subscribeOn(Schedulers.io())
43 | .map { CloudpaymentsThreeDsResponse(true, "", 0) }
44 | .onErrorReturn {
45 | val response: CloudpaymentsThreeDsResponse = if (it is HttpException && it.response()?.raw()!!.isRedirect) {
46 | val url = it.response()?.raw()?.header("Location")
47 | when {
48 | url?.startsWith(THREE_DS_FAIL_URL) == true -> {
49 | val uri = Uri.parse(url)
50 | val cardholderMessage = uri.getQueryParameter("CardHolderMessage")
51 | val reasonCode = uri.getQueryParameter("ReasonCode")?.toIntOrNull()
52 | val message = if (cardholderMessage != null) URLDecoder.decode(cardholderMessage, "utf-8") else ""
53 | CloudpaymentsThreeDsResponse(false, message, reasonCode)
54 | }
55 | url?.startsWith(THREE_DS_SUCCESS_URL) == true -> CloudpaymentsThreeDsResponse(true, null, 0)
56 | else -> CloudpaymentsThreeDsResponse(false, null, null)
57 | }
58 | } else {
59 | CloudpaymentsThreeDsResponse(true, null, 0)
60 | }
61 |
62 | response
63 | }
64 | }
65 |
66 | fun getTinkoffPayQrLink(requestBody: TinkoffPayQrLinkBody): Single {
67 | return apiService.getTinkoffPayQrLink(requestBody)
68 | .subscribeOn(Schedulers.io())
69 | }
70 |
71 | fun qrLinkStatusWait(requestBody: QrLinkStatusWaitBody): Single {
72 | return apiService.qrLinkStatusWait(requestBody)
73 | .subscribeOn(Schedulers.io())
74 | }
75 |
76 | fun getBinInfo(firstSixDigits: String): Single =
77 | if (firstSixDigits.length < 6) {
78 | Single.error(CloudpaymentsTransactionError("You must specify the first 6 digits of the card number"))
79 | } else {
80 | val firstSix = firstSixDigits.subSequence(0, 6).toString()
81 | apiService.getBinInfo(firstSix)
82 | .subscribeOn(Schedulers.io())
83 | .map { it.binInfo ?: CloudpaymentsBinInfo("", "") }
84 | .onErrorReturn { CloudpaymentsBinInfo("", "") }
85 | }
86 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/CloudpaymentsApiService.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api
2 |
3 | import io.reactivex.Single
4 | import retrofit2.http.Body
5 | import retrofit2.http.GET
6 | import retrofit2.http.POST
7 | import retrofit2.http.Path
8 | import retrofit2.http.Query
9 | import ru.cloudpayments.sdk.api.models.CloudpaymentsBinInfoResponse
10 | import ru.cloudpayments.sdk.api.models.CloudpaymentsGetTinkoffPayQrLinkResponse
11 | import ru.cloudpayments.sdk.api.models.CloudpaymentsMerchantConfigurationResponse
12 | import ru.cloudpayments.sdk.api.models.CloudpaymentsPublicKeyResponse
13 | import ru.cloudpayments.sdk.api.models.PaymentRequestBody
14 | import ru.cloudpayments.sdk.api.models.ThreeDsRequestBody
15 | import ru.cloudpayments.sdk.api.models.CloudpaymentsTransactionResponse
16 | import ru.cloudpayments.sdk.api.models.QrLinkStatusWaitBody
17 | import ru.cloudpayments.sdk.api.models.QrLinkStatusWaitResponse
18 | import ru.cloudpayments.sdk.api.models.TinkoffPayQrLinkBody
19 |
20 | interface CloudpaymentsApiService {
21 | @POST("payments/cards/charge")
22 | fun charge(@Body body: PaymentRequestBody): Single
23 |
24 | @POST("payments/cards/auth")
25 | fun auth(@Body body: PaymentRequestBody): Single
26 |
27 | @POST("payments/ThreeDSCallback")
28 | fun postThreeDs(@Body body: ThreeDsRequestBody): Single
29 |
30 | @GET("bins/info/{firstSixDigits}")
31 | fun getBinInfo(@Path("firstSixDigits") firstSixDigits: String): Single
32 |
33 | @GET("payments/publickey")
34 | fun getPublicKey(): Single
35 |
36 | @GET("merchant/configuration")
37 | fun getMerchantConfiguration(@Query("terminalPublicId") publicId: String): Single
38 |
39 | @POST("payments/qr/tinkoffpay/link")
40 | fun getTinkoffPayQrLink(@Body body: TinkoffPayQrLinkBody): Single
41 |
42 | @POST("payments/qr/status/wait")
43 | fun qrLinkStatusWait(@Body body: QrLinkStatusWaitBody): Single
44 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CardCryptogramPacket.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | data class CardCryptogramPacket(
9 | @SerializedName("Type") var type: String? = "CloudCard",
10 | @SerializedName("BrowserInfoBase64") var browserInfoBase64: String? = "",
11 | @SerializedName("CardInfo") var cardInfo: CardInfo?,
12 | @SerializedName("KeyVersion") var keyVersion: String?,
13 | @SerializedName("Format") var format: Int? = 1,
14 | @SerializedName("Value") var value: String?) : Parcelable
15 |
16 | @Parcelize
17 | data class CardInfo(
18 | @SerializedName("FirstSixDigits") var firstSixDigits: String?,
19 | @SerializedName("LastFourDigits") var lastFourDigits: String?,
20 | @SerializedName("ExpDateYear") var expDateYear: String?,
21 | @SerializedName("ExpDateMonth") var expDateMonth: String?) :Parcelable
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsBinInfoResponse.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class CloudpaymentsBinInfoResponse(
6 | @SerializedName("Success") val success: Boolean?,
7 | @SerializedName("Message") val message: String?,
8 | @SerializedName("Model") val binInfo: CloudpaymentsBinInfo?)
9 |
10 | data class CloudpaymentsBinInfo(
11 | @SerializedName("LogoUrl") val logoUrl: String?,
12 | @SerializedName("BankName") val bankName: String?)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsGetTinkoffPayQrLinkResponse.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 | import io.reactivex.Observable
5 |
6 | data class CloudpaymentsGetTinkoffPayQrLinkResponse(
7 | @SerializedName("Success") val success: Boolean?,
8 | @SerializedName("Message") val message: String?,
9 | @SerializedName("Model") val transaction: CloudpaymentsTinkoffPayQrLinkTransaction?) {
10 | fun handleError(): Observable {
11 | return if (success == true ) {
12 | Observable.just(this)
13 | } else {
14 | Observable.error(CloudpaymentsTransactionError(message ?: ""))
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsMerchantConfigurationResponse.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class CloudpaymentsMerchantConfigurationResponse(
6 | @SerializedName("Success") val success: Boolean?,
7 | @SerializedName("Message") val message: String?,
8 | @SerializedName("Model") val model: MerchantConfiguration?
9 | )
10 |
11 | data class MerchantConfiguration(
12 | @SerializedName("ExternalPaymentMethods") val externalPaymentMethods: ArrayList?,
13 | @SerializedName("Features") val features: Features?
14 | )
15 |
16 | data class ExternalPaymentMethods(
17 | @SerializedName("Type") val type: Int?,
18 | @SerializedName("Enabled") val enabled: Boolean?
19 | )
20 |
21 | data class Features(
22 | @SerializedName("IsSaveCard") val isSaveCard: Int?
23 | )
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsPublicKeyResponse.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class CloudpaymentsPublicKeyResponse(
6 | @SerializedName("Pem") val pem: String?,
7 | @SerializedName("Version") val version: Int?)
8 |
9 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsThreeDsResponse.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | data class CloudpaymentsThreeDsResponse(val success: Boolean, val message: String?, val reasonCode: Int?)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsTinkoffPayQrLinkTransaction.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class CloudpaymentsTinkoffPayQrLinkTransaction(
6 | @SerializedName("TransactionId") val transactionId: Int?,
7 | @SerializedName("ProviderQrId") val providerQrId: String?,
8 | @SerializedName("QrUrl") val qrUrl: String?)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsTransaction.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class CloudpaymentsTransaction(
6 | @SerializedName("TransactionId") val transactionId: Int?,
7 | @SerializedName("ReasonCode") val reasonCode: Int?,
8 | @SerializedName("CardHolderMessage") val cardHolderMessage: String?,
9 | @SerializedName("PaReq") val paReq: String?,
10 | @SerializedName("AcsUrl") val acsUrl: String?,
11 | @SerializedName("ThreeDsCallbackId") val threeDsCallbackId: String?)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsTransactionError.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | class CloudpaymentsTransactionError(override val message: String): Throwable()
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/CloudpaymentsTransactionResponse.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 | import io.reactivex.Observable
5 |
6 | data class CloudpaymentsTransactionResponse(
7 | @SerializedName("Success") val success: Boolean?,
8 | @SerializedName("Message") val message: String?,
9 | @SerializedName("Model") val transaction: CloudpaymentsTransaction?) {
10 | fun handleError(): Observable {
11 | return if (success == true || (!transaction?.acsUrl.isNullOrEmpty() && !transaction?.paReq.isNullOrEmpty())){
12 | Observable.just(this)
13 | } else {
14 | Observable.error(CloudpaymentsTransactionError(message ?: transaction?.cardHolderMessage.orEmpty()))
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/PaymentDataPayer.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | data class PaymentDataPayer(
9 | @SerializedName("FirstName") var firstName: String? = null,
10 | @SerializedName("LastName") var lastName: String? = null,
11 | @SerializedName("MiddleName") var middleName: String? = null,
12 | @SerializedName("Birth") var birthDay: String? = null,
13 | @SerializedName("Address") var address: String? = null,
14 | @SerializedName("Street") var street: String? = null,
15 | @SerializedName("City") var city: String? = null,
16 | @SerializedName("Country") var country: String? = null,
17 | @SerializedName("Phone") var phone: String? = null,
18 | @SerializedName("Postcode") var postcode: String? = null) : Parcelable
19 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/PaymentRequestBody.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class PaymentRequestBody(
6 | @SerializedName("Amount") val amount: String, // Сумма (Обязательный)
7 | @SerializedName("Currency") val currency: String, // Валюта (Обязательный)
8 | @SerializedName("IpAddress") val ipAddress: String, // IP адрес плательщика (Обязательный)
9 | @SerializedName("Name") val name: String, // Имя держателя карты в латинице (Обязательный для всех платежей кроме Apple Pay и Google Pay)
10 | @SerializedName("CardCryptogramPacket") val cryptogram: String, // Криптограмма платежных данных (Обязательный)
11 | @SerializedName("InvoiceId") val invoiceId: String? = null, // Номер счета или заказа в вашей системе (необязательный)
12 | @SerializedName("Description") val description: String? = null, // Описание оплаты в свободной форме (необязательный)
13 | @SerializedName("AccountId") val accountId: String? = null, // Идентификатор пользователя в вашей системе (необязательный)
14 | @SerializedName("Email") val email: String? = null, // E-mail, на который будет отправлена квитанция об оплате)
15 | @SerializedName("Payer") val payer: PaymentDataPayer? = null, // Доп. поле, куда передается информация о плательщике. Используйте следующие параметры: FirstName, LastName, MiddleName, Birth, Street, Address, City, Country, Phone, Postcode
16 | @SerializedName("JsonData") val jsonData: String? = null, //"{\"age\":27,\"name\":\"Ivan\",\"phone\":\"+79998881122\"}" Любые другие данные, которые будут связаны с транзакцией (необязательный)
17 | @SerializedName("scenario") val scenario: Int = 7)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/QrLinkStatusWait.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class QrLinkStatusWait(
6 | @SerializedName("TransactionId") val transactionId: Int?,
7 | @SerializedName("Status") val status: String?,
8 | @SerializedName("StatusCode") val statusCode: String?)
9 |
10 |
11 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/QrLinkStatusWaitBody.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class QrLinkStatusWaitBody(
6 | @SerializedName("TransactionId") val transactionId: Int)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/QrLinkStatusWaitResponse.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 | import io.reactivex.Observable
5 |
6 | data class QrLinkStatusWaitResponse(
7 | @SerializedName("Success") val success: Boolean?,
8 | @SerializedName("Message") val message: String?,
9 | @SerializedName("Model") val transaction: QrLinkStatusWait?) {
10 | fun handleError(): Observable {
11 | return if (success == true ){
12 | Observable.just(this)
13 | } else {
14 | Observable.error(CloudpaymentsTransactionError(message ?: ""))
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/ThreeDsMdData.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 | import java.io.Serializable
5 |
6 | data class ThreeDsMdData(
7 | @SerializedName("TransactionId") val transactionId: String,
8 | @SerializedName("ThreeDsCallbackId") val threeDsCallbackId: String,
9 | @SerializedName("SuccessUrl") val successURL: String,
10 | @SerializedName("FailUrl") val failURL: String): Serializable
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/ThreeDsRequestBody.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class ThreeDsRequestBody(
6 | @SerializedName("MD") val md: String,
7 | @SerializedName("PaRes") val paRes: String)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/api/models/TinkoffPayQrLinkBody.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.api.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class TinkoffPayQrLinkBody(
6 | @SerializedName("Webview") val webView: Boolean = true, // Мобильное устройство
7 | @SerializedName("Device") val device: String = "MobileApp", // Вызов из мобильных приложений
8 | @SerializedName("Amount") val amount: String, // Сумма
9 | @SerializedName("Currency") val currency: String, // Валюта
10 | @SerializedName("Description") val description: String? = null, // Описание платежа
11 | @SerializedName("AccountId") val accountId: String? = null, // Identity плательщика в системе мерчанта
12 | @SerializedName("Email") val email: String? = null, // E-mail плательщика
13 | @SerializedName("JsonData") val jsonData: String? = null, // Произвольные данные мерчанта в формате JSON
14 | @SerializedName("InvoiceId") val invoiceId: String? = null, // id заказа в системе мерчанта
15 | @SerializedName("Scheme") val scheme: String, // charge - одностадийная оплата, auth - двухстадийная оплата (Scheme":"0")
16 | @SerializedName("TtlMinutes") val ttlMinutes: Int = 30, // Время жизни Qr
17 | @SerializedName("SuccessRedirectUrl") val successRedirectUrl: String = "https://cp.ru", // Url успешной оплаты (мерчанта)
18 | @SerializedName("FailRedirectUrl") val failRedirectUrl: String = "https://cp.ru", // Url неуспешной оплаты (мерчанта)
19 | @SerializedName("SaveCard") var saveCard: Boolean? = null)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/card/CardType.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.card
2 |
3 | import ru.cloudpayments.sdk.R
4 | import java.util.*
5 |
6 | enum class CardType {
7 | UNKNOWN,
8 | VISA,
9 | MASTER_CARD,
10 | MAESTRO,
11 | MIR,
12 | JCB;
13 |
14 | companion object {
15 | fun fromString(value: String): CardType = when(value.toLowerCase(Locale.getDefault())){
16 | "visa" -> VISA
17 | "mastercard" -> MASTER_CARD
18 | "maestro" -> MAESTRO
19 | "mir" -> MIR
20 | "jcb" -> JCB
21 | else -> UNKNOWN
22 | }
23 |
24 | fun getType(cardNumber: String?): CardType {
25 | if (cardNumber == null || cardNumber.isEmpty()) return UNKNOWN
26 | val first = Integer.valueOf(cardNumber.substring(0, 1))
27 | if (first == 4) return VISA
28 | if (first == 6) return MAESTRO
29 | if (cardNumber.length < 2) return UNKNOWN
30 | val firstTwo = Integer.valueOf(cardNumber.substring(0, 2))
31 | if (firstTwo == 35) return JCB
32 | if (firstTwo == 50 || (firstTwo in 56..58)) return MAESTRO
33 | if (firstTwo in 51..55) return MASTER_CARD
34 | if (cardNumber.length < 4) return UNKNOWN
35 | val firstFour = Integer.valueOf(cardNumber.substring(0, 4))
36 | if (firstFour in 2200..2204) return MIR
37 | return if (firstFour in 2221..2720) MASTER_CARD else UNKNOWN
38 | }
39 | }
40 |
41 | override fun toString(): String {
42 | return when (this) {
43 | VISA -> "Visa"
44 | MASTER_CARD -> "MasterCard"
45 | MAESTRO -> "Maestro"
46 | MIR -> "MIR"
47 | JCB -> "JCB"
48 | else -> "Unknown"
49 | }
50 | }
51 |
52 | fun getIconRes(): Int? = when (this) {
53 | VISA -> R.drawable.cpsdk_ic_ps_visa
54 | MASTER_CARD -> R.drawable.cpsdk_ic_ps_mastercard
55 | MAESTRO -> R.drawable.cpsdk_ic_ps_maestro
56 | MIR -> R.drawable.cpsdk_ic_ps_mir
57 | JCB -> R.drawable.cpsdk_ic_ps_jcb
58 | else -> null
59 | }
60 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/configuration/CloudPaymentsIntentSender.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.configuration
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import androidx.activity.result.contract.ActivityResultContract
7 | import ru.cloudpayments.sdk.models.Transaction
8 |
9 | internal class CloudPaymentsIntentSender : ActivityResultContract() {
10 | override fun createIntent(context: Context, input: PaymentConfiguration): Intent {
11 | return CloudpaymentsSDK.getInstance().getStartIntent(context, input)
12 | }
13 |
14 | override fun parseResult(resultCode: Int, intent: Intent?): Transaction {
15 | if (resultCode == Activity.RESULT_OK) {
16 | val id = intent?.getIntExtra(CloudpaymentsSDK.IntentKeys.TransactionId.name, 0) ?: 0
17 | val status = intent?.getSerializableExtra(CloudpaymentsSDK.IntentKeys.TransactionStatus.name) as? CloudpaymentsSDK.TransactionStatus
18 | val reasonCode = intent?.getIntExtra(CloudpaymentsSDK.IntentKeys.TransactionReasonCode.name, 0) ?: 0
19 |
20 | return Transaction(id, status, reasonCode)
21 | }
22 |
23 | return Transaction(0, null, 0)
24 | }
25 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/configuration/CloudpaymentsSDK.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.configuration
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import androidx.activity.result.ActivityResultLauncher
6 | import androidx.appcompat.app.AppCompatActivity
7 | import androidx.fragment.app.Fragment
8 | import androidx.fragment.app.FragmentActivity
9 | import com.yandex.pay.core.YandexPayEnvironment
10 | import com.yandex.pay.core.YandexPayLib
11 | import com.yandex.pay.core.YandexPayLibConfig
12 | import com.yandex.pay.core.YandexPayLocale
13 | import com.yandex.pay.core.data.Merchant
14 | import com.yandex.pay.core.data.MerchantId
15 | import okhttp3.OkHttpClient
16 | import okhttp3.logging.HttpLoggingInterceptor
17 | import retrofit2.Retrofit
18 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
19 | import retrofit2.converter.gson.GsonConverterFactory
20 | import ru.cloudpayments.sdk.Constants
21 | import ru.cloudpayments.sdk.api.AuthenticationInterceptor
22 | import ru.cloudpayments.sdk.api.CloudpaymentsApiService
23 | import ru.cloudpayments.sdk.api.CloudpaymentsApi
24 | import ru.cloudpayments.sdk.models.Transaction
25 | import ru.cloudpayments.sdk.ui.PaymentActivity
26 | import java.util.concurrent.TimeUnit
27 |
28 | interface CloudpaymentsSDK {
29 | fun start(configuration: PaymentConfiguration, from: AppCompatActivity, requestCode: Int)
30 | fun launcher(from: AppCompatActivity, result: (Transaction) -> Unit) : ActivityResultLauncher
31 | fun launcher(from: FragmentActivity, result: (Transaction) -> Unit) : ActivityResultLauncher
32 | fun launcher(from: Fragment, result: (Transaction) -> Unit) : ActivityResultLauncher
33 |
34 | fun getStartIntent(context: Context, configuration: PaymentConfiguration): Intent
35 |
36 | enum class TransactionStatus {
37 | Succeeded,
38 | Failed;
39 | }
40 | enum class IntentKeys {
41 | TransactionId,
42 | TransactionStatus,
43 | TransactionReasonCode;
44 | }
45 |
46 | companion object {
47 |
48 | fun initialize(context: Context, yandexPayAppId: String, yandexPaySandboxMode: Boolean) {
49 | if (YandexPayLib.isSupported) {
50 | YandexPayLib.initialize(
51 | context = context,
52 | config = YandexPayLibConfig(
53 | merchantDetails = Merchant(
54 | id = MerchantId.from(yandexPayAppId),
55 | name = "Cloud",
56 | url = "https://cp.ru/",
57 | ),
58 | environment = if (yandexPaySandboxMode) YandexPayEnvironment.SANDBOX else YandexPayEnvironment.PROD,
59 | locale = YandexPayLocale.SYSTEM,
60 | logging = false
61 | )
62 | )
63 | }
64 | }
65 |
66 | fun getInstance(): CloudpaymentsSDK {
67 | return CloudpaymentsSDKImpl()
68 | }
69 |
70 | fun createApi(publicId: String) = CloudpaymentsApi(createService(publicId))
71 |
72 | private fun createService(publicId: String): CloudpaymentsApiService {
73 | val retrofit = Retrofit.Builder()
74 | .baseUrl(Constants.baseApiUrl)
75 | .addConverterFactory(GsonConverterFactory.create())
76 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
77 | .client(createClient(publicId))
78 | .build()
79 |
80 | return retrofit.create(CloudpaymentsApiService::class.java)
81 | }
82 |
83 | private fun createClient(publicId: String?): OkHttpClient {
84 | val okHttpClientBuilder = OkHttpClient.Builder()
85 | .addInterceptor(HttpLoggingInterceptor()
86 | .setLevel(HttpLoggingInterceptor.Level.BODY))
87 | val client = okHttpClientBuilder
88 | .connectTimeout(20, TimeUnit.SECONDS)
89 | .readTimeout(20, TimeUnit.SECONDS)
90 | .followRedirects(false)
91 |
92 | if (publicId != null){
93 | client.addInterceptor(AuthenticationInterceptor(publicId))
94 | }
95 |
96 | return client.build()
97 | }
98 | }
99 | }
100 |
101 | internal class CloudpaymentsSDKImpl: CloudpaymentsSDK {
102 | override fun start(configuration: PaymentConfiguration, from: AppCompatActivity, requestCode: Int) {
103 | from.startActivityForResult(this.getStartIntent(from, configuration), requestCode)
104 | }
105 |
106 | override fun launcher(
107 | from: AppCompatActivity,
108 | result: (Transaction) -> Unit): ActivityResultLauncher {
109 | return from.registerForActivityResult(CloudPaymentsIntentSender(), result)
110 | }
111 |
112 | override fun launcher(
113 | from: FragmentActivity,
114 | result: (Transaction) -> Unit): ActivityResultLauncher {
115 | return from.registerForActivityResult(CloudPaymentsIntentSender(), result)
116 | }
117 |
118 | override fun launcher(
119 | from: Fragment,
120 | result: (Transaction) -> Unit
121 | ): ActivityResultLauncher {
122 | return from.registerForActivityResult(CloudPaymentsIntentSender(), result)
123 | }
124 |
125 | override fun getStartIntent(context: Context, configuration: PaymentConfiguration): Intent {
126 | return PaymentActivity.getStartIntent(context, configuration)
127 | }
128 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/configuration/PaymentConfiguration.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.configuration
2 |
3 | import android.os.Parcelable
4 | import kotlinx.android.parcel.Parcelize
5 | import ru.cloudpayments.sdk.scanner.CardScanner
6 |
7 | @Parcelize
8 | data class PaymentConfiguration(val publicId: String,
9 | val paymentData: PaymentData,
10 | val scanner: CardScanner?,
11 | val requireEmail: Boolean = false,
12 | val useDualMessagePayment: Boolean = false,
13 | val disableGPay: Boolean = false,
14 | val disableYandexPay: Boolean = false,
15 | val yandexPayMerchantID: String = "",
16 | val apiUrl: String = ""): Parcelable
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/configuration/PaymentData.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.configuration
2 |
3 | import android.os.Parcelable
4 | import android.util.Log
5 | import com.google.gson.GsonBuilder
6 | import com.google.gson.JsonSyntaxException
7 | import com.google.gson.annotations.SerializedName
8 | import kotlinx.android.parcel.Parcelize
9 | import ru.cloudpayments.sdk.Constants
10 | import ru.cloudpayments.sdk.api.models.PaymentDataPayer
11 | import ru.cloudpayments.sdk.util.TAG
12 |
13 | @Parcelize
14 | class PaymentData(
15 | val amount: String,
16 | var currency: String = "RUB",
17 | val invoiceId: String? = null,
18 | val description: String? = null,
19 | val accountId: String? = null,
20 | var email: String? = null,
21 | val payer: PaymentDataPayer? = null,
22 | val jsonData: String? = null
23 | ) : Parcelable {
24 |
25 | fun jsonDataHasRecurrent(): Boolean {
26 |
27 | if (!jsonData.isNullOrEmpty()) {
28 | val gson = GsonBuilder()
29 | .setLenient()
30 | .create()
31 |
32 | try {
33 | val cpJsonData = gson.fromJson(jsonData, CpJsonData::class.java)
34 | cpJsonData.cloudPayments?.recurrent?.interval?.let {
35 | return true
36 | }
37 | } catch (e: JsonSyntaxException) {
38 | Log.e(TAG, "JsonData syntax error")
39 | }
40 | }
41 | return false
42 | }
43 | }
44 |
45 | data class CpJsonData(
46 | @SerializedName("cloudPayments") val cloudPayments: CloudPaymentsJsonData?
47 | )
48 |
49 | data class CloudPaymentsJsonData(
50 | @SerializedName("recurrent") val recurrent: CloudPaymentsRecurrentJsonData?
51 | )
52 |
53 | data class CloudPaymentsRecurrentJsonData(
54 | @SerializedName("interval") val interval: String?,
55 | @SerializedName("period") val period: String?,
56 | @SerializedName("amount") val amount: String?
57 | )
58 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/dagger2/CloudpaymentsModule.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.dagger2
2 |
3 | import dagger.Component
4 | import dagger.Module
5 | import dagger.Provides
6 | import okhttp3.OkHttpClient
7 | import okhttp3.logging.HttpLoggingInterceptor
8 | import retrofit2.Retrofit
9 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
10 | import retrofit2.converter.gson.GsonConverterFactory
11 | import ru.cloudpayments.sdk.Constants
12 | import ru.cloudpayments.sdk.api.AuthenticationInterceptor
13 | import ru.cloudpayments.sdk.api.CloudpaymentsApiService
14 | import ru.cloudpayments.sdk.api.CloudpaymentsApi
15 | import ru.cloudpayments.sdk.viewmodel.PaymentCardViewModel
16 | import ru.cloudpayments.sdk.viewmodel.PaymentOptionsViewModel
17 | import ru.cloudpayments.sdk.viewmodel.PaymentProcessViewModel
18 | import java.util.concurrent.TimeUnit
19 | import javax.inject.Singleton
20 |
21 | @Module
22 | class CloudpaymentsModule {
23 | @Provides
24 | @Singleton
25 | fun provideRepository(apiService: CloudpaymentsApiService)
26 | = CloudpaymentsApi(apiService)
27 | }
28 |
29 | @Module
30 | class CloudpaymentsNetModule(private val publicId: String, private var apiUrl: String = Constants.baseApiUrl) {
31 | @Provides
32 | @Singleton
33 | fun providesHttpLoggingInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor()
34 | .setLevel(HttpLoggingInterceptor.Level.BODY)
35 |
36 | @Provides
37 | @Singleton
38 | fun providesAuthenticationInterceptor(): AuthenticationInterceptor
39 | = AuthenticationInterceptor(publicId)
40 |
41 | @Provides
42 | @Singleton
43 | fun provideOkHttpClientBuilder(loggingInterceptor: HttpLoggingInterceptor): OkHttpClient.Builder
44 | = OkHttpClient.Builder()
45 | .addInterceptor(loggingInterceptor)
46 |
47 | @Provides
48 | @Singleton
49 | fun provideApiService(okHttpClientBuilder: OkHttpClient.Builder,
50 | authenticationInterceptor: AuthenticationInterceptor): CloudpaymentsApiService {
51 | val client = okHttpClientBuilder
52 | .addInterceptor(authenticationInterceptor)
53 | .connectTimeout(60, TimeUnit.SECONDS)
54 | .readTimeout(60, TimeUnit.SECONDS)
55 | .followRedirects(false)
56 | .build()
57 |
58 | if (apiUrl.isEmpty())
59 | apiUrl = Constants.baseApiUrl
60 |
61 | val retrofit = Retrofit.Builder()
62 | .baseUrl(apiUrl)
63 | .addConverterFactory(GsonConverterFactory.create())
64 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
65 | .client(client)
66 | .build()
67 |
68 | return retrofit.create(CloudpaymentsApiService::class.java)
69 | }
70 | }
71 |
72 | @Singleton
73 | @Component(modules = [CloudpaymentsModule::class, CloudpaymentsNetModule::class])
74 | internal interface CloudpaymentsComponent {
75 | fun inject(optionsViewModel: PaymentOptionsViewModel)
76 | fun inject(cardViewModel: PaymentCardViewModel)
77 | fun inject(processViewModel: PaymentProcessViewModel)
78 | }
79 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/models/ApiError.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.models
2 |
3 | import android.content.Context
4 | import ru.cloudpayments.sdk.R
5 |
6 | class ApiError {
7 |
8 | companion object {
9 |
10 | fun getFullErrorDescription(context: Context, code: String): String {
11 | var error = getErrorDescription(context, code)
12 | var errorExtra = getErrorDescriptionExtra(context, code)
13 | return "$error. $errorExtra"
14 | }
15 |
16 | fun getErrorDescription(context: Context, code: String): String {
17 | return when(code) {
18 | "3001" -> context.getString(R.string.cpsdk_error_3001)
19 | "3002" -> context.getString(R.string.cpsdk_error_3002)
20 | "3003" -> context.getString(R.string.cpsdk_error_3003)
21 | "3004" -> context.getString(R.string.cpsdk_error_3004)
22 | "3005" -> context.getString(R.string.cpsdk_error_3005)
23 | "3006" -> context.getString(R.string.cpsdk_error_3006)
24 | "3007" -> context.getString(R.string.cpsdk_error_3007)
25 | "3008" -> context.getString(R.string.cpsdk_error_3008)
26 | "5001" -> context.getString(R.string.cpsdk_error_5001)
27 | "5005" -> context.getString(R.string.cpsdk_error_5005)
28 | "5006" -> context.getString(R.string.cpsdk_error_5006)
29 | "5012" -> context.getString(R.string.cpsdk_error_5012)
30 | "5013" -> context.getString(R.string.cpsdk_error_5013)
31 | "5030" -> context.getString(R.string.cpsdk_error_5030)
32 | "5031" -> context.getString(R.string.cpsdk_error_5031)
33 | "5034" -> context.getString(R.string.cpsdk_error_5034)
34 | "5041" -> context.getString(R.string.cpsdk_error_5041)
35 | "5043" -> context.getString(R.string.cpsdk_error_5043)
36 | "5051" -> context.getString(R.string.cpsdk_error_5051)
37 | "5054" -> context.getString(R.string.cpsdk_error_5054)
38 | "5057" -> context.getString(R.string.cpsdk_error_5057)
39 | "5065" -> context.getString(R.string.cpsdk_error_5065)
40 | "5082" -> context.getString(R.string.cpsdk_error_5082)
41 | "5091" -> context.getString(R.string.cpsdk_error_5091)
42 | "5092" -> context.getString(R.string.cpsdk_error_5092)
43 | "5096" -> context.getString(R.string.cpsdk_error_5096)
44 | "5204" -> context.getString(R.string.cpsdk_error_5204)
45 | "5206" -> context.getString(R.string.cpsdk_error_5206)
46 | "5207" -> context.getString(R.string.cpsdk_error_5207)
47 | "5300" -> context.getString(R.string.cpsdk_error_5300)
48 | else -> context.getString(R.string.cpsdk_error_5204)
49 | }
50 | }
51 |
52 | fun getErrorDescriptionExtra(context: Context, code: String): String {
53 | return when(code) {
54 | "3001" -> context.getString(R.string.cpsdk_error_3001_extra)
55 | "3002" -> context.getString(R.string.cpsdk_error_3002_extra)
56 | "3003" -> context.getString(R.string.cpsdk_error_3003_extra)
57 | "3004" -> context.getString(R.string.cpsdk_error_3004_extra)
58 | "3005" -> context.getString(R.string.cpsdk_error_3005_extra)
59 | "3006" -> context.getString(R.string.cpsdk_error_3006_extra)
60 | "3007" -> context.getString(R.string.cpsdk_error_3007_extra)
61 | "3008" -> context.getString(R.string.cpsdk_error_3008_extra)
62 | "5001" -> context.getString(R.string.cpsdk_error_5001_extra)
63 | "5005" -> context.getString(R.string.cpsdk_error_5005_extra)
64 | "5006" -> context.getString(R.string.cpsdk_error_5006_extra)
65 | "5012" -> context.getString(R.string.cpsdk_error_5012_extra)
66 | "5013" -> context.getString(R.string.cpsdk_error_5013_extra)
67 | "5030" -> context.getString(R.string.cpsdk_error_5030_extra)
68 | "5031" -> context.getString(R.string.cpsdk_error_5031_extra)
69 | "5034" -> context.getString(R.string.cpsdk_error_5034_extra)
70 | "5041" -> context.getString(R.string.cpsdk_error_5041_extra)
71 | "5043" -> context.getString(R.string.cpsdk_error_5043_extra)
72 | "5051" -> context.getString(R.string.cpsdk_error_5051_extra)
73 | "5054" -> context.getString(R.string.cpsdk_error_5054_extra)
74 | "5057" -> context.getString(R.string.cpsdk_error_5057_extra)
75 | "5065" -> context.getString(R.string.cpsdk_error_5065_extra)
76 | "5082" -> context.getString(R.string.cpsdk_error_5082_extra)
77 | "5091" -> context.getString(R.string.cpsdk_error_5091_extra)
78 | "5092" -> context.getString(R.string.cpsdk_error_5092_extra)
79 | "5096" -> context.getString(R.string.cpsdk_error_5096_extra)
80 | "5204" -> context.getString(R.string.cpsdk_error_5204_extra)
81 | "5206" -> context.getString(R.string.cpsdk_error_5206_extra)
82 | "5207" -> context.getString(R.string.cpsdk_error_5207_extra)
83 | "5300" -> context.getString(R.string.cpsdk_error_5300_extra)
84 | else -> context.getString(R.string.cpsdk_error_5204_extra)
85 | }
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/models/Currency.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.models
2 |
3 | class Currency {
4 |
5 | companion object {
6 |
7 | val CODE_RUB = "RUB"
8 | val CODE_USD = "USD"
9 | val CODE_EUR = "EUR"
10 | val CODE_GBP = "GBP"
11 | val CODE_KZT = "KZT"
12 | val CODE_BYN = "BYN"
13 | val CODE_UAH = "UAH"
14 | val CODE_CHF = "CHF"
15 | val CODE_AZN = "AZN"
16 | val CODE_CZK = "CZK"
17 | val CODE_CAD = "CAD"
18 | val CODE_PLN = "PLN"
19 | val CODE_SEK = "SEK"
20 | val CODE_TRY = "TRY"
21 | val CODE_CNY = "CNY"
22 | val CODE_INR = "INR"
23 | val CODE_BRL = "BRL"
24 | val CODE_ZAR = "ZAR"
25 |
26 | val SYMBOL_RUB = "\u20BD"
27 | val SYMBOL_USD = "$"
28 | val SYMBOL_EUR = "€"
29 | val SYMBOL_GBP = "£"
30 | val SYMBOL_KZT = "₸"
31 | val SYMBOL_BYN = "Br"
32 | val SYMBOL_UAH = "грн"
33 | val SYMBOL_CHF = "Fr"
34 | val SYMBOL_AZN = "man"
35 | val SYMBOL_CZK = "Kč"
36 | val SYMBOL_CAD = "C$"
37 | val SYMBOL_PLN = "zł"
38 | val SYMBOL_SEK = "kr"
39 | val SYMBOL_TRY = "₺"
40 | val SYMBOL_CNY = "CNY"
41 | val SYMBOL_INR = "र"
42 | val SYMBOL_BRL = "R$"
43 | val SYMBOL_ZAR = "R"
44 |
45 | fun getSymbol(code: String): String {
46 | when (code) {
47 | CODE_RUB -> return SYMBOL_RUB
48 | CODE_USD -> return SYMBOL_USD
49 | CODE_EUR -> return SYMBOL_EUR
50 | CODE_GBP -> return SYMBOL_GBP
51 | CODE_KZT -> return SYMBOL_KZT
52 | CODE_BYN -> return SYMBOL_BYN
53 | CODE_UAH -> return SYMBOL_UAH
54 | CODE_CHF -> return SYMBOL_CHF
55 | CODE_AZN -> return SYMBOL_AZN
56 | CODE_CZK -> return SYMBOL_CZK
57 | CODE_CAD -> return SYMBOL_CAD
58 | CODE_PLN -> return SYMBOL_PLN
59 | CODE_SEK -> return SYMBOL_SEK
60 | CODE_TRY -> return SYMBOL_TRY
61 | CODE_CNY -> return SYMBOL_CNY
62 | CODE_INR -> return SYMBOL_INR
63 | CODE_BRL -> return SYMBOL_BRL
64 | CODE_ZAR -> return SYMBOL_ZAR
65 | }
66 | return code
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/models/PayParams.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.models
2 |
3 | data class PayParams(
4 | var saveCard: Boolean? = null
5 | )
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/models/Transaction.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.models
2 |
3 | import ru.cloudpayments.sdk.configuration.CloudpaymentsSDK
4 |
5 | data class Transaction (
6 | val transactionId: Int?,
7 | val status: CloudpaymentsSDK.TransactionStatus?,
8 | val reasonCode: Int?
9 | )
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/scanner/CardData.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.scanner
2 |
3 | data class CardData(val cardNumber: String?, // Номер карты без пробелов
4 | val cardExpMonth: String?, // Месяц. Например, январь - 01
5 | val cardExpYear: String?, // Последние 2 цифры года
6 | val cardholderName: String?)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/scanner/CardScanner.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.scanner
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Parcelable
6 | import kotlinx.android.parcel.Parcelize
7 | import java.io.Serializable
8 |
9 | abstract class CardScanner: Parcelable {
10 | abstract fun getScannerIntent(context: Context): Intent?
11 | abstract fun getCardDataFromIntent(data: Intent): CardData?
12 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/ui/dialogs/ThreeDsDialogFragment.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.ui.dialogs
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.webkit.JavascriptInterface
10 | import android.webkit.WebView
11 | import android.webkit.WebViewClient
12 | import androidx.core.view.isGone
13 | import androidx.fragment.app.DialogFragment
14 | import com.google.gson.JsonParser
15 | import org.jsoup.Jsoup
16 | import org.jsoup.nodes.Document
17 | import org.jsoup.nodes.Element
18 | import ru.cloudpayments.sdk.databinding.DialogCpsdkThreeDsBinding
19 | import java.io.UnsupportedEncodingException
20 | import java.net.URLEncoder
21 | import java.util.*
22 |
23 | class ThreeDsDialogFragment : DialogFragment() {
24 | interface ThreeDSDialogListener {
25 | fun onAuthorizationCompleted(md: String, paRes: String)
26 | fun onAuthorizationFailed(error: String?)
27 | }
28 |
29 | companion object {
30 | private const val POST_BACK_URL = "https://demo.cloudpayments.ru/WebFormPost/GetWebViewData"
31 | private const val ARG_ACS_URL = "acs_url"
32 | private const val ARG_MD = "md"
33 | private const val ARG_PA_REQ = "pa_req"
34 |
35 | fun newInstance(acsUrl: String, paReq: String, md: String) = ThreeDsDialogFragment().apply {
36 | arguments = Bundle().also {
37 | it.putString(ARG_ACS_URL, acsUrl)
38 | it.putString(ARG_MD, md)
39 | it.putString(ARG_PA_REQ, paReq)
40 | }
41 | }
42 | }
43 |
44 | private var _binding: DialogCpsdkThreeDsBinding? = null
45 |
46 | private val binding get() = _binding!!
47 |
48 | override fun onCreateView(
49 | inflater: LayoutInflater,
50 | container: ViewGroup?,
51 | savedInstanceState: Bundle?
52 | ): View? {
53 | _binding = DialogCpsdkThreeDsBinding.inflate(inflater, container, false)
54 | return binding.root
55 | }
56 |
57 | override fun onDestroyView() {
58 | super.onDestroyView()
59 | _binding = null
60 | }
61 |
62 | private val acsUrl by lazy {
63 | requireArguments().getString(ARG_ACS_URL) ?: ""
64 | }
65 |
66 | private val md by lazy {
67 | requireArguments().getString(ARG_MD) ?: ""
68 | }
69 |
70 | private val paReq by lazy {
71 | requireArguments().getString(ARG_PA_REQ) ?: ""
72 | }
73 |
74 | private var listener: ThreeDSDialogListener? = null
75 |
76 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
77 | super.onViewCreated(view, savedInstanceState)
78 |
79 | isCancelable = false
80 |
81 | binding.webView.webViewClient = ThreeDsWebViewClient()
82 | binding.webView.settings.domStorageEnabled = true
83 | binding.webView.settings.javaScriptEnabled = true
84 | binding.webView.settings.javaScriptCanOpenWindowsAutomatically = true
85 | binding.webView.addJavascriptInterface(ThreeDsJavaScriptInterface(), "JavaScriptThreeDs")
86 |
87 | try {
88 | val params = StringBuilder()
89 | .append("PaReq=").append(URLEncoder.encode(paReq, "UTF-8"))
90 | .append("&MD=").append(URLEncoder.encode(md, "UTF-8"))
91 | .append("&TermUrl=").append(URLEncoder.encode(POST_BACK_URL, "UTF-8"))
92 | .toString()
93 | binding.webView.postUrl(acsUrl, params.toByteArray())
94 | } catch (e: UnsupportedEncodingException) {
95 | e.printStackTrace()
96 | }
97 |
98 | binding.icClose.setOnClickListener {
99 | listener?.onAuthorizationFailed(null)
100 | dismiss()
101 | }
102 | }
103 |
104 | override fun onStart() {
105 | super.onStart()
106 | val window = dialog!!.window
107 | window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
108 | }
109 |
110 | private inner class ThreeDsWebViewClient : WebViewClient() {
111 | override fun onPageFinished(view: WebView, url: String) {
112 | if (url.toLowerCase(Locale.getDefault()) == POST_BACK_URL.toLowerCase(Locale.getDefault())) {
113 | view.isGone = true
114 | view.loadUrl("javascript:window.JavaScriptThreeDs.processHTML(''+document.getElementsByTagName('html')[0].innerHTML+'');")
115 | }
116 | }
117 | }
118 |
119 | internal inner class ThreeDsJavaScriptInterface {
120 | @JavascriptInterface
121 | fun processHTML(html: String?) {
122 | val doc: Document = Jsoup.parse(html)
123 | val element: Element? = doc.select("body").first()
124 | val jsonObject = JsonParser().parse(element?.ownText()).asJsonObject
125 | val paRes = jsonObject["PaRes"].asString
126 | requireActivity().runOnUiThread {
127 | if (!paRes.isNullOrEmpty()) {
128 | listener?.onAuthorizationCompleted(md, paRes)
129 | } else {
130 | listener?.onAuthorizationFailed(html ?: "")
131 | }
132 | dismissAllowingStateLoss()
133 | }
134 | }
135 | }
136 |
137 | override fun onAttach(context: Context) {
138 | super.onAttach(context)
139 |
140 | listener = targetFragment as? ThreeDSDialogListener
141 | if (listener == null) {
142 | listener = context as? ThreeDSDialogListener
143 | }
144 | }
145 |
146 | override fun onAttach(activity: Activity) {
147 | super.onAttach(activity)
148 |
149 | listener = targetFragment as? ThreeDSDialogListener
150 | if (listener == null) {
151 | listener = activity as? ThreeDSDialogListener
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/ui/dialogs/base/BasePaymentBottomSheetFragment.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.ui.dialogs.base
2 |
3 | import android.content.res.ColorStateList
4 | import android.os.Bundle
5 | import android.view.View
6 | import android.view.animation.Animation
7 | import android.view.animation.AnimationUtils
8 | import androidx.core.content.ContextCompat
9 | import com.google.android.material.textfield.TextInputEditText
10 | import com.google.android.material.textfield.TextInputLayout
11 | import ru.cloudpayments.sdk.R
12 | import ru.cloudpayments.sdk.configuration.PaymentConfiguration
13 | import ru.cloudpayments.sdk.ui.PaymentActivity
14 | import ru.cloudpayments.sdk.viewmodel.BaseViewModel
15 | import ru.cloudpayments.sdk.viewmodel.BaseViewState
16 |
17 |
18 | internal abstract class BasePaymentBottomSheetFragment>: BaseVMBottomSheetFragment() {
19 | interface IPaymentFragment {
20 | fun paymentWillFinish()
21 | }
22 |
23 | private fun getConfiguration(): PaymentConfiguration? {
24 | if (activity is PaymentActivity) {
25 | return (activity as PaymentActivity).paymentConfiguration
26 | }
27 | return null
28 | }
29 |
30 | protected val paymentConfiguration by lazy {
31 | getConfiguration()
32 | }
33 |
34 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
35 | super.onViewCreated(view, savedInstanceState)
36 |
37 | val fadeAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_fade_in)
38 | fadeAnim.fillAfter = true
39 |
40 | val slideAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_slide_in)
41 | slideAnim.fillAfter = true
42 | }
43 |
44 | protected fun close(force: Boolean, completion: (() -> (Unit))? = null){
45 | val slideAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_slide_out)
46 | slideAnim.fillAfter = true
47 | slideAnim.setAnimationListener(object : Animation.AnimationListener{
48 | override fun onAnimationStart(animation: Animation?) {
49 | }
50 |
51 | override fun onAnimationEnd(animation: Animation?) {
52 | animation?.setAnimationListener(null)
53 | requireActivity().supportFragmentManager.popBackStack()
54 | if (force) {
55 | val listener = requireActivity() as? IPaymentFragment
56 | listener?.paymentWillFinish()
57 | }
58 | completion?.invoke()
59 | }
60 |
61 | override fun onAnimationRepeat(animation: Animation?) {
62 | }
63 | })
64 |
65 | val fadeAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_fade_out)
66 | fadeAnim.fillAfter = true
67 | }
68 |
69 | fun handleBackButton(){
70 | close(true)
71 | }
72 |
73 | internal fun activity(): PaymentActivity {
74 | return activity as PaymentActivity
75 | }
76 |
77 | protected fun errorMode(isErrorMode: Boolean, editText: TextInputEditText, editLayout: TextInputLayout){
78 | if (isErrorMode) {
79 |
80 | val csl = ColorStateList(
81 | arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf()),
82 | intArrayOf(
83 | ContextCompat.getColor(requireContext(), R.color.cpsdk_pale_red),
84 | ContextCompat.getColor(requireContext(), R.color.cpsdk_pale_red)
85 | )
86 | )
87 |
88 | editLayout.defaultHintTextColor = csl
89 | editLayout.hintTextColor = csl
90 | editText.setTextColor(ContextCompat.getColor(requireContext(), R.color.cpsdk_pale_red))
91 | editText.setBackgroundResource(R.drawable.cpsdk_bg_edit_text_selector_error)
92 | } else {
93 |
94 | val csl = ColorStateList(
95 | arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf()),
96 | intArrayOf(
97 | ContextCompat.getColor(requireContext(), R.color.cpsdk_edit_text_hint),
98 | ContextCompat.getColor(requireContext(), R.color.cpsdk_edit_text_hint)
99 | )
100 | )
101 |
102 | editLayout.defaultHintTextColor = csl
103 | editLayout.hintTextColor = csl
104 | editText.setTextColor(ContextCompat.getColor(requireContext(), R.color.cpsdk_dark))
105 | editText.setBackgroundResource(R.drawable.cpsdk_bg_edit_text_selector)
106 | }
107 | }
108 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/ui/dialogs/base/BasePaymentDialogFragment.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.ui.dialogs.base
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import android.view.animation.Animation
6 | import android.view.animation.AnimationUtils
7 | import androidx.core.content.ContextCompat
8 | import com.google.android.material.textfield.TextInputEditText
9 | import ru.cloudpayments.sdk.R
10 | import ru.cloudpayments.sdk.configuration.PaymentConfiguration
11 | import ru.cloudpayments.sdk.ui.PaymentActivity
12 | import ru.cloudpayments.sdk.viewmodel.BaseViewModel
13 | import ru.cloudpayments.sdk.viewmodel.BaseViewState
14 |
15 | internal abstract class BasePaymentDialogFragment>: BaseVMDialogFragment() {
16 | interface IPaymentFragment {
17 | fun paymentWillFinish()
18 | }
19 |
20 | private fun getConfiguration(): PaymentConfiguration? {
21 | if (activity is PaymentActivity) {
22 | return (activity as PaymentActivity).paymentConfiguration
23 | }
24 | return null
25 | }
26 |
27 | protected val paymentConfiguration by lazy {
28 | getConfiguration()
29 | }
30 |
31 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
32 | super.onViewCreated(view, savedInstanceState)
33 |
34 | val fadeAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_fade_in)
35 | fadeAnim.fillAfter = true
36 |
37 | val slideAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_slide_in)
38 | slideAnim.fillAfter = true
39 | }
40 |
41 | protected fun close(force: Boolean, completion: (() -> (Unit))? = null){
42 | val slideAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_slide_out)
43 | slideAnim.fillAfter = true
44 | slideAnim.setAnimationListener(object : Animation.AnimationListener{
45 | override fun onAnimationStart(animation: Animation?) {
46 | }
47 |
48 | override fun onAnimationEnd(animation: Animation?) {
49 | animation?.setAnimationListener(null)
50 | requireActivity().supportFragmentManager.popBackStack()
51 | if (force) {
52 | val listener = requireActivity() as? IPaymentFragment
53 | listener?.paymentWillFinish()
54 | }
55 | completion?.invoke()
56 | }
57 |
58 | override fun onAnimationRepeat(animation: Animation?) {
59 | }
60 | })
61 |
62 | val fadeAnim = AnimationUtils.loadAnimation(requireContext(), R.anim.cpsdk_fade_out)
63 | fadeAnim.fillAfter = true
64 | }
65 |
66 | fun handleBackButton(){
67 | close(true)
68 | }
69 |
70 | internal fun activity(): PaymentActivity {
71 | return activity as PaymentActivity
72 | }
73 |
74 | protected fun errorMode(isErrorMode: Boolean, editText: TextInputEditText){
75 | if (isErrorMode) {
76 | editText.setTextColor(ContextCompat.getColor(requireContext(), R.color.cpsdk_pale_red))
77 | editText.setBackgroundResource(R.drawable.cpsdk_bg_edit_text_selector_error)
78 | } else {
79 | editText.setTextColor(ContextCompat.getColor(requireContext(), R.color.cpsdk_dark))
80 | editText.setBackgroundResource(R.drawable.cpsdk_bg_edit_text_selector)
81 | }
82 | }
83 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/ui/dialogs/base/BaseVMBottomSheetFragment.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.ui.dialogs.base
2 |
3 | import android.content.DialogInterface
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.lifecycle.Observer
7 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
8 | import ru.cloudpayments.sdk.viewmodel.BaseViewModel
9 | import ru.cloudpayments.sdk.viewmodel.BaseViewState
10 |
11 | internal abstract class BaseVMBottomSheetFragment>: BottomSheetDialogFragment() {
12 | abstract val viewModel: VM
13 | abstract fun render(state: VS)
14 |
15 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
16 | super.onViewCreated(view, savedInstanceState)
17 |
18 | viewModel.viewState.observe(viewLifecycleOwner, Observer {
19 | render(it)
20 | })
21 |
22 | }
23 | override fun onCancel(dialog: DialogInterface) {
24 | super.onCancel(dialog)
25 | activity?.finish()
26 | }
27 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/ui/dialogs/base/BaseVMDialogFragment.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.ui.dialogs.base
2 |
3 | import android.content.DialogInterface
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.constraintlayout.widget.Constraints
7 | import androidx.fragment.app.DialogFragment
8 | import androidx.lifecycle.Observer
9 | import ru.cloudpayments.sdk.R
10 | import ru.cloudpayments.sdk.viewmodel.BaseViewModel
11 | import ru.cloudpayments.sdk.viewmodel.BaseViewState
12 |
13 |
14 | internal abstract class BaseVMDialogFragment> :
15 | DialogFragment() {
16 | abstract val viewModel: VM
17 | abstract fun render(state: VS)
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 | setStyle(STYLE_NO_TITLE, R.style.cpsdk_Dialog);
22 | }
23 |
24 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
25 | super.onViewCreated(view, savedInstanceState)
26 |
27 | viewModel.viewState.observe(viewLifecycleOwner, Observer {
28 | render(it)
29 | })
30 | }
31 |
32 | override fun onStart() {
33 | super.onStart()
34 |
35 | dialog?.window?.setLayout(
36 | Constraints.LayoutParams.MATCH_PARENT,
37 | Constraints.LayoutParams.WRAP_CONTENT
38 | ) // full width dialog
39 | dialog?.setCancelable(false)
40 |
41 | }
42 |
43 | override fun onCancel(dialog: DialogInterface) {
44 | super.onCancel(dialog)
45 | activity?.finish()
46 | }
47 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/util/Constants.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.util
2 |
3 | import com.google.android.gms.wallet.WalletConstants
4 | import ru.cloudpayments.sdk.BuildConfig
5 |
6 | val TAG = "Payment SDK"
7 |
8 | val GOOGLE_PAY_ENVIRONMENT = if (BuildConfig.DEBUG)
9 | WalletConstants.ENVIRONMENT_TEST else
10 | WalletConstants.ENVIRONMENT_PRODUCTION
11 |
12 | val GOOGLE_PAY_SUPPORTED_NETWORKS = arrayListOf(
13 | WalletConstants.CARD_NETWORK_VISA,
14 | WalletConstants.CARD_NETWORK_MASTERCARD,
15 | WalletConstants.CARD_NETWORK_AMEX,
16 | WalletConstants.CARD_NETWORK_DISCOVER,
17 | WalletConstants.CARD_NETWORK_JCB,
18 | WalletConstants.CARD_NETWORK_INTERAC)
19 |
20 | val GOOGLE_PAY_SUPPORTED_METHODS = arrayListOf(
21 | WalletConstants.PAYMENT_METHOD_CARD,
22 | WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD)
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/util/Extensions.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.util
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.os.Build
6 | import android.view.WindowManager
7 | import android.view.inputmethod.InputMethodManager
8 | import androidx.fragment.app.Fragment
9 | import androidx.fragment.app.FragmentActivity
10 | import ru.cloudpayments.sdk.R
11 | import java.text.NumberFormat
12 |
13 | fun Activity.hideKeyboard() {
14 | currentFocus?.let {
15 | window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
16 | val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
17 | inputMethodManager.hideSoftInputFromWindow(it.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
18 | }
19 | }
20 |
21 | fun Activity.showKeyboard(){
22 | currentFocus?.let {
23 | val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
24 | imm.showSoftInput(currentFocus, 0)
25 | }
26 | }
27 |
28 | fun Fragment.nextFragment(fragment: Fragment, addToBackStack: Boolean = true, contentFrame: Int, animated: Boolean = false){
29 | activity?.nextFragment(fragment, addToBackStack, contentFrame, animated)
30 | }
31 |
32 | fun FragmentActivity.nextFragment(fragment: Fragment, addToBackStack: Boolean = true, contentFrame: Int, animated: Boolean = false) {
33 | hideKeyboard()
34 |
35 | val transaction = supportFragmentManager.beginTransaction()
36 |
37 | if (animated) {
38 | transaction.setCustomAnimations(R.anim.cpsdk_slide_in, R.anim.cpsdk_slide_out)
39 | }
40 |
41 | transaction.add(contentFrame, fragment, supportFragmentManager.backStackEntryCount.toString())
42 |
43 | if (addToBackStack) {
44 | transaction.addToBackStack(fragment::class.java.toString())
45 | }
46 | transaction.commit()
47 | }
48 |
49 | fun Context.getCurrencyString(currency: Double) = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
50 | NumberFormat.getCurrencyInstance(getRussianLocale()).format(currency)
51 | } else {
52 | getString(R.string.cpsdk_currency_template, currency)
53 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/util/GooglePayHandler.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.util
2 |
3 | import com.google.android.gms.wallet.*
4 | import io.ashdavies.rx.rxtasks.toSingle
5 | import io.reactivex.Single
6 | import ru.cloudpayments.sdk.configuration.PaymentConfiguration
7 | import ru.cloudpayments.sdk.ui.PaymentActivity
8 |
9 | internal class GooglePayHandler {
10 | companion object {
11 | fun present(configuration: PaymentConfiguration, activity: PaymentActivity, requestCode: Int) {
12 | val transactionInfo = TransactionInfo.newBuilder()
13 | .setTotalPriceStatus(WalletConstants.TOTAL_PRICE_STATUS_FINAL)
14 | .setTotalPrice(configuration.paymentData.amount)
15 | .setCurrencyCode(configuration.paymentData.currency)
16 | .build()
17 | val request = createPaymentDataRequest(transactionInfo, configuration.publicId)
18 | val client = createPaymentsClient(activity)
19 | AutoResolveHelper.resolveTask(client.loadPaymentData(request), activity, requestCode)
20 | }
21 |
22 | private fun createPaymentDataRequest(transactionInfo: TransactionInfo, publicId: String): PaymentDataRequest {
23 | val paramsBuilder = PaymentMethodTokenizationParameters.newBuilder()
24 | .setPaymentMethodTokenizationType(
25 | WalletConstants.PAYMENT_METHOD_TOKENIZATION_TYPE_PAYMENT_GATEWAY)
26 | .addParameter("gateway", "cloudpayments")
27 | .addParameter("gatewayMerchantId", publicId)
28 |
29 | return createPaymentDataRequest(transactionInfo, paramsBuilder.build())
30 | }
31 |
32 | private fun createPaymentDataRequest(transactionInfo: TransactionInfo, params: PaymentMethodTokenizationParameters): PaymentDataRequest {
33 | return PaymentDataRequest.newBuilder()
34 | .setPhoneNumberRequired(false)
35 | .setEmailRequired(false)
36 | .setShippingAddressRequired(false)
37 | .setTransactionInfo(transactionInfo)
38 | .addAllowedPaymentMethods(GOOGLE_PAY_SUPPORTED_METHODS)
39 | .setCardRequirements(
40 | CardRequirements.newBuilder()
41 | .addAllowedCardNetworks(GOOGLE_PAY_SUPPORTED_NETWORKS)
42 | .setAllowPrepaidCards(true)
43 | .setBillingAddressRequired(false)
44 | .setBillingAddressFormat(WalletConstants.BILLING_ADDRESS_FORMAT_MIN)
45 | .build())
46 | .setPaymentMethodTokenizationParameters(params)
47 | .setUiRequired(true)
48 | .build()
49 | }
50 |
51 | private fun createPaymentsClient(activity: PaymentActivity): PaymentsClient {
52 | val walletOptions = Wallet.WalletOptions.Builder()
53 | .setEnvironment(GOOGLE_PAY_ENVIRONMENT)
54 | .build()
55 | return Wallet.getPaymentsClient(activity, walletOptions)
56 | }
57 |
58 | fun isReadyToMakeGooglePay(activity: PaymentActivity): Single {
59 | val request = IsReadyToPayRequest.newBuilder()
60 | for (allowedMethod in GOOGLE_PAY_SUPPORTED_METHODS) {
61 | request.addAllowedPaymentMethod(allowedMethod)
62 | }
63 | return createPaymentsClient(activity).isReadyToPay(request.build()).toSingle()
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/util/HexPacketHelper.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.util
2 |
3 | class HexPacketHelper {
4 |
5 | companion object {
6 | fun numberToEvenLengthString(number: Int): String {
7 | var numberStr = number.toString()
8 |
9 | return if (numberStr.length % 2 == 0) numberStr
10 | else "0$numberStr";
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/util/InjectorUtils.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.util
2 |
3 | import ru.cloudpayments.sdk.configuration.PaymentData
4 | import ru.cloudpayments.sdk.viewmodel.PaymentProcessViewModelFactory
5 |
6 | internal object InjectorUtils {
7 | fun providePaymentProcessViewModelFactory(paymentData: PaymentData, cryptogram: String, useDualMessagePayment: Boolean, saveCard: Boolean?): PaymentProcessViewModelFactory {
8 | return PaymentProcessViewModelFactory(paymentData, cryptogram, useDualMessagePayment, saveCard)
9 | }
10 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/util/PublicKey.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.util
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.SharedPreferences
6 |
7 | class PublicKey private constructor() {
8 |
9 | companion object {
10 | private val publicKey = PublicKey()
11 | private lateinit var sharedPreferences: SharedPreferences
12 |
13 | private const val PEM = "pem"
14 | private const val VERSION = "version"
15 |
16 | fun getInstance(context: Context): PublicKey {
17 | if (!::sharedPreferences.isInitialized) {
18 | synchronized(PublicKey::class.java) {
19 | if (!::sharedPreferences.isInitialized) {
20 | sharedPreferences = context.getSharedPreferences(context.packageName, Activity.MODE_PRIVATE)
21 | }
22 | }
23 | }
24 | return publicKey
25 | }
26 | }
27 |
28 | val pem: String?
29 | get() = sharedPreferences.getString(PEM, "")
30 |
31 | fun savePem(pem: String) {
32 | sharedPreferences.edit()
33 | .putString(PEM, pem)
34 | .apply()
35 | }
36 |
37 | val version: Int?
38 | get() = sharedPreferences.getInt(VERSION, 0)
39 |
40 | fun saveVersion(version: Int) {
41 | sharedPreferences.edit()
42 | .putInt(VERSION, version)
43 | .apply()
44 | }
45 |
46 | fun clearAll() {
47 | sharedPreferences.edit().clear().apply()
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/util/Tools.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.util
2 |
3 | import android.text.Editable
4 | import android.text.TextWatcher
5 | import java.util.*
6 | import java.util.regex.Pattern
7 |
8 | open class TextWatcherAdapter: TextWatcher {
9 | override fun afterTextChanged(s: Editable?) {}
10 |
11 | override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {}
12 |
13 | override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {}
14 | }
15 |
16 | fun emailIsValid(email: String?): Boolean {
17 | if (email.isNullOrBlank()) {
18 | return false
19 | }
20 |
21 | val emailPattern = "^.+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*\$"
22 | return Pattern.compile(emailPattern).matcher(email).matches()
23 | }
24 |
25 | fun getRussianLocale() = Locale("ru", "RU")
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/viewmodel/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.viewmodel
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 |
6 | internal abstract class BaseViewModel : ViewModel() {
7 | abstract val viewState: MutableLiveData
8 | abstract var currentState: VS
9 | }
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/viewmodel/BaseViewState.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.viewmodel
2 |
3 | internal abstract class BaseViewState
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/viewmodel/PaymentCardViewModel.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.viewmodel
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import io.reactivex.disposables.Disposable
5 | import ru.cloudpayments.sdk.api.CloudpaymentsApi
6 | import javax.inject.Inject
7 |
8 | internal class PaymentCardViewModel: BaseViewModel() {
9 | override var currentState = PaymentCardViewState()
10 | override val viewState: MutableLiveData by lazy {
11 | MutableLiveData(currentState)
12 | }
13 |
14 | private var disposable: Disposable? = null
15 |
16 | @Inject lateinit var api: CloudpaymentsApi
17 |
18 | override fun onCleared() {
19 | super.onCleared()
20 |
21 | disposable?.dispose()
22 | }
23 | }
24 |
25 | internal data class PaymentCardViewState(val a: String? = null): BaseViewState()
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/viewmodel/PaymentOptionsViewModel.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.viewmodel
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import io.reactivex.android.schedulers.AndroidSchedulers
5 | import io.reactivex.disposables.Disposable
6 | import ru.cloudpayments.sdk.api.CloudpaymentsApi
7 | import javax.inject.Inject
8 |
9 | internal class PaymentOptionsViewModel: BaseViewModel() {
10 | override var currentState = PaymentOptionsViewState()
11 | override val viewState: MutableLiveData by lazy {
12 | MutableLiveData(currentState)
13 | }
14 |
15 | private var disposable: Disposable? = null
16 |
17 | @Inject
18 | lateinit var api: CloudpaymentsApi
19 |
20 | fun getPublicKey() {
21 | disposable = api.getPublicKey()
22 | .toObservable()
23 | .observeOn(AndroidSchedulers.mainThread())
24 | .map { response ->
25 | val state = currentState.copy(publicKeyPem = response.pem, publicKeyVersion = response.version)
26 | stateChanged(state)
27 | }
28 | .onErrorReturn {
29 |
30 | }
31 | .subscribe()
32 | }
33 |
34 | fun getMerchantConfiguration(publicId: String) {
35 | disposable = api.getMerchantConfiguration(publicId)
36 | .toObservable()
37 | .observeOn(AndroidSchedulers.mainThread())
38 | .map { response ->
39 |
40 | var isTinkoffPayAvailable = false
41 |
42 | for (paymentMethod in response.model?.externalPaymentMethods!!) {
43 | if (paymentMethod.type == 6) {
44 | isTinkoffPayAvailable = paymentMethod.enabled!!
45 | break
46 | }
47 | }
48 |
49 | val state = currentState.copy(isTinkoffPayAvailable = isTinkoffPayAvailable, isSaveCard = response.model?.features?.isSaveCard)
50 | stateChanged(state)
51 | }
52 | .onErrorReturn {
53 |
54 | }
55 | .subscribe()
56 | }
57 |
58 | private fun stateChanged(viewState: PaymentOptionsViewState) {
59 | currentState = viewState.copy()
60 | this.viewState.apply {
61 | value = viewState
62 | }
63 | }
64 |
65 | override fun onCleared() {
66 | super.onCleared()
67 |
68 | disposable?.dispose()
69 | }
70 | }
71 |
72 | internal data class PaymentOptionsViewState(
73 | val publicKeyPem: String? = null,
74 | val publicKeyVersion: Int? = null,
75 | val isTinkoffPayAvailable: Boolean? = null,
76 | val isSaveCard: Int? = null
77 | ): BaseViewState()
--------------------------------------------------------------------------------
/sdk/src/main/java/ru/cloudpayments/sdk/viewmodel/PaymentProcessViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package ru.cloudpayments.sdk.viewmodel
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import ru.cloudpayments.sdk.configuration.PaymentData
6 |
7 | internal class PaymentProcessViewModelFactory(
8 | private val paymentData: PaymentData,
9 | private val cryptogram: String,
10 | private val useDualMessagePayment: Boolean,
11 | private val saveCard: Boolean?
12 | ): ViewModelProvider.Factory {
13 |
14 | @Suppress("UNCHECKED_CAST")
15 | override fun create(modelClass: Class): T {
16 | return PaymentProcessViewModel(paymentData, cryptogram, useDualMessagePayment, saveCard) as T
17 | }
18 | }
--------------------------------------------------------------------------------
/sdk/src/main/res/anim/cpsdk_fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/anim/cpsdk_fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/anim/cpsdk_slide_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/anim/cpsdk_slide_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/color/cpsdk_color_edittext.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_button_tinkoff_pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_button_tinkoff_pay.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_ic_checkbox_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_ic_checkbox_checked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_ic_checkbox_unchecked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_ic_checkbox_unchecked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_ic_failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_ic_failure.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_ic_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_ic_progress.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_ic_ps_jcb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_ic_ps_jcb.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_ic_ps_mir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_ic_ps_mir.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/cpsdk_ic_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/cpsdk_ic_success.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/drag_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/drag_handle.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-hdpi/ic_required_email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-hdpi/ic_required_email.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/cpsdk_button_tinkoff_pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/cpsdk_button_tinkoff_pay.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/cpsdk_ic_checkbox_unchecked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/cpsdk_ic_checkbox_unchecked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/cpsdk_ic_failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/cpsdk_ic_failure.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/cpsdk_ic_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/cpsdk_ic_progress.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/cpsdk_ic_ps_jcb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/cpsdk_ic_ps_jcb.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/cpsdk_ic_ps_mir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/cpsdk_ic_ps_mir.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/cpsdk_ic_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/cpsdk_ic_success.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/drag_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/drag_handle.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-mdpi/ic_required_email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-mdpi/ic_required_email.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-v21/cpsdk_bg_button_gp.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_button_tinkoff_pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_button_tinkoff_pay.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_checkbox_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_checkbox_checked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_checkbox_unchecked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_checkbox_unchecked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_failure.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_progress.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_ps_jcb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_ps_jcb.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_ps_mir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_ps_mir.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/cpsdk_ic_success.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/drag_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/drag_handle.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xhdpi/ic_required_email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xhdpi/ic_required_email.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_button_tinkoff_pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_button_tinkoff_pay.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_checkbox_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_checkbox_checked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_checkbox_unchecked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_checkbox_unchecked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_failure.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_progress.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_ps_jcb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_ps_jcb.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_ps_mir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_ps_mir.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/cpsdk_ic_success.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/drag_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/drag_handle.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxhdpi/ic_required_email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxhdpi/ic_required_email.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_button_tinkoff_pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_button_tinkoff_pay.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_checkbox_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_checkbox_checked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_checkbox_unchecked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_checkbox_unchecked.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_failure.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_progress.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_ps_jcb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_ps_jcb.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_ps_mir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_ps_mir.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/cpsdk_ic_success.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/drag_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/drag_handle.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable-xxxhdpi/ic_required_email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/drawable-xxxhdpi/ic_required_email.png
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_button_close.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
12 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_button_gp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_button_gp_black.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_edit_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_edit_text_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_edit_text_focused.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_edit_text_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_edit_text_selector_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_popup.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_rounded_black_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_rounded_blue_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_rounded_bottom_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_rounded_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_rounded_dialog_inset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_bg_rounded_white_button_with_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_edit_text_underline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_edit_text_underline_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_googlepay_button_content.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
24 |
30 |
36 |
42 |
48 |
49 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_googlepay_button_overlay.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_blue_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
12 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_checkbox_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_close.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_ps_maestro.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_ps_mastercard.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_ps_troy.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_ps_visa.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
16 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_save_card_popup.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/sdk/src/main/res/drawable/cpsdk_ic_scan.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_black.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_black_italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_black_italic.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_bold.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_bold_italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_bold_italic.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_italic.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_light.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_light_italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_light_italic.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_medium.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_medium_italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_medium_italic.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/rubik_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/rubik_regular.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/font/sf_pro_text_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudpayments/CloudPayments-SDK-Android/2f022fe6f242486cc000a1a16ffa03df2def5049/sdk/src/main/res/font/sf_pro_text_regular.ttf
--------------------------------------------------------------------------------
/sdk/src/main/res/layout/activity_cpsdk_payment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/sdk/src/main/res/layout/dialog_cpsdk_payment_process.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
22 |
23 |
34 |
35 |
50 |
51 |
61 |
62 |
63 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/sdk/src/main/res/layout/dialog_cpsdk_three_ds.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
20 |
21 |
22 |
26 |
--------------------------------------------------------------------------------
/sdk/src/main/res/layout/googlepay_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
25 |
26 |
27 |
33 |
34 |
--------------------------------------------------------------------------------
/sdk/src/main/res/layout/popup_cpsdk_save_card_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
22 |
23 |
29 |
30 |
31 |
39 |
40 |
45 |
46 |
52 |
53 |
--------------------------------------------------------------------------------
/sdk/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/sdk/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6494DA
4 | #393861
5 | #6494DA
6 | #1f1f2e
7 | #62626c
8 | #c0c9d4
9 | #4297df
10 | #ec4444
11 | #ffffff
12 | #000000
13 | #2e71fc
14 | #64000000
15 | #8C949F
16 |
--------------------------------------------------------------------------------
/sdk/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 8dp
4 | 16dp
5 | 24dp
6 | 8dp
7 | 16dp
8 | 24dp
9 |
10 | 48dp
11 |
--------------------------------------------------------------------------------
/sdk/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
20 |
21 |
24 |
25 |
30 |
31 |
41 |
42 |
55 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
94 |
95 |
102 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 |
16 | include ':sdk'
17 | include ':app'
18 | rootProject.name = "Cloudpayments SDK"
--------------------------------------------------------------------------------