diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 8cb2c15951..0000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Default ignored files -/shelf/ \ No newline at end of file diff --git a/.idea/dictionaries/.xml b/.idea/dictionaries/.xml deleted file mode 100644 index fc9ea1f34e..0000000000 --- a/.idea/dictionaries/.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - blockchains - - - \ No newline at end of file diff --git a/.idea/dictionaries/tangem.xml b/.idea/dictionaries/tangem.xml deleted file mode 100644 index e77bbeb7ed..0000000000 --- a/.idea/dictionaries/tangem.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - binance - blockchain - cardano - ducatus - ethereum - litecoin - matic - tangem - testnet - tezos - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 15a15b218a..0000000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index cd2f3a654d..7bfef59df1 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,45 +1,5 @@ - - - - - - - - - diff --git a/app/build.gradle b/app/build.gradle index e80024ee8a..d1716ff095 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,24 +2,15 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' -apply plugin: 'com.google.firebase.crashlytics' -apply plugin: 'com.google.firebase.firebase-perf' -apply plugin: 'com.google.gms.google-services' - -static def generateVersionName() { - def gitCommitsCount = "git rev-list HEAD --count".execute().text.trim() -// def gitCurrentBranch = "git rev-parse --abbrev-ref HEAD".execute().text.trim() - return gitCommitsCount.toInteger() + 831// + "\\n" + gitCurrentBranch -} - -Properties properties = new Properties() -properties.load(project.rootProject.file('local.properties').newDataInputStream()) +//apply plugin: 'com.google.firebase.crashlytics' +//apply plugin: 'com.google.firebase.firebase-perf' +//apply plugin: 'com.google.gms.google-services' android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 29 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } androidExtensions { @@ -44,26 +35,19 @@ android { applicationIdSuffix ".debug" } } - flavorDimensions "" - productFlavors { - tangemAccess { - versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 116 - versionName project.hasProperty('versionName') ? project.property('versionName') : "0.1.0.-SNAPSHOT" - applicationId "com.tangem.wallet" - signingConfig signingConfigs.debug - } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 + coreLibraryDesugaringEnabled true } packagingOptions { - pickFirst('META-INF/proguard/okhttp3.pro') -// for one.block:eosiojava:0.1.0 exclude 'lib/x86_64/darwin/libscrypt.dylib' exclude 'lib/x86_64/freebsd/libscrypt.so' exclude 'lib/x86_64/linux/libscrypt.so' - exclude 'org.slf4j:slf4j-jdk14:1.7.25' } buildToolsVersion '29.0.3' } @@ -71,100 +55,45 @@ android { repositories { maven { url "https://jitpack.io" } } -configurations { - all*.exclude group: 'com.google.guava', module: 'listenablefuture' - implementation.exclude module:'protobuf-lite' -} dependencies { - implementation project(':tangem-card-old') - implementation project(':tangem-sdk-old') - implementation project(':server-android') + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin" + implementation 'androidx.core:core-ktx:1.3.1' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0' + implementation 'com.google.android.material:material:1.2.0' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10' - implementation 'androidx.navigation:navigation-fragment:2.2.2' - implementation 'androidx.navigation:navigation-ui-ktx:2.2.2' - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' - implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' - implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + implementation 'com.tangem:blockchain:1.25.0' + + //lifecycle implementation "androidx.lifecycle:lifecycle-runtime:2.2.0" implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.fragment:fragment:1.2.4' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation "androidx.preference:preference:1.1.1" - implementation 'androidx.biometric:biometric:1.0.1' - implementation 'androidx.core:core-ktx:1.3.0' - implementation 'com.google.android.material:material:1.1.0' + //koin - di +// implementation "org.koin:koin-android:2.1.5" +// implementation "org.koin:koin-android-scope:2.1.5" +// implementation "org.koin:koin-android-viewmodel:2.1.5" - implementation 'com.google.dagger:dagger:2.24' - kapt 'com.google.dagger:dagger-compiler:2.21' - annotationProcessor 'com.google.dagger:dagger-compiler:2.21' - implementation 'com.google.zxing:core:3.3.3' // Do not update to 3.4.0, it requires minSdk 24 - implementation 'com.google.code.gson:gson:2.8.5' - implementation 'com.madgag.spongycastle:core:1.56.0.0' - implementation 'com.madgag.spongycastle:prov:1.56.0.0' - implementation 'com.scottyab:rootbeer-lib:0.0.7' - implementation 'com.squareup.retrofit2:converter-gson:2.6.0' - implementation 'com.squareup.retrofit2:retrofit:2.6.0' - implementation 'com.squareup.retrofit2:converter-scalars:2.6.0' - implementation 'com.squareup.retrofit2:converter-jackson:2.6.0' - implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0' - implementation "com.squareup.okhttp3:okhttp-sse:3.11.0" - implementation 'com.skyfishjy.ripplebackground:library:1.0.1' - implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' - implementation "com.orhanobut:hawk:2.0.1" - implementation 'co.nstant.in:cbor:0.8' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3' - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3" -// implementation 'org.bitcoinj:bitcoinj-parent:0.14.7' //TODO: is this needed? - implementation 'org.bitcoinj:bitcoinj-core:0.15.2' - implementation 'org.greenrobot:eventbus:3.1.1' +// //Firebase +// implementation 'com.google.firebase:firebase-analytics:17.5.0' +// implementation 'com.google.firebase:firebase-crashlytics:17.2.1' +// implementation 'com.google.firebase:firebase-perf:19.0.8' + + implementation "org.rekotlin:rekotlin:1.0.4" + + // QR + implementation 'com.google.zxing:core:3.3.3' implementation 'me.dm7.barcodescanner:zxing:1.9.8' - implementation 'info.hoang8f:android-segmented:1.0.6' - implementation 'io.reactivex.rxjava2:rxjava:2.2.0' - implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' - implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' -// implementation 'com.github.stellar:java-stellar-sdk:0.4.1' - implementation 'net.i2p.crypto:eddsa:0.3.0' - implementation 'com.google.firebase:firebase-analytics:17.3.0' - implementation 'com.google.firebase:firebase-crashlytics:17.0.0-beta04' - implementation 'com.google.firebase:firebase-perf:19.0.6' + // Camera + implementation 'com.otaliastudios:cameraview:2.6.3' - //dependencies for XRP - implementation files('libs/ripple-core-0.0.1.jar') - //4 dependencies for ripple-core TODO: move to module? - implementation 'net.i2p.crypto:eddsa:0.3.0' - implementation 'org.bouncycastle:bcprov-jdk15on:1.61' - //noinspection DuplicatePlatformClasses - implementation 'org.json:json:20180813' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8' + testImplementation 'junit:junit:4.13' + testImplementation "com.google.truth:truth:1.0.1" + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - //dependencies for binance - implementation 'com.google.protobuf:protobuf-java:3.11.4' - implementation 'io.grpc:grpc-protobuf:1.17.1' - implementation 'io.grpc:grpc-stub:1.17.1' - implementation 'commons-codec:commons-codec:1.10' - implementation 'org.apache.commons:commons-lang3:3.6' - implementation 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.9.8' - implementation 'joda-time:joda-time:2.10.1' - testImplementation 'junit:junit:4.12' - - //dependencies for EOS - implementation 'io.jafka:jeos:0.9.15' -// implementation 'one.block:eosiojava:0.1.0' - implementation 'org.bouncycastle:bcpkix-jdk15on:1.61' - - implementation 'io.fotoapparat:fotoapparat:2.6.1' - implementation 'com.otaliastudios:cameraview:2.6.1' - - //dependencies for flow demo - implementation 'io.grpc:grpc-okhttp:1.28.0' - implementation 'io.grpc:grpc-stub:1.28.0' - - //dependencies for TokenEmvEngine - implementation 'com.github.walleth.kethereum:extensions_kotlin:0.81.4' } \ No newline at end of file diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml index 8cf74b318f..2784e858d0 100644 --- a/app/src/debug/AndroidManifest.xml +++ b/app/src/debug/AndroidManifest.xml @@ -1,18 +1,17 @@ - - + + + + + + diff --git a/app/src/debug/java/com/tangem/Test.java b/app/src/debug/java/com/tangem/Test.java deleted file mode 100644 index df5872e621..0000000000 --- a/app/src/debug/java/com/tangem/Test.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.tangem; - -public class Test { -} diff --git a/app/src/debug/res/drawable/ic_launcher_background.xml b/app/src/debug/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 2408e30d17..0000000000 --- a/app/src/debug/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml index c4a603d4cc..03bac10d6c 100644 --- a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,4 @@ - \ No newline at end of file diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml index c4a603d4cc..03bac10d6c 100644 --- a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,4 @@ - \ No newline at end of file diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml index 1c13a1dbc0..4cc2b19474 100644 --- a/app/src/debug/res/values/strings.xml +++ b/app/src/debug/res/values/strings.xml @@ -1,7 +1,6 @@ - DEBUG - com.tangem.debug.data.LogFileProvider + DEBUG \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 02a922f1a6..3fe3cc77a6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,7 +20,7 @@ - - - - - - + android:screenOrientation="portrait"> @@ -50,6 +43,7 @@ + @@ -71,9 +65,9 @@ + android:pathPrefix="/android.com:pkg" + android:scheme="vnd.android.nfc" /> diff --git a/app/src/main/assets/issuers.json b/app/src/main/assets/issuers.json deleted file mode 100644 index b1863c76ab..0000000000 --- a/app/src/main/assets/issuers.json +++ /dev/null @@ -1,119 +0,0 @@ -[ - { - "id": "TANGEM SDK", - "dataKey": { - "privateKey": "11121314151617184771ED81F2BACF57479E4735EB1405083927372D40DA9E92" - }, - "transactionKey": { - "privateKey": "11121314151617184771ED81F2BACF57479E4735EB1405081918171615141312" - } - }, - { - "id": "TANGEM", - "dataKey": { - "publicKey": "048196AA4B410AC44A3B9CCE18E7BE226AEA070ACC83A9CF67540FAC49AF25129F6A538A28AD6341358E3C4F9963064F7E365372A651D374E5C23CDD37FD099BF2" - }, - "transactionKey": { - "publicKey": "04343D40496CBE1FE8A8C026575C435A29141EA3BC335DA5549AB6C64685A646848036D481CF9A989390A8B034B229D99BD49E6F07D2FF02746EA265EF99380A80" - } - }, - { - "id": "SUPERBLOOM", - "dataKey": { - "publicKey": "04EAB7F2444CFFA2E9CB4AA01CF1CA3694888811BDF0F8E0CDBCCFB5F497F14A5B86655FEF0C7E8F86841B0C14660E09F28DDFB9690F7302DA56F661A6A064564E" - }, - "transactionKey": { - "publicKey": "04D292BFC802FFA70ABB1C094A19F6C6766DD353114C25415871BE4586129648CFD77B22FBC1AF3C612497732A04CF845B41D760AFDD820051AB250798503DB340" - } - }, - { - "id": "Qlear Protocol", - "dataKey": { - "publicKey": "048B02F0D912B74294E296654E7A008946A0F51E8B4F1141BCB302716C4D868BADCB495681BEA670FFB125C62816CEB3B3AA4AB5EE7336F9ACEC18955493C40058" - }, - "transactionKey": { - "publicKey": "04CBC1131BB4BB717C22CCF91C716A8BDACFB09D962A34FBFCE923B6070A40A35CC4E417B2E5ECC19EC78FA372CFF5A1D937D152981E4F0AFFDC1E60F9F0945272" - } - }, - { - "id": "CYCLE[bit]", - "dataKey": { - "publicKey": "04F743D0CFA3D3B7A01F9224ECA40A2F0E09558555D0961417A7B00964ECD0FA3338784C89363A695742AF2B13D73BB30B6E0B4E59CA0A14490ED73DCECE3BCF52" - }, - "transactionKey": { - "publicKey": "04ECA685AFD135EF2AB24D07BED71ED82CC1882C282976616DAC655ED3E5B8E75487C131F5D79A87895ECDE89AC58CD1BB220A0C29DD544D8D9AD5156184456F3F" - } - }, - { - "id": "Whirl", - "dataKey": { - "publicKey": "040B3484CB923DAB12915B7B4FC174543C242A4E49AD9046B2816F03DAFC344E7570CBCC245F5D82FAFDB7E413538238EDE2C196EEC2F9F91911AFC9C37F757810" - }, - "transactionKey": { - "publicKey": "042EC0898ADF5AF4883D2F077E89CE464766E8E47FA03612F5248494C88A923CA2C444EE71D3A2BE67F13FD65C19E114B577F2B12CE856F1AA80DEBB406F325171" - } - }, - { - "id": "D1", - "dataKey": { - "publicKey": "046F1155C3E75C2E0A4B816F53B739BA9DB3FC27C4CDE20E634AF09CA2D88A5199F97AE474B5833E69AD5A43FFB2F62E4E9B7A8BCC271805A5DD19A7AB9C9888D6" - }, - "transactionKey": { - "publicKey": "04AE9E9C50073ABCF3219A96806BE8B95DCA97A12A0DE3516C25959266F5DFD032B75E1CC926DAAC274EE0E638A2BDB717C4B9C6F28808D6BEAB2F4CBF91E2DD52" - } - }, - { - "id": "Coinstruction", - "dataKey": { - "publicKey": "042D6D305E2927FE18762CF2E74B207B3D7239279248450C31C88C4FEBDBC62D07976D10F7838CA52AF5A7ACB052D09EC8C513E7AC204673D2D3D078DBD859DF49" - }, - "transactionKey": { - "publicKey": "045B0561BD9E089E54D730D75F5205A1A3E094A2209D0F11002F2423D63F508BFD161F8BBA8FBAC441AD893287D67141BBEE39E403C43D12A9FE1A25BCF3A144E9" - } - }, - { - "id": "EvenToken", - "dataKey": { - "publicKey": "040FB60B37682AED10AB8B9DB324BBB10D7CEDF9D189332212C36A641CF81314E6CC8C219245DF04813DBB26931C547B6A4D55A10B5FFB163F54643A97213276F8" - }, - "transactionKey": { - "publicKey": "044CEB1A3C2931F55441B39EB06F938542309DDD436DA486DE605187418163B777684C15D10EE5029CDEFB73DBA2BF90173D27CACEBF4CABFD4553C63021ABBEBB" - } - }, - { - "id": "CARDANO", - "dataKey": { - "publicKey": "0445C312089E57A6952F96D74FF75C962E1E2C2DDA5FB4195661B92E2744791350FE6C60E1A1D145C6A34D8BEAD57506A90FE4A149A9AA43CFF3C6CAE0748B771E" - }, - "transactionKey": { - "publicKey": "04969A008E8A61F92EF8D380DB7BB7B8F6F667CA169934371F544F6697D1D2AF97FB87B8D75F550CD782472D46BFCADF354AF17D807C1D2EB82E184C367CACF1FC" - } - }, - { - "id": "RSK", - "dataKey": { - "publicKey": "04997C29B1158D5A5B7EDCF7A7844EA76C630C80CD326C83F2983C2EF0E632B37282D69CEEDB6445B79B26D73073122E22AB0FE1E9A1CA41D991C45057D9DF0F24" - }, - "transactionKey": { - "publicKey": "040E9DDC53387F1006F39451AF11EBD377B98484FC81D24A96A55DEFDDF6F1EE35F07B089EFD05E4E93BDE20372171274ECD8D8805D0CB1FFEF012673F4E330C95" - } - }, - { - "id": "DIGIX", - "dataKey": { - "publicKey": "049533C082D074ACC285E9B7E97F50F0883DF0308871232ED2370F19CA8993F01C5D4ABAF848949C7628D48F60F68DA3E5726A53C394619179D42D7F20D347001E" - }, - "transactionKey": { - "publicKey": "04346D597CBE34A409C4CC77AED4DB2332D18C181DD6EB0A695FEA8672FF790B1C2518DF3A357484BB1EC89BCB1C3F2A962B2781DF094C8EE0F9C45D98BBA92610" - } - }, - { - "id": "Start2Coin", - "dataKey": { - "publicKey": "043D21AFD0E20468F210547079819CB947031F4A31E591A4193E98DEE84AFB5976066CDD43F94820E0B5F82C063603B48C9A84B4C28C3B6DD9E54BB66A1C75036F" - }, - "transactionKey": { - "publicKey": "0442C6413C81FCCF6FA18318ECEA270F7B7242E82863A9208253A85BEC394E5F58E6A12F9FE8A708BD05B73862C8833EB0634FF98E527277F625D4AB139B86AEAC" - } - } -] \ No newline at end of file diff --git a/app/src/main/java/com/tangem/App.kt b/app/src/main/java/com/tangem/App.kt deleted file mode 100644 index ba734b7bba..0000000000 --- a/app/src/main/java/com/tangem/App.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.tangem - -import android.app.Application -import androidx.appcompat.app.AppCompatDelegate -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import com.tangem.data.dp.PrefsManager -import com.tangem.data.local.PendingTransactionsStorage -import com.tangem.di.DaggerNetworkComponent -import com.tangem.di.DaggerToastHelperComponent -import com.tangem.di.NetworkComponent -import com.tangem.di.ToastHelperComponent -import com.tangem.server_android.data.LocalStorage -import com.tangem.tangem_card.data.Issuer -import com.tangem.tangem_sdk.android.data.Firmwares -import com.tangem.tangem_sdk.android.data.PINStorage -import com.tangem.util.Analytics -import com.tangem.wallet.BuildConfig -import java.io.InputStreamReader -import java.nio.charset.StandardCharsets - -class App : Application() { - companion object { - @get:Synchronized - var instance: App? = null - private set - - init { - AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) - } - - lateinit var networkComponent: NetworkComponent - lateinit var toastHelperComponent: ToastHelperComponent - - lateinit var firmwaresStorage: Firmwares - lateinit var localStorage: LocalStorage - lateinit var pinStorage: PINStorage - lateinit var pendingTransactionsStorage: PendingTransactionsStorage - } - - override fun onCreate() { - super.onCreate() - // initialize the singleton - instance = this - - networkComponent = DaggerNetworkComponent.create() - toastHelperComponent = buildToastHelperComponent() - - PrefsManager.getInstance().init(this) - - // common init - if (PINStorage.needInit()) - PINStorage.init(applicationContext) - - initIssuers() - - firmwaresStorage = Firmwares(applicationContext) - localStorage = LocalStorage(applicationContext) - pinStorage = PINStorage() - pendingTransactionsStorage = PendingTransactionsStorage(applicationContext) - - if (BuildConfig.DEBUG) { - Runtime.getRuntime().exec("logcat -G 16M") - com.tangem.tangem_card.util.Log.setLogger( - object : com.tangem.tangem_card.util.LoggerInterface { - override fun i(logTag: String, message: String) { - android.util.Log.i(logTag, message) - } - - override fun e(logTag: String, message: String) { - android.util.Log.e(logTag, message) - } - - override fun v(logTag: String, message: String) { - android.util.Log.v(logTag, message) - } - } - ) - } - - Analytics.setFirebaseEnabled(this) - } - - private fun buildToastHelperComponent(): ToastHelperComponent { - return DaggerToastHelperComponent.builder() - .build() - } - - private fun initIssuers() { - try { - applicationContext.assets.open("issuers.json").use { `is` -> - InputStreamReader(`is`, StandardCharsets.UTF_8).use { reader -> - val listType = object : TypeToken>() { - - }.type - - Issuer.fillIssuers(Gson().fromJson(reader, listType)) - } - } - } catch (e: Exception) { - e.printStackTrace() - } - - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/Constant.kt b/app/src/main/java/com/tangem/Constant.kt deleted file mode 100644 index db0b7531de..0000000000 --- a/app/src/main/java/com/tangem/Constant.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.tangem - -import android.app.Activity - -object Constant { - - const val FLAVOR_TANGEM_ACCESS = "tangemAccess" - const val FLAVOR_TANGEM_CARDANO = "tangemCardano" - - - const val PREF_LAST_WALLET_ADDRESS = "last_wallet_address" - - const val URL_TANGEM = "https://play.google.com/store/apps/details?id=com.tangem.wallet" - - const val EXTRA_BLOCKCHAIN_DATA = "BLOCKCHAIN_DATA" - - const val WALLET_ADDRESS = "Wallet address" - - const val EXTRA_MESSAGE = "message" - - const val EXTRA_MODIFICATION = "modification" - const val EXTRA_MODIFICATION_DELETE = "delete" - const val EXTRA_MODIFICATION_UPDATE = "update" - - const val EXTRA_MODE = "mode" - - const val INTENT_TYPE_TEXT_PLAIN = "text/plain" - - // LoadedWalletFragment, VerifyCardFragment - const val REQUEST_CODE_SEND_TRANSACTION = "REQUEST_CODE_SEND_TRANSACTION" - const val REQUEST_CODE_PURGE = "REQUEST_CODE_PURGE" - const val REQUEST_CODE_REQUEST_PIN2_FOR_PURGE = "REQUEST_CODE_REQUEST_PIN2_FOR_PURGE" - const val REQUEST_CODE_VERIFY_CARD = "REQUEST_CODE_VERIFY_CARD" - const val REQUEST_CODE_ENTER_NEW_PIN = "REQUEST_CODE_ENTER_NEW_PIN" - const val REQUEST_CODE_ENTER_NEW_PIN2 = "REQUEST_CODE_ENTER_NEW_PIN2" - const val REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = "REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN" - const val REQUEST_CODE_SWAP_PIN = "REQUEST_CODE_SWAP_PIN" - const val REQUEST_CODE_RECEIVE_TRANSACTION = "REQUEST_CODE_RECEIVE_TRANSACTION" - - // MainFragment - const val REQUEST_CODE_SHOW_CARD_ACTIVITY = "REQUEST_CODE_SHOW_CARD_ACTIVITY" - const val REQUEST_CODE_ENTER_PIN_ACTIVITY = "REQUEST_CODE_ENTER_PIN_ACTIVITY" - const val REQUEST_CODE_SEND_EMAIL = "REQUEST_CODE_SEND_EMAIL" - const val REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS = 3 - - const val EXTRA_LAST_DISCOVERED_TAG = "extra_last_tag" - const val EXTRA_PIN2 = "PIN2" - - // LogoFragment - const val EXTRA_AUTO_HIDE = "extra_auto_hide" - const val MILLIS_AUTO_HIDE = 1000 - - // PinRequestFragment - - const val KEY_ALIAS = "pinKey" - const val KEYSTORE = "AndroidKeyStore" - - // QrScanFragment - const val EXTRA_QR_CODE = "QRCode" - - // PinSwapFragment - const val EXTRA_CONFIRM_PIN = "confirmPIN" - const val EXTRA_CONFIRM_PIN_2 = "confirmPIN2" - const val EXTRA_NEW_PIN = "newPIN" - const val EXTRA_NEW_PIN_2 = "newPIN2" - - // CreateNewWalletFragment - const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER - - // EmptyWalletFragment - const val REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY = "REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY" - const val REQUEST_CODE_REQUEST_PIN2 = "REQUEST_CODE_REQUEST_PIN2" - - // ConfirmTransactionFragment - const val REQUEST_CODE_SIGN_TRANSACTION = "REQUEST_CODE_SIGN_TRANSACTION" - const val REQUEST_CODE_REQUEST_PIN2_ = "REQUEST_CODE_REQUEST_PIN2_" - - // SendTransactionFragment - const val EXTRA_TX: String = "TX" - - // SignTransactionFragment - const val EXTRA_AMOUNT = "Amount" - const val EXTRA_AMOUNT_CURRENCY = "AmountCurrency" - const val EXTRA_FEE = "Fee" - const val EXTRA_FEE_CURRENCY = "FeeCurrency" - const val EXTRA_FEE_INCLUDED = "FeeIncluded" - const val EXTRA_TARGET_ADDRESS = "TargetAddress" - const val REQUEST_CODE_SEND_TRANSACTION_ = "REQUEST_CODE_SEND_TRANSACTION_" - const val RESULT_INVALID_PIN_ = Activity.RESULT_FIRST_USER - - // PrepareTransactionFragment - const val REQUEST_CODE_SCAN_QR = "REQUEST_CODE_SCAN_QR" - const val REQUEST_CODE_SEND_TRANSACTION__ = "REQUEST_CODE_SEND_TRANSACTION__" - - // PrepareCryptonitOtherApiWithdrawalFragment - const val REQUEST_CODE_SCAN_QR_KEY = "REQUEST_CODE_SCAN_QR_KEY" - const val REQUEST_CODE_SCAN_QR_SECRET = "REQUEST_CODE_SCAN_QR_SECRET" - const val REQUEST_CODE_SCAN_QR_USER_ID = "REQUEST_CODE_SCAN_QR_USER_ID" - - const val TERMINAL_PRIVATE_KEY = "terminalPrivateKey" - const val TERMINAL_PUBLIC_KEY = "terminalPublicKey" -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/Blockchain.java b/app/src/main/java/com/tangem/data/Blockchain.java deleted file mode 100644 index 75b9b28495..0000000000 --- a/app/src/main/java/com/tangem/data/Blockchain.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.tangem.data; - -import com.tangem.tangem_sdk.R; - -/** - * Created by dvol on 06.08.2017. - */ -public enum Blockchain { - Unknown("", "", 1.0, R.drawable.ic_logo_unknown, "Unknown"), - Bitcoin("BTC", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"), - BitcoinTestNet("BTC/test", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin_testnet, "Bitcoin Testnet"), - BitcoinDual("BTC/dual", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"), - Ethereum("ETH", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"), - EthereumId("ETH/ID", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"), - EthereumTestNet("ETH/test", "ETH", 1.0, R.drawable.ic_logo_ethereum_testnet, "Ethereum Testnet"), - Token("Token", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"), - NftToken("NftToken", "", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"), - BitcoinCash("BCH", "BCH", 100000000.0, R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash"), - Litecoin("LTC", "LTC", 100000000.0, R.drawable.ic_logo_litecoin, "Litecoin"), - Rootstock("RSK", "RBTC", 1.0, R.drawable.tangem2, "RSK"), - RootstockToken("RskToken", "RBTC", 1.0, R.drawable.tangem2, "RSK"), - Cardano("CARDANO", "ADA", 1000000.0, R.drawable.tangem2, "Cardano"), - Ripple("XRP", "XRP", 1000000.0, R.drawable.ic_logo_xrp, "XRP Ledger"), - Binance("BINANCE", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance"), - BinanceTestNet("BINANCE/test", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance Testnet"), - BinanceAsset("BinanceAsset", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance"), - Matic("MATIC", "MTX", 1.0, R.drawable.tangem2, "Matic"), - MaticTestNet("MATIC/test", "MTX", 1.0, R.drawable.tangem2, "Matic Testnet"), - Stellar("XLM", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar"), - StellarTestNet("XLM/test", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar Testnet"), - StellarAsset("Asset", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar"), - StellarTag("XLM-Tag", "XLM", 1000000.0, R.drawable.ic_logo_stellar, "Stellar"), - Eos("EOS", "EOS", 10000.0, R.drawable.tangem2, "EOS"), - Ducatus("DUC", "DUC", 100000000.0, R.drawable.tangem2, "Ducatus"), - Tezos("TEZOS", "XTZ", 10000000.0, R.drawable.ic_logo_tezos, "Tezos"), - FlowDemo("FLOW/demo", "", 1.0, R.drawable.tangem2, "Flow demo"), - TokenEmv("TTW", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"); - - Blockchain(String ID, String currency, double multiplier, int imageResource, String officialName) { - mID = ID; - mCurrency = currency; -// mMultiplier = multiplier; - mImageResource = imageResource; - mOfficialName = officialName; - } - - private String mID, mOfficialName; - //private double mMultiplier; - private String mCurrency; - private int mImageResource; - - public String getID() { - return mID; - } - - public String getOfficialName() { - return mOfficialName; - } - -// public double getMultiplier() { -// return mMultiplier; -// } - - public String getCurrency() { - return mCurrency; - } - - public static Blockchain fromId(String id) { - for (Blockchain blockchain : values()) { - if (blockchain.getID().equals(id)) return blockchain; - } - return Blockchain.Unknown; - } - - public static Blockchain fromCurrency(String currency) { - for (Blockchain blockchain : values()) { - if (blockchain.getCurrency() == currency) return blockchain; - } - return null; - } - - public static String[] getCurrencies() { - String[] result = new String[values().length - 1]; - for (int i = 0; i < result.length - 1; i++) { - result[i] = values()[i + 1].getCurrency(); - } - return result; - } - - private int getImageResource() { - return mImageResource; - } - - public int getLogoImageResource(String symbolName) { - switch (this) { - case Token: - if (symbolName.equals("SEED")) - return R.drawable.ic_logo_seed; - break; - case RootstockToken: - if (symbolName.equals("RIF")) - return R.drawable.ic_logo_rif; - } - - return getImageResource(); - } - - public String getUriScheme() { - String scheme = null; - switch (this) { - case Bitcoin: - case BitcoinDual: - scheme = "bitcoin"; - break; - case Ethereum: - case Token: - case TokenEmv: - scheme = "ethereum"; - break; - case Litecoin: - scheme = "litecoin"; - break; - case Ripple: - scheme = "ripple"; - } - return scheme; - } -} diff --git a/app/src/main/java/com/tangem/data/LogFileProvider.java b/app/src/main/java/com/tangem/data/LogFileProvider.java deleted file mode 100644 index b5461ae90d..0000000000 --- a/app/src/main/java/com/tangem/data/LogFileProvider.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.tangem.data; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.UriMatcher; -import android.database.Cursor; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -import com.tangem.wallet.R; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.Objects; - -/** - * Created by dvol on 15.02.2018. - */ - -public class LogFileProvider extends ContentProvider { - - private static final String TAG = LogFileProvider.class.getSimpleName() + "-oF"; - - // UriMatcher used to match against incoming requests - private UriMatcher uriMatcher; - - @Override - public boolean onCreate() { - uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - - // Add a URI to the matcher which will match against the form - // 'content://it.my.app.LogFileProvider/*' - // and return 1 in the case that the incoming Uri matches this pattern - - uriMatcher.addURI(Objects.requireNonNull(getContext()).getString(R.string.log_file_provider_authorities), "*", 1); - - return true; - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - - Log.v(TAG, "Called with uri: '" + uri + "'." + uri.getLastPathSegment()); - - // check incoming Uri against the matcher - switch (uriMatcher.match(uri)) { - - // If it returns 1 - then it matches the Uri defined in onCreate - case 1: - - // The desired file name is specified by the last segment of the - // path - // E.g. - // 'content://it.my.app.LogFileProvider/Test1.txt' - // Take this and build the path to the file - String fileLocation = getContext().getCacheDir() + File.separator - + uri.getLastPathSegment(); - - // Create & return a ParcelFileDescriptor pointing to the file - // Note: I don't care what mode they ask for - they're only getting - // read only - ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY); - return pfd; - - // Otherwise unrecognised Uri - default: - Log.v(TAG, "Unsupported uri: '" + uri + "'."); - throw new FileNotFoundException("Unsupported uri: " + uri.toString()); - } - } - - // ////////////////////////////////////////////////////////////// - // Not supported / used / required for this example - // ////////////////////////////////////////////////////////////// - - @Override - public int update(Uri uri, ContentValues contentvalues, String s, - String[] as) { - return 0; - } - - @Override - public int delete(Uri uri, String s, String[] as) { - return 0; - } - - @Override - public Uri insert(Uri uri, ContentValues contentvalues) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Cursor query(Uri uri, String[] projection, String s, String[] as1, - String s1) { - return null; - } -} diff --git a/app/src/main/java/com/tangem/data/Logger.java b/app/src/main/java/com/tangem/data/Logger.java deleted file mode 100644 index 8cf42d6737..0000000000 --- a/app/src/main/java/com/tangem/data/Logger.java +++ /dev/null @@ -1,285 +0,0 @@ -package com.tangem.data; - -import android.content.Context; -import android.util.Log; - -import com.tangem.tangem_card.util.Util; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Date; - -public class Logger { - - public static File collectLogs(Context context) { - File f = new File(context.getCacheDir().getAbsolutePath() + "/Wallet_" + Util.formatDateTimeToFileName(new Date()) + ".log"); - try { - if (f.createNewFile()) { - f.setReadable(true); - FileWriter fileWriter = new FileWriter(f, true); - Process process = Runtime.getRuntime().exec("logcat -d -v time"); - try { - InputStream is = process.getInputStream(); - InputStreamReader isr = new InputStreamReader(is); - BufferedReader bufferedReader = new BufferedReader(isr); - BufferedWriter buf = new BufferedWriter(fileWriter); - buf.append("Tangem Wallet logs"); - buf.newLine(); - - int i = 0; - String line; - while ((line = bufferedReader.readLine()) != null) { - buf.append(line); - buf.newLine(); - i++; - } - Log.e("Logger", String.format("%d log lines collected", i)); - buf.newLine(); - buf.flush(); - buf.close(); - - } finally { - process.destroy(); - } - - return f; - } - } catch (Exception e) { - e.printStackTrace(); - } - - return null; - } - - -} - -//public class Logger { -// -// public static File[] getLastLogFiles() { -// File path = new File(Environment.getExternalStorageDirectory(), "Tangem/logs"); -// if (!path.exists()) { -// return null; -// } -// File[] files = path.listFiles(); -// Arrays.sort(files, new Comparator() { -// @Override -// public int compare(File o1, File o2) { -// if (o1.lastModified() < o2.lastModified()) { -// return -1; -// } else if (o1.lastModified() > o2.lastModified()) { -// return 1; -// } -// return 0; -// } -// }); -// if (files.length < 5) return files; -// return Arrays.copyOfRange(files, files.length - 5, files.length); -// } -// -// private static File logFile = null; -// -// private static void initLogFile(Context context) { -// try { -// File path = new File(Environment.getExternalStorageDirectory(), "Tangem/logs"); -// if (!path.exists()) { -// path.mkdirs(); -// MediaScannerConnection.scanFile(context, new String[]{path.getParentFile().toString()}, null, null); -// } -// logFile = new File(path, String.format("wallet_%s.log", Util.formatDateTimeToFileName(new Date()))); -// logFile.createNewFile(); -// logFile.setReadable(true); -// -// // initiate media scan and put the new things into the path array to -// // make the scanner aware of the location and the files you want to see -// MediaScannerConnection.scanFile(context, new String[]{logFile.getAbsolutePath()}, null, null); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// -// } -// -// public static boolean isCurrent(File f) { -// if (f == null || logFile == null) return false; -// return f.getAbsolutePath().equals(logFile.getAbsolutePath()); -// } -// -// -// private static class LogCatThread extends Thread { -// private boolean Terminated; -// -// private static final Object oSync = new Object(); -// -// public void Terminate() { -// Terminated = true; -// synchronized (oSync) { -// oSync.notifyAll(); -// } -// try { -// join(1000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// interrupt(); -// } -// } -// -// public void collectLogs(Writer out) { -// try { -// Process process = Runtime.getRuntime().exec("logcat -d -b main -v time"); -// try { -// InputStream is = process.getInputStream(); -// InputStreamReader isr = new InputStreamReader(is); -// BufferedReader bufferedReader = new BufferedReader(isr); -// try { -// -// try { -// //BufferedWriter for performance, true to set append to file flag -// BufferedWriter buf = new BufferedWriter(out); -// -// while (!Terminated && isr.ready()) { -// String line = bufferedReader.readLine(); -// buf.append(line); -// buf.newLine(); -// } -// //Log.i("Logger",String.format("%d lines added",i)); -// buf.newLine(); -// buf.close(); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// -// -// } catch (Exception e) { -// e.printStackTrace(); -// } -// -// } finally { -// process.destroy(); -// } -// } catch (IOException e) { -// e.printStackTrace(); -// } -// -// } -// -// @Override -// public void run() { -// Process process = null; -// try { -// if (logFile == null) return; -// process = Runtime.getRuntime().exec("logcat -b main -v time"); -// try { -// InputStream is = process.getInputStream(); -// InputStreamReader isr = new InputStreamReader(is); -// BufferedReader bufferedReader = new BufferedReader(isr); -// while (!Terminated) { -// try { -// synchronized (oSync) { -// oSync.wait(1000); -// } -// if (!logFile.exists()) { -// try { -// logFile.createNewFile(); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } -// try { -// //BufferedWriter for performance, true to set append to file flag -// BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); -// -// while (isr.ready()) { -// String line = bufferedReader.readLine(); -// buf.append(line); -// buf.newLine(); -// } -// //Log.i("Logger",String.format("%d lines added",i)); -// buf.newLine(); -// buf.close(); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// -// -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// } finally { -// process.destroy(); -// } -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } -// } -// -// static LogCatThread t = new LogCatThread(); -// -// public static void StartSaveToFile(Activity activity) { -// try { -// if (logFile != null) return; -// -// verifyStoragePermissions(activity); -// initLogFile(activity.getApplicationContext()); -// t.init(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// -// public static void StopSaveToFile(Context context) { -// final Object oSync = new Object(); -// if (t.isAlive()) { -// t.Terminate(); -// } -// if (logFile != null) { -// MediaScannerConnection.scanFile(context, new String[]{logFile.getAbsolutePath().toString()}, null, new MediaScannerConnection.OnScanCompletedListener() { -// @Override -// public void onScanCompleted(String path, Uri uri) { -//// synchronized (oSync) { -//// oSync.notifyAll(); -//// } -// } -// }); -//// try { -//// synchronized (oSync) { -//// oSync.wait(10000); -// logFile = null; -//// } -//// } catch (InterruptedException e) { -//// e.printStackTrace(); -//// } -// } -// -// } -// -// // Storage Permissions -// private static final int REQUEST_EXTERNAL_STORAGE = 1; -// private static String[] PERMISSIONS_STORAGE = { -// Manifest.permission.READ_EXTERNAL_STORAGE, -// Manifest.permission.WRITE_EXTERNAL_STORAGE -// }; -// -// //Checks if the app has permission to write to device storage -// //If the app does not has permission then the user will be prompted to grant permissions -// public static void verifyStoragePermissions(Activity activity) { -// // check if we have write permission -// int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); -// -// if (permission != PackageManager.PERMISSION_GRANTED) { -// // We don't have permission so prompt the user -// ActivityCompat.requestPermissions( -// activity, -// PERMISSIONS_STORAGE, -// REQUEST_EXTERNAL_STORAGE -// ); -// } -// } -// -//} - diff --git a/app/src/main/java/com/tangem/data/PayId.kt b/app/src/main/java/com/tangem/data/PayId.kt deleted file mode 100644 index 3c882fbdd7..0000000000 --- a/app/src/main/java/com/tangem/data/PayId.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.tangem.data - -import java.util.* - -private val payIdSupported = EnumSet.of( - Blockchain.Ripple, - Blockchain.Ethereum, - Blockchain.Bitcoin, - Blockchain.Token, - Blockchain.Litecoin, - Blockchain.Stellar, - Blockchain.StellarAsset, - Blockchain.Cardano, - Blockchain.Ducatus, - Blockchain.BitcoinCash, - Blockchain.Binance, - Blockchain.BinanceAsset, - Blockchain.Rootstock, - Blockchain.RootstockToken -) - -fun Blockchain.isPayIdSupported(): Boolean { - return payIdSupported.contains(this) -} - -fun Blockchain.getPayIdNetwork(): String { - return when (this) { - Blockchain.Ripple -> "XRPL" - Blockchain.Rootstock, Blockchain.RootstockToken -> "RSK" - else -> this.currency - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/dp/PrefsManager.kt b/app/src/main/java/com/tangem/data/dp/PrefsManager.kt deleted file mode 100644 index 598c719e2b..0000000000 --- a/app/src/main/java/com/tangem/data/dp/PrefsManager.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.tangem.data.dp - -import android.annotation.SuppressLint -import android.content.Context -import android.content.SharedPreferences -import androidx.preference.PreferenceManager -import com.orhanobut.hawk.Hawk -import com.tangem.Constant -import com.tangem.tangem_card.reader.CardCrypto - -class PrefsManager { - companion object { - const val PREF_NAME = "tangem_access" - - @SuppressLint("StaticFieldLeak") - private var instance: PrefsManager? = null - - fun getInstance(): PrefsManager { - if (instance == null) { - instance = PrefsManager() - } - return instance as PrefsManager - } - } - - private lateinit var context: Context - private lateinit var preferences: SharedPreferences - - fun init(context: Context) { - this.context = context - preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - Hawk.init(context).build() - } - - val lastWalletAddress: String - get() = Hawk.get(Constant.PREF_LAST_WALLET_ADDRESS, "") - - fun saveLastWalletAddress(value: String) { - Hawk.put(Constant.PREF_LAST_WALLET_ADDRESS, value) - } - - fun clearLastWalletAddress() { - Hawk.delete(Constant.PREF_LAST_WALLET_ADDRESS) - } - - fun getSettingsBoolean(key: Int, default: Boolean): Boolean { - return PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean(context.getString(key), default) - } - - fun appendCid(newCid: String) { - val prevCids: String = Hawk.get("CID_Key", "") - if (!prevCids.contains(newCid)) Hawk.put("CID_Key", "$prevCids$newCid, ") - } - - fun getAllCids(): String = Hawk.get("CID_Key", "") - - val terminalKeys: Map - get() { - val privateKey = Hawk.get(Constant.TERMINAL_PRIVATE_KEY) ?: byteArrayOf() - val publicKey = Hawk.get(Constant.TERMINAL_PUBLIC_KEY) ?: byteArrayOf() - return if (privateKey.isNotEmpty() && publicKey.isNotEmpty()) { - mapOf(Constant.TERMINAL_PRIVATE_KEY to privateKey, Constant.TERMINAL_PUBLIC_KEY to publicKey) - } else { - val keys = CardCrypto.generateTerminalKeys() - Hawk.put(Constant.TERMINAL_PRIVATE_KEY, keys[Constant.TERMINAL_PRIVATE_KEY]) - Hawk.put(Constant.TERMINAL_PUBLIC_KEY, keys[Constant.TERMINAL_PUBLIC_KEY]) - keys - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/fingerprint/ConfirmWithFingerprintTask.java b/app/src/main/java/com/tangem/data/fingerprint/ConfirmWithFingerprintTask.java deleted file mode 100644 index e4562d7688..0000000000 --- a/app/src/main/java/com/tangem/data/fingerprint/ConfirmWithFingerprintTask.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.tangem.data.fingerprint; - -import android.os.AsyncTask; -import android.widget.Toast; - -import com.tangem.ui.fragment.pin.PinSaveFragment; -import com.tangem.wallet.R; - -import java.lang.ref.WeakReference; - -import javax.crypto.Cipher; - -public class ConfirmWithFingerprintTask extends AsyncTask { - private WeakReference reference; - - public ConfirmWithFingerprintTask(PinSaveFragment context) { - reference = new WeakReference<>(context); - - reference.get().setFingerprintHelper(new FingerprintHelper(reference.get())); - } - - @Override - protected Boolean doInBackground(Void... params) { - PinSaveFragment pinSaveFragment = reference.get(); - - if (!pinSaveFragment.getKeyStore()) - return false; - - if (!pinSaveFragment.createNewKey(false)) - return false; - - if (!pinSaveFragment.getCipher()) - return false; - - return pinSaveFragment.initCipher(Cipher.ENCRYPT_MODE) && pinSaveFragment.initCryptObject(); - - } - - @Override - protected void onPostExecute(final Boolean success) { - PinSaveFragment pinSaveFragment = reference.get(); - - onCancelled(); - - if (!success) { - Toast.makeText(pinSaveFragment.getContext(), R.string.pin_save_notification_failed, Toast.LENGTH_LONG).show(); - } else { - pinSaveFragment.getFingerprintHelper().startAuth(pinSaveFragment.getFingerprintManager(), pinSaveFragment.getCryptoObject()); - } - } - - @Override - protected void onCancelled() { - PinSaveFragment pinSaveFragment = reference.get(); - - if (pinSaveFragment.getDFingerPrintConfirmation() != null) { - pinSaveFragment.getDFingerPrintConfirmation().cancel(); - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/fingerprint/FingerprintHelper.java b/app/src/main/java/com/tangem/data/fingerprint/FingerprintHelper.java deleted file mode 100644 index 3f36830d2d..0000000000 --- a/app/src/main/java/com/tangem/data/fingerprint/FingerprintHelper.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.tangem.data.fingerprint; - -import android.annotation.TargetApi; -import android.hardware.fingerprint.FingerprintManager; -import android.os.Build; -import android.os.CancellationSignal; - -/** - * Created by dtaka on 8/20/2016. - */ -@TargetApi(Build.VERSION_CODES.M) -public class FingerprintHelper extends FingerprintManager.AuthenticationCallback { - private FingerprintHelperListener listener; - - public FingerprintHelper(FingerprintHelperListener listener) { - this.listener = listener; - } - - private CancellationSignal cancellationSignal; - - public void startAuth(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) { - cancellationSignal = new CancellationSignal(); - - try { - manager.authenticate(cryptoObject, cancellationSignal, 0, this, null); - } catch (SecurityException ex) { - listener.authenticationFailed("An error occurred:\n" + ex.getMessage()); - } catch (Exception ex) { - listener.authenticationFailed("An error occurred\n" + ex.getMessage()); - } - } - - public void cancel() { - if (cancellationSignal != null) - cancellationSignal.cancel(); - } - - public interface FingerprintHelperListener { - public void authenticationFailed(String error); - public void authenticationSucceeded(FingerprintManager.AuthenticationResult result); - } - - @Override - public void onAuthenticationError(int errMsgId, CharSequence errString) { - listener.authenticationFailed("Authentication error\n" + errString); - } - - @Override - public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { - listener.authenticationFailed("Authentication help\n" + helpString); - } - - @Override - public void onAuthenticationFailed() { - listener.authenticationFailed("Authentication failed."); - } - - @Override - public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { - listener.authenticationSucceeded(result); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/fingerprint/StartFingerprintReaderTask.java b/app/src/main/java/com/tangem/data/fingerprint/StartFingerprintReaderTask.java deleted file mode 100644 index 90b3456b45..0000000000 --- a/app/src/main/java/com/tangem/data/fingerprint/StartFingerprintReaderTask.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.tangem.data.fingerprint; - -import android.annotation.TargetApi; -import android.hardware.fingerprint.FingerprintManager; -import android.os.AsyncTask; -import android.os.Build; -import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.KeyPermanentlyInvalidatedException; -import android.security.keystore.KeyProperties; - -import com.tangem.Constant; -import com.tangem.tangem_sdk.android.data.PINStorage; -import com.tangem.ui.fragment.pin.PinRequestFragment; -import com.tangem.util.LOG; - -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; - -public class StartFingerprintReaderTask extends AsyncTask { - public static final String TAG = StartFingerprintReaderTask.class.getSimpleName(); - - private WeakReference reference; - - private KeyStore keyStore; - private Cipher cipher; - - private FingerprintManager.CryptoObject cryptoObject; - - FingerprintManager fingerprintManager; - FingerprintHelper fingerprintHelper; - - PinRequestFragment fragment; - - public StartFingerprintReaderTask(PinRequestFragment fragment, FingerprintManager fingerprintManager, FingerprintHelper fingerprintHelper) { - reference = new WeakReference<>(fragment); - this.fingerprintManager = fingerprintManager; - this.fingerprintHelper = fingerprintHelper; - this.fragment = fragment; - } - - @Override - protected Boolean doInBackground(Void... params) { - if (!getKeyStore()) - return false; - - if (!createNewKey(false)) - return false; - - if (!getCipher()) - return false; - - if (!initCipher(Cipher.DECRYPT_MODE)) - return false; - - return initCryptObject(); - } - - @Override - protected void onPostExecute(final Boolean success) { - - onCancelled(); - - if (!success) { - LOG.i(TAG, "Authentication failed!"); - } else { - fingerprintHelper.startAuth(fingerprintManager, cryptoObject); - LOG.i(TAG, "Authenticate using fingerprint!"); - } - } - - @Override - protected void onCancelled() { - PinRequestFragment fragment = reference.get(); - - fragment.setStartFingerprintReaderTask(null); - } - - private boolean getKeyStore() { - LOG.i(TAG, "Getting keystore..."); - try { - keyStore = KeyStore.getInstance(Constant.KEYSTORE); - keyStore.load(null); // Create empty keystore - return true; - } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) { - e.printStackTrace(); - } - - return false; - } - - @TargetApi(Build.VERSION_CODES.M) - public boolean createNewKey(boolean forceCreate) { - LOG.i(TAG, "Creating new key..."); - try { - if (forceCreate) - keyStore.deleteEntry(Constant.KEY_ALIAS); - - if (!keyStore.containsAlias(Constant.KEY_ALIAS)) { - KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, Constant.KEYSTORE); - - generator.init(new KeyGenParameterSpec.Builder(Constant.KEY_ALIAS, - KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(KeyProperties.BLOCK_MODE_CBC) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) - .setUserAuthenticationRequired(true) - .build() - ); - - generator.generateKey(); - LOG.i(TAG, "Key created."); - } else - LOG.i(TAG, "Key exists."); - - return true; - } catch (Exception e) { - e.printStackTrace(); - } - - return false; - } - - private boolean getCipher() { - LOG.i(TAG, "Getting cipher..."); - try { - cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7); - return true; - } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { - e.printStackTrace(); - } - - return false; - } - - @TargetApi(Build.VERSION_CODES.M) - private boolean initCipher(int mode) { - PinRequestFragment fragment = reference.get(); - - LOG.i(TAG, "Initializing cipher..."); - try { - keyStore.load(null); - SecretKey keyspec = (SecretKey) keyStore.getKey(Constant.KEY_ALIAS, null); - - if (mode == Cipher.ENCRYPT_MODE) { - cipher.init(mode, keyspec); - } else { - byte[] iv = null; - if (fragment.getMode() == PinRequestFragment.Mode.RequestPIN || - fragment.getMode() == PinRequestFragment.Mode.RequestNewPIN || - fragment.getMode() == PinRequestFragment.Mode.ConfirmNewPIN) { - iv = PINStorage.loadEncryptedIV(); - } else if (fragment.getMode() == PinRequestFragment.Mode.RequestPIN2 || - fragment.getMode() == PinRequestFragment.Mode.RequestNewPIN2 || - fragment.getMode() == PinRequestFragment.Mode.ConfirmNewPIN2) { - iv = PINStorage.loadEncryptedIV2(); - } - IvParameterSpec ivspec = new IvParameterSpec(iv); - cipher.init(mode, keyspec, ivspec); - } - - return true; - } catch (KeyPermanentlyInvalidatedException e) { - e.printStackTrace(); - createNewKey(true); // Retry after clearing entry - } catch (Exception e) { - e.printStackTrace(); - } - - return false; - } - - @TargetApi(Build.VERSION_CODES.M) - private boolean initCryptObject() { - LOG.i(TAG, "Initializing crypt object..."); - try { - cryptoObject = new FingerprintManager.CryptoObject(cipher); - return true; - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } - -} diff --git a/app/src/main/java/com/tangem/data/local/PendingTransactionsStorage.kt b/app/src/main/java/com/tangem/data/local/PendingTransactionsStorage.kt deleted file mode 100644 index dca7483d44..0000000000 --- a/app/src/main/java/com/tangem/data/local/PendingTransactionsStorage.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.tangem.data.local - -import android.content.Context -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import com.tangem.tangem_card.data.TangemCard -import java.io.File -import java.util.* -import kotlin.collections.HashMap - -class PendingTransactionsStorage -( - val context: Context -) { - private lateinit var cardTransactions: MutableMap - private val transactionsFile: File = File(context.filesDir, "transactions.json") - - private var cacheDir: File? = null - - init { - cacheDir = File(context.filesDir, "artworks") - if (!cacheDir!!.exists()) - cacheDir!!.mkdirs() - - if (transactionsFile.exists()) { - try { - transactionsFile.bufferedReader().use { cardTransactions = Gson().fromJson(it, object : TypeToken>() {}.type) } - } catch (e: Exception) { - e.printStackTrace() - cardTransactions = HashMap() - } - } else { - cardTransactions = HashMap() - } - } - - private fun clearExpired() - { - for(cardId in cardTransactions.keys) { - cardTransactions[cardId]!!.transactions.removeAll { it.isExpired() } - } - cardTransactions.entries.removeAll { it.value.isEmpty() } - } - - fun save() { - clearExpired() - val sTransactions = Gson().toJson(cardTransactions) - - transactionsFile.bufferedWriter().use { it.write(sTransactions) } - } - - fun putTransaction(card: TangemCard, txId: String, expireTimeoutInSeconds: Int) { - val sendDate=Date() - val calendar=Calendar.getInstance() - calendar.time=sendDate - calendar.add(Calendar.SECOND, expireTimeoutInSeconds) - val expireDate=calendar.time - putTransaction(card.cidDescription, txId, sendDate, expireDate) - } - - private fun putTransaction(cardId: String, txId: String, sendDate: Date, expireDate: Date) { - val transactionInfo = TransactionInfo( - txId, sendDate, expireDate - ) - if (cardTransactions[cardId] == null) { - cardTransactions[cardId] = CardTransactionsInfo(arrayListOf()) - } - cardTransactions[cardId]?.transactions?.add(transactionInfo) - save() - } - - fun getTransactions(card: TangemCard): CardTransactionsInfo? { - clearExpired() - return cardTransactions[card.cidDescription] - } - - fun hasTransactions(card: TangemCard): Boolean { - val cardTransactionsInfo=getTransactions(card) - if( cardTransactionsInfo!=null ) return cardTransactionsInfo.transactions.count()>0 - return false - } - - fun removeTransaction(card: TangemCard, txId: String) - { - cardTransactions[card.cidDescription]?.transactions?.removeAll { it.tx==txId } - save() - } - - data class TransactionInfo( - val tx: String, - val sendDate: Date, - val expireDate: Date - ) { - fun isExpired(): Boolean { - return Date().after(expireDate) - } - } - - data class CardTransactionsInfo( - var transactions: MutableList - ) { - fun isEmpty(): Boolean { - return transactions.count()==0 - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/AdaliteApi.java b/app/src/main/java/com/tangem/data/network/AdaliteApi.java deleted file mode 100644 index 3a6b380945..0000000000 --- a/app/src/main/java/com/tangem/data/network/AdaliteApi.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.AdaliteBody; -import com.tangem.data.network.model.AdaliteResponse; -import com.tangem.data.network.model.AdaliteResponseUtxo; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.Headers; -import retrofit2.http.POST; -import retrofit2.http.Path; - -public interface AdaliteApi { - @GET(ServerApiAdalite.ADALITE_ADDRESS) - Call adaliteAddress(@Path("address") String address); - - @Headers("Content-Type: application/json") - @POST(ServerApiAdalite.ADALITE_UNSPENT_OUTPUTS) - Call adaliteUnspent(@Body String address); - -// @GET(ServerApiAdalite.ADALITE_TRANSACTION) -// Call adaliteTransaction(@Path("txId") String txId); - - @Headers("Content-Type: application/json") - @POST(ServerApiAdalite.ADALITE_SEND) - Call adaliteSend(@Body AdaliteBody adaliteBody); -} diff --git a/app/src/main/java/com/tangem/data/network/BinanceApi.java b/app/src/main/java/com/tangem/data/network/BinanceApi.java deleted file mode 100644 index 5bc0b95059..0000000000 --- a/app/src/main/java/com/tangem/data/network/BinanceApi.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.BinanceFees; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.http.GET; - -public interface BinanceApi { - @GET("fees") - Call> binanceFees(); -} diff --git a/app/src/main/java/com/tangem/data/network/BlockchainInfoApi.java b/app/src/main/java/com/tangem/data/network/BlockchainInfoApi.java deleted file mode 100644 index 7584a12d64..0000000000 --- a/app/src/main/java/com/tangem/data/network/BlockchainInfoApi.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.BlockchainInfoAddress; -import com.tangem.data.network.model.BlockchainInfoUnspents; - -import io.reactivex.Single; -import okhttp3.ResponseBody; -import retrofit2.http.Field; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; -import retrofit2.http.Query; - -public interface BlockchainInfoApi { - @GET(Server.ApiBlockchainInfo.Method.ADDRESS) - Single blockchainInfoAddress(@Path("address") String address, @Query("offset") Integer offset); - - @GET(Server.ApiBlockchainInfo.Method.UTXO) - Single blockchainInfoUnspents(@Query("active") String address); - - @FormUrlEncoded - @POST(Server.ApiBlockchainInfo.Method.PUSH) - Single blockchainInfoPush(@Field("tx") String tx); -} diff --git a/app/src/main/java/com/tangem/data/network/BlockchairApi.java b/app/src/main/java/com/tangem/data/network/BlockchairApi.java deleted file mode 100644 index ae6f01624b..0000000000 --- a/app/src/main/java/com/tangem/data/network/BlockchairApi.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.BlockchairAddressResponse; -import com.tangem.data.network.model.BlockchairSendBody; -import com.tangem.data.network.model.BlockchairStatsResponse; -import com.tangem.data.network.model.BlockchairTransactionResponse; - -import io.reactivex.Completable; -import io.reactivex.Single; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; - -public interface BlockchairApi { - @GET(Server.ApiBlockchair.Method.ADDRESS) - Single getAddress(@Path("blockchain") String blockchain, @Path("address") String address); - - @GET(Server.ApiBlockchair.Method.TRANSACTION) - Single getTransaction(@Path("blockchain") String blockchain, @Path("transaction") String transaction); - - @GET(Server.ApiBlockchair.Method.STATS) - Single getStats(@Path("blockchain") String blockchain); - - @POST(Server.ApiBlockchair.Method.PUSH) - Completable sendTransaction(@Path("blockchain") String blockchain, @Body BlockchairSendBody body); -} diff --git a/app/src/main/java/com/tangem/data/network/BlockcypherApi.java b/app/src/main/java/com/tangem/data/network/BlockcypherApi.java deleted file mode 100644 index 8bba6dfdee..0000000000 --- a/app/src/main/java/com/tangem/data/network/BlockcypherApi.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.BlockcypherBody; -import com.tangem.data.network.model.BlockcypherResponse; -import com.tangem.data.network.model.BlockcypherFee; -import com.tangem.data.network.model.BlockcypherTx; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.Headers; -import retrofit2.http.POST; -import retrofit2.http.Path; -import retrofit2.http.Query; - -public interface BlockcypherApi { - @GET(Server.ApiBlockcypher.Method.MAIN) - Call blockcypherMain(@Path("blockchain") String blockchain, @Path("network") String network, @Query("token") String token); - - @GET(Server.ApiBlockcypher.Method.ADDRESS) - Call blockcypherAddress(@Path("blockchain") String blockchain, @Path("network") String network, @Path("address") String address, @Query("token") String token); - - @GET(Server.ApiBlockcypher.Method.TXS) - Call blockcypherTxs(@Path("blockchain") String blockchain, @Path("network") String network, @Path("txHash") String txHash, @Query("token") String token); - - @Headers("Content-Type: application/json") - @POST(Server.ApiBlockcypher.Method.PUSH) - Call blockcypherPush(@Path("blockchain") String blockchain, @Path("network") String network, @Body BlockcypherBody blockcypherBody, @Query("token") String token); -} diff --git a/app/src/main/java/com/tangem/data/network/BlockcypherToken.kt b/app/src/main/java/com/tangem/data/network/BlockcypherToken.kt deleted file mode 100644 index 32bf303df9..0000000000 --- a/app/src/main/java/com/tangem/data/network/BlockcypherToken.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.tangem.data.network - -enum class BlockcypherToken(val token: String) { - T_001("aa8184b0e0894b88a5688e01b3dc1e82"), - T_002("56c4ca23c6484c8f8864c32fde4def8d"), - T_003("66a8a37c5e9d4d2c9bb191acfe7f93aa") -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/CoinmarketApi.java b/app/src/main/java/com/tangem/data/network/CoinmarketApi.java deleted file mode 100644 index fd3699ba08..0000000000 --- a/app/src/main/java/com/tangem/data/network/CoinmarketApi.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.RateInfoResponse; - -import io.reactivex.Observable; -import retrofit2.http.GET; -import retrofit2.http.Headers; -import retrofit2.http.Query; - -public interface CoinmarketApi { - @Headers("X-CMC_PRO_API_KEY: f6622117-c043-47a0-8975-9d673ce484de") - @GET(Server.ApiCoinmarket.Method.PRICE_CONVERSION) - Observable getRateInfo(@Query("amount") int amount, @Query("symbol") String cryptoId); -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/Cryptonit.java b/app/src/main/java/com/tangem/data/network/Cryptonit.java deleted file mode 100644 index 75f9586baa..0000000000 --- a/app/src/main/java/com/tangem/data/network/Cryptonit.java +++ /dev/null @@ -1,317 +0,0 @@ -package com.tangem.data.network; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.internal.LinkedTreeMap; -import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import com.tangem.wallet.R; - -import java.io.IOException; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -//import okhttp3.logging.HttpLoggingInterceptor; -import retrofit2.Call; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import retrofit2.http.Body; -import retrofit2.http.Header; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -/** - * HTTP - * Used in Cryptonit service - */ -public class Cryptonit { - private static final String SERVER_URL = "https://www.cryptonit.net:443/gateway/"; - - private static class Method { - public static final String AUTHENTICATE = SERVER_URL + "public/authenticate"; - public static final String BALANCE = SERVER_URL + "private/balance"; - public static final String WITHDRAW_COINS = SERVER_URL + "private/withdrawCoins"; - } - - public static class Model { - - static class Authenticate - { - public static class Request - { - public String username; - public String password; - } - public static class Response - { - boolean success; - String[] missing_authenticators; - public Object[] infos; - public Object[] warnings; - public Object[] errors; - AuthenticationResult results; - } - - static class AuthenticationResult { -// token (string): authentication token, -// nick (string), -// stayLoggedIn (boolean), -// integer lastLogin (integer): JavaScript time OR NEVER for first login, -// preferredLanguage (string) = ['en' or 'de'] - - } - - } - - public static class Balance { - static class Request { - String[] currencies; - } - public static class Response { - public boolean success; - public Object[] infos; - public Object[] warnings; - public Object[] errors; - public BalanceResult[] results; - - public static class BalanceResult { - public String currency; - public double balance; - public String receiveAddress; //the current address to receive funds for this account, if available, - public boolean fiat; // Is this a FIAT currency? If false, this is a CRYPTO currency., - public Object[] unprocessedTransactions; // (array, optional): list of unprocessed transactions, if pass field withTransactions - } - } - } - - public static class WithdrawCoins { - public static class Request { - public String currency; - public Double amount; - String toAddress; - Double includeMinerFee; - String password; - } - public static class Response { - public Boolean success; - public String[] missing_authenticators; - public Object[] infos; - public Object[] warnings; - public Object[] errors; - } - } - } - - public interface Api { - @Headers("Content-Type: application/json") - @POST(Method.AUTHENTICATE) - Call authenticate(@Body Model.Authenticate.Request request); - - @Headers("Content-Type: application/json") - @POST(Method.BALANCE) - Observable getBalance(@Header("Auth-Token") String authToken, @Body Model.Balance.Request request); - - @Headers("Content-Type: application/json") - @POST(Method.WITHDRAW_COINS) - Observable withdrawCoins(@Header("Auth-Token") String authToken, @Body Model.WithdrawCoins.Request request); - } - - private Api api = null; - private BalanceListener balanceListener; - private WithdrawalListener withdrawalListener; - private ErrorListener errorListener; - private Context context; - private String authToken; - - public Cryptonit(Context context) { - this.context = context; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - username = sp.getString(context.getResources().getString(R.string.key_cryptonit_username), ""); - password = sp.getString(context.getResources().getString(R.string.key_cryptonit_password), ""); - fee = sp.getString(context.getResources().getString(R.string.key_cryptonit_fee), "0.0"); - } - - public String username; - public String password; - private String fee; - - public String getFee() { - return fee; - } - - public void setFee(String value) - { - fee=value; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - sp.edit() - .putString(context.getResources().getString(R.string.key_cryptonit_fee), fee) - .apply(); - } - - public Boolean haveAccountInfo() { - return !username.isEmpty() && !password.isEmpty(); - } - - public void saveAccountInfo() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - sp.edit() - .putString(context.getResources().getString(R.string.key_cryptonit_username), username) - .putString(context.getResources().getString(R.string.key_cryptonit_password), password) - .apply(); - - } - - public interface BalanceListener { - void onBalanceData(Model.Balance.Response response); - } - - public interface WithdrawalListener { - void onWithdrawalComplete(Model.WithdrawCoins.Response response); - } - - public interface ErrorListener { - void onError(Throwable throwable); - } - - public void setBalanceListener(BalanceListener listener) { - balanceListener = listener; - } - - public void setWithdrawalListener(WithdrawalListener listener) { - withdrawalListener = listener; - } - - public void setErrorListener(ErrorListener listener) { - errorListener = listener; - } - - @SuppressLint("CheckResult") - public void requestBalance(String currency) { - - initApi(); - -// Log.e("CRYPTONIT2", "username: " + username); -// Log.e("CRYPTONIT2", "password: " + password); -// Log.e("CRYPTONIT2", "auth-token: " + authToken); - - Model.Balance.Request request=new Model.Balance.Request(); - request.currencies=new String[] {currency}; - api.getBalance(authToken, request) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(balanceModel -> balanceListener.onBalanceData(balanceModel), - // handle error - this::FireError - ); - } - - @SuppressLint("CheckResult") - public void requestWithdrawCoins(String currency, Double amount, String address) { - - initApi(); - -// Log.e("CRYPTONIT2", "username: " + username); -// Log.e("CRYPTONIT2", "password: " + password); -// Log.e("CRYPTONIT2", "auth-token: " + authToken); - - Model.WithdrawCoins.Request request=new Model.WithdrawCoins.Request(); - request.currency=currency; - request.amount=amount; - request.toAddress=address; - request.includeMinerFee=Double.parseDouble(fee); - request.password=password; - - api.withdrawCoins(authToken, request) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> { - if (response.success != null && response.success) - withdrawalListener.onWithdrawalComplete(response); - else { - errorListener.onError(new Exception(((LinkedTreeMap) response.errors[0]).entrySet().toArray()[0].toString())); - } - }, - // handle error - this::FireError - ); - } - - private void FireError(Throwable e) throws IOException { - if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) { - JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject(); - errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("errors").getAsString())); -// if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000; - } else { - errorListener.onError(e); - } - } - - private void initApi() { - - if (api != null) return; - -// HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); -// logging.setLevel(HttpLoggingInterceptor.Level.BODY); - - OkHttpClient httpClient = new OkHttpClient.Builder(). -// addInterceptor(logging). - addInterceptor(new AuthorizationInterceptor()).build(); - - Retrofit retrofit = new Retrofit.Builder() - .baseUrl(SERVER_URL) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .client(httpClient) - .build(); - - api = retrofit.create(Api.class); - } - - public class AuthorizationInterceptor implements Interceptor { - - AuthorizationInterceptor() { - } - - @Override - public Response intercept(Chain chain) throws IOException { - Request mainRequest=chain.request(); - - if( !mainRequest.url().toString().endsWith("authenticate")&& authToken==null ) - { - Model.Authenticate.Request authRequest=new Model.Authenticate.Request(); - authRequest.username=username; - authRequest.password=password; - retrofit2.Response authResponse=api.authenticate(authRequest).execute(); - if( authResponse.isSuccessful() && authResponse.body().success) - { - String newToken = authResponse.headers().get("auth-token"); - if (newToken != null) { - authToken = newToken; - } - }else{ - throw new IOException("Authentication error: "+authResponse.message()); - } - } - - if( authToken!=null ) { - mainRequest = mainRequest.newBuilder().addHeader("auth-token", authToken).build(); - } - Response mainResponse = chain.proceed(mainRequest); - if (!mainResponse.isSuccessful()) { - authToken=null; - } - return mainResponse; - - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/CryptonitOtherApi.java b/app/src/main/java/com/tangem/data/network/CryptonitOtherApi.java deleted file mode 100644 index 48f1480ebd..0000000000 --- a/app/src/main/java/com/tangem/data/network/CryptonitOtherApi.java +++ /dev/null @@ -1,283 +0,0 @@ -package com.tangem.data.network; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.annotations.SerializedName; -import com.google.gson.internal.LinkedTreeMap; -import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import com.tangem.tangem_card.util.Util; -import com.tangem.wallet.R; - -import java.io.IOException; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.RequestBody; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import retrofit2.http.Headers; -import retrofit2.http.Multipart; -import retrofit2.http.POST; -import retrofit2.http.Part; -import retrofit2.http.Path; - -//import okhttp3.logging.HttpLoggingInterceptor; - -/** - * HTTP - * Used in CryptonitOtherApi service - */ -public class CryptonitOtherApi { - private static final String SERVER_URL = "https://api.cryptonit.net/api/"; - - private static class Method { - public static final String BALANCE = SERVER_URL + "balance/{cryptoCurrency}%2F{fiatCurrency}"; - public static final String CRYPTO_WITHDRAWAL = SERVER_URL + "crypto_withdrawal/"; - } - - public static class Response { - public static class Balance{ - @SerializedName("btc_balance") - public String btc_balance; - @SerializedName("eur_balance") - public String eur_balance; - @SerializedName("eth_balance") - public String eth_balance; - @SerializedName("etn_balance") - public String etn_balance; - @SerializedName("btc_reserved") - public String btc_reserved; - @SerializedName("eur_reserved") - public String eur_reserved; - @SerializedName("eth_reserved") - public String eth_reserved; - @SerializedName("etn_reserved") - public String etn_reserved; - @SerializedName("btc_available") - public String btc_available; - @SerializedName("eur_available") - public String eur_available; - @SerializedName("eth_available") - public String eth_available; - @SerializedName("etn_available") - public String etn_available; - @SerializedName("btceur_fee") - public String btceur_fee; - @SerializedName("etheur_fee") - public String etheur_fee; - @SerializedName("etnbtc_fee") - public String etnbtc_fee; - @SerializedName("fee") - public String fee; - } - - public static class CryptoWithdrawal { - @SerializedName("success") - public Boolean success; - @SerializedName("status") - public String status; - @SerializedName("reason") - public Object reason; - } - } - - public interface Api { - @Multipart - @Headers("accept: multipart/form-data") - @POST(Method.BALANCE) - Observable getBalance( - @Path("cryptoCurrency") String cryptoCurrency, @Path("fiatCurrency") String fiatCurrency, - @Part(value = "key") RequestBody key, @Part("signature") RequestBody signature, @Part("nonce") RequestBody nonce); - - @Multipart - @Headers("accept: multipart/form-data") - @POST(Method.CRYPTO_WITHDRAWAL) - Observable cryptoWithdrawal( - @Part(value = "currency") RequestBody currency, @Part("amount") RequestBody amount, @Part("address") RequestBody address, - @Part(value = "key") RequestBody key, @Part("signature") RequestBody signature, @Part("nonce") RequestBody nonce); - } - - private Api api = null; - private BalanceListener balanceListener; - private WithdrawalListener withdrawalListener; - private ErrorListener errorListener; - private Context context; - - public CryptonitOtherApi(Context context) { - this.context = context; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - key = sp.getString(context.getResources().getString(R.string.key_cryptonit_key), ""); - userId = sp.getString(context.getResources().getString(R.string.key_cryptonit_user_id), ""); - secret = sp.getString(context.getResources().getString(R.string.key_cryptonit_secret), ""); - nonce = sp.getInt(context.getResources().getString(R.string.key_cryptonit_nonce), 0); - } - - public String key; - public String userId; - public String secret; - private Integer nonce; - - public String getSecretDescription() { - if (secret == null || secret.isEmpty()) return ""; - return secret.substring(0, 3) + "..." + secret.substring(secret.length() - 3, secret.length()); - } - - public Boolean havaAccountInfo() { - return (!userId.isEmpty() && !key.isEmpty() && !secret.isEmpty()); - } - - public void saveAccountInfo() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - nonce = 1; - sp.edit() - .putString(context.getResources().getString(R.string.key_cryptonit_key), key) - .putString(context.getResources().getString(R.string.key_cryptonit_user_id), userId) - .putString(context.getResources().getString(R.string.key_cryptonit_secret), secret) - .putInt(context.getResources().getString(R.string.key_cryptonit_nonce), nonce) - .apply(); - - } - - private void incNonce() { - nonce++; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - sp.edit().putInt(context.getResources().getString(R.string.key_cryptonit_nonce), nonce).apply(); - } - - public interface BalanceListener { - void onBalanceData(Response.Balance response); - } - - public interface WithdrawalListener { - void onWithdrawalComplete(Response.CryptoWithdrawal response); - } - - public interface ErrorListener { - void onError(Throwable throwable); - } - - public void setBalanceListener(BalanceListener listener) { - balanceListener = listener; - } - - public void setWithdrawalListener(WithdrawalListener listener) { - withdrawalListener = listener; - } - - public void setErrorListener(ErrorListener listener) { - errorListener = listener; - } - - private String calcSignature() throws Exception { - incNonce(); - Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); - SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"); - sha256_HMAC.init(secret_key); - - String data = nonce.toString() + userId + key; - return Util.bytesToHex(sha256_HMAC.doFinal(data.getBytes("UTF-8"))); - } - - @SuppressLint("CheckResult") - public void requestBalance(String cryptoCurrency, String fiatCurrency) throws Exception { - - initApi(); - - String signature = calcSignature(); - -// Log.e("CRYPTONIT", "user: " + userId); -// Log.e("CRYPTONIT", "key: " + key); -// Log.e("CRYPTONIT", "secret: " + secret); -// Log.e("CRYPTONIT", "nonce: " + nonce); -// Log.e("CRYPTONIT", "signature: " + signature); - - api.getBalance(cryptoCurrency, fiatCurrency, - RequestBody.create(MediaType.parse("text/plain"), key), - RequestBody.create(MediaType.parse("text/plain"), signature), - RequestBody.create(MediaType.parse("text/plain"), nonce.toString())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(balanceModel -> balanceListener.onBalanceData(balanceModel), - // handle error - this::FireError - ); - } - - @SuppressLint("CheckResult") - public void requestCryptoWithdrawal(String currency, String amount, String address) throws Exception { - - initApi(); - - String signature = calcSignature(); - -// Log.e("CRYPTONIT", "user: " + userId); -// Log.e("CRYPTONIT", "key: " + key); -// Log.e("CRYPTONIT", "secret: " + secret); -// Log.e("CRYPTONIT", "nonce: " + nonce); -// Log.e("CRYPTONIT", "signature: " + signature); -// - api.cryptoWithdrawal( - RequestBody.create(MediaType.parse("text/plain"), currency), - RequestBody.create(MediaType.parse("text/plain"), amount), - RequestBody.create(MediaType.parse("text/plain"), address), - RequestBody.create(MediaType.parse("text/plain"), key), - RequestBody.create(MediaType.parse("text/plain"), signature), - RequestBody.create(MediaType.parse("text/plain"), nonce.toString())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> { - if (response.success != null && response.success) - withdrawalListener.onWithdrawalComplete(response); - else { - LinkedTreeMap reason = (LinkedTreeMap) response.reason; - errorListener.onError(new Exception(reason.entrySet().toArray()[0].toString())); - } - }, - // handle error - this::FireError - ); - } - - private void FireError(Throwable e) throws IOException { - if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) { - JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject(); - errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("reason").getAsString())); - if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000; - } else { - errorListener.onError(e); - } - } - - private void initApi() { - - if (api != null) return; - -// HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); -// logging.setLevel(HttpLoggingInterceptor.Level.BODY); - - OkHttpClient httpClient = new OkHttpClient.Builder(). -// addInterceptor(logging). - build(); - - Retrofit retrofit = new Retrofit.Builder() - .baseUrl(SERVER_URL) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .client(httpClient) - .build(); - - api = retrofit.create(Api.class); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/DucatusApi.java b/app/src/main/java/com/tangem/data/network/DucatusApi.java deleted file mode 100644 index 53957f70fc..0000000000 --- a/app/src/main/java/com/tangem/data/network/DucatusApi.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.BitcoreBalance; -import com.tangem.data.network.model.BitcoreSendBody; -import com.tangem.data.network.model.BitcoreSendResponse; -import com.tangem.data.network.model.BitcoreUtxo; - -import java.util.List; - -import io.reactivex.Single; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; - -public interface DucatusApi { - @GET(Server.ApiDucatus.Method.BALANCE) - Single ducatusBalance(@Path("address") String address); - - @GET(Server.ApiDucatus.Method.UTXO) - Single> ducatusUnspents(@Path("address") String address); - - @POST(Server.ApiDucatus.Method.SEND) - Single ducatusSend(@Body BitcoreSendBody body); -} diff --git a/app/src/main/java/com/tangem/data/network/ElectrumRequest.java b/app/src/main/java/com/tangem/data/network/ElectrumRequest.java deleted file mode 100644 index 591b359973..0000000000 --- a/app/src/main/java/com/tangem/data/network/ElectrumRequest.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.tangem.data.network; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Created by dvol on 16.07.2017. - */ - -public class ElectrumRequest { - public static final String METHOD_GetBalance = "blockchain.address.get_balance"; - public static final String METHOD_ListUnspent = "blockchain.address.listunspent"; - public static final String METHOD_GetHistory = "blockchain.address.get_history"; - public static final String METHOD_GetTransaction = "blockchain.transaction.get"; - public static final String METHOD_GetHeader = "blockchain.block.get_header"; - public static final String METHOD_SendTransaction = "blockchain.transaction.broadcast"; - public static final String METHOD_GetFee = "blockchain.estimatefee"; - - private JSONObject jsRequestData; - String answerData; - private String error = null; - private String walletAddress; - public String txHash; - private String TX; - String host; - int port; - - private ElectrumRequest() { - } - - public ElectrumRequest(JSONObject jsRequest) { - try { - jsRequestData = new JSONObject(jsRequest.toString()); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public JSONObject getAnswer() { - try { - return new JSONObject(answerData); - } catch (Exception e) { - try { - return new JSONObject(String.format("[\"Error\":\"%s\"]", e.getMessage())); - } catch (JSONException e1) { - e1.printStackTrace(); - return null; - } - } - } - - public String getAsString() { - return jsRequestData.toString(); - } - - public void setID(int value) { - try { - jsRequestData.put("id", String.format("%d", value)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public int getID() { - try { - return jsRequestData.getInt("id"); - } catch (JSONException e) { - e.printStackTrace(); - return 0; - } - } - - public static ElectrumRequest checkBalance(String wallet) { - ElectrumRequest request = new ElectrumRequest(); - try { - request.walletAddress = wallet; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetBalance + "\", \"params\":[\"" + wallet + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - - public static ElectrumRequest getFee() { - ElectrumRequest request = new ElectrumRequest(); - try { - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetFee + "\", \"params\":[\"" + 6 + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static ElectrumRequest listUnspent(String wallet) { - ElectrumRequest request = new ElectrumRequest(); - try { - request.walletAddress = wallet; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_ListUnspent + "\", \"params\":[\"" + wallet + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static ElectrumRequest broadcast(String wallet, String tx) { - ElectrumRequest request = new ElectrumRequest(); - try { - request.walletAddress = wallet; - request.TX = tx; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_SendTransaction + "\", \"params\":[\"" + tx + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static ElectrumRequest getTransaction(String wallet, String tx_hash) { - ElectrumRequest request = new ElectrumRequest(); - try { - request.walletAddress = wallet; - request.txHash = tx_hash; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetTransaction + "\", \"params\":[\"" + tx_hash + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public String getMethod() { - try { - return jsRequestData.getString("method"); - } catch (JSONException e) { - e.printStackTrace(); - } - return ""; - } - - public boolean isMethod(String methodName) { - return getMethod().equals(methodName); - } - - public JSONArray getParams() throws JSONException { - return jsRequestData.getJSONArray("params"); - } - - public JSONObject getResult() throws JSONException { - return getAnswer().getJSONObject("result"); - } - - public String getError() { - if( answerData!=null ) { - // answer received - return error from it - JSONObject answer = getAnswer(); - if (answer.has("error")) { - try { - return getAnswer().getJSONObject("error").toString(); - } catch (JSONException e) { - e.printStackTrace(); - return null; - } - } else { - return null; - } - }else{ - // no answer received - return saved error reason - return error; - } - } - - public void setError(String error) { - this.error = error; - } - - public String getResultString() throws JSONException { - if (getAnswer().has("result")) { - return getAnswer().getString("result"); - } else { - return null; - } - } - - public JSONArray getResultArray() throws JSONException { - return getAnswer().getJSONArray("result"); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/EstimatefeeApi.java b/app/src/main/java/com/tangem/data/network/EstimatefeeApi.java deleted file mode 100644 index a004db3864..0000000000 --- a/app/src/main/java/com/tangem/data/network/EstimatefeeApi.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.data.network; - -import retrofit2.Call; -import retrofit2.http.GET; - -public interface EstimatefeeApi { - @GET(Server.ApiEstimatefee.Method.N_2) - Call getEstimateFeePriority(); - - @GET(Server.ApiEstimatefee.Method.N_3) - Call getEstimateFeeNormal(); - - @GET(Server.ApiEstimatefee.Method.N_6) - Call getEstimateFeeMinimal(); -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/InfuraApi.java b/app/src/main/java/com/tangem/data/network/InfuraApi.java deleted file mode 100644 index 2ad1802e25..0000000000 --- a/app/src/main/java/com/tangem/data/network/InfuraApi.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.InfuraBody; -import com.tangem.data.network.model.InfuraResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -public interface InfuraApi { - @Headers("Content-Type: application/json") - @POST(Server.ApiInfura.Method.MAIN) - Call infura(@Body InfuraBody body); -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/InsightApi.java b/app/src/main/java/com/tangem/data/network/InsightApi.java deleted file mode 100644 index 4095326dc5..0000000000 --- a/app/src/main/java/com/tangem/data/network/InsightApi.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.InsightBody; -import com.tangem.data.network.model.InsightResponse; -import com.tangem.data.network.model.InsightUtxo; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.Headers; -import retrofit2.http.POST; -import retrofit2.http.Path; -import retrofit2.http.Query; - -public interface InsightApi { - @GET(ServerApiInsight.INSIGHT_ADDRESS) - Call insightAddress(@Path("address") String address); - - @GET(ServerApiInsight.INSIGHT_UNSPENT_OUTPUTS) - Call> insightUnspent(@Path("address") String address); - - @GET(ServerApiInsight.INSIGHT_TRANSACTION) - Call insightTransaction(@Path("txId") String txId); - - @GET(ServerApiInsight.INSIGHT_FEE) - Call insightFee(); - - @Headers("Content-Type: application/json") - @POST(ServerApiInsight.INSIGHT_SEND) - Call insightSend(@Body InsightBody body ); -} diff --git a/app/src/main/java/com/tangem/data/network/Kraken.java b/app/src/main/java/com/tangem/data/network/Kraken.java deleted file mode 100644 index 4f7eaae457..0000000000 --- a/app/src/main/java/com/tangem/data/network/Kraken.java +++ /dev/null @@ -1,358 +0,0 @@ -package com.tangem.data.network; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import com.tangem.tangem_card.util.Util; -import com.tangem.wallet.R; - -import org.spongycastle.util.encoders.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okio.Buffer; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import retrofit2.http.Field; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.POST; - -//import okhttp3.logging.HttpLoggingInterceptor; - -/** - * HTTP - * Used in Kraken service - */ -public class Kraken { - private static final String SERVER_URL = "https://api.kraken.com"; - - private static class Method { - public static final String BALANCE = SERVER_URL + "/0/private/Balance"; - public static final String WITHDRAW_INFO = SERVER_URL + "/0/private/WithdrawInfo"; - public static final String WITHDRAW = SERVER_URL + "/0/private/Withdraw"; - } - - public static class Model { - - public static class Balance { - public static class Response { - public String[] error; - public Result result; - - public static class Result { - public String XXBT; - public String XETH; - public String BCH; - } - } - } - - public static class WithdrawInfo { - public static class Response { - public String[] error; - public Result result; - - public static class Result { - public String fee; - public String amount; - } - } - } - - public static class Withdraw { - public static class Response { - public String[] error; - public Result result; - - public static class Result { - public String refid; - } - } - } - } - - public interface Api { - @FormUrlEncoded - @POST(Method.BALANCE) - Observable getBalance(@Field("nonce") String nonce); - - @FormUrlEncoded - @POST(Method.WITHDRAW_INFO) - Observable WithdrawInfo(@Field("nonce") String nonce, @Field("asset") String asset, @Field("key") String key, @Field("amount") String amount); - - @FormUrlEncoded - @POST(Method.WITHDRAW) - Observable Withdraw(@Field("nonce") String nonce, @Field("asset") String asset, @Field("key") String key, @Field("amount") String amount); - } - - private Api api = null; - private BalanceListener balanceListener; - private WithdrawalListener withdrawalListener; - private WithdrawalInfoListener withdrawalInfoListener; - private ErrorListener errorListener; - private Context context; - - public Kraken(Context context) { - this.context = context; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - key = sp.getString(context.getResources().getString(R.string.key_kraken_key), ""); - secret = sp.getString(context.getResources().getString(R.string.key_kraken_secret), ""); - nonce = sp.getInt(context.getResources().getString(R.string.key_kraken_nonce), 0); - } - - public String key; - public String secret; - private Integer nonce; - - public String getSecretDescription() { - if (secret == null || secret.isEmpty()) return ""; - return secret.substring(0, 3) + "..." + secret.substring(secret.length() - 3, secret.length()); - } - - public Boolean haveAccountInfo() { - return (!key.isEmpty() && !secret.isEmpty()); - } - - public void saveAccountInfo() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - sp.edit() - .putString(context.getResources().getString(R.string.key_kraken_key), key) - .putString(context.getResources().getString(R.string.key_kraken_secret), secret) - .putInt(context.getResources().getString(R.string.key_kraken_nonce), nonce) - .apply(); - - } - - private void incNonce() { - nonce++; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - sp.edit().putInt(context.getResources().getString(R.string.key_kraken_nonce), nonce).apply(); - } - - public interface BalanceListener { - void onBalanceData(Model.Balance.Response response); - } - - public interface WithdrawalInfoListener { - void onWithdrawalInfoComplete(Model.WithdrawInfo.Response response); - } - - public interface WithdrawalListener { - void onWithdrawalComplete(Model.Withdraw.Response response); - } - - public interface ErrorListener { - void onError(Throwable throwable); - } - - public void setBalanceListener(BalanceListener listener) { - balanceListener = listener; - } - - public void setWithdrawalListener(WithdrawalListener listener) { - withdrawalListener = listener; - } - - public void setWithdrawalInfoListener(WithdrawalInfoListener listener) { - withdrawalInfoListener = listener; - } - - public void setErrorListener(ErrorListener listener) { - errorListener = listener; - } - - - private static final String HMAC_SHA512 = "HmacSHA512"; - - - private String bodyToString(final RequestBody request){ - try { - final RequestBody copy = request; - final Buffer buffer = new Buffer(); - if(copy != null) - copy.writeTo(buffer); - else - return ""; - return buffer.readUtf8(); - } - catch (final IOException e) { - return "did not work"; - } - } - - private String calcSignature(String url, RequestBody requestBody) throws NoSuchAlgorithmException, InvalidKeyException, IOException { - - String postData=bodyToString(requestBody); - - // create SHA-256 hash of the nonce and the POST data - - String s=nonce+postData; - byte[] sha256 = Util.calculateSHA256(s); - - // set the API method and retrieve the path - byte[] path = url.getBytes(StandardCharsets.UTF_8); - - // decode the API secret, it's the HMAC key - byte[] hmacKey = Base64.decode(secret); - - // create the HMAC message from the path and the previous hash - ByteArrayOutputStream outputStream=new ByteArrayOutputStream(); - outputStream.write(path); - outputStream.write(sha256); - byte[] hmacMessage = outputStream.toByteArray();//concatArrays(path, sha256); - - Mac mac = Mac.getInstance(HMAC_SHA512); - mac.init(new SecretKeySpec(hmacKey, HMAC_SHA512)); - byte[] hmacSignature=mac.doFinal(hmacMessage); - - byte[] b64Signature = Base64.encode(hmacSignature); - - return new String(b64Signature, StandardCharsets.UTF_8); - } - - @SuppressLint("CheckResult") - public void requestBalance() throws Exception { - - initApi(); - -// Log.e("kraken", "key: " + key); -// Log.e("kraken", "secret: " + secret); -// Log.e("kraken", "nonce: " + nonce); - - api.getBalance(nonce.toString()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> balanceListener.onBalanceData(response), - // handle error - this::FireError - ); - } - - @SuppressLint("CheckResult") - public void requestWithdrawInfo(String currency, String amount, String withdrawKey) throws Exception { - - initApi(); - -// Log.e("kraken", "key: " + key); -// Log.e("kraken", "secret: " + secret); -// Log.e("kraken", "nonce: " + nonce); - - String asset=CurrencyToAsset(currency); - -// withdrawKey = "test"; - api.WithdrawInfo(nonce.toString(), asset, withdrawKey, amount) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> withdrawalInfoListener.onWithdrawalInfoComplete(response), - // handle error - this::FireError - ); - } - - private static String CurrencyToAsset(String currency) throws Exception { - switch (currency) - { - case "BTC": return "XXBT"; - case "BCH": return "BCH"; - case "ETH": return "XETH"; - default: - throw new Exception("Unsupported currency!"); - } - } - - @SuppressLint("CheckResult") - public void requestWithdraw(String currency, String amount, String withdrawKey) throws Exception { - initApi(); - -// Log.e("kraken", "key: " + key); -// Log.e("kraken", "secret: " + secret); -// Log.e("kraken", "nonce: " + nonce); - - String asset=CurrencyToAsset(currency); - -// withdrawKey = "test"; - api.Withdraw(nonce.toString(), asset, withdrawKey, amount) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> withdrawalListener.onWithdrawalComplete(response), - // handle error - this::FireError - ); - } - - private void FireError(Throwable e) throws IOException { -// if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) { -// JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject(); -// errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("reason").getAsString())); -// if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000; -// } else { - errorListener.onError(e); -// } - } - - private void initApi() { - - if (api != null) return; - -// HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); -// logging.setLevel(HttpLoggingInterceptor.Level.BODY); - - OkHttpClient httpClient = new OkHttpClient.Builder(). - addInterceptor(new AuthorizationInterceptor()). -// addInterceptor(logging). - build(); - - Retrofit retrofit = new Retrofit.Builder() - .baseUrl(SERVER_URL) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .client(httpClient) - .build(); - - api = retrofit.create(Api.class); - } - - public class AuthorizationInterceptor implements Interceptor { - - AuthorizationInterceptor() { - } - - - @Override - public Response intercept(Chain chain) throws IOException { - Request mainRequest=chain.request(); - - try { - mainRequest = mainRequest.newBuilder(). - addHeader("API-Key", key). - addHeader("API-Sign", calcSignature(mainRequest.url().toString().substring(SERVER_URL.length()), mainRequest.body())). - build(); - incNonce(); - } catch (Exception e) { - e.printStackTrace(); - throw new IOException("Can't calculate signature: "+e.getMessage()); - } - - return chain.proceed(mainRequest); - - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/MaticApi.java b/app/src/main/java/com/tangem/data/network/MaticApi.java deleted file mode 100644 index de29ef8178..0000000000 --- a/app/src/main/java/com/tangem/data/network/MaticApi.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.InfuraBody; -import com.tangem.data.network.model.InfuraResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -public interface MaticApi { - @Headers("Content-Type: application/json") - @POST(Server.ApiMaticTesnet.Method.MAIN) - Call matic(@Body InfuraBody body); -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/PayIdApi.java b/app/src/main/java/com/tangem/data/network/PayIdApi.java deleted file mode 100644 index 4616c01240..0000000000 --- a/app/src/main/java/com/tangem/data/network/PayIdApi.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.PayIdResponse; - -import io.reactivex.Single; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.Headers; -import retrofit2.http.Path; - -public interface PayIdApi { - @Headers("PayID-Version: 1.0") - @GET("{user}") - Single getAddress(@Path("user") String user, @Header("Accept") String acceptHeader); -} diff --git a/app/src/main/java/com/tangem/data/network/RippleApi.java b/app/src/main/java/com/tangem/data/network/RippleApi.java deleted file mode 100644 index 2b6ad9fe29..0000000000 --- a/app/src/main/java/com/tangem/data/network/RippleApi.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.RippleBody; -import com.tangem.data.network.model.RippleResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -public interface RippleApi { - @Headers("Content-Type: application/json") - @POST("./") - Call ripple(@Body RippleBody body); -} diff --git a/app/src/main/java/com/tangem/data/network/RootstockApi.java b/app/src/main/java/com/tangem/data/network/RootstockApi.java deleted file mode 100644 index 7faadfb4c0..0000000000 --- a/app/src/main/java/com/tangem/data/network/RootstockApi.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.InfuraBody; -import com.tangem.data.network.model.InfuraResponse; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.Headers; -import retrofit2.http.POST; - -public interface RootstockApi { - @Headers("Content-Type: application/json") - @POST(Server.ApiRootstock.Method.MAIN) - Call rootstock(@Body InfuraBody body); -} diff --git a/app/src/main/java/com/tangem/data/network/Server.java b/app/src/main/java/com/tangem/data/network/Server.java deleted file mode 100644 index 8ef83ebd52..0000000000 --- a/app/src/main/java/com/tangem/data/network/Server.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.tangem.data.network; - -public class Server { - - public static class ApiUpdateVersion { - public static final String URL_UPDATE_VERSION = ServerURL.API_UPDATE_VERSION; - - public static class Method { - static final String LAST_VERSION = URL_UPDATE_VERSION + "TangemCash/tangem-binaries/master/apk-version.txt"; - } - } - - /** - * https://coinmarketcap.com/api/ - */ - public static class ApiCoinmarket { - public static final String URL_COINMARKET = ServerURL.API_COINMARKETCAP; - - public static class Method { - static final String PRICE_CONVERSION = URL_COINMARKET + "v1/tools/price-conversion"; - } - } - - /** - * https://infura.io/ - */ - public static class ApiInfura { - public static final String URL_INFURA = ServerURL.API_INFURA; - - public static class Method { - public static final String MAIN = "v3/613a0b14833145968b1f656240c7d245"; - } - } - - public static class ApiInfuraTestnet { - public static final String URL_INFURA_TESTNET = ServerURL.API_INFURA_TESTNET; - - public static class Method { - public static final String MAIN = "v3/613a0b14833145968b1f656240c7d245"; - } - } - - public static class ApiInfuraRopsten { - public static final String URL_INFURA_ROPSTEN = ServerURL.API_INFURA_ROPSTEN; - - public static class Method { - public static final String MAIN = "v3/613a0b14833145968b1f656240c7d245"; - } - } - - - public static class ApiSoChain { - public static final String URL = ServerURL.API_SOCHAIN_V2; - - public static class Method { - public static final String ADDRESS_BALANCE = "api/v2/get_address_balance/{network}/{address}"; - public static final String UNSPENT_TX = "api/v2/get_tx_unspent/{network}/{address}"; - public static final String GET_TX = "api/v2/get_tx/{network}/{txid}"; - public static final String SEND_TRANSACTION = "api/v2/send_tx/{network}"; - } - } - - /** - * https://public-node.rsk.co/ - */ - public static class ApiRootstock { - public static final String URL_ROOTSTOCK = ServerURL.API_ROOTSTOCK; - - public static class Method { - static final String MAIN = URL_ROOTSTOCK; - } - } - - /** - * https://testnet2.matic.network - */ - public static class ApiMaticTesnet { - public static final String URL_MATIC_TESTNET = ServerURL.API_MATIC_TESTNET ; - - public static class Method { - static final String MAIN = URL_MATIC_TESTNET; - } - } - - /** - * https://estimatefee.com/ - */ - public static class ApiEstimatefee { - public static final String URL_ESTIMATEFEE = ServerURL.API_ESTIMATEFEE; - - public static class Method { - static final String N_2 = URL_ESTIMATEFEE + "n/2"; - static final String N_3 = URL_ESTIMATEFEE + "n/3"; - static final String N_6 = URL_ESTIMATEFEE + "n/6"; - } - } - - /** - * https://dex.binance.org/ - */ - - public static class ApiBinance { - public static final String URL_BINANCE = ServerURL.API_BINANCE; - - public static class Method { - public static final String API_V1 = URL_BINANCE + "api/v1/"; - } - } - - /** - * https://testnet-dex.binance.org/ - */ - - public static class ApiBinanceTestnet { - public static final String URL_BINANCE_TESTNET = ServerURL.API_BINANCE_TESTNET; - - public static class Method { - public static final String API_V1 = URL_BINANCE_TESTNET + "api/v1/"; - } - } - - /** - * https://api.blockcypher.com/ - */ - - public static class ApiBlockcypher { - public static final String URL_BLOCKCYPHER = ServerURL.API_BLOCKCYPHER; - static final String V1_MAIN = "v1/{blockchain}/{network}"; - - public static class Method { - static final String MAIN = URL_BLOCKCYPHER + V1_MAIN; - static final String ADDRESS = MAIN + "/addrs/{address}?includeScript=true&limit=2000"; - static final String TXS = MAIN + "/txs/{txHash}?includeHex=true"; - static final String PUSH = MAIN + "/txs/push"; - } - } - - public static class ApiBlockchainInfo { - public static final String URL_BLOCKCHAININFO = ServerURL.API_BLOCKCHAIN_INFO; - - public static class Method { - static final String ADDRESS = URL_BLOCKCHAININFO + "rawaddr/{address}"; - static final String UTXO = URL_BLOCKCHAININFO + "unspent"; -// static final String TX = URL_BLOCKCHAININFO + "rawtx/{txHash}"; - static final String PUSH = URL_BLOCKCHAININFO + "pushtx"; - } - } - - public static class ApiDucatus { - public static final String URL_DUCATUS = ServerURL.API_DUCATUS + "api/DUC/mainnet/"; - - public static class Method { - static final String BALANCE = URL_DUCATUS + "address/{address}/balance"; - static final String UTXO = URL_DUCATUS + "address/{address}/?unspent=true"; - static final String SEND = URL_DUCATUS + "tx/send"; - } - } - - public static class ApiBlockchair { - public static final String URL_BLOCKCHAIR = ServerURL.API_BLOCKCHAIR + "{blockchain}/"; - private static final String API_KEY = "?key=A___0Shpsu4KagE7oSabrw20DfXAqWlT"; - - public static class Method { - static final String ADDRESS = URL_BLOCKCHAIR + "dashboards/address/{address}" + API_KEY; - static final String TRANSACTION = URL_BLOCKCHAIR + "dashboards/transaction/{transaction}" + API_KEY; - static final String STATS = URL_BLOCKCHAIR + "stats" + API_KEY; - static final String PUSH = URL_BLOCKCHAIR + "push/transaction" + API_KEY; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerApiAdalite.java b/app/src/main/java/com/tangem/data/network/ServerApiAdalite.java deleted file mode 100644 index d36bcf2caa..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiAdalite.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.data.network.model.AdaliteBody; -import com.tangem.data.network.model.AdaliteResponse; -import com.tangem.data.network.model.AdaliteResponseUtxo; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import retrofit2.converter.scalars.ScalarsConverterFactory; - -public class ServerApiAdalite { - private static String TAG = ServerApiAdalite.class.getSimpleName(); - - public static final String ADALITE_ADDRESS = "/api/addresses/summary/{address}"; - public static final String ADALITE_UNSPENT_OUTPUTS = "/api/bulk/addresses/utxo"; - // public static final String ADALITE_TRANSACTION = "/api/txs/raw/{txId}}"; - public static final String ADALITE_SEND = "/api/v2/txs/signed"; - - private int requestsCount = 0; - - private final String adaliteURL1 = "https://explorer2.adalite.io"; //TODO: make random selection, add more?, move - private final String adaliteURL2 = "https://nodes.southeastasia.cloudapp.azure.com"; - - private String currentURL = adaliteURL1; - - public String getCurrentURL() { - return currentURL; - } - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - private ResponseListener responseListener; - - public interface ResponseListener { - void onSuccess(String method, AdaliteResponse adaliteResponse); - - void onSuccess(String method, AdaliteResponseUtxo adaliteResponseUtxo); - - void onSuccess(String method, String stringResponse); - - void onFail(String method, String message); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void requestData(String method, String wallet, String tx) { - requestData(method, wallet, tx, false); - } - - public void requestData(String method, String wallet, String tx, boolean isRetry) { - requestsCount++; - - Retrofit retrofitAdalite = new Retrofit.Builder() - .baseUrl(currentURL) - .addConverterFactory(ScalarsConverterFactory.create()) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - - AdaliteApi adaliteApi = retrofitAdalite.create(AdaliteApi.class); - - switch (method) { - case ADALITE_ADDRESS: - - Call addressCall = adaliteApi.adaliteAddress(wallet); - addressCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - - if (!isRetry) { - retryRequest(method, wallet, tx); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - } - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - requestsCount--; - - if (!isRetry) { - retryRequest(method, wallet, tx); - } else { - responseListener.onFail(method, String.valueOf(t.getMessage())); - } - } - }); - break; - - case ADALITE_UNSPENT_OUTPUTS: - Call outputsCall = adaliteApi.adaliteUnspent("[\"" + wallet + "\"]"); - outputsCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - - if (!isRetry) { - retryRequest(method, wallet, tx); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - } - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - requestsCount--; - - if (!isRetry) { - retryRequest(method, wallet, tx); - } else { - responseListener.onFail(method, String.valueOf(t.getMessage())); - } - } - }); - break; - - case ADALITE_SEND: - Call sendCall = adaliteApi.adaliteSend(new AdaliteBody(tx)); - sendCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - - if (!isRetry) { - retryRequest(method, wallet, tx); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - } - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - requestsCount--; - - if (!isRetry) { - retryRequest(method, wallet, tx); - } else { - responseListener.onFail(method, String.valueOf(t.getMessage())); - } - } - }); - break; - - default: - requestsCount--; - responseListener.onFail(method, "undeclared method"); - Log.e(TAG, "requestData " + method + " onFailure - undeclared method"); - break; - } - - } - - private void retryRequest(String method, String wallet, String tx) { -// currentURL = adaliteURL2; - requestData(method, wallet, tx, true); - } -} - diff --git a/app/src/main/java/com/tangem/data/network/ServerApiBinance.java b/app/src/main/java/com/tangem/data/network/ServerApiBinance.java deleted file mode 100644 index 8527a9c0d4..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiBinance.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import com.tangem.wallet.TangemContext; -import com.tangem.wallet.Transaction; -import com.tangem.wallet.binance.BinanceAssetData; -import com.tangem.wallet.binance.BinanceData; -import com.tangem.wallet.binance.client.BinanceDexApiRestClient; -import com.tangem.wallet.binance.client.domain.Account; -import com.tangem.wallet.binance.client.domain.Balance; -import com.tangem.wallet.binance.client.domain.TransactionMetadata; -import com.tangem.wallet.binance.client.encoding.message.TransactionRequestAssemblerExtSign; - -import java.util.ArrayList; -import java.util.List; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.observers.DefaultObserver; -import io.reactivex.schedulers.Schedulers; -import okhttp3.RequestBody; - -public class ServerApiBinance { - private static String TAG = ServerApiBinance.class.getSimpleName(); - - private ResponseListener responseListener; - - public interface ResponseListener { - void onSuccess(); - void onFail(); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void getBalance(TangemContext ctx, BinanceDexApiRestClient client) { - Log.i(TAG, "new getBalance request"); - - Observable balanceObservable = Observable.just(new Account()) - .map(account -> client.getAccount(ctx.getCoinData().getWallet())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - balanceObservable.subscribe(new DefaultObserver() { - @Override - public void onNext(Account account) { - Log.i(TAG, "getBalance onNext"); -// account = client.getAccount(ctx.getCoinData().getWallet()); - BinanceData binanceData = (BinanceData) ctx.getCoinData(); - - for (Balance balance : account.getBalances()) { - if (balance.getSymbol().equals("BNB")) { - binanceData.setBalanceReceived(true); - binanceData.setBalance(balance.getFree()); - break; - } - } - - if (binanceData instanceof BinanceAssetData) { - BinanceAssetData binanceAssetData = (BinanceAssetData) binanceData; - for (Balance balance : account.getBalances()) { - if (balance.getSymbol().equals(ctx.getCard().getContractAddress())) { - binanceAssetData.setAssetBalance(balance.getFree()); - break; - } - } - } - - if (!binanceData.isBalanceReceived()) { - binanceData.setBalanceReceived(true); - binanceData.setBalance("0"); - } - - binanceData.setAccountNumber(account.getAccountNumber()); - binanceData.setSequence(account.getSequence()); - } - - @Override - public void onError(Throwable e) { - Log.e(TAG, "getBalance onError" + e.getMessage()); - if (e.getMessage().contains("account not found")) { - ((BinanceData)ctx.getCoinData()).setError404(true); - responseListener.onFail(); - } else { - e.printStackTrace(); - ctx.setError(e.getMessage()); - responseListener.onFail(); - } - } - - @Override - public void onComplete() { - Log.i(TAG, "getBalance onComplete"); - responseListener.onSuccess(); - } - }); - } - - public void sendTransaction (byte[] txForSend, BinanceDexApiRestClient client) { - Log.i(TAG, "new sendTransaction request"); - - RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend); - - Observable> sendObservable = Observable.just(new ArrayList<>()) - .map(metadatas -> client.broadcastNoWallet(requestBody, true)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - sendObservable.subscribe(new DefaultObserver>() { - @Override - public void onNext(List metadatas ) { -// RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend); -// List metadatas = client.broadcastNoWallet(requestBody, true); - if (!metadatas.isEmpty() && metadatas.get(0).isOk()) { - responseListener.onSuccess(); - } else { - Log.e(TAG, "Transaction send error"); - responseListener.onFail(); - } - } - - @Override - public void onError(Throwable e) { - Log.e(TAG, "sendTransaction onError" + e.getMessage()); - e.printStackTrace(); - responseListener.onFail(); - } - - @Override - public void onComplete() { - Log.i(TAG, "sendTransaction onComplete"); - } - }); - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiBitcore.java b/app/src/main/java/com/tangem/data/network/ServerApiBitcore.java deleted file mode 100644 index de9de087eb..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiBitcore.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.App; -import com.tangem.data.network.model.BitcoreBalance; -import com.tangem.data.network.model.BitcoreBalanceAndUnspents; -import com.tangem.data.network.model.BitcoreSendBody; -import com.tangem.data.network.model.BitcoreSendResponse; -import com.tangem.data.network.model.BitcoreUtxo; -import com.tangem.tangem_card.util.Log; - -import java.util.ArrayList; -import java.util.List; - -import io.reactivex.Single; -import io.reactivex.SingleObserver; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class ServerApiBitcore { - private static String TAG = ServerApiBitcore.class.getSimpleName(); - - public void getBalanceAndUnspents(String wallet, SingleObserver balanceAndUnspentsObserver) { - Log.i(TAG, "new getAddressAndUnspents request"); - DucatusApi api = App.Companion.getNetworkComponent().getRetrofitDucatus().create(DucatusApi.class); - - Single balanceObservable = api.ducatusBalance(wallet); - - Single> unspentsObservable = api.ducatusUnspents(wallet) - .onErrorReturnItem(new ArrayList<>()); - - Single.zip(balanceObservable, unspentsObservable, BitcoreBalanceAndUnspents::new) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(balanceAndUnspentsObserver); - } - - public void sendTransaction(String tx, SingleObserver sendObserver) { - Log.i(TAG, "new getAddress request"); - DucatusApi api = App.Companion.getNetworkComponent().getRetrofitDucatus().create(DucatusApi.class); - - Single sendObservable = api.ducatusSend(new BitcoreSendBody(tx)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - sendObservable.subscribe(sendObserver); - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiBlockchainInfo.java b/app/src/main/java/com/tangem/data/network/ServerApiBlockchainInfo.java deleted file mode 100644 index a16f25ddfc..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiBlockchainInfo.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import com.tangem.App; -import com.tangem.data.network.model.BlockchainInfoAddress; -import com.tangem.data.network.model.BlockchainInfoAddressAndUnspents; -import com.tangem.data.network.model.BlockchainInfoTransaction; -import com.tangem.data.network.model.BlockchainInfoUnspents; - -import java.util.ArrayList; -import java.util.List; - -import io.reactivex.Single; -import io.reactivex.SingleObserver; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.ResponseBody; - -public class ServerApiBlockchainInfo { - private static String TAG = ServerApiBlockchainInfo.class.getSimpleName(); - private int page = 1; - - public void getAddressAndUnspents(String wallet, SingleObserver addressAndUnspentsObserver) { - Log.i(TAG, "new getAddressAndUnspents request"); - BlockchainInfoApi api = App.Companion.getNetworkComponent().getRetrofitBlockchainInfo().create(BlockchainInfoApi.class); - - Single addressObservable = api.blockchainInfoAddress(wallet, null); - - Single unspentsObservable = api.blockchainInfoUnspents(wallet) - .onErrorReturnItem(new BlockchainInfoUnspents(new ArrayList<>())); - - Single.zip(addressObservable, unspentsObservable, BlockchainInfoAddressAndUnspents::new) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(addressAndUnspentsObserver); - } - - public void sendTransaction(String tx, SingleObserver sendObserver) { - Log.i(TAG, "new getAddress request"); - BlockchainInfoApi api = App.Companion.getNetworkComponent().getRetrofitBlockchainInfo().create(BlockchainInfoApi.class); - - Single sendObservable = api.blockchainInfoPush(tx) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - sendObservable.subscribe(sendObserver); - } - - public Single> getMoreAddressTxs(String wallet) { - Log.i(TAG, "new getAddress request"); - BlockchainInfoApi api = App.Companion.getNetworkComponent().getRetrofitBlockchainInfo().create(BlockchainInfoApi.class); - - Single> addressObservable = api.blockchainInfoAddress(wallet, page * 50) - .map(BlockchainInfoAddress::getTxs) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - page++; - return addressObservable; - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiBlockchair.java b/app/src/main/java/com/tangem/data/network/ServerApiBlockchair.java deleted file mode 100644 index f77bb83449..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiBlockchair.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.data.network.model.BlockchairAddressResponse; -import com.tangem.data.network.model.BlockchairSendBody; -import com.tangem.data.network.model.BlockchairStatsResponse; -import com.tangem.data.network.model.BlockchairTransactionResponse; -import com.tangem.tangem_card.util.Log; - -import io.reactivex.Completable; -import io.reactivex.CompletableObserver; -import io.reactivex.Single; -import io.reactivex.SingleObserver; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class ServerApiBlockchair { - private static String TAG = ServerApiBlockchair.class.getSimpleName(); - private String blockchain; - - public ServerApiBlockchair(Blockchain blockchain) { - if (blockchain == Blockchain.BitcoinCash) this.blockchain = "bitcoin-cash"; - } - - public void getAddress(String wallet, SingleObserver addressObserver) { - Log.i(TAG, "new getAddress request"); - BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitBlockchair().create(BlockchairApi.class); - - Single addressSingle = api.getAddress(blockchain, wallet) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - addressSingle.subscribe(addressObserver); - } - - public void getTransaction(String transaction, SingleObserver transactionObserver) { - Log.i(TAG, "new getAddress request"); - BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitBlockchair().create(BlockchairApi.class); - - Single transactionSingle = api.getTransaction(blockchain, transaction) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - transactionSingle.subscribe(transactionObserver); - } - - public void getStats(SingleObserver statsObserver) { - Log.i(TAG, "new getStats request"); - BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitBlockchair().create(BlockchairApi.class); - - Single statsSingle = api.getStats(blockchain) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - statsSingle.subscribe(statsObserver); - } - - public void sendTransaction(String tx, CompletableObserver sendObserver) { - Log.i(TAG, "new getAddress request"); - BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitDucatus().create(BlockchairApi.class); - - Completable sendCompletable = api.sendTransaction(blockchain, new BlockchairSendBody(tx)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - sendCompletable.subscribe(sendObserver); - } - - public String getUrl() { - return ServerURL.API_BLOCKCHAIR; - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiBlockcypher.java b/app/src/main/java/com/tangem/data/network/ServerApiBlockcypher.java deleted file mode 100644 index bccbfd5a1e..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiBlockcypher.java +++ /dev/null @@ -1,212 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.data.network.model.BlockcypherBody; -import com.tangem.data.network.model.BlockcypherFee; -import com.tangem.data.network.model.BlockcypherResponse; -import com.tangem.data.network.model.BlockcypherTx; - -import java.util.Random; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ServerApiBlockcypher { - private static String TAG = ServerApiBlockcypher.class.getSimpleName(); - - public static final String BLOCKCYPHER_ADDRESS = "blockcypher_address"; - public static final String BLOCKCYPHER_FEE = "blockcypher_fee"; - public static final String BLOCKCYPHER_TXS = "blockcypher_txs"; - public static final String BLOCKCYPHER_SEND = "blockcypher_send"; - - private int requestsCount = 0; - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - private String apiKey = null; - - private ResponseListener responseListener; - private TxResponseListener txResponseListener; - - public interface ResponseListener { - void onSuccess(String method, BlockcypherResponse blockcypherResponse); - - void onSuccess(String method, BlockcypherFee blockcypherFee); - - void onFail(String method, String message); - } - - public interface TxResponseListener { - void onSuccess(BlockcypherTx blockcypherTx); - - void onFail(String message); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void setTxResponseListener(TxResponseListener txListener) { - txResponseListener = txListener; - } - - public void requestData(String blockchainID, String method, String wallet, String tx) { - requestsCount++; - String blockchain = blockchainID.toLowerCase(); - BlockcypherApi blockcypherApi = App.Companion.getNetworkComponent().getRetrofitBlockcypher().create(BlockcypherApi.class); - - String network = "main"; - if (blockchainID.equals(Blockchain.BitcoinTestNet.getID())) { - blockchain = "btc"; - network = "test3"; - } - if (blockchainID.equals(Blockchain.Token.getID())) blockchain = "eth"; - if (blockchainID.equals(Blockchain.BitcoinDual.getID())) blockchain = "btc"; - - switch (method) { - case BLOCKCYPHER_ADDRESS: - Call addressCall = blockcypherApi.blockcypherAddress(blockchain, network, wallet, apiKey); - addressCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - switch (response.code()) { - case 200: - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - break; - case 429: - apiKey = getRandomApiKey(); - requestData(blockchainID, method, wallet, tx); - break; - default: - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - break; - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - break; - - case BLOCKCYPHER_FEE: - Call feeCall = blockcypherApi.blockcypherMain(blockchain, network, apiKey); - feeCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - switch (response.code()) { - case 200: - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - break; - case 429: - apiKey = getRandomApiKey(); - requestData(blockchainID, method, wallet, tx); - break; - default: - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - break; - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - break; - - case BLOCKCYPHER_TXS: - Call txsCall = blockcypherApi.blockcypherTxs(blockchain, network, tx, apiKey); - txsCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call,@NonNull Response response) { - requestsCount--; - switch (response.code()) { - case 200: - txResponseListener.onSuccess(response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - break; - case 429: - apiKey = getRandomApiKey(); - requestData(blockchainID, method, wallet, tx); - break; - default: - txResponseListener.onFail(String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - break; - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - txResponseListener.onFail(String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - break; - - case BLOCKCYPHER_SEND: - Call sendCall = blockcypherApi.blockcypherPush(blockchain, network, new BlockcypherBody(tx), apiKey); - sendCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - switch (response.code()) { - case 201: - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - break; - case 429: - apiKey = getRandomApiKey(); - requestData(blockchainID, method, wallet, tx); - break; - default: - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - break; - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - break; - - default: - requestsCount--; - responseListener.onFail(method, "undeclared method"); - Log.e(TAG, "requestData " + method + " onFailure - undeclared method"); - break; - } - } - - private String getRandomApiKey() { - return BlockcypherToken - .values()[new Random().nextInt(BlockcypherToken.values().length)].getToken(); - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiCommon.java b/app/src/main/java/com/tangem/data/network/ServerApiCommon.java deleted file mode 100644 index d6c7b315f0..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiCommon.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.tangem.data.network; - -import android.annotation.SuppressLint; -import androidx.annotation.NonNull; -import android.util.Log; - -import com.tangem.App; -import com.tangem.data.network.model.RateInfoResponse; - -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.ResponseBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ServerApiCommon { - private static String TAG = ServerApiCommon.class.getSimpleName(); - - /** - * HTTP - * Estimate fee - */ - public static final int ESTIMATE_FEE_PRIORITY = 2; - public static final int ESTIMATE_FEE_NORMAL = 3; - public static final int ESTIMATE_FEE_MINIMAL = 6; - private EstimatedFeeListener estimatedFeeListener; - - public interface EstimatedFeeListener { - void onSuccess(int blockCount, String estimateFeeResponse); - void onFail(int blockCount, String message); - } - - public void setBtcEstimatedFeeListener(EstimatedFeeListener listener) { - estimatedFeeListener = listener; - } - - public void requestBtcEstimatedFee(int blockCount) { - EstimatefeeApi estimatefeeApi = App.Companion.getNetworkComponent().getRetrofitEstimatefee().create(EstimatefeeApi.class); - - Call call; - switch (blockCount) { - case ESTIMATE_FEE_PRIORITY: - call = estimatefeeApi.getEstimateFeePriority(); - break; - - case ESTIMATE_FEE_NORMAL: - call = estimatefeeApi.getEstimateFeeNormal(); - break; - - case ESTIMATE_FEE_MINIMAL: - call = estimatefeeApi.getEstimateFeeMinimal(); - break; - - default: - call = estimatefeeApi.getEstimateFeeNormal(); - } - - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if (response.code() == 200) { - estimatedFeeListener.onSuccess(blockCount, response.body()); - Log.i(TAG, "requestBtcEstimatedFee onResponse " + response.code() + " " + response.body()); - } else - estimatedFeeListener.onFail(blockCount, response.body()); - Log.e(TAG, "requestBtcEstimatedFee onResponse " + response.code()); - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - estimatedFeeListener.onFail(blockCount, t.getMessage()); - Log.e(TAG, "requestBtcEstimatedFee onFailure " + t.getMessage()); - } - }); - } - - /** - * HTTP - * Used in Crypto-currency course - */ - private RateInfoListener rateInfoListener; - - public interface RateInfoListener { - void onSuccess(RateInfoResponse rateInfoResponse); - - void onFail(String message); - } - - public void setRateInfoListener(RateInfoListener listener) { - rateInfoListener = listener; - } - - public void requestRateInfo(String cryptoId) { - CoinmarketApi coinmarketApi = App.Companion.getNetworkComponent().getRetrofitCoinmarketcap().create(CoinmarketApi.class); - -// Call call = coinmarketApi.getRateInfo(1, cryptoId); -// -// call.enqueue(new Callback() { -// @Override -// public void onResponse(@NonNull Call call, @NonNull Response response) { -// if (response.code() == 200) { -// rateInfoListener.onSuccess(response.body()); -// Log.i(TAG, "coinmarketcap onResponse " + response.code()); -// } else { -// rateInfoListener.onFail("Rate info error:" + String.valueOf(response.code())); -// Log.e(TAG, "coinmarketcap onResponse " + response.code()); -// } -// } -// -// @Override -// public void onFailure(@NonNull Call call, @NonNull Throwable t) { -// rateInfoListener.onFail(String.valueOf(t.getMessage())); -// Log.e(TAG, "coinmarketcap onFailure " + t.getMessage()); -// } -// }); - coinmarketApi.getRateInfo(1, cryptoId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(rateInfoResponse -> { - if (rateInfoResponse.getData().getQuote().getUsd().getPrice() != null) { - rateInfoListener.onSuccess(rateInfoResponse); - Log.i(TAG, "coinmarketcap onResponse " + 200); - } else { - rateInfoListener.onFail("Rate info error: wrong response"); - } - }, - // handle error - Throwable::printStackTrace); - } - - /** - * HTTP - * Last version request from GitHub - */ - private LastVersionListener lastVersionListener; - - public interface LastVersionListener { - void onSuccess(String lastVersion); - } - - public void setLastVersionListener(LastVersionListener listener) { - lastVersionListener = listener; - } - - public void requestLastVersion() { - UpdateVersionApi updateVersionApi = App.Companion.getNetworkComponent().getRetrofitGitHubUserContent().create(UpdateVersionApi.class); - - Call call = updateVersionApi.getLastVersion(); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - Log.i(TAG, "requestLastVersion onResponse " + response.code()); - if (response.code() == 200) { - String stringResponse; - try { - stringResponse = response.body() != null ? response.body().string() : null; - lastVersionListener.onSuccess(stringResponse); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - Log.e(TAG, "lastVersion onFailure " + t.getMessage()); - } - }); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java b/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java deleted file mode 100644 index b2e8f91540..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java +++ /dev/null @@ -1,386 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.wallet.R; -import com.tangem.wallet.TangemContext; -import com.tangem.wallet.bch.BitcoinCashNode; -import com.tangem.wallet.btc.BitcoinNode; -import com.tangem.wallet.btc.BitcoinNodeTestNet; -import com.tangem.wallet.ltc.LitecoinNode; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.observers.DefaultObserver; -import io.reactivex.schedulers.Schedulers; - -/** - * Request processor for Electrum Api - * Every request live cycle: - * 1. In application create request and call {@link ServerApiElectrum}.requestData(..) - * 2. Try send every request for max 4 times, - * 3. If all 4 times fail call DefaultObserver.onError (defined in .requestData(..)) and than - * {@link ResponseListener}.onFail(...) callback - * Error can be acquired with {@link ElectrumRequest}.getError() method - * 4. If request network communication finished successfully then call DefaultObserver.onComplete (defined in .requestData) and than - * {@link ResponseListener}.onSuccess(...) callback - */ -public class ServerApiElectrum { - public static final String ERROR_STARTS_WITH_CODE_32601 = "{\"code\":-32601,"; - private static String TAG = ServerApiElectrum.class.getSimpleName(); - - /** - * TCP, SSL - * Used in BTC, BCH - */ - private ResponseListener responseListener; - private String host; - private int port; - - private int requestsCount=0; - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - /** - * Interface for notification every request result - */ - public interface ResponseListener { - - /** - * Notify that request processing was successful - * @param electrumRequest - processed request containing received answer {@see electrumRequest.getAnswer() method} - */ - void onSuccess(ElectrumRequest electrumRequest); - /** - * Notify that request processing was successful - * @param electrumRequest - processed request containing occurred error {@see electrumRequest.getError() method} - */ - void onFail(ElectrumRequest electrumRequest); - } - - /** - * Set notificaion listener - * @param listener - */ - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - - /** - * Start process request - * @param ctx - * @param electrumRequest - */ - public void requestData(TangemContext ctx, ElectrumRequest electrumRequest) { - requestsCount++; - Log.i(TAG, String.format("New request[%d]: %s", requestsCount,electrumRequest.getMethod())); - Observable checkElectrumDataObserver = Observable.just(electrumRequest) - .doOnNext(electrumRequest1 -> doElectrumRequest(ctx, electrumRequest)) - - .flatMap(electrumRequest1 -> { - if (electrumRequest1.answerData == null) { - Log.e(TAG, "NullPointerException " + electrumRequest.getMethod()); - return Observable.error(new NullPointerException()); - } else - return Observable.just(electrumRequest1); - }) - - .retryWhen(errors -> errors - .filter(throwable -> throwable instanceof NullPointerException) - .zipWith(Observable.range(1, 4), (n, i) -> i)) - - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - checkElectrumDataObserver.subscribe(new DefaultObserver() { - //TODO remove onNext - @Override - public void onNext(ElectrumRequest v) { - if (electrumRequest.answerData != null) { - Log.i(TAG, "requestData " + electrumRequest.getMethod() + " onNext != null"); - } else { - Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onNext == null"); - } - } - - @Override - public void onError(Throwable e) { - requestsCount--; - Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onError " + e.getMessage()); - Log.e(TAG, String.format("%d requests left in processing",requestsCount)); - electrumRequest.setError(ctx.getString(R.string.loaded_wallet_error_obtaining_blockchain_data)); - //setErrorOccurred(e.getMessage());//; - responseListener.onFail(electrumRequest); - } - - /** - * Called after completion request processing - */ - @Override - public void onComplete() { - requestsCount--; - if (electrumRequest.answerData != null) { - Log.i(TAG, "requestData " + electrumRequest.getMethod() + " onComplete, answerData!=null"); - } else { - Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onComplete, answerData==null"); - } - Log.e(TAG, String.format("%d requests left in processing",requestsCount)); - if (electrumRequest.answerData != null && electrumRequest.getError()==null) { - responseListener.onSuccess(electrumRequest); - } else { -// if( error==null || error.isEmpty() ) setErrorOccurred(ctx.getString(R.string.cannot_obtain_data_from_blockchain)); - responseListener.onFail(electrumRequest); - } - } - - }); - } - - private void doElectrumRequest(TangemContext ctx, ElectrumRequest electrumRequest) { - String host; - int port; - String proto; - electrumRequest.setError(null); - // todo - get available URL list from coinEngine, remove if( ctx.getBlockchain()==...) - if (ctx.getBlockchain() == Blockchain.BitcoinTestNet) { - BitcoinNodeTestNet bitcoinNodeTestNet = BitcoinNodeTestNet.values()[new Random().nextInt(BitcoinNodeTestNet.values().length)]; - host = bitcoinNodeTestNet.getHost(); - port = bitcoinNodeTestNet.getPort(); - - this.host = host; - this.port = port; - - doElectrumRequestTcp(electrumRequest, host, port); - } else if (ctx.getBlockchain() == Blockchain.BitcoinCash) { - BitcoinCashNode bitcoinCashNode = BitcoinCashNode.values()[new Random().nextInt(BitcoinCashNode.values().length)]; - host = bitcoinCashNode.getHost(); - port = bitcoinCashNode.getPort(); - proto = bitcoinCashNode.getProto(); - - this.host = host; - this.port = port; - - if (proto.equals("tcp")) { - doElectrumRequestTcp(electrumRequest, host, port); - } else { - doElectrumRequestSsl(electrumRequest, host, port); - } - - } else if (ctx.getBlockchain() == Blockchain.Bitcoin) { - BitcoinNode bitcoinNode = BitcoinNode.values()[new Random().nextInt(BitcoinNode.values().length)]; - host = bitcoinNode.getHost(); - port = bitcoinNode.getPort(); - proto = bitcoinNode.getProto(); - - this.host = host; - this.port = port; - - if (proto.equals("tcp")) { - doElectrumRequestTcp(electrumRequest, host, port); - } else { - doElectrumRequestSsl(electrumRequest, host, port); - } - } else if (ctx.getBlockchain() == Blockchain.Litecoin) { - LitecoinNode litecoinNode = LitecoinNode.values()[new Random().nextInt(LitecoinNode.values().length)]; - host = litecoinNode.getHost(); - port = litecoinNode.getPort(); - proto = litecoinNode.getProto(); - - this.host = host; - this.port = port; - - if (proto.equals("tcp")) { - doElectrumRequestTcp(electrumRequest, host, port); - } else { - doElectrumRequestSsl(electrumRequest, host, port); - } - } - } - - private void doElectrumRequestTcp(ElectrumRequest electrumRequest, String host, int port) { - try { - Socket socket = App.Companion.getNetworkComponent().getSocket(); - socket.setSoTimeout(3000); - Log.i(TAG, "Start process "+electrumRequest.getMethod()+" @ "+host + ":" + port); - socket.connect(new InetSocketAddress(InetAddress.getByName(host), port)); - try { - OutputStream os = socket.getOutputStream(); - OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8"); - InputStream is = socket.getInputStream(); - BufferedReader in = new BufferedReader(new InputStreamReader(is)); - electrumRequest.setID(1); - - out.write(electrumRequest.getAsString() + "\n"); - out.flush(); - - electrumRequest.answerData = in.readLine(); - electrumRequest.host = host; - electrumRequest.port = port; - if (electrumRequest.answerData != null) { - Log.i(TAG, ">> " + electrumRequest.answerData); - if( (electrumRequest.getError()!=null && electrumRequest.getError().startsWith(ERROR_STARTS_WITH_CODE_32601)) ) - { - // method unknown error??? - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_obtaining_blockchain_data)); - electrumRequest.answerData=null; - } - } else { - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_empty_answer)); - Log.i(TAG, ">> "); - } - - } catch (ConnectException e) { - //e.printStackTrace(); - //responseListener.onFail(e.getMessage()); - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_connection_refused)); - Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " ConnectException " + e.getMessage()); - } finally { - Log.i(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " socket.close"); - try { - if( socket.isConnected() ) socket.close(); - } - catch (Exception e) - { - e.printStackTrace(); - Log.e(TAG,"Can't close socket"); - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error)); - } - } - } catch (IOException e) { - //e.printStackTrace(); - //responseListener.onFail(e.getMessage()); - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error)); - Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " IOException " + e.getMessage()); - } - } - - private void doElectrumRequestSsl(ElectrumRequest electrumRequest, String host, int port) { - try { - // create a trust manager that does not validate certificate chains - TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) { - - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) { - - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - }}; - - // install the all-trusting trust manager - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, trustAllCerts, new java.security.SecureRandom()); - SSLSocketFactory sf = sc.getSocketFactory(); - HttpsURLConnection.setDefaultSSLSocketFactory(sf); - - // create all-trusting host name verifier - HostnameVerifier allHostsValid = (hostname, session) -> true; - - // install the all-trusting host verifier - HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); - - Socket sslSocket = new Socket(); - - List result = new ArrayList<>(); - Collections.addAll(result, electrumRequest); - - try { - Log.i(TAG, host + " " + port); - sslSocket.connect(new InetSocketAddress(host,port), 3000); - sslSocket.setSoTimeout(3000); - sslSocket = sf.createSocket(sslSocket, host, port, true); - try { - OutputStream os = sslSocket.getOutputStream(); - OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8"); - InputStream is = sslSocket.getInputStream(); - BufferedReader in = new BufferedReader(new InputStreamReader(is)); - electrumRequest.setID(1); - - out.write(electrumRequest.getAsString() + "\n"); - out.flush(); - - electrumRequest.answerData = in.readLine(); - if (electrumRequest.answerData != null) { - Log.i(TAG, ">> " + electrumRequest.answerData); - if( (electrumRequest.getError()!=null && electrumRequest.getError().startsWith(ERROR_STARTS_WITH_CODE_32601)) ) - { - // method unknown error??? - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_obtaining_blockchain_data)); - electrumRequest.answerData=null; - } - } else { - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_empty_answer)); - Log.i(TAG, ">> "); - } - - } catch (ConnectException e) { - e.printStackTrace(); - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_connection_refused)); - Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " ConnectException " + e.getMessage()); - } finally { - Log.i(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " socket.close"); - try { - if( sslSocket.isConnected() ) sslSocket.close(); - } - catch (Exception e) - { - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error)); - e.printStackTrace(); - Log.e(TAG, "Can't close ssl socket"); - } - } - - } catch (IOException e) { - e.printStackTrace(); - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error)); - Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " IOException " + e.getMessage()); - } - } catch (NoSuchAlgorithmException | KeyManagementException e) { - electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_obtaining_blockchain_data)); - Log.e(TAG, e.getMessage()); - } - } - - public String getValidationNodeDescription() { - return "Electrum, " + host + ":" + String.valueOf(port); - } - - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerApiEos.java b/app/src/main/java/com/tangem/data/network/ServerApiEos.java deleted file mode 100644 index 99bc68b9cb..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiEos.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import com.tangem.wallet.eos.EosApiPush; -import com.tangem.wallet.eos.EosPushTransactionRequest; - -import io.jafka.jeos.EosApi; -import io.jafka.jeos.EosApiFactory; -import io.jafka.jeos.core.response.chain.account.Account; -import io.jafka.jeos.core.response.chain.transaction.PushedTransaction; -import io.jafka.jeos.impl.EosApiServiceGenerator; -import io.reactivex.Observable; -import io.reactivex.Observer; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -public class ServerApiEos { - private static String TAG = ServerApiEos.class.getSimpleName(); - - public static void getBalance(String wallet, Observer accountObserver) { - Log.i(TAG, "new getBalance request"); - EosApi eosApi = EosApiFactory.create("https://api.eosdetroit.io:443"); //TODO: add random server request - - Observable accountObservable = Observable.just(new Account()) - .map(account -> eosApi.getAccount(wallet)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - accountObservable.subscribe(accountObserver); - } - - public static void sendTransaction(EosPushTransactionRequest req, Observer sendObserver) { - Log.i(TAG, "new getBalance request"); -// EosApi eosApi = EosApiFactory.create("https://api.eosdetroit.io:443"); //TODO: add random server request - EosApiPush eosApiPush = EosApiServiceGenerator.createService(EosApiPush.class, "https://api.eosdetroit.io:443"); //TODO: add random server request - - Observable sendObservable = Observable.just(new PushedTransaction()) - .map(pushedTransaction -> EosApiServiceGenerator.executeSync(eosApiPush.pushTransaction(req))) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - - sendObservable.subscribe(sendObserver); - } - -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiInfura.java b/app/src/main/java/com/tangem/data/network/ServerApiInfura.java deleted file mode 100644 index 29ded17af1..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiInfura.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.data.network.model.InfuraBody; -import com.tangem.data.network.model.InfuraResponse; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ServerApiInfura { - private static String TAG = ServerApiInfura.class.getSimpleName(); - - /** - * HTTP - * Infura - *

- * eth_getBalance - * eth_getTransactionCount - * eth_call - * eth_sendRawTransaction - * eth_gasPrice - */ - public static final String INFURA_ETH_GET_BALANCE = "eth_getBalance"; - public static final String INFURA_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount"; - public static final String INFURA_ETH_GET_PENDING_COUNT = "eth_getPendingCount"; - public static final String INFURA_ETH_CALL = "eth_call"; - public static final String INFURA_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction"; - public static final String INFURA_ETH_GAS_PRICE = "eth_gasPrice"; - - private int requestsCount=0; - - private InfuraApi infuraApi = App.Companion.getNetworkComponent().getRetrofitInfura().create(InfuraApi.class); - - public ServerApiInfura() {} - - public ServerApiInfura(Blockchain blockchain) { - if (blockchain == Blockchain.EthereumTestNet) { - infuraApi = App.Companion.getNetworkComponent().getRetrofitInfuraTestnet().create(InfuraApi.class); - } else if (blockchain == Blockchain.TokenEmv) { - infuraApi = App.Companion.getNetworkComponent().getRetrofitInfuraRopsten().create(InfuraApi.class); - } - } - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - private ResponseListener responseListener; - - public interface ResponseListener { - void onSuccess(String method, InfuraResponse infuraResponse); - - void onFail(String method, String message); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void requestData(String method, int id, String wallet, String contract, String tx) { - requestsCount++; - - - InfuraBody infuraBody; - switch (method) { - case INFURA_ETH_GET_BALANCE: - case INFURA_ETH_GET_TRANSACTION_COUNT: - infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id); - break; - case INFURA_ETH_GET_PENDING_COUNT: - infuraBody = new InfuraBody(INFURA_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id); - break; - case INFURA_ETH_CALL: - String address = wallet.substring(2); - infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id); - break; - - case INFURA_ETH_SEND_RAW_TRANSACTION: - infuraBody = new InfuraBody(method, new String[]{tx}, id); - break; - - case INFURA_ETH_GAS_PRICE: - infuraBody = new InfuraBody(method, id); - break; - - default: - infuraBody = new InfuraBody(); - } - - Call call = infuraApi.infura(infuraBody); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerApiInsight.java b/app/src/main/java/com/tangem/data/network/ServerApiInsight.java deleted file mode 100644 index 5a768471e6..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiInsight.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.data.network.model.InsightBody; -import com.tangem.data.network.model.InsightResponse; -import com.tangem.data.network.model.InsightUtxo; - -import java.util.List; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -public class ServerApiInsight { - private static String TAG = ServerApiInsight.class.getSimpleName(); - - public static final String INSIGHT_ADDRESS = "addr/{address}"; - public static final String INSIGHT_UNSPENT_OUTPUTS = "addr/{address}/utxo"; - public static final String INSIGHT_TRANSACTION = "rawtx/{txId}"; - public static final String INSIGHT_FEE = "utils/estimatefee?nbBlocks=2,3,6"; - public static final String INSIGHT_SEND = "tx/send"; - - private int requestsCount = 0; - - public static String lastNode; - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - private ResponseListener responseListener; - - public interface ResponseListener { - void onSuccess(String method, InsightResponse insightResponse); - - void onSuccess(String method, List utxoList); - - void onFail(String method, String message); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void requestData(String method, String wallet, String tx) { - requestsCount++; - String insightURL = "https://insight.ducatus.io/insight-lite-api/"; //TODO: make random selection - this.lastNode = insightURL; //TODO: show node instead of URL - - Retrofit retrofitInsight = new Retrofit.Builder() - .baseUrl(insightURL) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - -// InsightApi insightApi = App.getNetworkComponent().getRetrofitInsight(insightURL).create(InsightApi.class); - InsightApi insightApi = retrofitInsight.create(InsightApi.class); - - if (method.equals(INSIGHT_UNSPENT_OUTPUTS)) { - Call> call = insightApi.insightUnspent(wallet); - call.enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - - } else { - Call call; - - switch (method) { - case INSIGHT_ADDRESS: - call = insightApi.insightAddress(wallet); - break; - -// case INSIGHT_FEE: -// call = insightApi.insightFee(); -// break; - - case INSIGHT_SEND: - call = insightApi.insightSend(new InsightBody(tx)); - break; - - default: - call = insightApi.insightAddress(wallet); - break; - } - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - } - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiMatic.java b/app/src/main/java/com/tangem/data/network/ServerApiMatic.java deleted file mode 100644 index 448fa02fc6..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiMatic.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.App; -import com.tangem.data.network.model.InfuraBody; -import com.tangem.data.network.model.InfuraResponse; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ServerApiMatic { - private static String TAG = ServerApiMatic.class.getSimpleName(); - - /** - * HTTP - * Infura - *

- * eth_getBalance - * eth_getTransactionCount - * eth_call - * eth_sendRawTransaction - * eth_gasPrice - */ - public static final String MATIC_ETH_GET_BALANCE = "eth_getBalance"; - public static final String MATIC_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount"; - public static final String MATIC_ETH_GET_PENDING_COUNT = "eth_getPendingCount"; - public static final String MATIC_ETH_CALL = "eth_call"; - public static final String MATIC_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction"; - public static final String MATIC_ETH_GAS_PRICE = "eth_gasPrice"; - - private int requestsCount=0; - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - private ResponseListener responseListener; - - public interface ResponseListener { - void onSuccess(String method, InfuraResponse infuraResponse); - - void onFail(String method, String message); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void requestData(String method, int id, String wallet, String contract, String tx) { - requestsCount++; - MaticApi maticApi = App.Companion.getNetworkComponent().getRetrofitMaticTesnet().create(MaticApi.class); - - InfuraBody infuraBody; - switch (method) { - case MATIC_ETH_GET_BALANCE: - case MATIC_ETH_GET_TRANSACTION_COUNT: - infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id); - break; - case MATIC_ETH_GET_PENDING_COUNT: - infuraBody = new InfuraBody(MATIC_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id); - break; - case MATIC_ETH_CALL: - String address = wallet.substring(2); - infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id); - break; - - case MATIC_ETH_SEND_RAW_TRANSACTION: - infuraBody = new InfuraBody(method, new String[]{tx}, id); - break; - - case MATIC_ETH_GAS_PRICE: - infuraBody = new InfuraBody(method, id); - break; - - default: - infuraBody = new InfuraBody(); - } - - Call call = maticApi.matic(infuraBody); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerApiPayId.java b/app/src/main/java/com/tangem/data/network/ServerApiPayId.java deleted file mode 100644 index 03a8a03a68..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiPayId.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.tangem.data.network; - -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import com.tangem.data.Blockchain; -import com.tangem.data.network.model.PayIdResponse; -import com.tangem.tangem_card.util.Log; - -import java.security.InvalidParameterException; - -import io.reactivex.Single; -import io.reactivex.SingleObserver; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -public class ServerApiPayId { - private static String TAG = ServerApiPayId.class.getSimpleName(); - - private int requestsCount = 0; - - public String getAcceptHeader(Blockchain blockchain) throws InvalidParameterException { - switch (blockchain) { - case Ripple: return "application/xrpl-mainnet+json"; - case Bitcoin: return "application/btc-mainnet+json"; - case Litecoin: return "application/ltc-mainnet+json"; - case Cardano: return "application/ada-mainnet+json"; - case Ducatus: return "application/duc-mainnet+json"; - case BitcoinCash: return "application/bch-mainnet+json"; - case Ethereum: - case Token: - return "application/eth-mainnet+json"; - case Stellar: - case StellarAsset: - return "application/xlm-mainnet+json"; - case Binance: - case BinanceAsset: - return "application/bnb-mainnet+json"; - case Rootstock: - case RootstockToken: - return "application/rsk-mainnet+json"; - default: throw new InvalidParameterException("PayID is not supported for " + blockchain.getOfficialName()); - } - } - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - public void getAddress(String payID, Blockchain blockchain, SingleObserver addressObserver) throws InvalidParameterException { - requestsCount++; - Log.i(TAG, "new getAddress request"); - - String[] addressParts = payID.split("\\$"); - String user = addressParts[0]; - String domain = addressParts[1]; - - Retrofit retrofit = new Retrofit.Builder() - .baseUrl("https://" + domain + "/") - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .build(); - - PayIdApi api = retrofit.create(PayIdApi.class); - - Single addressSingle = api.getAddress(user, getAcceptHeader(blockchain)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnEvent((object, throwable) -> requestsCount--); - - addressSingle.subscribe(addressObserver); - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiRipple.java b/app/src/main/java/com/tangem/data/network/ServerApiRipple.java deleted file mode 100644 index 85563c0df4..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiRipple.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.data.network.model.RippleBody; -import com.tangem.data.network.model.RippleResponse; - -import java.util.HashMap; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -public class ServerApiRipple { - private static String TAG = ServerApiRipple.class.getSimpleName(); - - public static final String RIPPLE_ACCOUNT_INFO = "account_info"; - public static final String RIPPLE_ACCOUNT_UNCONFIRMED = "account_unconfirmed"; - public static final String RIPPLE_SUBMIT = "submit"; - public static final String RIPPLE_FEE = "fee"; - public static final String RIPPLE_SERVER_STATE = "server_state"; - - private int requestsCount = 0; - - private final String rippleURL1 = "https://s1.ripple.com:51234"; //TODO: make random selection, add more?, move - private final String rippleURL2 = "https://s2.ripple.com:51234"; - - private String currentURL = rippleURL1; - - public String getCurrentURL() { - return currentURL; - } - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - private ResponseListener responseListener; - - public interface ResponseListener { - void onSuccess(String method, RippleResponse rippleResponse); - - void onFail(String method, String message); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void requestData(String method, String wallet, String tx) { - requestsCount++; - - Retrofit retrofitRipple = new Retrofit.Builder() - .baseUrl(currentURL) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - - RippleApi rippleApi = retrofitRipple.create(RippleApi.class); - - RippleBody rippleBody; - HashMap paramsMap; - - switch (method) { - case RIPPLE_ACCOUNT_INFO: - paramsMap = new HashMap<>(); - paramsMap.put("account", wallet); - paramsMap.put("ledger_index", "validated"); - rippleBody = new RippleBody(method, paramsMap); - break; - - case RIPPLE_ACCOUNT_UNCONFIRMED: - paramsMap = new HashMap<>(); - paramsMap.put("account", wallet); - paramsMap.put("ledger_index", "current"); -// paramsMap.put("queue", "true"); TODO: make queue check if needed - rippleBody = new RippleBody(RIPPLE_ACCOUNT_INFO, paramsMap); - break; - - case RIPPLE_SERVER_STATE: - rippleBody = new RippleBody(method, new HashMap<>()); - break; - - case RIPPLE_FEE: - rippleBody = new RippleBody(method, new HashMap<>()); - break; - - case RIPPLE_SUBMIT: - paramsMap = new HashMap<>(); - paramsMap.put("tx_blob", tx); - rippleBody = new RippleBody(method, paramsMap); - break; - - default: - rippleBody = new RippleBody(); - } - - Call call = rippleApi.ripple(rippleBody); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if (response.code() == 200) { - requestsCount--; - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - retryRequest(method, rippleBody); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - retryRequest(method, rippleBody); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - } - - private void retryRequest(String method, RippleBody rippleBody) { - currentURL = rippleURL2; - - Retrofit retrofitRipple = new Retrofit.Builder() - .baseUrl(currentURL) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - - RippleApi rippleApi = retrofitRipple.create(RippleApi.class); - - Call call = rippleApi.ripple(rippleBody); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiRootstock.java b/app/src/main/java/com/tangem/data/network/ServerApiRootstock.java deleted file mode 100644 index ce1c152a39..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiRootstock.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.App; -import com.tangem.data.network.model.InfuraBody; -import com.tangem.data.network.model.InfuraResponse; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ServerApiRootstock { - private static String TAG = ServerApiRootstock.class.getSimpleName(); - - /** - * HTTP - * Rootstock - *

- * eth_getBalance - * eth_getTransactionCount - * eth_call - * eth_sendRawTransaction - * eth_gasPrice - */ - public static final String ROOTSTOCK_ETH_GET_BALANCE = "eth_getBalance"; - public static final String ROOTSTOCK_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount"; - public static final String ROOTSTOCK_ETH_GET_PENDING_COUNT = "eth_getPendingCount"; - public static final String ROOTSTOCK_ETH_CALL = "eth_call"; - public static final String ROOTSTOCK_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction"; - public static final String ROOTSTOCK_ETH_GAS_PRICE = "eth_gasPrice"; - - private int requestsCount=0; - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - private ResponseListener responseListener; - - public interface ResponseListener { - void onSuccess(String method, InfuraResponse infuraResponse); - - void onFail(String method, String message); - } - - public void setResponseListener(ResponseListener listener) { - responseListener = listener; - } - - public void requestData(String method, int id, String wallet, String contract, String tx) { - requestsCount++; - RootstockApi rootstockApi = App.Companion.getNetworkComponent().getRetrofitRootstock().create(RootstockApi.class); - - InfuraBody infuraBody; - switch (method) { - case ROOTSTOCK_ETH_GET_BALANCE: - case ROOTSTOCK_ETH_GET_TRANSACTION_COUNT: - infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id); - break; - case ROOTSTOCK_ETH_GET_PENDING_COUNT: - infuraBody = new InfuraBody(ROOTSTOCK_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id); - break; - case ROOTSTOCK_ETH_CALL: - String address = wallet.substring(2); - infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id); - break; - - case ROOTSTOCK_ETH_SEND_RAW_TRANSACTION: - infuraBody = new InfuraBody(method, new String[]{tx}, id); - break; - - case ROOTSTOCK_ETH_GAS_PRICE: - infuraBody = new InfuraBody(method, id); - break; - - default: - infuraBody = new InfuraBody(); - } - - Call call = rootstockApi.rootstock(infuraBody); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - - if (response.code() == 200) { - responseListener.onSuccess(method, response.body()); - Log.i(TAG, "requestData " + method + " onResponse " + response.code()); - } else { - responseListener.onFail(method, String.valueOf(response.code())); - Log.e(TAG, "requestData " + method + " onResponse " + response.code()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - responseListener.onFail(method, String.valueOf(t.getMessage())); - Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage()); - } - }); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerApiSoChain.java b/app/src/main/java/com/tangem/data/network/ServerApiSoChain.java deleted file mode 100644 index ceb90697d5..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiSoChain.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.tangem.data.network; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.data.network.model.SoChain; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ServerApiSoChain { - - private static String TAG = ServerApiSoChain.class.getSimpleName(); - - private int requestsCount = 0; - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - - public interface AddressInfoListener { - void onSuccess(SoChain.Response.AddressBalance response); - - void onSuccess(SoChain.Response.TxUnspent response); - - void onFail(String message); - } - - private AddressInfoListener addressInfoListener; - - public void setAddressInfoListener(AddressInfoListener listener) { - addressInfoListener = listener; - } - - public interface SendTxListener { - void onSuccess(SoChain.Response.SendTx response); - - void onFail(String message); - } - - private SendTxListener sendTxListener; - - public void setSendTxListener(SendTxListener listener) { - sendTxListener = listener; - } - - - public interface TransactionInfoListener { - void onSuccess(SoChain.Response.GetTx response); - - void onFail(String message); - } - - private TransactionInfoListener txInfoListener; - - public void setTransactionInfoListener(TransactionInfoListener listener) { - txInfoListener=listener; - } - - - private String getNetwork(Blockchain blockchain) throws Exception { - switch (blockchain) { - case Bitcoin: - return "BTC"; - case BitcoinTestNet: - return "BTCTEST"; - case Litecoin: - return "LTC"; - default: - throw new Exception("SoChainAPI don't support blockchain " + blockchain.getID()); - } - } - - public void requestAddressBalance(Blockchain blockchain, String wallet) throws Exception { - requestsCount++; - SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class); - - Call call = api.getAddressBalance(getNetwork(blockchain), wallet); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - Log.i(TAG, "requestAddressBalance onResponse " + response.code()); - if (response.code() == 200) { - addressInfoListener.onSuccess(response.body()); - } else { - addressInfoListener.onFail(String.valueOf(response.code())); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage()); - addressInfoListener.onFail(String.valueOf(t.getMessage())); - } - }); - } - - public void requestUnspentTx(Blockchain blockchain, String wallet) throws Exception { - requestsCount++; - SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class); - - Call call = api.getUnspentTx(getNetwork(blockchain), wallet); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - Log.i(TAG, "requestAddressBalance onResponse " + response.code()); - if (response.code() == 200) { - addressInfoListener.onSuccess(response.body()); - } else { - addressInfoListener.onFail(String.valueOf(response.code())); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage()); - addressInfoListener.onFail(String.valueOf(t.getMessage())); - } - }); - } - - public void requestSendTransaction(Blockchain blockchain, String txHEX) throws Exception { - requestsCount++; - SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class); - - SoChain.Request.SendTx tx=new SoChain.Request.SendTx(); - tx.setTx_hex(txHEX); - Call call = api.sendTransaction(getNetwork(blockchain), tx); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - Log.i(TAG, "requestAddressBalance onResponse " + response.code()); - if (response.code() == 200) { - sendTxListener.onSuccess(response.body()); - } else { - sendTxListener.onFail(String.valueOf(response.code())); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage()); - sendTxListener.onFail(String.valueOf(t.getMessage())); - } - }); - } - - public void requestTransactionInfo(Blockchain blockchain, String txId) throws Exception { - requestsCount++; - SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class); - - Call call = api.getTx(getNetwork(blockchain), txId); - call.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - requestsCount--; - Log.i(TAG, "requestAddressBalance onResponse " + response.code()); - if (response.code() == 200) { - txInfoListener.onSuccess(response.body()); - } else { - txInfoListener.onFail(String.valueOf(response.code())); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - requestsCount--; - Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage()); - txInfoListener.onFail(String.valueOf(t.getMessage())); - } - }); - } - -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiStellar.java b/app/src/main/java/com/tangem/data/network/ServerApiStellar.java deleted file mode 100644 index 77427e3fc4..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiStellar.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.util.LOG; -import com.tangem.wallet.R; -import com.tangem.wallet.TangemContext; - -import org.stellar.sdk.Network; -import org.stellar.sdk.Server; -import org.stellar.sdk.requests.ErrorResponse; - -import java.io.IOException; - -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.observers.DefaultObserver; -import io.reactivex.schedulers.Schedulers; - -/** - * Created by dvol on 7.01.2019. - *

- * Request processor for Stellar Horizon Rest Api - * Every request live cycle: - * 1. In application create request and call {@link ServerApiStellar}.requestData(..) - * 2. Try send every request for max 4 times, - * 3. If all 4 times fail call DefaultObserver.onError (defined in .requestData(..)) and than - * {@link Listener}.onFail(...) callback - * Error can be acquired with {@link StellarRequest}.getError() method - * 4. If request network communication finished successfully then call DefaultObserver.onComplete (defined in .requestData) and than - * {@link Listener}.onSuccess(...) callback - */ -public class ServerApiStellar { - - public ServerApiStellar(Blockchain blockchain) { - if (blockchain == Blockchain.Stellar || blockchain == Blockchain.StellarAsset || blockchain == Blockchain.StellarTag) { - currentURL = ServerURL.API_STELLAR; - } else { - currentURL = ServerURL.API_STELLAR_TESTNET; - } - } - - private static String TAG = ServerApiStellar.class.getSimpleName(); - - /** - * TCP, SSL - * Used in BTC, BCH - */ - private Listener listener; - - private int requestsCount = 0; - - private String currentURL; - - public String getCurrentURL() { - return currentURL; - } - - public boolean isRequestsSequenceCompleted() { - LOG.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - /** - * Interface for notification every request result - */ - public interface Listener { - - /** - * Notify that request processing was successful - * - * @param stellarRequest - processed request containing received answer {@see stellarRequest.getAnswer() method} - */ - void onSuccess(StellarRequest.Base stellarRequest); - - /** - * Notify that request processing was successful - * - * @param stellarRequest - processed request containing occurred error {@see stellarRequest.getError() method} - */ - void onFail(StellarRequest.Base stellarRequest); - } - - /** - * Set notificaion listener - * - * @param listener - */ - public void setListener(Listener listener) { - this.listener = listener; - } - - - /** - * Start process request - * - * @param ctx - * @param stellarRequest - */ - - public void requestData(TangemContext ctx, StellarRequest.Base stellarRequest) { - requestData(ctx, stellarRequest, false); - } - - public void requestData(TangemContext ctx, StellarRequest.Base stellarRequest, boolean isRetry) { - requestsCount++; - LOG.i(TAG, String.format("New request[%d]: %s", requestsCount, stellarRequest.getClass().getSimpleName())); - - Observable stellarObserver = Observable.just(stellarRequest) - .doOnEach(stellarRequest1 -> doStellarRequest(ctx, stellarRequest)) - - .flatMap(stellarRequest1 -> { - if (stellarRequest1.errorResponse != null) { - LOG.e(TAG, "Error response on " + stellarRequest.getClass().getSimpleName()); - return Observable.error(stellarRequest.errorResponse); - } else - return Observable.just(stellarRequest1); - } - ) -// .retryWhen(errors -> errors -// .filter(throwable -> (throwable instanceof IOException) || (throwable instanceof ErrorResponse)) -// .zipWith(Observable.range(1, 4), (n, i) -> i)) - - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - stellarObserver.subscribe(new DefaultObserver() { - - @Override - public void onNext(StellarRequest.Base stellarRequest) { - LOG.e(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onNext "); - } - - @Override - public void onError(Throwable e) { - requestsCount--; - LOG.e(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onError " + e.getMessage()); - LOG.e(TAG, String.format("%d requests left in processing", requestsCount)); - - if (isRetry || (stellarRequest.errorResponse != null && stellarRequest.errorResponse.getCode() == 404)) { - stellarRequest.setError(e.getMessage()); - //setErrorOccurred(e.getMessage());//; - listener.onFail(stellarRequest); - } else { - retryRequest(ctx, stellarRequest); - } - } - - /** - * Called after completion request processing - */ - @Override - public void onComplete() { - requestsCount--; - LOG.e(TAG, String.format("%d requests left in processing", requestsCount)); - if (stellarRequest.getError() != null) { - LOG.i(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onComplete, error!=null"); - - if (isRetry || (stellarRequest.errorResponse != null && stellarRequest.errorResponse.getCode() == 404)) { - listener.onFail(stellarRequest); - } else { - retryRequest(ctx, stellarRequest); - } - } else { - LOG.e(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onComplete, error==null"); - listener.onSuccess(stellarRequest); - } - } - - }); - } - - public void doStellarRequest(TangemContext ctx, StellarRequest.Base stellarRequest) throws IOException { - stellarRequest.setError(null); - try { - Server server; - Blockchain blockchain = ctx.getBlockchain(); - if (blockchain == Blockchain.Stellar || blockchain == Blockchain.StellarAsset || blockchain == Blockchain.StellarTag) { - Network.usePublicNetwork(); - server = new Server(currentURL); - } else if (blockchain == Blockchain.StellarTestNet) { - Network.useTestNetwork(); - server = new Server(currentURL); - } else { - throw new IOException("Wrong blockchain for ServerApiStellar"); - } - try { - LOG.e(TAG, "--- request " + stellarRequest.getClass().getSimpleName()); - stellarRequest.process(server); - } catch (ErrorResponse errorResponse) { - LOG.e(TAG, "--- error response: " + errorResponse.getMessage()); - stellarRequest.errorResponse = errorResponse; - stellarRequest.setError(errorResponse.getMessage()); - } - } catch (Exception e) { - e.printStackTrace(); - stellarRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error)); - throw e; - } - } - - public void retryRequest (TangemContext ctx, StellarRequest.Base stellarRequest) { - currentURL = ServerURL.API_STELLAR_RESERVE; - requestData(ctx, stellarRequest, true); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerApiTezos.java b/app/src/main/java/com/tangem/data/network/ServerApiTezos.java deleted file mode 100644 index b5300912ca..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiTezos.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.tangem.data.network; - -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import com.tangem.data.network.model.TezosAccountResponse; -import com.tangem.data.network.model.TezosForgeBody; -import com.tangem.data.network.model.TezosHeaderResponse; -import com.tangem.data.network.model.TezosPreapplyBody; -import com.tangem.tangem_card.util.Log; - -import java.util.ArrayList; -import java.util.List; - -import io.reactivex.Single; -import io.reactivex.SingleObserver; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.OkHttpClient; -import okhttp3.logging.HttpLoggingInterceptor; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import retrofit2.converter.scalars.ScalarsConverterFactory; - -public class ServerApiTezos { - private static String TAG = ServerApiTezos.class.getSimpleName(); - - private final String letzbakeURI = "https://teznode.letzbake.com"; - private final String tezrpcURI = "https://mainnet.tezrpc.me"; - - static final String TEZOS_ADDRESS = "chains/main/blocks/head/context/contracts/{address}"; - static final String TEZOS_HEADER = "chains/main/blocks/head/header"; - static final String TEZOS_MANAGER_KEY = "chains/main/blocks/head/context/contracts/{address}/manager_key"; - static final String TEZOS_FORGE_OPERATIONS = "chains/main/blocks/head/helpers/forge/operations"; - static final String TEZOS_PREAPPLY_OPERATIONS = "chains/main/blocks/head/helpers/preapply/operations"; - static final String TEZOS_RUN_OPERATION = "chains/main/blocks/head/helpers/scripts/run_operation"; - static final String TEZOS_INJECT_OPERATIONS = "injection/operation"; - - private Retrofit retrofitTezos = new Retrofit.Builder() - .baseUrl(letzbakeURI) - .addConverterFactory(GsonConverterFactory.create()) - .addConverterFactory(ScalarsConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - //logging for testing - .client(new OkHttpClient.Builder().addInterceptor( - new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY) - ).build()) - - .build(); - - private TezosApi tezosApi = retrofitTezos.create(TezosApi.class); - - private int requestsCount = 0; - - public boolean isRequestsSequenceCompleted() { - Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount)); - return requestsCount <= 0; - } - - public void getAddress(String wallet, SingleObserver accountObserver) { - requestsCount++; - Log.i(TAG, "new getAddress request"); - - Single accountSingle = tezosApi.getAccount(wallet) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnEvent((object, throwable) -> requestsCount--); - - accountSingle.subscribe(accountObserver); - } - - public void getMangerKey(String wallet, SingleObserver accountObserver) { - requestsCount++; - Log.i(TAG, "new getManagerKey request"); - - Single managerKeySingle = tezosApi.getManagerKey(wallet) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnEvent((object, throwable) -> requestsCount--); - - managerKeySingle.subscribe(accountObserver); - } - - public TezosHeaderResponse getHeader() throws Exception { // TODO? not async - requestsCount++; - Log.i(TAG, "new getHeader request"); - - Response headerResponse = tezosApi.getHeader().execute(); - - requestsCount--; - if (headerResponse.code() == 200) { - return headerResponse.body(); - } else { - throw new Exception("Wrong header response, code: " + headerResponse.code()); - } - } - - public String forgeOperations(TezosForgeBody tezosForgeBody) throws Exception { // TODO? not async - requestsCount++; - Log.i(TAG, "new forgeOperations request"); - - Response forgeResponse = tezosApi.forgeOperations(tezosForgeBody).execute(); - - requestsCount--; - if (forgeResponse.code() == 200) { - return forgeResponse.body(); - } else { - throw new Exception("Wrong forge response, code: " + forgeResponse.code()); - } - } - - public void peapplyOperations(TezosPreapplyBody tezosPreapplyBody) throws Exception { - Log.i(TAG, "new peapplyOperations request"); - - List tezosPreapplyBodyList = new ArrayList<>(); - tezosPreapplyBodyList.add(tezosPreapplyBody); - Response preapplyResponse = tezosApi.preapplyOperations(tezosPreapplyBodyList).execute(); - - if (preapplyResponse.code() != 200) { - String error = "Preapply error: unknown error"; - if (preapplyResponse.errorBody() != null) { - error = "Preapply error: " + preapplyResponse.errorBody().string(); - } - Log.e(TAG, error); - throw new Exception(error); - } - } - - public void injectOperations(String txForSend, SingleObserver injectObserver) { - requestsCount++; - Log.i(TAG, "new injectOperations request"); - - Single injectSingle = tezosApi.injectOperations(txForSend) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnEvent((object, throwable) -> requestsCount--); - - injectSingle.subscribe(injectObserver); - } -} diff --git a/app/src/main/java/com/tangem/data/network/ServerApiTokenEmv.kt b/app/src/main/java/com/tangem/data/network/ServerApiTokenEmv.kt deleted file mode 100644 index d3fdba5f87..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerApiTokenEmv.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.tangem.data.network - -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory -import com.tangem.data.network.model.TokenEmvGetTransferFeeAnswer -import com.tangem.data.network.model.TokenEmvGetTransferFeeBody -import com.tangem.data.network.model.TokenEmvTransferAnswer -import com.tangem.data.network.model.TokenEmvTransferBody -import com.tangem.tangem_card.util.Log -import io.reactivex.SingleObserver -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.schedulers.Schedulers -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.converter.scalars.ScalarsConverterFactory -import java.util.concurrent.TimeUnit - -class ServerApiTokenEmv { - private val TAG = ServerApiTokenEmv::class.java.simpleName - - private val tangemServer = "https://emvsupport.appspot.com/" - - private val tokenEmvApi = Retrofit.Builder() - .baseUrl(tangemServer) - .addConverterFactory(GsonConverterFactory.create()) - .addConverterFactory(ScalarsConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //logging for testing - .client(OkHttpClient.Builder().addInterceptor( - HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY) - ).build()) - .build() - .create(TokenEmvApi::class.java) - - fun transfer(tokenEmvTransferBody: TokenEmvTransferBody, transferObserver: SingleObserver) { - Log.i(TAG, "new transfer request") - - tokenEmvApi.transfer(tokenEmvTransferBody) - .timeout(30, TimeUnit.SECONDS) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(transferObserver) - } - - fun getTransferFee(tokenEmvGetTransferFeeBody: TokenEmvGetTransferFeeBody, transferObserver: SingleObserver) { - Log.i(TAG, "new get transfer fee request") - - tokenEmvApi.getTransferFee(tokenEmvGetTransferFeeBody) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(transferObserver) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/ServerURL.java b/app/src/main/java/com/tangem/data/network/ServerURL.java deleted file mode 100644 index dedda6858d..0000000000 --- a/app/src/main/java/com/tangem/data/network/ServerURL.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.data.network; - -class ServerURL { - static final String API_TANGEM = "https://verify.tangem.com/"; - static final String API_COINMARKETCAP = "https://pro-api.coinmarketcap.com/"; - static final String API_INFURA = "https://mainnet.infura.io/"; - static final String API_INFURA_TESTNET = "https://rinkeby.infura.io/"; - static final String API_INFURA_ROPSTEN = "https://ropsten.infura.io/"; - static final String API_SOCHAIN_V2 = "https://chain.so/"; - static final String API_ESTIMATEFEE = "https://estimatefee.com/"; - static final String API_UPDATE_VERSION = "https://raw.githubusercontent.com/"; - static final String API_ROOTSTOCK = "https://public-node.rsk.co/"; - static final String API_BLOCKCYPHER = "https://api.blockcypher.com/"; - static final String API_BINANCE = "https://dex.binance.org/"; - static final String API_BINANCE_TESTNET = "https://testnet-dex.binance.org/"; - static final String API_MATIC_TESTNET = "https://testnet2.matic.network/"; - static final String API_STELLAR = "https://horizon.stellar.org/"; - static final String API_STELLAR_RESERVE = "https://horizon.sui.li/"; - static final String API_STELLAR_TESTNET = "https://horizon-testnet.stellar.org/"; - static final String API_BLOCKCHAIN_INFO = "https://blockchain.info/"; - static final String API_DUCATUS = "https://ducapi.rocknblock.io/"; - static final String API_BLOCKCHAIR = "https://api.blockchair.com/"; -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/SoChainApi.java b/app/src/main/java/com/tangem/data/network/SoChainApi.java deleted file mode 100644 index ea1f3fb89d..0000000000 --- a/app/src/main/java/com/tangem/data/network/SoChainApi.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.tangem.data.network; - - -import com.tangem.data.network.model.SoChain; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.Headers; -import retrofit2.http.POST; -import retrofit2.http.Path; - -public interface SoChainApi { - @GET(Server.ApiSoChain.Method.ADDRESS_BALANCE) - Call getAddressBalance(@Path("network") String network, @Path("address") String address); - - @GET(Server.ApiSoChain.Method.UNSPENT_TX) - Call getUnspentTx(@Path("network") String network, @Path("address") String address); - - @GET(Server.ApiSoChain.Method.GET_TX) - Call getTx(@Path("network") String network, @Path("txid") String txId); - - @Headers("Content-Type: application/json") - @POST(Server.ApiSoChain.Method.SEND_TRANSACTION) - Call sendTransaction(@Path("network") String network, @Body SoChain.Request.SendTx body); -} diff --git a/app/src/main/java/com/tangem/data/network/StellarRequest.java b/app/src/main/java/com/tangem/data/network/StellarRequest.java deleted file mode 100644 index fe4f27230c..0000000000 --- a/app/src/main/java/com/tangem/data/network/StellarRequest.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.tangem.data.network; - -import org.stellar.sdk.KeyPair; -import org.stellar.sdk.Server; -import org.stellar.sdk.Transaction; -import org.stellar.sdk.requests.ErrorResponse; -import org.stellar.sdk.requests.RequestBuilder; -import org.stellar.sdk.responses.AccountResponse; -import org.stellar.sdk.responses.LedgerResponse; -import org.stellar.sdk.responses.Page; -import org.stellar.sdk.responses.SubmitTransactionResponse; -import org.stellar.sdk.responses.operations.OperationResponse; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.List; - -/** - * Created by dvol on 7.01.2019. - */ - -public class StellarRequest { - - public static abstract class Base { - public ErrorResponse errorResponse; - private String error = null; - - public String getError() { - return error; - } - - public void setError(String error) { - this.error = error; - } - - public abstract void process(Server server) throws IOException; - } - - public static class Balance extends Base { - KeyPair accountKeyPair; - public AccountResponse accountResponse; - - public Balance(String walletAddress) { - accountKeyPair = KeyPair.fromAccountId(walletAddress); - } - - @Override - public void process(Server server) throws IOException { - accountResponse = server.accounts().account(accountKeyPair); - } - } - - public static class SubmitTransaction extends Base { - public Transaction transaction; - public SubmitTransactionResponse response; - - public SubmitTransaction(Transaction transaction) { - this.transaction = transaction; - } - - @Override - public void process(Server server) throws IOException { -// // First, check to make sure that the destination account exists. -// // You could skip this, but if the account does not exist, you will be charged -// // the transaction fee when the transaction fails. -// // It will throw HttpResponseException if account does not exist or there was another error. -// server.accounts().account(targetAccount); -// -// // If there was no error, load up-to-date information on your account. -// AccountResponse sourceAccount = server.accounts().account(sourceAccount); - - // And finally, send it off to Stellar! - response = server.submitTransaction(transaction); - } - } - - public static class Ledgers extends Base { - public LedgerResponse ledgerResponse; - - public Ledgers() { - } - - @Override - public void process(Server server) throws IOException { - int latestLedger = server.root().getHistoryLatestLedger(); - ledgerResponse = server.ledgers().ledger(latestLedger); - } - } - - public static class Operations extends Base { - KeyPair accountKeyPair; - public List operationsList; - int limit = 200; - - public Operations(String walletAddress) { - accountKeyPair = KeyPair.fromAccountId(walletAddress); - } - - @Override - public void process(Server server) throws IOException { - Page operationsResponse = server.operations().forAccount(accountKeyPair).limit(limit).order(RequestBuilder.Order.DESC).execute(); - operationsList = operationsResponse.getRecords(); - while (operationsResponse.getRecords().size() == limit) { - try { - operationsResponse = operationsResponse.getNextPage(server.getHttpClient()); - operationsList.addAll(operationsResponse.getRecords()); - } catch (URISyntaxException e) { - break; - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/TezosApi.java b/app/src/main/java/com/tangem/data/network/TezosApi.java deleted file mode 100644 index e61809b3d7..0000000000 --- a/app/src/main/java/com/tangem/data/network/TezosApi.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.tangem.data.network; - -import com.tangem.data.network.model.TezosAccountResponse; -import com.tangem.data.network.model.TezosForgeBody; -import com.tangem.data.network.model.TezosHeaderResponse; -import com.tangem.data.network.model.TezosPreapplyBody; - -import java.util.List; - -import io.reactivex.Single; -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.GET; -import retrofit2.http.POST; -import retrofit2.http.Path; - -public interface TezosApi { - @GET(ServerApiTezos.TEZOS_ADDRESS) - Single getAccount(@Path("address") String address); - - @GET(ServerApiTezos.TEZOS_HEADER) - Call getHeader(); - - @GET(ServerApiTezos.TEZOS_MANAGER_KEY) - Single getManagerKey(@Path("address") String address); - - @POST(ServerApiTezos.TEZOS_FORGE_OPERATIONS) - Call forgeOperations(@Body TezosForgeBody tezosForgeBody); - - @POST(ServerApiTezos.TEZOS_PREAPPLY_OPERATIONS) - Call preapplyOperations(@Body List tezosPreapplyBodyList); - - @POST(ServerApiTezos.TEZOS_INJECT_OPERATIONS) - Single injectOperations(@Body String txForSend); -} diff --git a/app/src/main/java/com/tangem/data/network/TokenEmvApi.kt b/app/src/main/java/com/tangem/data/network/TokenEmvApi.kt deleted file mode 100644 index 43e09897c0..0000000000 --- a/app/src/main/java/com/tangem/data/network/TokenEmvApi.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.tangem.data.network - -import com.tangem.data.network.model.TokenEmvGetTransferFeeAnswer -import com.tangem.data.network.model.TokenEmvGetTransferFeeBody -import com.tangem.data.network.model.TokenEmvTransferAnswer -import com.tangem.data.network.model.TokenEmvTransferBody -import io.reactivex.Completable -import io.reactivex.Single -import retrofit2.http.Body -import retrofit2.http.POST - -interface TokenEmvApi { - @POST("./card/transfer") - fun transfer(@Body tokenEmvTransferBody: TokenEmvTransferBody): Single - @POST("./card/transfer/fee") - fun getTransferFee(@Body tokenEmvGetTransferFeeBody: TokenEmvGetTransferFeeBody): Single -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/UpdateVersionApi.java b/app/src/main/java/com/tangem/data/network/UpdateVersionApi.java deleted file mode 100644 index ab443b7815..0000000000 --- a/app/src/main/java/com/tangem/data/network/UpdateVersionApi.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.data.network; - -import okhttp3.ResponseBody; -import retrofit2.Call; -import retrofit2.http.GET; - -public interface UpdateVersionApi { - @GET(Server.ApiUpdateVersion.Method.LAST_VERSION) - Call getLastVersion(); -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/exception/Failure.kt b/app/src/main/java/com/tangem/data/network/exception/Failure.kt deleted file mode 100644 index f2fbb19c5b..0000000000 --- a/app/src/main/java/com/tangem/data/network/exception/Failure.kt +++ /dev/null @@ -1,31 +0,0 @@ -/** - - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.tangem.data.network.exception - -/** - * Base Class for handling errors/failures/exceptions. - * Every feature specific failure should extend [FeatureFailure] class. - */ -sealed class Failure { - class ApplicationError(val message: String) : Failure() - class NotFound : FeatureFailure() - class NetworkConnection : Failure() - class ServerError : Failure() - class Unauthorized : Failure() // 401 - - /** * Extend this class for feature specific failures.*/ - abstract class FeatureFailure : Failure() -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/AdaliteBody.java b/app/src/main/java/com/tangem/data/network/model/AdaliteBody.java deleted file mode 100644 index a8208d01cf..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/AdaliteBody.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.data.network.model; - -public class AdaliteBody { - private String signedTx; - - public AdaliteBody(String signedTx) { - this.signedTx = signedTx; - } -} diff --git a/app/src/main/java/com/tangem/data/network/model/AdaliteResponse.kt b/app/src/main/java/com/tangem/data/network/model/AdaliteResponse.kt deleted file mode 100644 index d560d5fefc..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/AdaliteResponse.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class AdaliteResponse( - @SerializedName("Right") - var right: AdaliteAddressData? = null -) - -data class AdaliteResponseUtxo( - @SerializedName("Right") - var right: List -) - -data class AdaliteAddressData( - @SerializedName("caAddress") - var caAddress: String? = null, - - @SerializedName("caBalance") - var caBalance: AdaliteCoins? = null, - - @SerializedName("caTxList") - var caTxList: List -) - -data class AdaliteCoins( - @SerializedName("getCoin") - var getCoin: Long? = null -) - -data class AdaliteUtxoData( - @SerializedName("cuId") - var cuId: String? = null, - - @SerializedName("cuOutIndex") - var cuOutIndex: Int? = null, - - @SerializedName("cuCoins") - var cuCoins: AdaliteCoins? = null -) - -data class AdaliteTxData( - @SerializedName("ctbId") - var ctbId: String? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/BinanceFee.kt b/app/src/main/java/com/tangem/data/network/model/BinanceFee.kt deleted file mode 100644 index 061b9dbb27..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BinanceFee.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class BinanceFees( - @SerializedName("fixed_fee_params") - var fixed_fee_params: BinanceFixedFee? = null -) - -data class BinanceFixedFee( - @SerializedName("msg_type") - var msg_type: String? = null, - - @SerializedName("fee") - var fee: Int? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/BitcoreResponse.kt b/app/src/main/java/com/tangem/data/network/model/BitcoreResponse.kt deleted file mode 100644 index 119c1fb3ef..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BitcoreResponse.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class BitcoreBalance( - @SerializedName("confirmed") - var confirmed: Long? = null, - - @SerializedName("unconfirmed") - var unconfirmed: Long? = null -) - -data class BitcoreUtxo( - @SerializedName("mintTxid") - var mintTxid: String? = null, - - @SerializedName("mintIndex") - var mintIndex: Int? = null, - - @SerializedName("value") - var value: Long? = null, - - @SerializedName("script") - var script: String? = null -) - -data class BitcoreBalanceAndUnspents( - var balance: BitcoreBalance, - var unspents: List -) - -data class BitcoreSendResponse( - var txid: String? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/BitcoreSendBody.java b/app/src/main/java/com/tangem/data/network/model/BitcoreSendBody.java deleted file mode 100644 index 019b4c4e80..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BitcoreSendBody.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.data.network.model; - -import java.util.ArrayList; -import java.util.List; - -public class BitcoreSendBody { - private List rawTx; - - public BitcoreSendBody(String tx) { - List txList = new ArrayList<>(); - txList.add(tx); - rawTx = txList; - } -} diff --git a/app/src/main/java/com/tangem/data/network/model/BlockchainInfoResponse.kt b/app/src/main/java/com/tangem/data/network/model/BlockchainInfoResponse.kt deleted file mode 100644 index 8133dbf180..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BlockchainInfoResponse.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class BlockchainInfoAddress( - @SerializedName("final_balance") - var final_balance: Long? = null, - - @SerializedName("txs") - var txs: List? = null -) - -data class BlockchainInfoTransaction( - @SerializedName("hash") - var hash: String? = null, - - @SerializedName("block_height") - var block_height: Long? = null, - - @SerializedName("inputs") - var inputs: List -) - -data class BlockchainInfoUnspents( - @SerializedName("unspent_outputs") - var unspent_outputs: List -) - -data class BlockchainInfoUtxo( - @SerializedName("tx_hash_big_endian") - var tx_hash_big_endian: String? = null, - - @SerializedName("tx_output_n") - var tx_output_n: Int? = null, - - @SerializedName("value") - var value: Long? = null, - - @SerializedName("script") - var script: String? = null -) - -data class BlockchainInfoInput( - @SerializedName("prev_out") - var prev_out: BlockchainInfoOutput -) - -data class BlockchainInfoOutput( - @SerializedName("addr") - var addr: String? = null -) - -data class BlockchainInfoAddressAndUnspents( - var address: BlockchainInfoAddress, - var unspents: BlockchainInfoUnspents -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/BlockchairResponse.kt b/app/src/main/java/com/tangem/data/network/model/BlockchairResponse.kt deleted file mode 100644 index 8e8f65aae1..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BlockchairResponse.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class BlockchairAddressResponse( - @SerializedName("data") - val data: Map? = null -) - -data class BlockchairAddressData( - @SerializedName("address") - val address: BlockchairAddressInfo? = null, - - @SerializedName("utxo") - val unspentOutputs: List? = null, - - @SerializedName("transactions") - val transactions: List -) - -data class BlockchairAddressInfo( - @SerializedName("balance") - val balance: Long? = null, - - @SerializedName("output_count") - val outputCount: Int? = null, - - @SerializedName("unspent_output_count") - val unspentOutputCount: Int? = null -) - -data class BlockchairUnspentOutput( - @SerializedName("block_id") - val block: Int? = null, - - @SerializedName("transaction_hash") - val transactionHash: String? = null, - - @SerializedName("index") - val index: Int? = null, - - @SerializedName("value") - val amount: Long? = null -) - -data class BlockchairTransactionResponse( - @SerializedName("data") - val data: Map? = null -) - -data class BlockchairTransactionData( - @SerializedName("transaction") - val transaction: BlockchairTransactionInfo? = null -) - -data class BlockchairTransactionInfo( - @SerializedName("block_id") - val block: Int? = null -) - -data class BlockchairStatsResponse( - @SerializedName("data") - val data: BlockchairStatsData? = null -) - -data class BlockchairStatsData( - @SerializedName("suggested_transaction_fee_per_byte_sat") - val feePerByte: Int? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/BlockchairSendBody.java b/app/src/main/java/com/tangem/data/network/model/BlockchairSendBody.java deleted file mode 100644 index 3e6458c090..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BlockchairSendBody.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.data.network.model; - -public class BlockchairSendBody { - private String data; - - public BlockchairSendBody(String data) { - this.data = data; - } -} diff --git a/app/src/main/java/com/tangem/data/network/model/BlockcypherBody.java b/app/src/main/java/com/tangem/data/network/model/BlockcypherBody.java deleted file mode 100644 index 065b899dcf..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BlockcypherBody.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.data.network.model; - -public class BlockcypherBody { - private String tx; - - public BlockcypherBody(String tx) { - this.tx = tx; - } -} diff --git a/app/src/main/java/com/tangem/data/network/model/BlockcypherResponse.kt b/app/src/main/java/com/tangem/data/network/model/BlockcypherResponse.kt deleted file mode 100644 index f3c2e951cd..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/BlockcypherResponse.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class BlockcypherResponse( - @SerializedName("address") - var address: String? = null, - - @SerializedName("balance") - var balance: Long? = null, - - @SerializedName("unconfirmed_balance") - var unconfirmed_balance: Long? = null, - - @SerializedName("txrefs") - var txrefs: List? = null, - - @SerializedName("unconfirmed_txrefs") - var unconfirmed_txrefs: List? = null, - - @SerializedName("hasMore") - var hasMore: Boolean? = null -) - -data class BlockcypherTxref( - @SerializedName("tx_hash") - var tx_hash: String? = null, - - @SerializedName("tx_input_n") - var tx_input_n: Int? = null, - - @SerializedName("tx_output_n") - var tx_output_n: Int? = null, - - @SerializedName("value") - var value: Long? = null, - - @SerializedName("confirmations") - var confirmations: Long? = null, - - @SerializedName("script") - var script: String? = null, - - @SerializedName("spent") - var spent: Boolean? = null -) - -data class BlockcypherTx( - @SerializedName("hex") - var hex: String? = null, - - @SerializedName("addresses") - var addesses: List? = null -) - -data class BlockcypherFee( - @SerializedName("low_fee_per_kb") - var low_fee_per_kb: Long? = null, - - @SerializedName("medium_fee_per_kb") - var medium_fee_per_kb: Long? = null, - - @SerializedName("high_fee_per_kb") - var high_fee_per_kb: Long? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/InfuraBody.java b/app/src/main/java/com/tangem/data/network/model/InfuraBody.java deleted file mode 100644 index 7f104e419e..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/InfuraBody.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.tangem.data.network.model; - -public class InfuraBody { - private String method; - private Object[] params; - private int id; - private String jsonrpc = "2.0"; - - public InfuraBody() { - } - - // body for eth gasPrice - public InfuraBody(String method, int id) { - this.method = method; - this.id = id; - } - - // body for eth getBalance, eth getTransactionCount, eth sendRawTransaction - public InfuraBody(String method, String[] params, int id) { - this.method = method; - this.params = params; - this.id = id; - } - - // body for eth call - public InfuraBody(String method, Object[] params, int id) { - this.method = method; - this.params = params; - this.id = id; - } - - public static class EthCallParams { - private String data; - private String to; - - public EthCallParams(String data, String to) { - this.data = data; - this.to = to; - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/InfuraResponse.kt b/app/src/main/java/com/tangem/data/network/model/InfuraResponse.kt deleted file mode 100644 index d565ef79c8..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/InfuraResponse.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class InfuraResponse( - @SerializedName("jsonrpc") - var jsonrpc: String = "", - - @SerializedName("id") - var id: Int? = null, - - @SerializedName("result") - var result: String? = null, - - @SerializedName("error") - var error: Object -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/InsightBody.java b/app/src/main/java/com/tangem/data/network/model/InsightBody.java deleted file mode 100644 index 4d8951adfa..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/InsightBody.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.data.network.model; - -public class InsightBody { - private String rawtx; - - public InsightBody(String rawtx){ - this.rawtx = rawtx; - } -} diff --git a/app/src/main/java/com/tangem/data/network/model/InsightResponse.kt b/app/src/main/java/com/tangem/data/network/model/InsightResponse.kt deleted file mode 100644 index a16c535649..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/InsightResponse.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class InsightResponse( - @SerializedName("balanceSat") - var balanceSat: Long? = null, - - @SerializedName("unconfirmedBalanceSat") - var unconfirmedBalanceSat: Long? = null, - - @SerializedName("addrStr") - var addrStr: String = "", - -// @SerializedName("2") -// var fee2: String = "", -// -// @SerializedName("3") -// var fee3: String = "", -// -// @SerializedName("6") -// var fee6: String = "", - - @SerializedName("error") - var error: String = "" -) - -data class InsightUtxo( - @SerializedName("txid") - var txid: String = "", - - @SerializedName("satoshis") - var satoshis: Long? = null, - - @SerializedName("vout") - var vout: Int? = null, - - @SerializedName("scriptPubKey") - var scriptPubKey: String? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/PayIdResponse.kt b/app/src/main/java/com/tangem/data/network/model/PayIdResponse.kt deleted file mode 100644 index dfdf6220b3..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/PayIdResponse.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class PayIdResponse( - @SerializedName("addresses") - var addresses: List? = null -) - -data class PayIdAddress( - @SerializedName("paymentNetwork") - var paymentNetwork: String? = null, - - @SerializedName("environment") - var environment: String? = null, - - @SerializedName("addressDetails") - var addressDetails: PayIdAddressDetails? = null -) - -data class PayIdAddressDetails( - @SerializedName("address") - var address: String? = null, - - @SerializedName("tag") - var tag: String? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/RateInfoResponse.kt b/app/src/main/java/com/tangem/data/network/model/RateInfoResponse.kt deleted file mode 100644 index 6fd76e8581..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/RateInfoResponse.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class RateInfoResponse( - @SerializedName("data") - var data: RateData? = null -) - -data class RateData( - @SerializedName("quote") - var quote: Quote? = null -) - -data class Quote( - @SerializedName("USD") - var usd: CurrencyRate? = null -) - -data class CurrencyRate( - @SerializedName("price") - var price: Float? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/RippleBody.java b/app/src/main/java/com/tangem/data/network/model/RippleBody.java deleted file mode 100644 index 0423f357a1..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/RippleBody.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.tangem.data.network.model; - -import java.util.ArrayList; -import java.util.HashMap; - -public class RippleBody { - private String method; - private ArrayList> params; - - public RippleBody() { - } - - //for RIPPLE_FEE - public RippleBody(String method) { - this.method = method; - } - - public RippleBody(String method, HashMap paramsMap) { - this.method = method; - ArrayList> paramsList = new ArrayList<>(); - paramsList.add(paramsMap); - this.params = paramsList; - } -} diff --git a/app/src/main/java/com/tangem/data/network/model/RippleResponse.kt b/app/src/main/java/com/tangem/data/network/model/RippleResponse.kt deleted file mode 100644 index 4a865aca67..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/RippleResponse.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class RippleResponse( - @SerializedName("result") - var result: RippleResult? = null -) - -data class RippleResult( - @SerializedName("account_data") - var account_data: RippleAccountData? = null, - - @SerializedName("validated") - var validated: Boolean? = null, - - //for RIPPLE_FEE - @SerializedName("drops") - var drops: RippleFeeDrops? = null, - - //for RIPPLE_SUBMIT - @SerializedName("engine_result_code") - var engine_result_code: Int? = null, - - //for RIPPLE_SUBMIT - @SerializedName ("engine_result_message") - var engine_result_message: String? = null, - - //for RIPPLE_SUBMIT - @SerializedName("error") - var error: String? = null, - - //for RIPPLE_SUBMIT - @SerializedName("error_exception") - var error_exception: String? = null, - - //for RIPPLE_SERVER_STATE - @SerializedName("state") - var state: RippleState? = null, - - //for "Account not found error" - @SerializedName("error_code") - var error_code: Int? = null -) - -data class RippleAccountData( - @SerializedName("Account") - var account: String? = null, - - @SerializedName("Balance") - var balance: String? = null, - - @SerializedName("Sequence") - var sequence: Long? = null -) - -data class RippleFeeDrops( - //enough to put tx to queue - @SerializedName("minimum_fee") - var minimum_fee: String? = null, - - //enough to put tx to current ledger - @SerializedName("open_ledger_fee") - var open_ledger_fee: String? = null, - - @SerializedName("median_fee") - var median_fee: String? = null -) - -data class RippleState( - @SerializedName("validated_ledger") - var validated_ledger: RippleLedger? = null -) - -data class RippleLedger( - @SerializedName("reserve_base") - var reserve_base: Long? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/SoChain.kt b/app/src/main/java/com/tangem/data/network/model/SoChain.kt deleted file mode 100644 index 65a7103689..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/SoChain.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.tangem.data.network.model - -class SoChain { - class Request { - class SendTx{ - var tx_hex: String? = null - } - } - - class Response { - class AddressBalance { - class Data { - var network: String? = null - var address: String? = null - var confirmed_balance: String? = null - var unconfirmed_balance: String? = null - var confirmations: String? = null - } - - var status: String? = null - var data: Data? = null - } - - class TxUnspent { - class Data { - class Tx { - var txid: String? = null //"9b5c8fbeb1e42bb2a6da40e2eab49c368d1a205707a1ec88aa13f0f2ecdfe944", - var output_no: Int? = null // 0, - var script_asm: String? = null // "OP_DUP OP_HASH160 8541eb0593bb19c3755198e7d2a71e134da21a97 OP_EQUALVERIFY OP_CHECKSIG", - var script_hex: String? = null // "76a9148541eb0593bb19c3755198e7d2a71e134da21a9788ac", - var value: String? = null // "11.38404832", - var confirmations: Long? = null - var time: Long? = null// : 1555509495 - } - - var network: String? = null - var address: String? = null - var txs: Array? = null - } - - var status: String? = null - var data: Data? = null - - } - - class SendTx { - class Data { - var network: String? = null - var txid: String? = null - var tx_hex: String? = null - } - var status: String? = null - var data: Data? = null - } - - class GetTx { - class Data { - // restricted data - var network: String? = null - var address: String? = null - var txid: String? = null - var tx_hex: String? = null - } - - var status: String? = null - var data: Data? = null - } - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/TezosBody.kt b/app/src/main/java/com/tangem/data/network/model/TezosBody.kt deleted file mode 100644 index 16bf34b145..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/TezosBody.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.data.network.model - -data class TezosForgeBody( - val branch: String, - val contents: List -) - -data class TezosOperationContent( - val kind: String, - val source: String, - val fee: String, - val counter: String, - val gas_limit: String, - val storage_limit: String, - val public_key: String? = null, - val destination: String? = null, - val amount: String? = null -) - -data class TezosPreapplyBody( - val protocol: String, - val branch: String, - val contents: List, - val signature: String -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/TezosResponse.kt b/app/src/main/java/com/tangem/data/network/model/TezosResponse.kt deleted file mode 100644 index db3bece398..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/TezosResponse.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class TezosAccountResponse( - @SerializedName("balance") - var balance: Long? = null, - - @SerializedName("counter") - var counter: Long? = null -) - -data class TezosHeaderResponse( - @SerializedName("protocol") - var protocol: String? = null, - - @SerializedName("hash") - var hash: String? = null -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/model/TokenEmvBody.kt b/app/src/main/java/com/tangem/data/network/model/TokenEmvBody.kt deleted file mode 100644 index ea89dd88d9..0000000000 --- a/app/src/main/java/com/tangem/data/network/model/TokenEmvBody.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.tangem.data.network.model - -import com.google.gson.annotations.SerializedName - -data class TokenEmvTransferBody( - val CID: String, - val publicKey: String, - val amount: String, - val currency: String, - val recipient: String, - @SerializedName("fee_limit") - val feeLimit: String, - val sequence: Int, - val signature: String -) - -data class TokenEmvTransferAnswer( - val error: String?, - val errorCode: Int?, - val success: Boolean?, - val tx_id: String?, - val blockchain_tx_id: String? -) - -data class TokenEmvGetTransferFeeBody( - val CID: String, - val publicKey: String -) - -data class TokenEmvGetTransferFeeAnswer( - val error: String?, - val errorCode: Int?, - val success: Boolean?, - val fee: String?, - val currency: String? -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/AppModule.kt b/app/src/main/java/com/tangem/di/AppModule.kt deleted file mode 100644 index 6fa481881b..0000000000 --- a/app/src/main/java/com/tangem/di/AppModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.di - -import android.app.Application -import android.content.Context -import dagger.Module -import javax.inject.Singleton -import dagger.Provides - -@Module -class AppModule { - - @Provides - @Singleton - fun provideContext(application: Application): Context { - return application - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/NavigatorModule.kt b/app/src/main/java/com/tangem/di/NavigatorModule.kt deleted file mode 100644 index b0bfb00afc..0000000000 --- a/app/src/main/java/com/tangem/di/NavigatorModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.di - -import com.tangem.ui.dialog.WaitSecurityDelayDialogNew -import dagger.Module -import dagger.Provides -import javax.inject.Singleton - -@Module -internal class NavigatorModule { - - @Singleton - @Provides - fun provideToastHelper(): ToastHelper { - return ToastHelper() - } - - @Singleton - @Provides - fun provideWaitSecurityDelayDialogNew(): WaitSecurityDelayDialogNew { - return WaitSecurityDelayDialogNew() - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/NetworkComponent.kt b/app/src/main/java/com/tangem/di/NetworkComponent.kt deleted file mode 100644 index 3d100a99e6..0000000000 --- a/app/src/main/java/com/tangem/di/NetworkComponent.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.tangem.di - -import com.tangem.data.network.Server -import dagger.Component -import retrofit2.Retrofit -import java.net.Socket -import javax.inject.Named -import javax.inject.Singleton - -@Singleton -@Component(modules = [NetworkModule::class]) -interface NetworkComponent { - - @get:Named(Server.ApiInfura.URL_INFURA) - val retrofitInfura: Retrofit - - @get:Named(Server.ApiInfuraTestnet.URL_INFURA_TESTNET) - val retrofitInfuraTestnet: Retrofit - - @get:Named(Server.ApiInfuraRopsten.URL_INFURA_ROPSTEN) - val retrofitInfuraRopsten: Retrofit - - @get:Named(Server.ApiMaticTesnet.URL_MATIC_TESTNET) - val retrofitMaticTesnet: Retrofit - - @get:Named(Server.ApiEstimatefee.URL_ESTIMATEFEE) - val retrofitEstimatefee: Retrofit - - @get:Named(Server.ApiCoinmarket.URL_COINMARKET) - val retrofitCoinmarketcap: Retrofit - - @get:Named(Server.ApiUpdateVersion.URL_UPDATE_VERSION) - val retrofitGitHubUserContent: Retrofit - - @get:Named(Server.ApiRootstock.URL_ROOTSTOCK) - val retrofitRootstock: Retrofit - - @get:Named(Server.ApiBlockcypher.URL_BLOCKCYPHER) - val retrofitBlockcypher: Retrofit - - @get:Named(Server.ApiSoChain.URL) - val retrofitSoChain: Retrofit - - @get:Named(Server.ApiBlockchainInfo.URL_BLOCKCHAININFO) - val retrofitBlockchainInfo: Retrofit - - @get:Named(Server.ApiDucatus.URL_DUCATUS) - val retrofitDucatus: Retrofit - - @get:Named(Server.ApiBlockchair.URL_BLOCKCHAIR) - val retrofitBlockchair: Retrofit - - @get:Named("socket") - val socket: Socket -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/NetworkModule.kt b/app/src/main/java/com/tangem/di/NetworkModule.kt deleted file mode 100644 index 339a0ca5d8..0000000000 --- a/app/src/main/java/com/tangem/di/NetworkModule.kt +++ /dev/null @@ -1,216 +0,0 @@ -package com.tangem.di - -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory -import com.tangem.data.network.Server -import com.tangem.wallet.BuildConfig -import dagger.Module -import dagger.Provides -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.converter.scalars.ScalarsConverterFactory -import java.io.IOException -import java.net.InetSocketAddress -import java.net.Socket -import java.net.SocketException -import javax.inject.Named -import javax.inject.Singleton - -@Module -internal class NetworkModule { - - @Singleton - @Provides - @Named(Server.ApiInfura.URL_INFURA) - fun provideRetrofitInfura(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiInfura.URL_INFURA) - .addConverterFactory(GsonConverterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiInfuraTestnet.URL_INFURA_TESTNET) - fun provideRetrofitInfuraTestnet(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiInfuraTestnet.URL_INFURA_TESTNET) - .addConverterFactory(GsonConverterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiInfuraRopsten.URL_INFURA_ROPSTEN) - fun provideRetrofitInfuraRopsten(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiInfuraRopsten.URL_INFURA_ROPSTEN) - .addConverterFactory(GsonConverterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiRootstock.URL_ROOTSTOCK) - fun provideRetrofitRootstock(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiRootstock.URL_ROOTSTOCK) - .addConverterFactory(GsonConverterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiMaticTesnet.URL_MATIC_TESTNET) - fun provideRetrofitMaticTestnet(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiMaticTesnet.URL_MATIC_TESTNET) - .addConverterFactory(GsonConverterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiEstimatefee.URL_ESTIMATEFEE) - fun provideRetrofitEstimatefee(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiEstimatefee.URL_ESTIMATEFEE) - .addConverterFactory(GsonConverterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiUpdateVersion.URL_UPDATE_VERSION) - fun provideGithubusercontent(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiUpdateVersion.URL_UPDATE_VERSION) - .addConverterFactory(GsonConverterFactory.create()) - .client(createOkHttpClient()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiCoinmarket.URL_COINMARKET) - fun provideRetrofitCoinmarketcap(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiCoinmarket.URL_COINMARKET) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) -// if (BuildConfig.DEBUG) -// builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiBlockcypher.URL_BLOCKCYPHER) - fun provideRetrofitBlockcypher(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiBlockcypher.URL_BLOCKCYPHER) - .addConverterFactory(GsonConverterFactory.create()) - .client(createOkHttpClient()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiSoChain.URL) - fun provideRetrofitSoChain(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiSoChain.URL) - .addConverterFactory(GsonConverterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiBlockchainInfo.URL_BLOCKCHAININFO) - fun provideRetrofitBlockchainInfo(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiBlockchainInfo.URL_BLOCKCHAININFO) - .addConverterFactory(GsonConverterFactory.create()) - .addConverterFactory(ScalarsConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiDucatus.URL_DUCATUS) - fun provideRetrofitDucatus(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiDucatus.URL_DUCATUS) - .addConverterFactory(GsonConverterFactory.create()) - .addConverterFactory(ScalarsConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - @Singleton - @Provides - @Named(Server.ApiBlockchair.URL_BLOCKCHAIR) - fun provideRetrofitBlockchair(): Retrofit { - val builder = Retrofit.Builder() - .baseUrl(Server.ApiBlockchair.URL_BLOCKCHAIR) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - if (BuildConfig.DEBUG) - builder.client(createOkHttpClient()) - return builder.build() - } - - private fun createOkHttpClient(): OkHttpClient { - return OkHttpClient.Builder().addInterceptor(createHttpLoggingInterceptor()).build() - } - - private fun createHttpLoggingInterceptor(): HttpLoggingInterceptor { - val logging = HttpLoggingInterceptor() - logging.level = HttpLoggingInterceptor.Level.BODY - return logging - } - - @Provides - @Named("socket") - fun provideSocket(): Socket { - val socket = Socket() - try { - socket.soTimeout = 2000 - try { - socket.bind(InetSocketAddress(0)) - } catch (e: IOException) { - e.printStackTrace() - } - - } catch (e: SocketException) { - e.printStackTrace() - } - - return socket - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/ToastHelper.kt b/app/src/main/java/com/tangem/di/ToastHelper.kt deleted file mode 100644 index e18d8f2734..0000000000 --- a/app/src/main/java/com/tangem/di/ToastHelper.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.tangem.di - -import android.content.ActivityNotFoundException -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.view.ViewGroup -import android.widget.Toast -import com.google.android.material.snackbar.Snackbar -import com.tangem.Constant -import com.tangem.wallet.R -import java.util.* - -class ToastHelper { - fun showSnackbarUpdateVersion(context: Context, vg: ViewGroup, versionName: String) { - Snackbar.make(vg, String.format(context.getString(R.string.main_screen_new_version_toast), versionName), Snackbar.LENGTH_INDEFINITE) - .setAction(R.string.main_screen_btn_update) { - try { - val intent = Intent(Intent.ACTION_VIEW) - intent.data = Uri.parse(Constant.URL_TANGEM) - context.startActivity(intent) - } catch (e: ActivityNotFoundException) { - e.printStackTrace() - } - }.show() - } - - fun showSnackbarSuccess(context: Context, vg: ViewGroup, message: String) { - val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_INDEFINITE) - val snackView = snackbar.view - snackView.setBackgroundColor(context.resources.getColor(R.color.msg_okay)) - snackbar.setAction(R.string.general_ok) { - snackbar.dismiss() - } - snackbar.show() - } - - fun showSnackbarError(context: Context, vg: ViewGroup, message: String) { - val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_INDEFINITE) - val snackView = snackbar.view - snackView.setBackgroundColor(context.resources.getColor(R.color.msg_err)) - snackbar.setAction(R.string.general_ok) { - snackbar.dismiss() - } - snackbar.show() - } - - fun showSnackbarWarning(context: Context, vg: ViewGroup, message: String) { - val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_LONG) - val snackView = snackbar.view - snackView.setBackgroundColor(context.resources.getColor(R.color.msg_err)) - snackbar.show() - } - - private var singleToast: Toast? = null - private var showTime: Date = Date() - - fun showSingleToast(context: Context?, text: String) { - if (singleToast == null || !singleToast!!.view.isShown || showTime.time + 2000 < Date().time) { - if (singleToast != null) - singleToast!!.cancel() - if (context != null) { - singleToast = Toast.makeText(context, text, Toast.LENGTH_LONG) - singleToast!!.show() - showTime = Date() - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/di/ToastHelperComponent.kt b/app/src/main/java/com/tangem/di/ToastHelperComponent.kt deleted file mode 100644 index b98d944333..0000000000 --- a/app/src/main/java/com/tangem/di/ToastHelperComponent.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.di - -import com.tangem.ui.activity.MainActivity -import dagger.Component -import javax.inject.Singleton - -@Singleton -@Component(modules = [NavigatorModule::class]) -interface ToastHelperComponent { - - fun inject(activity: MainActivity) - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt new file mode 100644 index 0000000000..d5c3a5b75d --- /dev/null +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -0,0 +1,70 @@ +package com.tangem.tap + +import android.content.pm.ActivityInfo +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.tangem.CardFilter +import com.tangem.Config +import com.tangem.TangemSdk +import com.tangem.common.extensions.CardType +import com.tangem.tangem_sdk_new.extensions.init +import com.tangem.tap.common.redux.NotificationsHandler +import com.tangem.tap.common.redux.navigation.AppScreen +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.domain.TangemSdkManager +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import java.lang.ref.WeakReference +import java.util.* +import kotlin.coroutines.CoroutineContext + +lateinit var tangemSdk: TangemSdk +lateinit var tangemSdkManager: TangemSdkManager +var notificationsHandler: NotificationsHandler? = null + +private val coroutineContext: CoroutineContext + get() = Job() + Dispatchers.IO + initCoroutineExceptionHandler() +val scope = CoroutineScope(coroutineContext) + + +private fun initCoroutineExceptionHandler(): CoroutineExceptionHandler { + return CoroutineExceptionHandler { _, throwable -> throw throwable } +} + +class MainActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + store.dispatch(NavigationAction.ActivityCreated(WeakReference(this))) + + tangemSdk = TangemSdk.init( + this, Config(cardFilter = CardFilter(EnumSet.allOf(CardType::class.java))) + ) + tangemSdkManager = TangemSdkManager(this) + } + + override fun onResume() { + super.onResume() + notificationsHandler = NotificationsHandler(fragment_container) + if (supportFragmentManager.backStackEntryCount == 0) { + store.dispatch( + NavigationAction.NavigateTo(AppScreen.Home) + ) + } + } + + override fun onStop() { + notificationsHandler = null + super.onStop() + } + + override fun onDestroy() { + store.dispatch(NavigationAction.ActivityDestroyed) + super.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt new file mode 100644 index 0000000000..4ab0e12db4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -0,0 +1,14 @@ +package com.tangem.tap + +import android.app.Application +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.common.redux.appReducer +import org.rekotlin.Store + +val store = Store( + reducer = ::appReducer, + middleware = AppState.getMiddleware(), + state = AppState() +) + +class TapApplication : Application() \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/entities/Button.kt b/app/src/main/java/com/tangem/tap/common/entities/Button.kt new file mode 100644 index 0000000000..14383c3c99 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/entities/Button.kt @@ -0,0 +1,3 @@ +package com.tangem.tap.common.entities + +abstract class Button(val enabled: Boolean) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt b/app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt new file mode 100644 index 0000000000..e8b3891ce9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt @@ -0,0 +1,15 @@ +package com.tangem.tap.common.extensions + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import java.io.ByteArrayOutputStream + +fun Bitmap.toByteArray(): ByteArray { + val stream = ByteArrayOutputStream() + this.compress(Bitmap.CompressFormat.JPEG, 20, stream) + return stream.toByteArray() +} + +fun ByteArray.toBitmap(): Bitmap { + return BitmapFactory.decodeByteArray(this, 0, this.size) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt new file mode 100644 index 0000000000..a1f13c87d4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -0,0 +1,38 @@ +package com.tangem.tap.common.extensions + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.FragmentManager +import com.tangem.tap.common.redux.navigation.AppScreen +import com.tangem.tap.features.home.HomeFragment +import com.tangem.tap.features.wallet.ui.WalletFragment +import com.tangem.wallet.R + +fun FragmentActivity.openFragment(screen: AppScreen, addToBackStack: Boolean = true) { + val transaction = this.supportFragmentManager.beginTransaction() + .replace( + R.id.fragment_container, + fragmentFactory(screen), + screen.name + ) + if (addToBackStack && screen != AppScreen.Home) transaction.addToBackStack(null) + transaction.commit(); +} + +fun FragmentActivity.popBackTo(screen: AppScreen?, inclusive: Boolean = false) { + val inclusiveFlag = if (inclusive) FragmentManager.POP_BACK_STACK_INCLUSIVE else 0 + this.supportFragmentManager.popBackStack(screen?.name, inclusiveFlag) +} + +fun FragmentActivity.getPreviousScreen(): AppScreen? { + val indexOfLastFragment = this.supportFragmentManager.backStackEntryCount - 1 + val tag = this.supportFragmentManager.getBackStackEntryAt(indexOfLastFragment).name + return tag?.let { AppScreen.valueOf(tag) } +} + +private fun fragmentFactory(screen: AppScreen): Fragment { + return when (screen) { + AppScreen.Home -> HomeFragment() + AppScreen.Wallet -> WalletFragment() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt new file mode 100644 index 0000000000..18434bb3d6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -0,0 +1,30 @@ +package com.tangem.tap.common.extensions + +import android.graphics.Bitmap +import android.graphics.Color +import com.google.zxing.BarcodeFormat +import com.google.zxing.EncodeHintType +import com.google.zxing.qrcode.QRCodeWriter +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel +import java.util.* + + +fun String.toQrCode(): Bitmap { + val hintMap = Hashtable() + hintMap[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M // H = 30% damage + hintMap[EncodeHintType.MARGIN] = 2 + + val qrCodeWriter = QRCodeWriter() + + val size = 256 + + val bitMatrix = qrCodeWriter.encode(this, BarcodeFormat.QR_CODE, size, size, hintMap) + val width = bitMatrix.width + val bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565) + for (x in 0 until width) { + for (y in 0 until width) { + bmp.setPixel(y, x, if (bitMatrix.get(x, y)) Color.BLACK else Color.WHITE) + } + } + return bmp +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt new file mode 100644 index 0000000000..8e68a1bd6f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt @@ -0,0 +1,127 @@ +package com.tangem.tap.common.extensions + +import android.app.Activity +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.content.Intent +import android.graphics.drawable.Drawable +import android.os.Build +import android.text.Spannable +import android.text.style.ForegroundColorSpan +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager +import androidx.annotation.DrawableRes +import androidx.core.content.ContextCompat +import androidx.core.text.toSpannable +import androidx.fragment.app.Fragment +import com.google.android.material.card.MaterialCardView + +fun Fragment.getDrawable(@DrawableRes drawableResId: Int): Drawable? { + return ContextCompat.getDrawable(requireContext(), drawableResId) +} + +fun View.show(show: Boolean) { + if (show) this.visibility = View.VISIBLE else this.visibility = View.GONE +} + +fun View.show() { + this.visibility = View.VISIBLE +} + +fun View.hide() { + this.visibility = View.GONE +} + +fun View.makeInvisible() { + this.visibility = View.INVISIBLE +} + +fun Context.dpToPixels(dp: Int): Int = + TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), this.resources.displayMetrics + ).toInt() + +fun MaterialCardView.setMargins( + marginLeftDp: Int = 16, + marginTopDp: Int = 8, + marginRightDp: Int = 16, + marginBottomDp: Int = 8 +) { + val params = this.layoutParams + (params as ViewGroup.MarginLayoutParams).setMargins( + context.dpToPixels(marginLeftDp), + context.dpToPixels(marginTopDp), + context.dpToPixels(marginRightDp), + context.dpToPixels(marginBottomDp) + ) + this.layoutParams = params +} + +fun Activity.setSystemBarTextColor(setTextDark: Boolean) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val flags = this.window.decorView.systemUiVisibility + // Update the SystemUiVisibility dependening on whether we want a Light or Dark theme. + this.window.decorView.systemUiVisibility = + if (setTextDark) { + flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() + } else { + flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } + } +} + + + +fun String.colorSegment( + context: Context, + color: Int, + startIndex: Int = 0, + endIndex: Int = this.length +): Spannable { + return this.toSpannable() + .also { spannable -> + spannable.setSpan( + ForegroundColorSpan(ContextCompat.getColor(context, color)), + startIndex, + endIndex, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } +} + +fun View.hideKeyboard() { + val inputMethodManager = context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? InputMethodManager + inputMethodManager?.hideSoftInputFromWindow(this.windowToken, 0) +} + +fun Context.copyToClipboard(value: Any, label: String = "") { + val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager ?: return + + val clip: ClipData = ClipData.newPlainText(label, value.toString()) + clipboard.setPrimaryClip(clip) +} + +fun Context.shareText(text: String) { + val sendIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, text) + type = "text/plain" + } + val shareIntent = Intent.createChooser(sendIntent, null) + startActivity(shareIntent) +} + +fun Fragment.shareText(text: String) { + requireContext().shareText(text) +} + +fun ViewGroup.inflate(viewToInflate: Int, rootView: ViewGroup?, parent: ViewGroup) { + if (rootView == null) { + val inflatedView = LayoutInflater.from(context).inflate(viewToInflate, rootView) + parent.addView(inflatedView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt new file mode 100644 index 0000000000..57539883be --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -0,0 +1,19 @@ +package com.tangem.tap.common.redux + +import com.tangem.tap.common.redux.navigation.navigationReducer +import com.tangem.tap.features.wallet.redux.walletReducer +import org.rekotlin.Action + +fun appReducer(action: Action, state: AppState?): AppState { + requireNotNull(state) + if (action is AppAction.RestoreState) return action.state + return AppState( + navigationState = navigationReducer(action, state), +// homeState = homeReducer(action, state), + walletState = walletReducer(action, state), + ) +} + +sealed class AppAction : Action { + data class RestoreState(val state: AppState) : AppAction() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt new file mode 100644 index 0000000000..397b2dad27 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -0,0 +1,25 @@ +package com.tangem.tap.common.redux + +import com.tangem.tap.common.redux.navigation.NavigationState +import com.tangem.tap.common.redux.navigation.navigationMiddleware +import com.tangem.tap.features.home.redux.homeMiddleware +import com.tangem.tap.features.wallet.redux.WalletState +import com.tangem.tap.features.wallet.redux.walletMiddleware +import org.rekotlin.Middleware +import org.rekotlin.StateType + +data class AppState( + val navigationState: NavigationState = NavigationState(), + val walletState: WalletState = WalletState() +) : StateType { + + companion object { + fun getMiddleware(): List> { + return listOf( + navigationMiddleware, notificationsMiddleware, + homeMiddleware, walletMiddleware, + ) + } + } +} + diff --git a/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt new file mode 100644 index 0000000000..60f216a815 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt @@ -0,0 +1,48 @@ +package com.tangem.tap.common.redux + +import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.google.android.material.snackbar.Snackbar +import com.tangem.TangemError +import com.tangem.tap.notificationsHandler +import org.rekotlin.Action +import org.rekotlin.Middleware +import java.lang.ref.WeakReference + +class NotificationsHandler(coordinatorLayout: CoordinatorLayout) { + private val coordinatorLayoutWeak = WeakReference(coordinatorLayout) + + fun showNotification(message: String) { + coordinatorLayoutWeak.get()?.let { layout -> + Snackbar.make(layout, message, Snackbar.LENGTH_LONG) + .also { snackbar -> snackbar.show() } + } + } + + fun showNotification(message: Int) { + coordinatorLayoutWeak.get()?.let { + showNotification(it.context.getString(message)) + } + } +} + +val notificationsMiddleware: Middleware = { dispatch, state -> + { next -> + { action -> + if (action is NotificationAction) { + notificationsHandler?.showNotification(action.messageResource) + } + if (action is ErrorAction) { + notificationsHandler?.showNotification(action.error.customMessage) + } + next(action) + } + } +} + +interface NotificationAction : Action { + val messageResource: Int +} + +interface ErrorAction : Action { + val error: TangemError +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/Request.kt b/app/src/main/java/com/tangem/tap/common/redux/Request.kt new file mode 100644 index 0000000000..4faae37c93 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/Request.kt @@ -0,0 +1,7 @@ +package com.tangem.tap.common.redux + +import org.rekotlin.Action + +abstract class Request : Action { + abstract suspend fun execute() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt new file mode 100644 index 0000000000..5cbdb915f6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt @@ -0,0 +1,15 @@ +package com.tangem.tap.common.redux.navigation + +import androidx.fragment.app.FragmentActivity +import org.rekotlin.Action +import java.lang.ref.WeakReference + +sealed class NavigationAction : Action { + data class NavigateTo(val screen: AppScreen, val addToBackstack: Boolean = true) : + NavigationAction() + + data class PopBackTo(val screen: AppScreen? = null) : NavigationAction() + + data class ActivityCreated(val activity: WeakReference) : NavigationAction() + object ActivityDestroyed : NavigationAction() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt new file mode 100644 index 0000000000..8c4d5e9fea --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt @@ -0,0 +1,30 @@ +package com.tangem.tap.common.redux.navigation + +import com.tangem.tap.common.extensions.openFragment +import com.tangem.tap.common.extensions.popBackTo +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.store +import org.rekotlin.Middleware + +val navigationMiddleware: Middleware = { dispatch, state -> + { next -> + { action -> + if (action is NavigationAction) { + val navState = store.state.navigationState + when (action) { + is NavigationAction.NavigateTo -> { + navState.activity?.get()?.openFragment(action.screen, action.addToBackstack) + } + is NavigationAction.PopBackTo -> { + if (action.screen == AppScreen.Home) { + navState.activity?.get()?.popBackTo(null, true) + } else { + navState.activity?.get()?.popBackTo(action.screen) + } + } + } + } + next(action) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt new file mode 100644 index 0000000000..ae05c06a6e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt @@ -0,0 +1,25 @@ +package com.tangem.tap.common.redux.navigation + +import com.tangem.tap.common.extensions.getPreviousScreen +import com.tangem.tap.common.redux.AppState +import org.rekotlin.Action + +fun navigationReducer(action: Action, state: AppState): NavigationState { + + val navigationAction = action as? NavigationAction ?: return state.navigationState + val navState = state.navigationState + + return when (navigationAction) { + is NavigationAction.NavigateTo -> { + navState.copy(backStack = navState.backStack + navigationAction.screen) + } + is NavigationAction.PopBackTo -> { + val screen = + navigationAction.screen ?: navState.activity?.get()?.getPreviousScreen() + val index = navState.backStack.lastIndexOf(screen) + 1 + state.navigationState.copy(backStack = navState.backStack.subList(0, index)) + } + is NavigationAction.ActivityCreated -> navState.copy(activity = navigationAction.activity) + is NavigationAction.ActivityDestroyed -> navState.copy(activity = null) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt new file mode 100644 index 0000000000..72463f9da8 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.common.redux.navigation + +import androidx.fragment.app.FragmentActivity +import org.rekotlin.StateType +import java.lang.ref.WeakReference + +data class NavigationState( + val backStack: List = listOf(AppScreen.Home), + val activity: WeakReference? = null +) : StateType + +enum class AppScreen { Home, Wallet } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/BlockchainManager.kt b/app/src/main/java/com/tangem/tap/domain/BlockchainManager.kt new file mode 100644 index 0000000000..845635dbe2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/BlockchainManager.kt @@ -0,0 +1,7 @@ +package com.tangem.tap.domain + +class BlockchainManager { + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt new file mode 100644 index 0000000000..370261ce46 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -0,0 +1,41 @@ +package com.tangem.tap.domain + +import androidx.activity.ComponentActivity +import com.tangem.* +import com.tangem.commands.CommandResponse +import com.tangem.common.CompletionResult +import com.tangem.common.extensions.CardType +import com.tangem.tangem_sdk_new.extensions.init +import com.tangem.tap.domain.tasks.ScanNoteResponse +import com.tangem.tap.domain.tasks.ScanNoteTask +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.util.* +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +class TangemSdkManager(val activity: ComponentActivity) { + private val tangemSdk = TangemSdk.init( + activity, Config(cardFilter = CardFilter(EnumSet.allOf(CardType::class.java))) + ) + + suspend fun scanNote(): CompletionResult { + return runTaskAsyncReturnOnMain(ScanNoteTask()) + } + + private suspend fun runTaskAsync( + runnable: CardSessionRunnable, cardId: String? = null, initialMessage: Message? = null + ): CompletionResult = + suspendCoroutine { continuation -> + tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage) { result -> + continuation.resume(result) + } + } + + private suspend fun runTaskAsyncReturnOnMain( + runnable: CardSessionRunnable, cardId: String? = null, initialMessage: Message? = null + ): CompletionResult { + val result = runTaskAsync(runnable, cardId, initialMessage) + return withContext(Dispatchers.Main) { result } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt new file mode 100644 index 0000000000..797fb2ccd6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/tasks/ScanNoteTask.kt @@ -0,0 +1,24 @@ +package com.tangem.tap.domain.tasks + +import com.tangem.CardSession +import com.tangem.CardSessionRunnable +import com.tangem.TangemSdkError +import com.tangem.blockchain.common.WalletManager +import com.tangem.blockchain.common.WalletManagerFactory +import com.tangem.commands.CommandResponse +import com.tangem.common.CompletionResult + +data class ScanNoteResponse(val walletManager: WalletManager) : CommandResponse + +class ScanNoteTask : CardSessionRunnable { + override val requiresPin2 = false + + override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { + val walletManager = session.environment.card?.let { WalletManagerFactory.makeWalletManager(it) } + if (walletManager == null) { + callback(CompletionResult.Failure(TangemSdkError.CardError())) + return + } + callback(CompletionResult.Success(ScanNoteResponse(walletManager))) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt new file mode 100644 index 0000000000..dd556e3e40 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -0,0 +1,21 @@ +package com.tangem.tap.features.home + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import com.tangem.tap.features.home.redux.HomeAction +import com.tangem.tap.store +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.fragment_home.* + +class HomeFragment : Fragment(R.layout.fragment_home) { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + btn_yes?.setOnClickListener { store.dispatch(HomeAction.ReadCard) } + btn_shop?.setOnClickListener { store.dispatch(HomeAction.GoToShop(requireContext())) } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt new file mode 100644 index 0000000000..ab54ccf665 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt @@ -0,0 +1,9 @@ +package com.tangem.tap.features.home.redux + +import android.content.Context +import org.rekotlin.Action + +sealed class HomeAction : Action { + object ReadCard : HomeAction() + data class GoToShop(val context: Context) : HomeAction() +} diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt new file mode 100644 index 0000000000..4fc79cdca4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -0,0 +1,43 @@ +package com.tangem.tap.features.home.redux + +import android.content.Intent +import android.net.Uri +import androidx.core.content.ContextCompat.startActivity +import com.tangem.common.CompletionResult +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.common.redux.navigation.AppScreen +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager +import kotlinx.coroutines.launch +import org.rekotlin.Middleware + +val homeMiddleware: Middleware = { dispatch, state -> + { next -> + { action -> + when (action) { + is HomeAction.ReadCard -> { + scope.launch { + val result = tangemSdkManager.scanNote() + when (result) { + is CompletionResult.Success -> { + store.dispatch(WalletAction.LoadWallet(result.data.walletManager)) + store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) + } + } + } + } + is HomeAction.GoToShop -> { + val uri = Uri.parse(CARD_SHOP_URI) + val intent = Intent(Intent.ACTION_VIEW, uri) + startActivity(action.context, intent, null) + } + } + next(action) + } + } +} + +private const val CARD_SHOP_URI = "https://shop.tangem.com/?afmc=1i&utm_campaign=1i&utm_source=leaddyno&utm_medium=affiliate" diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt new file mode 100644 index 0000000000..e6b811ce27 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -0,0 +1,34 @@ +package com.tangem.tap.features.wallet.redux + +import android.content.Context +import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.WalletManager +import com.tangem.tap.common.redux.NotificationAction +import com.tangem.wallet.R +import org.rekotlin.Action + +sealed class WalletAction : Action { + data class LoadWallet(val walletManager: WalletManager) : WalletAction() { + data class Success(val wallet: Wallet): WalletAction() + object Failure: WalletAction() + } + data class LoadPayId(val address: String) : WalletAction() { + object Success: WalletAction() + object Failure: WalletAction() + } + object Scan : WalletAction() + object Send : WalletAction() + object CreatePayId : WalletAction() { + object Success: WalletAction() + object Failure: WalletAction() + } + data class CopyAddress(val context: Context) : WalletAction() { + object Success : WalletAction(), NotificationAction { + override val messageResource = R.string.notification_address_copied + } + } + object ShowQrCode : WalletAction() + object HideQrCode : WalletAction() + data class ExploreAddress(val context: Context) : WalletAction() + object CreateWallet : WalletAction() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt new file mode 100644 index 0000000000..6aae47add8 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt @@ -0,0 +1,64 @@ +package com.tangem.tap.features.wallet.redux + +import android.content.Intent +import android.net.Uri +import androidx.core.content.ContextCompat +import com.tangem.common.CompletionResult +import com.tangem.tap.common.extensions.copyToClipboard +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.rekotlin.Middleware + + +val walletMiddleware: Middleware = { dispatch, state -> + { next -> + { action -> + when (action) { + is WalletAction.LoadWallet -> { + scope.launch { + try { + action.walletManager.update() + } catch (ex: Exception) { + store.dispatch(WalletAction.LoadWallet.Failure) +// callback(CompletionResult.Failure(BlockchainInternalErrorConverter.convert(ex))) + return@launch + } + withContext(Dispatchers.Main) { + store.dispatch(WalletAction.LoadWallet.Success(action.walletManager.wallet)) + } + } + } + is WalletAction.Scan -> { + scope.launch { + val result = tangemSdkManager.scanNote() + when (result) { + is CompletionResult.Success -> { + withContext(Dispatchers.Main) { + store.dispatch(WalletAction.LoadWallet(result.data.walletManager)) + } + } + } + } + } + is WalletAction.CopyAddress -> { + store.state.walletState.wallet?.address?.let { + action.context.copyToClipboard(it) + store.dispatch(WalletAction.CopyAddress.Success) + } + } + is WalletAction.ExploreAddress -> { + val uri = Uri.parse(store.state.walletState.wallet?.exploreUrl) + val intent = Intent(Intent.ACTION_VIEW, uri) + ContextCompat.startActivity(action.context, intent, null) + } + + } + next(action) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt new file mode 100644 index 0000000000..ad6fe3db94 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt @@ -0,0 +1,53 @@ +package com.tangem.tap.features.wallet.redux + +import com.tangem.blockchain.common.AmountType +import com.tangem.tap.common.extensions.toQrCode +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.features.wallet.ui.BalanceStatus +import com.tangem.tap.features.wallet.ui.BalanceWidgetData +import com.tangem.tap.features.wallet.ui.TokenData +import org.rekotlin.Action + +fun walletReducer(action: Action, state: AppState): WalletState { + + if (action !is WalletAction) return state.walletState + + var newState = state.walletState + + when (action) { + is WalletAction.LoadWallet -> newState = WalletState( + state = ProgressState.Loading, walletManager = action.walletManager, + currencyData = BalanceWidgetData( + BalanceStatus.Loading, action.walletManager.wallet.blockchain.fullName + ) + ) + is WalletAction.LoadWallet.Success -> { + val token = action.wallet.amounts[AmountType.Token] + val tokenData = if (token != null) { + TokenData(token.value.toString(), token.currencySymbol) + } else { + null + } + newState = newState.copy( + state = ProgressState.Done, wallet = action.wallet, + currencyData = BalanceWidgetData( + BalanceStatus.VerifiedOnline, action.wallet.blockchain.fullName, + action.wallet.amounts[AmountType.Coin]?.value?.toString(), + token = tokenData + ) + ) + } + is WalletAction.LoadWallet.Failure -> newState = newState.copy( + state = ProgressState.Done, + currencyData = newState.currencyData.copy(status = BalanceStatus.Unreachable) + ) + is WalletAction.ShowQrCode -> { + newState = newState.copy(qrCode = newState.wallet?.shareUrl?.toQrCode()) + } + is WalletAction.HideQrCode -> { + newState = newState.copy(qrCode = null) + } + + } + return newState +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt new file mode 100644 index 0000000000..3ecc29fa9e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -0,0 +1,21 @@ +package com.tangem.tap.features.wallet.redux + +import android.graphics.Bitmap +import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.WalletManager +import com.tangem.tap.features.wallet.ui.BalanceWidgetData +import com.tangem.tap.features.wallet.ui.PayIdData +import org.rekotlin.StateType + +data class WalletState( + val state: ProgressState = ProgressState.Done, + val cardImage: Bitmap? = null, + val walletManager: WalletManager? = null, + val wallet: Wallet? = null, + val currencyData: BalanceWidgetData = BalanceWidgetData(), + val payIdData: PayIdData = PayIdData(), + val qrCode: Bitmap? = null +) : StateType + + +enum class ProgressState { Loading, Done, Error } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt new file mode 100644 index 0000000000..a0733186cb --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt @@ -0,0 +1,99 @@ +package com.tangem.tap.features.wallet.ui + +import androidx.annotation.IdRes +import androidx.fragment.app.Fragment +import com.tangem.tap.common.extensions.hide +import com.tangem.tap.common.extensions.show +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.layout_balance.* +import kotlinx.android.synthetic.main.layout_token.view.* + +enum class PayIdState { + Loading, + NotCreated, + Loaded, + Error +} + +data class PayIdData( + val address: String? = null, + val state: PayIdState? = null +) + +enum class BalanceStatus { + VerifiedOnline, + Unreachable, + Loading +} + +data class BalanceWidgetData( + val status: BalanceStatus? = null, + val currency: String? = null, + val amount: String? = null, + val fiatAmount: String? = null, + val token: TokenData? = null +) + +data class TokenData( + val amount: String, + val tokenSymbol: String +) + + +class BalanceWidget( + val fragment: Fragment, + val data: BalanceWidgetData, +) { + + fun setup() { + + when (data.status) { + BalanceStatus.Loading -> { + fragment.tv_currency.text = data.currency + fragment.tv_amount.text = "-" + fragment.tv_fiat_amount.hide() + showStatus(R.id.tv_status_loading) + fragment.l_token.hide() + } + BalanceStatus.VerifiedOnline -> { + fragment.tv_currency.text = data.currency + fragment.tv_amount.text = data.amount + fragment.tv_fiat_amount.text = data.fiatAmount + showStatus(R.id.tv_status_verified) + + if (data.token != null) { + fragment.l_token.show() + fragment.l_token.tv_token_symbol.text = data.token.tokenSymbol + fragment.l_token.tv_token_amount.text = data.token.amount + } else { + fragment.l_token.hide() + + } + + } + BalanceStatus.Unreachable -> { + fragment.l_token.hide() + showStatus(R.id.tv_status_error) + + + } + } + } + + private fun showStatus(@IdRes viewRes: Int) { + fragment.tv_status_error.show(viewRes == R.id.tv_status_error) + fragment.tv_status_loading.show(viewRes == R.id.tv_status_loading) + fragment.tv_status_verified.show(viewRes == R.id.tv_status_verified) + } +} + + +enum class BalanceErrorWidgetState { + NoAccount, + NoWallet, + BlockchainError +} + +class BalanceErrorWidget( + +) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/QrDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/QrDialog.kt new file mode 100644 index 0000000000..e3073fcdcf --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/QrDialog.kt @@ -0,0 +1,26 @@ +package com.tangem.tap.features.wallet.ui + +import android.app.Dialog +import android.content.Context +import android.graphics.Bitmap +import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.store +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.dialog_qrcode.* + +class QrDialog(context: Context) : Dialog(context) { + + init { + this.setContentView(R.layout.dialog_qrcode) + } + + fun show(qrCode: Bitmap, shareUrl: String) { + this.setOnDismissListener { store.dispatch(WalletAction.HideQrCode) } + this.btn_done?.setOnClickListener { store.dispatch(WalletAction.HideQrCode) } + + this.tv_qr_dialog_address?.text = shareUrl + this.iv_qrcode?.setImageBitmap(qrCode) + super.show() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt new file mode 100644 index 0000000000..bd2baa29e2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -0,0 +1,113 @@ +package com.tangem.tap.features.wallet.ui + +import android.os.Bundle +import android.view.View +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.Fragment +import com.tangem.tap.common.extensions.hide +import com.tangem.tap.common.extensions.show +import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.features.wallet.redux.WalletState +import com.tangem.tap.store +import com.tangem.wallet.R +import kotlinx.android.synthetic.main.card_balance.* +import kotlinx.android.synthetic.main.fragment_wallet.* +import kotlinx.android.synthetic.main.layout_address.* +import org.rekotlin.StoreSubscriber + +class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber { + + var dialog: QrDialog? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + store.dispatch(NavigationAction.PopBackTo()) + } + }) + } + + override fun onStart() { + super.onStart() + store.subscribe(this) { state -> + state.skipRepeats { oldState, newState -> + oldState.walletState == newState.walletState + }.select { it.walletState } + } + } + + override fun onStop() { + super.onStop() + store.unsubscribe(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + + toolbar.setNavigationOnClickListener { + store.dispatch(NavigationAction.PopBackTo()) + } + + btn_scan.setOnClickListener { + store.dispatch(WalletAction.Scan) + } + } + + override fun newState(state: WalletState) { + if (activity == null) return + + state.wallet?.address?.let { tv_address.text = it } + tv_explore?.setOnClickListener { + store.dispatch(WalletAction.ExploreAddress(requireContext())) + } + + btn_copy.setOnClickListener { store.dispatch(WalletAction.CopyAddress(requireContext())) } + btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowQrCode) } + + if (state.qrCode != null && state.wallet?.shareUrl != null) { + dialog = QrDialog(requireContext()) + dialog?.show(state.qrCode, state.wallet.shareUrl) + } else { + dialog?.dismiss() + } + + when (state.state) { + ProgressState.Loading -> { + l_balance.show() + BalanceWidget(this, state.currencyData).setup() + } + ProgressState.Done -> { + l_balance.show() + BalanceWidget(this, state.currencyData).setup() + } + ProgressState.Error -> { + + } + } + + when (state.payIdData.state) { + PayIdState.Loading -> { + group_payid.hide() + } + PayIdState.NotCreated -> { + group_payid.show() + tv_create_payid.show() + tv_payid_address.hide() + } + PayIdState.Loaded -> { + group_payid.show() + tv_create_payid.hide() + tv_payid_address.show() + tv_payid_address.text = state.payIdData.address + } + PayIdState.Error -> group_payid.hide() + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/activity/GlobalViewModel.kt b/app/src/main/java/com/tangem/ui/activity/GlobalViewModel.kt deleted file mode 100644 index 639a9ac7d4..0000000000 --- a/app/src/main/java/com/tangem/ui/activity/GlobalViewModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.ui.activity - -import androidx.lifecycle.ViewModel -import com.tangem.ui.navigation.NavigationResult - -class GlobalViewModel : ViewModel() { - var navigationResult: NavigationResult? = null -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/activity/MainActivity.kt b/app/src/main/java/com/tangem/ui/activity/MainActivity.kt deleted file mode 100644 index 8c6f685715..0000000000 --- a/app/src/main/java/com/tangem/ui/activity/MainActivity.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.tangem.ui.activity - -import android.content.Context -import android.content.Intent -import android.content.pm.ActivityInfo -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Bundle -import android.util.Log -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProviders -import androidx.navigation.findNavController -import com.scottyab.rootbeer.RootBeer -import com.tangem.App -import com.tangem.di.ToastHelper -import com.tangem.tangem_sdk.android.nfc.NfcLifecycleObserver -import com.tangem.tangem_sdk.android.reader.NfcManager -import com.tangem.ui.dialog.RootFoundDialog -import com.tangem.ui.fragment.MainFragment -import com.tangem.wallet.BuildConfig -import com.tangem.wallet.R -import javax.inject.Inject - -class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback { - - companion object { - val TAG: String = MainActivity::class.java.simpleName - fun callingIntent(context: Context) = Intent(context, MainActivity::class.java) - } - - @Inject - internal lateinit var toastHelper: ToastHelper - lateinit var viewModel: GlobalViewModel - lateinit var nfcManager: NfcManager - - override fun onNewIntent(intent: Intent?) { - super.onNewIntent(intent) - if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action || NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action)) { - val tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) - if (tag != null) { - navigateSafelyToMainFragment() - onTagDiscovered(tag) - } - } - } - - private fun navigateSafelyToMainFragment() { - if (getActiveFragment() is MainFragment) return - - try { - findNavController(R.id.nav_host_fragment).popBackStack() - } catch (e: IllegalArgumentException) { - Log.w(this::class.java.simpleName, e.message) - } catch (e: IllegalStateException) { - Log.w(this::class.java.simpleName, e.message) - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - - viewModel = ViewModelProviders.of(this).get(GlobalViewModel::class.java) - - App.toastHelperComponent.inject(this) - - requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT - - nfcManager = NfcManager(this, this) - lifecycle.addObserver(NfcLifecycleObserver(nfcManager)) - - // check if root device - val rootBeer = RootBeer(this) - if (rootBeer.isRootedWithoutBusyBoxCheck && !BuildConfig.DEBUG) - RootFoundDialog().show(supportFragmentManager, RootFoundDialog.TAG) - } - - override fun onTagDiscovered(tag: Tag) { - val activeFragment = getActiveFragment() - if (activeFragment is NfcAdapter.ReaderCallback) { - activeFragment.onTagDiscovered(tag) - } else { - nfcManager.ignoreTag(tag) - } - } - - private fun getActiveFragment(): Fragment? { - return supportFragmentManager.findFragmentById(R.id.nav_host_fragment) - ?.childFragmentManager?.primaryNavigationFragment - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/dialog/NoExtendedLengthSupportDialog.kt b/app/src/main/java/com/tangem/ui/dialog/NoExtendedLengthSupportDialog.kt deleted file mode 100644 index eb3f1c8357..0000000000 --- a/app/src/main/java/com/tangem/ui/dialog/NoExtendedLengthSupportDialog.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.ui.dialog - -import android.app.AlertDialog -import android.app.Dialog -import android.os.Bundle -import androidx.fragment.app.DialogFragment - -import com.tangem.wallet.R - -class NoExtendedLengthSupportDialog : DialogFragment() { - - companion object { - val TAG: String = NoExtendedLengthSupportDialog::class.java.simpleName - var allReadyShowed = false - var message = ""// = R.string.the_nfc_adapter_length_apdu - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - return AlertDialog.Builder(activity) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle(R.string.dialog_warning) - .setMessage(message) - .setPositiveButton(R.string.dialog_btn_got_it) { _, _ -> NoExtendedLengthSupportDialog.allReadyShowed = false } - .create() - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/dialog/PINSwapWarningDialog.java b/app/src/main/java/com/tangem/ui/dialog/PINSwapWarningDialog.java deleted file mode 100644 index 1a28371634..0000000000 --- a/app/src/main/java/com/tangem/ui/dialog/PINSwapWarningDialog.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.tangem.ui.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; - -import com.tangem.Constant; -import com.tangem.wallet.R; - -public class PINSwapWarningDialog extends DialogFragment { - public static final String TAG = PINSwapWarningDialog.class.getSimpleName(); - - private String message = ""; - private OnPositiveButton mOnPositiveButton; - - public interface OnPositiveButton { - void onRefresh(); - } - - public void setOnRefreshPage(OnPositiveButton listener) { - mOnPositiveButton = listener; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - message = getArguments().getString(Constant.EXTRA_MESSAGE); - } - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle(R.string.dialog_title_money_is_at_risk) - .setMessage(message) - .setCancelable(true) - .setNegativeButton(R.string.general_cancel, (dialog, which) -> dismiss()) - .setPositiveButton(R.string.general_continue, (dialog, whichButton) -> mOnPositiveButton.onRefresh()) - .create(); - } - - @Override - public void onCancel(@NonNull DialogInterface dialog) { - super.onCancel(dialog); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/dialog/RootFoundDialog.kt b/app/src/main/java/com/tangem/ui/dialog/RootFoundDialog.kt deleted file mode 100644 index d8650844e3..0000000000 --- a/app/src/main/java/com/tangem/ui/dialog/RootFoundDialog.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.ui.dialog - -import android.app.AlertDialog -import android.app.Dialog -import android.os.Bundle -import androidx.fragment.app.DialogFragment - -import com.tangem.wallet.R - -class RootFoundDialog : DialogFragment() { - - companion object { - val TAG: String = RootFoundDialog::class.java.simpleName - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - return AlertDialog.Builder(activity) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle(R.string.dialog_device_is_rooted) - .setCancelable(false) - .setPositiveButton(R.string.dialog_btn_got_it, null) - .create() - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/dialog/ShowQRCodeDialog.java b/app/src/main/java/com/tangem/ui/dialog/ShowQRCodeDialog.java deleted file mode 100644 index 06e8627054..0000000000 --- a/app/src/main/java/com/tangem/ui/dialog/ShowQRCodeDialog.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.tangem.ui.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.DialogFragment; - -import com.tangem.util.UtilHelper; -import com.tangem.wallet.R; - -/** - * Created by dvol on 06.03.2018. - */ -public class ShowQRCodeDialog extends DialogFragment { - public static final String TAG = ShowQRCodeDialog.class.getSimpleName(); - - private ImageView ivQR; - private TextView tvQRaddress; - private Bitmap bmQR; - private String addr; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - LayoutInflater inflater = getActivity().getLayoutInflater(); - - // Inflate and set the layout for the dialog - // Pass null as the parent view because its going in the dialog layout - View v = inflater.inflate(R.layout.dialog_show_qr, null); - ivQR = v.findViewById(R.id.ivQR); - ivQR.setImageBitmap(bmQR); - tvQRaddress = v.findViewById(R.id.tvQRaddress); - tvQRaddress.setText(addr); - - return new AlertDialog.Builder(getActivity()) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle(R.string.loaded_wallet_dialog_show_qr) - .setView(v) - .setPositiveButton(R.string.general_ok, (dialog, which)->dismiss() ) - .create(); - } - - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - } - - public void setup(String content) { - try { - bmQR = UtilHelper.INSTANCE.generateQrCode(content); - addr = content; - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static void show(final AppCompatActivity activity, final String content) { - activity.runOnUiThread(() -> { - ShowQRCodeDialog instance = new ShowQRCodeDialog(); - instance.setup(content); - instance.show(activity.getSupportFragmentManager(), TAG); - }); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialog.java b/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialog.java deleted file mode 100644 index 6e428897c4..0000000000 --- a/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialog.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.tangem.ui.dialog; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.ProgressBar; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.FragmentActivity; - -import com.tangem.tangem_card.util.Log; -import com.tangem.wallet.R; - -import java.util.Timer; -import java.util.TimerTask; - -/** - * Created by dvol on 06.03.2018. - */ -public class WaitSecurityDelayDialog extends DialogFragment { - public static final String TAG = WaitSecurityDelayDialog.class.getSimpleName(); - - private ProgressBar progressBar; - private int msTimeout = 60000, msProgress = 0; - private Timer timer; - - private static Timer timerToShowDelayDialog = null; - private static WaitSecurityDelayDialog instance = null; - - private final static int minRemainingDelayToShowDialog = 1000; - private final static int delayBeforeShowDialog = 5000; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - LayoutInflater inflater = getActivity().getLayoutInflater(); - - View v = inflater.inflate(R.layout.dialog_wait_pin2, null); - - progressBar = v.findViewById(R.id.progressBar); - progressBar.setMax(msTimeout); - progressBar.setProgress(msProgress); - - timer = new Timer(); - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - progressBar.post(() -> { - int progress = WaitSecurityDelayDialog.this.progressBar.getProgress(); - if (progress < WaitSecurityDelayDialog.this.progressBar.getMax()) { - WaitSecurityDelayDialog.this.progressBar.setProgress(progress + 1000); - } - }); - } - }, 1000, 1000); - return new AlertDialog.Builder(getActivity()) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle(R.string.dialog_security_delay) - .setView(v) - .setCancelable(false) - .create(); - } - - @Override - public void onCancel(@NonNull DialogInterface dialog) { - super.onCancel(dialog); - } - - public static void onReadBeforeRequest(final FragmentActivity activity, final int timeout) { - if (activity == null) return; - - Log.e(TAG, "onReadBeforeRequest callback(" + timeout + ")"); - activity.runOnUiThread(() -> { - if (timerToShowDelayDialog != null || timeout < delayBeforeShowDialog + minRemainingDelayToShowDialog) - return; - timerToShowDelayDialog = new Timer(); - timerToShowDelayDialog.schedule(new TimerTask() { - @Override - public void run() { - if (WaitSecurityDelayDialog.instance != null) return; - instance = new WaitSecurityDelayDialog(); - instance.setup(timeout, delayBeforeShowDialog); - instance.setCancelable(false); - activity.getSupportFragmentManager().beginTransaction() - .add(instance, TAG).commitAllowingStateLoss(); - } - }, delayBeforeShowDialog); - }); - } - - public static void onReadAfterRequest(final Activity activity) { - if (timerToShowDelayDialog == null) return; - timerToShowDelayDialog.cancel(); - timerToShowDelayDialog = null; - } - - public static void onReadWait(final FragmentActivity activity, final int msec) { - Log.e(TAG, "onReadWait callback(" + msec + ")"); - if (timerToShowDelayDialog != null) { - timerToShowDelayDialog.cancel(); - timerToShowDelayDialog = null; - } - - if (msec == 0 && instance != null) { - try { - instance.dismissAllowingStateLoss(); - instance = null; - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (activity == null) return; - - activity.runOnUiThread(() -> { - Log.e(TAG, "onReadWait on ui thread(" + msec + ")"); - - if (instance == null) { - if (msec > delayBeforeShowDialog + minRemainingDelayToShowDialog) { - instance = new WaitSecurityDelayDialog(); - // 1000ms - card delay notification interval - instance.setup(msec + 1000, 1000); - instance.setCancelable(false); - activity.getSupportFragmentManager().beginTransaction() - .add(instance, TAG).commitAllowingStateLoss(); - } - } else - instance.setRemainingTimeout(msec); - }); - } - - private void setup(int msTimeout, int msProgress) { - this.msTimeout = msTimeout; - this.msProgress = msProgress; - } - - private void setRemainingTimeout(final int msec) { - if (progressBar != null) { - progressBar.post(() -> { - int progress = WaitSecurityDelayDialog.this.progressBar.getProgress(); - if (timer != null) { - // we get delay latency from card for first time - don't change progress by timer, only by card answer - progressBar.setMax(progress + msec); - timer.cancel(); - timer = null; - } else { - int newProgress = progressBar.getMax() - msec; - if (newProgress > progress) - progressBar.setProgress(newProgress); - else - progressBar.setMax(progress + msec); - } - }); - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialogNew.kt b/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialogNew.kt deleted file mode 100644 index c55657a9d4..0000000000 --- a/app/src/main/java/com/tangem/ui/dialog/WaitSecurityDelayDialogNew.kt +++ /dev/null @@ -1,156 +0,0 @@ -package com.tangem.ui.dialog - -import android.annotation.SuppressLint -import android.app.AlertDialog -import android.app.Dialog -import android.os.Bundle -import android.widget.ProgressBar -import androidx.appcompat.app.AppCompatDialogFragment -import com.tangem.ui.event.ReadAfterRequest -import com.tangem.ui.event.ReadBeforeRequest -import com.tangem.ui.event.ReadWait -import com.tangem.util.LOG -import com.tangem.wallet.R -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import java.util.* - -class WaitSecurityDelayDialogNew : AppCompatDialogFragment() { - - companion object { - val TAG: String = WaitSecurityDelayDialogNew::class.java.simpleName - - private const val MIN_REMAINING_DELAY_TO_SHOW_DIALOG = 1000 - private const val DELAY_BEFORE_SHOW_DIALOG = 5000 - } - - private lateinit var pb: ProgressBar - - private var msTimeout = 60000 - private var msProgress = 0 - private var timer: Timer? = null - private var timerToShowDelayDialog: Timer? = null - - @SuppressLint("InflateParams") - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val inflater = activity!!.layoutInflater - val v = inflater.inflate(R.layout.dialog_wait_pin2, null) - - pb = v.findViewById(R.id.progressBar) - - pb.max = msTimeout - pb.progress = msProgress - - timer = Timer() - timer!!.scheduleAtFixedRate(object : TimerTask() { - override fun run() { - pb.post { - val progress = pb.progress - if (progress < pb.max) - pb.progress = progress + 1000 - } - } - }, 1000, 1000) - - return AlertDialog.Builder(activity) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle(R.string.dialog_security_delay) - .setView(v) - .setCancelable(false) - .create() - } - - override fun onStart() { - super.onStart() - EventBus.getDefault().register(this) - } - - override fun onStop() { - super.onStop() - EventBus.getDefault().unregister(this) - } - - @Subscribe - fun readBeforeRequest(readBeforeRequest: ReadBeforeRequest) { - LOG.i(TAG, "readBeforeRequest 111") - - if (timerToShowDelayDialog != null || readBeforeRequest.timeout!! < DELAY_BEFORE_SHOW_DIALOG + MIN_REMAINING_DELAY_TO_SHOW_DIALOG) - return - - timerToShowDelayDialog = Timer() - timerToShowDelayDialog!!.schedule(object : TimerTask() { - override fun run() { - setup(readBeforeRequest.timeout!!, DELAY_BEFORE_SHOW_DIALOG) - isCancelable = false - -// if (!isAdded) - show(activity!!.supportFragmentManager, TAG) - -// if (isHidden) -// activity?.supportFragmentManager?.let { show(it, TAG) } - } - }, DELAY_BEFORE_SHOW_DIALOG.toLong()) - } - - @Subscribe - fun readAfterRequest(readAfterRequest: ReadAfterRequest) { - LOG.i(TAG, "readAfterRequest 222") - - if (timerToShowDelayDialog == null) - return - - timerToShowDelayDialog!!.cancel() - timerToShowDelayDialog = null - } - - @Subscribe - fun readWait(readWait: ReadWait) { - LOG.i(TAG, "readWait 333") - - if (timerToShowDelayDialog != null) { - timerToShowDelayDialog!!.cancel() - timerToShowDelayDialog = null - } - - if (readWait.msec == 0) { - dismiss() - return - } - - if (readWait.msec!! > MIN_REMAINING_DELAY_TO_SHOW_DIALOG) { - // 1000ms - card delay notification interval - setup(readWait.msec!! + 1000, 1000) - isCancelable = false - - if (isHidden) - activity?.supportFragmentManager?.let { show(it, TAG) } - - } else - setRemainingTimeout(readWait.msec!!) - } - - private fun setup(msTimeout: Int, msProgress: Int) { - this.msTimeout = msTimeout - this.msProgress = msProgress - } - - private fun setRemainingTimeout(msec: Int) { - pb.post { - val progress = pb.progress - if (timer != null) { - - // we get delay latency from card for first time - don't change progress by timer, only by card answer - pb.max = progress + msec - timer!!.cancel() - timer = null - } else { - val newProgress = pb.max - msec - if (pb.max > progress) - pb.progress = newProgress - else - pb.max = progress + msec - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/event/DeletingWalletFinish.kt b/app/src/main/java/com/tangem/ui/event/DeletingWalletFinish.kt deleted file mode 100644 index c9683549d5..0000000000 --- a/app/src/main/java/com/tangem/ui/event/DeletingWalletFinish.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.tangem.ui.event - -class DeletingWalletFinish \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/event/ReadAfterRequest.kt b/app/src/main/java/com/tangem/ui/event/ReadAfterRequest.kt deleted file mode 100644 index 8c61063c75..0000000000 --- a/app/src/main/java/com/tangem/ui/event/ReadAfterRequest.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.tangem.ui.event - -class ReadAfterRequest \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/event/ReadBeforeRequest.kt b/app/src/main/java/com/tangem/ui/event/ReadBeforeRequest.kt deleted file mode 100644 index 203b0e1edb..0000000000 --- a/app/src/main/java/com/tangem/ui/event/ReadBeforeRequest.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.ui.event - -class ReadBeforeRequest { - var timeout: Int? = null -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/event/ReadWait.kt b/app/src/main/java/com/tangem/ui/event/ReadWait.kt deleted file mode 100644 index cd4e013295..0000000000 --- a/app/src/main/java/com/tangem/ui/event/ReadWait.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.ui.event - -class ReadWait { - var msec: Int? = null -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/event/TransactionFinishWithError.kt b/app/src/main/java/com/tangem/ui/event/TransactionFinishWithError.kt deleted file mode 100644 index fd21ee0083..0000000000 --- a/app/src/main/java/com/tangem/ui/event/TransactionFinishWithError.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.ui.event - -class TransactionFinishWithError { - var message: String? = null -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/event/TransactionFinishWithSuccess.kt b/app/src/main/java/com/tangem/ui/event/TransactionFinishWithSuccess.kt deleted file mode 100644 index 00d24a8b33..0000000000 --- a/app/src/main/java/com/tangem/ui/event/TransactionFinishWithSuccess.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.ui.event - -class TransactionFinishWithSuccess { - var message: String? = null -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/BaseFragment.kt b/app/src/main/java/com/tangem/ui/fragment/BaseFragment.kt deleted file mode 100644 index ed903c4d47..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/BaseFragment.kt +++ /dev/null @@ -1,110 +0,0 @@ -package com.tangem.ui.fragment - -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.annotation.IdRes -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.NavHostFragment.findNavController -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.navigation.NavigationResult -import com.tangem.ui.navigation.NavigationResultListener - -abstract class BaseFragment : Fragment() { - - protected val requestCode: String - get() = arguments?.getString(ARGUMENT_NAVIGATION_REQUEST_CODE, REQUEST_CODE_NOT_SET) - ?: REQUEST_CODE_NOT_SET - protected val navigatedBack: Boolean - get() = (activity as? MainActivity)?.viewModel?.navigationResult != null - - protected abstract val layoutId: Int - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - Log.d("LIFECYCLE", "onCreate: ${this::class.java.simpleName}") - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(layoutId, container, false) - } - - override fun onStart() { - super.onStart() - Log.d("LIFECYCLE", "onStart: ${this::class.java.simpleName}") - if (this is NavigationResultListener) { - val navigationResult = (activity as? MainActivity)?.viewModel?.navigationResult - navigationResult?.run { - onNavigationResult(this.requestCode, this.resultCode, this.data) - (activity as? MainActivity)?.viewModel?.navigationResult = null - } - } - } - - override fun onPause() { - super.onPause() - Log.d("LIFECYCLE", "onPause: ${this::class.java.simpleName}") - } - - override fun onStop() { - super.onStop() - Log.d("LIFECYCLE", "onStop: ${this::class.java.simpleName}") - } - - override fun onDestroy() { - super.onDestroy() - Log.d("LIFECYCLE", "onDestroy: ${this::class.java.simpleName}") - } - - protected fun navigateUp(@IdRes destination: Int = DESTINATION_NOT_SET) { - try { - if (destination == DESTINATION_NOT_SET) { - findNavController(this).popBackStack() - } else { - findNavController(this).popBackStack(destination, false) - } - } catch (e: IllegalArgumentException) { - Log.w(this::class.java.simpleName, e.message) - } catch (e: IllegalStateException) { - Log.w(this::class.java.simpleName, e.message) - } - } - - protected fun navigateForResult(requestCode: String, @IdRes destination: Int, data: Bundle? = null) { - val argumentsWithRequestCode = (data ?: Bundle()).apply { - putString(ARGUMENT_NAVIGATION_REQUEST_CODE, requestCode) - } - navigateToDestination(destination, argumentsWithRequestCode) - } - - protected fun navigateToDestination(@IdRes destination: Int, data: Bundle? = null) { - try { - findNavController(this).navigate(destination, data) - } catch (e: IllegalArgumentException) { - Log.w(this::class.java.simpleName, e.message) - } catch (e: IllegalStateException) { - Log.w(this::class.java.simpleName, e.message) - } - } - - protected fun navigateBackWithResult(resultCode: Int, data: Bundle? = null, - @IdRes destination: Int = DESTINATION_NOT_SET) { - try { - (requireActivity() as MainActivity).viewModel.navigationResult = - NavigationResult(requestCode, resultCode, data) - return navigateUp(destination) - } catch (e: IllegalArgumentException) { - Log.w(this::class.java.simpleName, e.message) - } catch (e: IllegalStateException) { - Log.w(this::class.java.simpleName, e.message) - } - } - - companion object { - private const val ARGUMENT_NAVIGATION_REQUEST_CODE = "NAVIGATION_REQUEST_CODE" - private const val DESTINATION_NOT_SET = -1 - private const val REQUEST_CODE_NOT_SET = "REQUEST_CODE_NOT_SET" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/LogoFragment.kt b/app/src/main/java/com/tangem/ui/fragment/LogoFragment.kt deleted file mode 100644 index 080f917a41..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/LogoFragment.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.tangem.ui.fragment - -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.view.View -import com.tangem.Constant -import com.tangem.wallet.BuildConfig -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_logo.* - -class LogoFragment : BaseFragment() { - companion object { - fun callingIntent(context: Context, autoHide: Boolean): Intent { - val intent = Intent(context, LogoFragment::class.java) - intent.putExtra(Constant.EXTRA_AUTO_HIDE, autoHide) - return intent - } - } - - override val layoutId = R.layout.fragment_logo - - private val hideRunnable = Runnable { this.hide() } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - clLogoContainer.setOnClickListener { hide() } - // set beta version name - if (BuildConfig.DEBUG) - tvAppVersion.text = String.format(getString(R.string.splash_version_name_debug), BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) - else - tvAppVersion.text = String.format(getString(R.string.splash_version_name_release), BuildConfig.VERSION_NAME) - - // set flavor app name - when (BuildConfig.FLAVOR) { - Constant.FLAVOR_TANGEM_CARDANO -> { - tvExtension.visibility = View.VISIBLE - tvExtension.text = getString(R.string.splash_cardano) - } - else -> { - tvExtension.visibility = View.GONE - } - } - - if (arguments?.getBoolean(Constant.EXTRA_AUTO_HIDE, true) != false) - ivLogo.postDelayed(hideRunnable, Constant.MILLIS_AUTO_HIDE.toLong()) - } - - private fun hide() { - when (BuildConfig.FLAVOR) { - Constant.FLAVOR_TANGEM_CARDANO -> { - navigateToDestination(R.id.action_logoFragment_to_prepareTransactionFragment, - Bundle().apply { TangemContext().saveToBundle(this) }) - } - else -> { - navigateToDestination(R.id.action_logoFragment_to_main) - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/MainFragment.kt b/app/src/main/java/com/tangem/ui/fragment/MainFragment.kt deleted file mode 100644 index bd386f97c4..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/MainFragment.kt +++ /dev/null @@ -1,477 +0,0 @@ -package com.tangem.ui.fragment - -import android.app.Activity -import android.app.AlertDialog -import android.content.Intent -import android.net.Uri -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.nfc.tech.NfcV -import android.os.Bundle -import android.text.Spannable -import android.text.SpannableString -import android.text.style.ForegroundColorSpan -import android.util.Log -import android.view.* -import android.widget.PopupMenu -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.core.os.bundleOf -import androidx.lifecycle.ViewModelProviders -import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.google.firebase.perf.FirebasePerformance -import com.google.firebase.perf.metrics.Trace -import com.tangem.App -import com.tangem.Constant -import com.tangem.data.Blockchain -import com.tangem.data.Logger -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.reader.TLV -import com.tangem.tangem_card.reader.TLVException -import com.tangem.tangem_card.reader.TLVList -import com.tangem.tangem_card.tasks.CustomReadCardTask -import com.tangem.tangem_card.tasks.ReadCardInfoTask -import com.tangem.tangem_sdk.android.data.PINStorage -import com.tangem.tangem_sdk.android.nfc.NfcDeviceAntennaLocation -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.android.reader.NfcVReader -import com.tangem.tangem_sdk.android.reader.ReadResult -import com.tangem.tangem_sdk.android.reader.ReadSlixTagTask -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.loadFromBundle -import com.tangem.tangem_sdk.data.saveToBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.fragment.pin.PinRequestFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.util.* -import com.tangem.util.extensions.colorFrom -import com.tangem.wallet.BuildConfig -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import com.tangem.wallet.xlmTag.XlmTagEngine -import kotlinx.android.synthetic.main.fragment_main.* -import kotlinx.android.synthetic.main.layout_touch_card.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch -import java.io.File -import kotlin.coroutines.CoroutineContext - -class MainFragment : BaseFragment(), NavigationResultListener, NfcAdapter.ReaderCallback, - CardProtocol.Notifications, androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener, - PopupMenu.OnMenuItemClickListener { - - companion object { - fun newInstance() = MainFragment() - val TAG: String = MainFragment::class.java.simpleName - const val CARD_SHOP_URI = "https://shop.tangem.com/?afmc=1i&utm_campaign=1i&utm_source=leaddyno&utm_medium=affiliate" - } - - override val layoutId = R.layout.fragment_main - private lateinit var viewModel: MainViewModel - private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation - private var tapTimerTrace: Trace? = null - private var unsuccessReadCount = 0 - private var task: CustomReadCardTask? = null - private var lastTag: Tag? = null - private var zipFile: File? = null - private var unknownBlockchain = false - - private val parentJob = Job() - private val coroutineContext: CoroutineContext - get() = parentJob + Dispatchers.IO - private val scope = CoroutineScope(coroutineContext) - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - setHasOptionsMenu(true) - return super.onCreateView(inflater, container, savedInstanceState) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - rippleBackgroundNfc.startRippleAnimation() - -// navigateToDestination(R.id.action_main_to_emptyIdFragment) - // init NFC Antenna - nfcDeviceAntenna = NfcDeviceAntennaLocation(requireContext(), ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc) - nfcDeviceAntenna.init() - - // set phone name - if (nfcDeviceAntenna.fullName != "") - tvNFCHint.text = String.format(getString(R.string.main_screen_scan_card), nfcDeviceAntenna.fullName) - else - tvNFCHint.text = String.format(getString(R.string.main_screen_scan_card), getString(R.string.main_screen_phone)) - - // set listeners -// ivMenu.setOnClickListener { showMenu(it) } - - val toolbar = tb_main - (activity as? AppCompatActivity)?.setSupportActionBar(toolbar) - (activity as? AppCompatActivity)?.supportActionBar?.setDisplayShowTitleEnabled(false) - - - setCardStoreLink() - - FirebaseAnalytics.getInstance(requireActivity()) - .logEvent(AnalyticsEvent.READY_TO_SCAN.event, bundleOf()) - } - - private fun setCardStoreLink() { - val text = getString(R.string.main_screen_visit_store, getString(R.string.main_screen_store_address)) - val spannable = SpannableString(text) - spannable.setSpan( - ForegroundColorSpan(requireContext().colorFrom(R.color.colorAccent)), - text.indexOf(getString(R.string.main_screen_store_address)), - text.length, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - - tvBuyCards?.setText(spannable, TextView.BufferType.SPANNABLE) - llShoppingView?.setOnClickListener { - val uri = Uri.parse(CARD_SHOP_URI) - val intent = Intent(Intent.ACTION_VIEW, uri) - startActivity(intent) - } - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) -// -// // show snackbar about new version app -// viewModel.getVersionName().observe(this, Observer { text -> -// (activity as MainActivity).toastHelper.showSnackbarUpdateVersion(requireContext(), cl, text) -// }) - - val intent = activity?.intent - if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action || NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action)) { - val tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) - onTagDiscovered(tag) - } - } - - override fun onResume() { - tapTimerTrace = FirebasePerformance.getInstance() - .newTrace(AnalyticsEvent.CARD_TAP_USER_TIMER.event) - tapTimerTrace?.start() - super.onResume() - nfcDeviceAntenna.animate() - } - - override fun onPause() { - task?.cancel(true) - super.onPause() - } - - override fun onStop() { - task?.cancel(true) - tapTimerTrace = null - super.onStop() - } - - override fun onTagDiscovered(tag: Tag) { - if (unknownBlockchain) { - (activity as MainActivity).nfcManager.ignoreTag(tag) - return - } - - NfcV.get(tag)?.let { onNfcVDiscovered(it, tag.id) } - - try { - // get IsoDep handle and run cardReader thread - val isoDep = IsoDep.get(tag) - if (unsuccessReadCount < 2) - isoDep.timeout = 2000 + 5000 * unsuccessReadCount - else - isoDep.timeout = 90000 - - lastTag = tag - - val terminalKeys = viewModel.getTerminalKeys() - PINStorage.setTerminalPrivateKey(terminalKeys[Constant.TERMINAL_PRIVATE_KEY]) - PINStorage.setTerminalPublicKey(terminalKeys[Constant.TERMINAL_PUBLIC_KEY]) - - task = ReadCardInfoTask(NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, this) - task?.start() - } catch (e: Exception) { - e.printStackTrace() - (activity as MainActivity).nfcManager.notifyReadResult(false) - } - } - - - private fun onNfcVDiscovered(nfcV: NfcV, uid: ByteArray) { - scope.launch { - when (val readResult = ReadSlixTagTask(NfcVReader(nfcV)).read()) { - is ReadResult.Failure -> (activity as MainActivity).nfcManager.notifyReadResult(false) - is ReadResult.Success -> { - try { - val tlvs = readResult.tlvs - val cardDataTlv = TLVList.fromBytes((tlvs.getTLV(TLV.Tag.TAG_CardData)).Value) - Log.v(TAG, "\n" + tlvs.getParsedTLVs("")) - val card = TangemCard(uid.toString()) - card.batch = cardDataTlv.getTLV(TLV.Tag.TAG_Batch).asHexString - card.setIssuer(cardDataTlv.getTLV(TLV.Tag.TAG_Issuer_ID).Value.toString(), null) - card.blockchainID = Blockchain.StellarTag.id - card.walletPublicKey = tlvs.getTLV(TLV.Tag.TAG_Wallet_PublicKey).Value - card.status = TangemCard.Status.Loaded - card.tagSignature = tlvs.getTLV(TLV.Tag.TAG_Signature).Value - - val ctx = TangemContext(card) - val engineCoin = XlmTagEngine(ctx) - engineCoin.defineWallet() - launch(Dispatchers.Main) { - - val bundle = Bundle() - bundle.putParcelable(Constant.EXTRA_LAST_DISCOVERED_TAG, lastTag) - ctx.saveToBundle(bundle) - navigateForResult(Constant.REQUEST_CODE_SHOW_CARD_ACTIVITY, - R.id.action_main_to_tagFragment, bundle) - } - } catch (e: TLVException) { - e.printStackTrace() - Log.v(TAG, e.message) - } - } - } - } - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar?.visibility = View.VISIBLE } - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - tapTimerTrace?.stop() - task = null - if (cardProtocol != null) { - if (cardProtocol.error == null) { - (activity as MainActivity).nfcManager.notifyReadResult(true) - rlProgressBar?.post { - rlProgressBar?.visibility = View.GONE - - // TODO - ??? remove save and load??? - val cardInfo = Bundle() - val bCard = Bundle() - - cardInfo.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - cardInfo.putBundle(EXTRA_TANGEM_CARD, bCard) - cardProtocol.card.saveToBundle(bCard) - - val uid = cardInfo.getString(EXTRA_TANGEM_CARD_UID) - val card = TangemCard(uid) - cardInfo.getBundle(EXTRA_TANGEM_CARD)?.let { card.loadFromBundle(it) } - - val terminalKeys = viewModel.getTerminalKeys() - card.terminalPrivateKey = terminalKeys[Constant.TERMINAL_PRIVATE_KEY] - card.terminalPublicKey = terminalKeys[Constant.TERMINAL_PUBLIC_KEY] - - val ctx = TangemContext(card) - - FirebaseAnalytics.getInstance(requireActivity()) - .logEvent(AnalyticsEvent.CARD_IS_SCANNED.event, Analytics.setCardData(ctx)) - - when { - card.status == TangemCard.Status.Loaded -> lastTag?.let { - val engineCoin = CoinEngineFactory.create(ctx) - if (engineCoin != null) { - if (card.isIDCard) { - val bundle = Bundle() - bundle.putParcelable(Constant.EXTRA_LAST_DISCOVERED_TAG, lastTag) - ctx.saveToBundle(bundle) - navigateToDestination(R.id.action_main_to_idFragment, bundle) - } else { - engineCoin.defineWallet() - val bundle = Bundle() - bundle.putParcelable(Constant.EXTRA_LAST_DISCOVERED_TAG, lastTag) - ctx.saveToBundle(bundle) - navigateForResult(Constant.REQUEST_CODE_SHOW_CARD_ACTIVITY, - R.id.action_main_to_loadedWalletFragment, bundle) - } - } else { - showUnkownBlockchainWarning() - } - } - card.status == TangemCard.Status.Empty -> { - val engineCoin = CoinEngineFactory.create(ctx) - if (engineCoin != null) { - val bundle = Bundle().apply { ctx.saveToBundle(this) } - navigateToDestination(R.id.action_main_to_emptyWalletFragment, bundle) - } else { - showUnkownBlockchainWarning() - } - } - card.status == TangemCard.Status.Purged -> Toast.makeText(context, R.string.main_screen_erased_wallet, Toast.LENGTH_SHORT).show() - card.status == TangemCard.Status.NotPersonalized -> Toast.makeText(context, R.string.main_screen_not_personalized, Toast.LENGTH_SHORT).show() - else -> { - -// val bundle = Bundle() -// bundle.putParcelable(Constant.EXTRA_LAST_DISCOVERED_TAG, lastTag) -// ctx.saveToBundle(bundle) -// navController.navigate(R.id.loadedWallet, bundle) - -// lastTag?.let { navigator.showLoadedWallet(this, it, ctx) } - } - } - } - - } else { - FirebaseCrashlytics.getInstance().recordException(cardProtocol.error) - // remove last UIDs because of error and no card read - rlProgressBar.post { - context?.let { Toast.makeText(it, R.string.general_notification_scan_again, Toast.LENGTH_SHORT).show() } - unsuccessReadCount++ - - if (cardProtocol.error is CardProtocol.TangemException_InvalidPIN) { - val data = Bundle().apply { putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN.toString()) } - navigateForResult(Constant.REQUEST_CODE_ENTER_PIN_ACTIVITY, - R.id.action_main_to_pinRequestFragment, data) - } else { - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) - if (!NoExtendedLengthSupportDialog.allReadyShowed) - NoExtendedLengthSupportDialog().show(requireActivity().supportFragmentManager, NoExtendedLengthSupportDialog.TAG) - - lastTag = null - ReadCardInfoTask.resetLastReadInfo() - (activity as? MainActivity)?.nfcManager?.notifyReadResult(false) - } - } - } - } - - rlProgressBar?.postDelayed({ rlProgressBar?.visibility = View.GONE }, 500) - } - - private fun showUnkownBlockchainWarning() { - unknownBlockchain = true - AlertDialog.Builder(context) - .setTitle(R.string.dialog_warning) - .setMessage(R.string.alert_unknown_blockchain) - .setPositiveButton(R.string.general_ok) { _, _ -> } - .setOnDismissListener { unknownBlockchain = false } - .create() - .show() - } - - override fun onReadCancel() { - task = null - ReadCardInfoTask.resetLastReadInfo() - rlProgressBar?.postDelayed({ rlProgressBar?.visibility = View.GONE }, 500) - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - when (requestCode) { - Constant.REQUEST_CODE_SEND_EMAIL -> { - if (zipFile != null) { - zipFile!!.delete() - zipFile = null - } - } - Constant.REQUEST_CODE_ENTER_PIN_ACTIVITY -> { - if (resultCode == Activity.RESULT_OK && lastTag != null) - onTagDiscovered(lastTag!!) - else - ReadCardInfoTask.resetLastReadInfo() - } - } - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_main, menu) - if (BuildConfig.DEBUG) { - for (i in 0 until menu.size()) menu.getItem(i).isVisible = true - } - super.onCreateOptionsMenu(menu, inflater) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.sendLogs -> { - var f: File? = null - try { - f = Logger.collectLogs(activity) - if (f != null) { - LOG.e(TAG, String.format("Collect %d log bytes", f.length())) - CommonUtil.sendEmail(activity, zipFile, TAG, "Logs", UtilHelper.getDeviceInfo(), arrayOf(f)) - } else { - LOG.e(TAG, "Can't create temporarily log file") - } - } catch (e: Exception) { - e.printStackTrace() - } finally { - if (f != null && f.exists()) - f.delete() - } - return true - } - R.id.managePIN -> { - navigateToDestination(R.id.action_main_to_pinSaveFragment, - bundleOf(Constant.EXTRA_PIN2 to false)) - return true - } - - R.id.managePIN2 -> { - navigateToDestination(R.id.action_main_to_pinSaveFragment, - bundleOf(Constant.EXTRA_PIN2 to true)) - return true - } - - R.id.settings -> { - navigateToDestination(R.id.action_main_to_settingsFragment) - return true - } - - R.id.about -> { - val bundle = Bundle().apply { putBoolean(Constant.EXTRA_AUTO_HIDE, false) } - navigateToDestination(R.id.action_main_to_logoFragment, bundle) - return true - } - } - return super.onOptionsItemSelected(item) - } - - override fun onReadWait(msec: Int) { - WaitSecurityDelayDialog.onReadWait(requireActivity() as AppCompatActivity?, msec) - } - - override fun onReadBeforeRequest(timeout: Int) { - WaitSecurityDelayDialog.onReadBeforeRequest(requireActivity() as AppCompatActivity?, timeout) - } - - override fun onReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(requireActivity()) - } - - override fun onMenuItemClick(item: MenuItem?): Boolean { - return onOptionsItemSelected(item!!) - } - - private fun showMenu(v: View) { - val popup = PopupMenu(context, v) - val inflater = popup.menuInflater - inflater.inflate(R.menu.menu_main, popup.menu) - - if (BuildConfig.DEBUG) { - popup.menu.findItem(R.id.managePIN).isEnabled = true - popup.menu.findItem(R.id.managePIN2).isEnabled = true - popup.menu.findItem(R.id.sendLogs).isVisible = true - } - - popup.setOnMenuItemClickListener(this) - popup.show() - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/MainViewModel.kt b/app/src/main/java/com/tangem/ui/fragment/MainViewModel.kt deleted file mode 100644 index ce2cc664db..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/MainViewModel.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.tangem.ui.fragment - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.tangem.Constant -import com.tangem.data.dp.PrefsManager -import com.tangem.data.network.ServerApiCommon -import com.tangem.wallet.BuildConfig - -class MainViewModel : ViewModel() { - private var serverApiCommon: ServerApiCommon = ServerApiCommon() - - private var versionName = MutableLiveData() - - fun getVersionName(): LiveData { - versionName = MutableLiveData() - requestVersionName() - return versionName - } - - private fun requestVersionName() { - serverApiCommon.setLastVersionListener { response -> - try { - if (response.isNullOrEmpty()) - return@setLastVersionListener - val responseVersionName = response.trim(' ', '\n', '\r', '\t') - val responseBuildVersion = responseVersionName.split('.').last() - val appBuildVersion = BuildConfig.VERSION_NAME.split('.').last() - if (responseBuildVersion.toInt() > appBuildVersion.toInt()) - if (BuildConfig.FLAVOR.equals(Constant.FLAVOR_TANGEM_ACCESS)) - versionName.value = responseVersionName - } catch (E: Exception) { - E.printStackTrace() - } - } - serverApiCommon.requestLastVersion() - } - - fun getTerminalKeys(): Map { - return PrefsManager.getInstance().terminalKeys - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/PurgeFragment.kt b/app/src/main/java/com/tangem/ui/fragment/PurgeFragment.kt deleted file mode 100644 index 2130c741a9..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/PurgeFragment.kt +++ /dev/null @@ -1,229 +0,0 @@ -package com.tangem.ui.fragment - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.content.res.ColorStateList -import android.graphics.Color -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Bundle -import android.view.View -import android.widget.Toast -import androidx.core.os.bundleOf -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.PurgeTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.nfc.NfcDeviceAntennaLocation -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.asBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialogNew -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_purge.* -import kotlinx.android.synthetic.main.layout_touch_card.* -import javax.inject.Inject - -class PurgeFragment : BaseFragment(), NfcAdapter.ReaderCallback, CardProtocol.Notifications { - companion object { - val TAG: String = PurgeFragment::class.java.simpleName - - fun callingIntent(context: Context, ctx: TangemContext): Intent { - val intent = Intent(context, PurgeFragment::class.java) - ctx.saveToIntent(intent) - return intent - } - - const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER - } - - @Inject - internal lateinit var waitSecurityDelayDialogNew: WaitSecurityDelayDialogNew - - override val layoutId = R.layout.fragment_purge - - private lateinit var ctx: TangemContext - - private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation - - private var purgeTask: PurgeTask? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - // init NFC Antenna - nfcDeviceAntenna = NfcDeviceAntennaLocation(requireContext(), ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc) - nfcDeviceAntenna.init() - - tvCardID.text = ctx.card.cidDescription - progressBar.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar.visibility = View.INVISIBLE - } - - override fun onStop() { - purgeTask?.cancel(true) - super.onStop() - } - - override fun onTagDiscovered(tag: Tag) { - try { - // get IsoDep handle and run cardReader thread - val isoDep = IsoDep.get(tag) - val uid = tag.id - val sUID = Util.byteArrayToHexString(uid) - if (sUID == ctx.card.uid) { - isoDep.timeout = ctx.card.pauseBeforePIN2 + 65000 - purgeTask = PurgeTask(ctx.card, NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, this) - purgeTask?.start() - } else { - (activity as MainActivity).nfcManager.ignoreTag(isoDep.tag) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - override fun onReadWait(msec: Int) { - activity?.let { WaitSecurityDelayDialog.onReadWait(it, msec) } - -// val readWait = ReadWait() -// readWait.msec = msec -// EventBus.getDefault().post(readWait) - } - - override fun onReadBeforeRequest(timeout: Int) { - activity?.let { WaitSecurityDelayDialog.onReadBeforeRequest(it, timeout) } - -// if (!waitSecurityDelayDialogNew.isAdded) -// waitSecurityDelayDialogNew.show(supportFragmentManager, WaitSecurityDelayDialogNew.TAG) -// -// -// val readBeforeRequest = ReadBeforeRequest() -// readBeforeRequest.timeout = timeout -// EventBus.getDefault().post(readBeforeRequest) - } - - override fun onReadAfterRequest() { - activity?.let { WaitSecurityDelayDialog.onReadAfterRequest(it) } - -// val readAfterRequest = ReadAfterRequest() -// EventBus.getDefault().post(readAfterRequest) - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar.visibility = View.VISIBLE } - - progressBar?.post { - progressBar.visibility = View.VISIBLE - progressBar.progress = 5 - } - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - purgeTask = null - - if (cardProtocol != null) { - if (cardProtocol.error == null) { - rlProgressBar?.post { rlProgressBar?.visibility = View.GONE } - - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.GREEN) - - val data = Bundle() - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - - navigateToDestination(R.id.action_purgeFragment_to_mainFragment) - } - } else { - FirebaseCrashlytics.getInstance().recordException(cardProtocol.error) - if (cardProtocol.error is CardProtocol.TangemException_InvalidPIN) { - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - - val data = bundleOf( - EXTRA_TANGEM_CARD_UID to cardProtocol.card.uid, - EXTRA_TANGEM_CARD to cardProtocol.card.asBundle, - Constant.EXTRA_MESSAGE to getString(R.string.nfc_error_cannot_erase_wallet) - ) - navigateBackWithResult(RESULT_INVALID_PIN, data) - return@postDelayed - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } else { - progressBar?.post { - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allReadyShowed) - NoExtendedLengthSupportDialog().show(requireActivity().supportFragmentManager, NoExtendedLengthSupportDialog.TAG) - } else - Toast.makeText(context, R.string.general_notification_scan_again_to_verify, Toast.LENGTH_LONG).show() - - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - } - } - } - - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - progressBar?.post { progressBar?.progress = progress } - } - - override fun onReadCancel() { - purgeTask = null - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/SendTransactionFragment.kt b/app/src/main/java/com/tangem/ui/fragment/SendTransactionFragment.kt deleted file mode 100644 index 4e9de2f02e..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/SendTransactionFragment.kt +++ /dev/null @@ -1,98 +0,0 @@ -package com.tangem.ui.fragment - -import android.app.Activity -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Bundle -import android.widget.Toast -import androidx.activity.OnBackPressedCallback -import androidx.core.os.bundleOf -import com.google.firebase.analytics.FirebaseAnalytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.tangem_card.util.Util -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.event.TransactionFinishWithSuccess -import com.tangem.util.AnalyticsEvent -import com.tangem.util.AnalyticsParam -import com.tangem.util.UtilHelper -import com.tangem.wallet.CoinEngine -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import org.greenrobot.eventbus.EventBus -import java.io.IOException - -class SendTransactionFragment : BaseFragment(), NfcAdapter.ReaderCallback { - - override val layoutId = R.layout.fragment_send_transaction - - private lateinit var ctx: TangemContext - - private var tx: ByteArray? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - tx = arguments?.getByteArray(Constant.EXTRA_TX) - - val engine = CoinEngineFactory.create(ctx) - - engine!!.requestSendTransaction( - object : CoinEngine.BlockchainRequestsCallbacks { - override fun onComplete(success: Boolean) { - if (success) { - App.pendingTransactionsStorage.putTransaction(ctx.card, Util.bytesToHex(tx), engine.pendingTransactionTimeoutInSeconds()) - finishWithSuccess() - } else - finishWithError(ctx.error) - } - - override fun onProgress() { - } - - override fun allowAdvance(): Boolean { - return UtilHelper.isOnline(requireContext()) - } - }, - tx - ) - - val callback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - Toast.makeText(context, R.string.send_transaction_notification_wait, Toast.LENGTH_LONG).show() - } - - } - requireActivity().onBackPressedDispatcher.addCallback(this, callback) - } - - override fun onTagDiscovered(tag: Tag) { - try { - (activity as MainActivity).nfcManager.ignoreTag(tag) - } catch (e: IOException) { - e.printStackTrace() - } - } - - private fun finishWithSuccess() { - activity?.let { - val params = bundleOf(AnalyticsParam.BLOCKCHAIN.param to ctx.blockchainName) - FirebaseAnalytics.getInstance(it).logEvent(AnalyticsEvent.TRANSACTION_IS_SENT.event, params) - } - - val transactionFinishWithSuccess = TransactionFinishWithSuccess() - EventBus.getDefault().post(transactionFinishWithSuccess) - - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.send_transaction_success)) - navigateBackWithResult(Activity.RESULT_OK, data, R.id.loadedWalletFragment) - } - - private fun finishWithError(message: String) { - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, String.format(getString(R.string.send_transaction_error_failed_to_send), message)) - navigateBackWithResult(Activity.RESULT_CANCELED, data, R.id.loadedWalletFragment) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/SettingsFragment.kt b/app/src/main/java/com/tangem/ui/fragment/SettingsFragment.kt deleted file mode 100644 index 84aad44a88..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/SettingsFragment.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.tangem.ui.fragment - -import android.content.SharedPreferences -import android.os.Bundle -import android.view.View -import androidx.appcompat.app.AppCompatActivity -import androidx.core.os.bundleOf -import androidx.navigation.fragment.NavHostFragment -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceFragmentCompat -import com.google.firebase.analytics.FirebaseAnalytics -import com.tangem.util.Analytics -import com.tangem.util.AnalyticsEvent -import com.tangem.wallet.BuildConfig -import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_settings.* - -class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.pref_main) - - val categoryCommon = findPreference(getString(R.string.pref_category_common)) - val selectNodes = findPreference(getString(R.string.pref_select_nodes)) - val encryptionModes = findPreference(getString(R.string.pref_encryption_modes)) - - if (!BuildConfig.DEBUG) { - categoryCommon?.removePreference(selectNodes) - categoryCommon?.removePreference(encryptionModes) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initToolbar() - } - - private fun initToolbar() { - toolbar?.setTitle(R.string.settings_title) - toolbar?.setNavigationIcon(android.R.drawable.ic_menu_close_clear_cancel) - (activity as AppCompatActivity).setSupportActionBar(toolbar) - toolbar?.setNavigationOnClickListener { - NavHostFragment.findNavController(this).popBackStack() - } - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - if (key == getString(R.string.pref_analytics)) { - activity?.let {activity -> - val analytics = FirebaseAnalytics.getInstance(activity) - if (!Analytics.isEnabled()) { - analytics.logEvent(AnalyticsEvent.ANALYTICS_TURNED_OFF.event, bundleOf()) - } - Analytics.setFirebaseEnabled(activity) - } - } - } - - override fun onResume() { - super.onResume() - preferenceScreen.sharedPreferences - .registerOnSharedPreferenceChangeListener(this); - } - - override fun onPause() { - super.onPause() - preferenceScreen.sharedPreferences - .unregisterOnSharedPreferenceChangeListener(this); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/VerifyCardFragment.kt b/app/src/main/java/com/tangem/ui/fragment/VerifyCardFragment.kt deleted file mode 100644 index 3fa306f8c0..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/VerifyCardFragment.kt +++ /dev/null @@ -1,478 +0,0 @@ -package com.tangem.ui.fragment - -import android.app.Activity -import android.content.Intent -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Build -import android.os.Bundle -import android.text.Html -import android.text.format.DateUtils -import android.view.View -import android.widget.PopupMenu -import android.widget.Toast -import androidx.activity.OnBackPressedCallback -import androidx.core.content.ContextCompat -import com.tangem.App -import com.tangem.Constant -import com.tangem.data.Blockchain -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_sdk.android.data.PINStorage -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.loadFromBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.PINSwapWarningDialog -import com.tangem.ui.event.DeletingWalletFinish -import com.tangem.ui.fragment.pin.PinRequestFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.wallet.BuildConfig -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fr_verify_card.* -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import java.io.IOException -import java.util.* - -class VerifyCardFragment : BaseFragment(), NavigationResultListener, NfcAdapter.ReaderCallback { - companion object { - val TAG: String = VerifyCardFragment::class.java.simpleName - } - - override val layoutId = R.layout.fr_verify_card - - private lateinit var ctx: TangemContext - - private var requestPIN2Count = 0 - private var timerHideErrorAndMessage: Timer? = null - private var newPIN = "" - private var newPIN2 = "" - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - - val callback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - val data = prepareResultIntent() - data.putExtra(Constant.EXTRA_MODIFICATION, getString(R.string.main_screen_btn_update)) - navigateUp() - } - } - requireActivity().onBackPressedDispatcher.addCallback(this, callback) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - updateViews() - - val card = ctx.card - if (!card.allowSwapPIN() && !card.allowSwapPIN2() && card.forbidPurgeWallet()) { - fabMenu.hide() - } - - // set listeners - fabMenu.setOnClickListener { showMenu(fabMenu) } - - btnOk.setOnClickListener { - val data = prepareResultIntent() - data.putExtra(Constant.EXTRA_MODIFICATION, getString(R.string.main_screen_btn_update)) - navigateUp() - } - } - - override fun onStart() { - super.onStart() - if (!EventBus.getDefault().isRegistered(this)) - EventBus.getDefault().register(this) - } - - override fun onDestroy() { - EventBus.getDefault().unregister(this) - super.onDestroy() - } - - @Subscribe - fun onDeleteWalletFinish(deletingWalletFinish: DeletingWalletFinish) { - activity?.finish() - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - when (requestCode) { - Constant.REQUEST_CODE_ENTER_NEW_PIN -> if (resultCode == Activity.RESULT_OK) { - if (data != null) { - if (data.containsKey(Constant.EXTRA_CONFIRM_PIN)) { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(bundle) - newPIN = data.getString(Constant.EXTRA_NEW_PIN) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_verifyCard_to_pinRequestFragment, bundle) - } else { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_NEW_PIN, data.getString(Constant.EXTRA_NEW_PIN)) - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.ConfirmNewPIN.toString()) - navigateForResult(Constant.REQUEST_CODE_ENTER_NEW_PIN, - R.id.action_verifyCard_to_pinRequestFragment, bundle) - - } - } - } - - Constant.REQUEST_CODE_ENTER_NEW_PIN2 -> if (resultCode == Activity.RESULT_OK) { - if (data != null) { - if (data.containsKey(Constant.EXTRA_CONFIRM_PIN_2)) { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(bundle) - newPIN2 = data.getString(Constant.EXTRA_NEW_PIN_2) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_verifyCard_to_pinRequestFragment, bundle) - - } else { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_NEW_PIN_2, data.getString(Constant.EXTRA_NEW_PIN_2)) - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.ConfirmNewPIN2.toString()) - navigateForResult(Constant.REQUEST_CODE_ENTER_NEW_PIN2, - R.id.action_verifyCard_to_pinRequestFragment, bundle) - } - } - } - - Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) { - if (newPIN == "") newPIN = ctx.card!!.pin - - if (newPIN2 == "") newPIN2 = App.pinStorage.piN2 - - val pinSwapWarningDialog = PINSwapWarningDialog() - pinSwapWarningDialog.setOnRefreshPage { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_NEW_PIN, newPIN) - bundle.putString(Constant.EXTRA_NEW_PIN_2, newPIN2) - navigateForResult(Constant.REQUEST_CODE_SWAP_PIN, - R.id.action_verifyCard_to_pinSwapFragment, bundle) - } - val bundle = Bundle() - if (!CardProtocol.isDefaultPIN(newPIN) || !CardProtocol.isDefaultPIN2(newPIN2)) - bundle.putString(Constant.EXTRA_MESSAGE, getString(R.string.loaded_wallet_warning_dont_forget_pin)) - else - bundle.putString(Constant.EXTRA_MESSAGE, getString(R.string.loaded_wallet_warning_default_pin)) - pinSwapWarningDialog.arguments = bundle - activity?.supportFragmentManager?.let { pinSwapWarningDialog.show(it, PINSwapWarningDialog.TAG) } - } - - Constant.REQUEST_CODE_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) { - if (data == null) { - val newData = Bundle() - ctx.saveToBundle(newData) - newData.putString(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_DELETE) - navigateBackWithResult(Activity.RESULT_OK, newData) - } else { - data.putString(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_UPDATE) - navigateBackWithResult(Activity.RESULT_OK, data) - } - } else { - if (data != null && data.containsKey(EXTRA_TANGEM_CARD_UID) && data.containsKey(EXTRA_TANGEM_CARD)) { - val updatedCard = TangemCard(data.getString(EXTRA_TANGEM_CARD_UID)) - updatedCard.loadFromBundle(data.getBundle(EXTRA_TANGEM_CARD)) - ctx.card = updatedCard - } - if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) { - requestPIN2Count++ - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(bundle) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_verifyCard_to_pinRequestFragment, bundle) - return - } else { - if (data != null && data.containsKey(Constant.EXTRA_MESSAGE)) { - ctx.error = data.getString(Constant.EXTRA_MESSAGE) - } - } - } - - Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE -> if (resultCode == Activity.RESULT_OK) { - val bundle = Bundle().apply { ctx.saveToBundle(this) } - navigateForResult(Constant.REQUEST_CODE_PURGE, - R.id.action_verifyCard_to_purgeFragment, bundle) - } else { - if (data != null && data.containsKey(EXTRA_TANGEM_CARD_UID) && data.containsKey(EXTRA_TANGEM_CARD)) { - val updatedCard = TangemCard(data.getString(EXTRA_TANGEM_CARD_UID)) - updatedCard.loadFromBundle(data.getBundle(EXTRA_TANGEM_CARD)) - ctx.card = updatedCard - } - if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) { - requestPIN2Count++ - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(bundle) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE, - R.id.action_verifyCard_to_pinRequestFragment, data) - return - } else { - if (data != null && data.containsKey(Constant.EXTRA_MESSAGE)) { - ctx.error = data.getString(Constant.EXTRA_MESSAGE) - } - } - updateViews() - } - } - } - - override fun onTagDiscovered(tag: Tag?) { - try { - (activity as MainActivity).nfcManager.ignoreTag(tag!!) - } catch (e: IOException) { - e.printStackTrace() - } - } - - private fun updateViews() { - try { - if (timerHideErrorAndMessage != null) { - timerHideErrorAndMessage!!.cancel() - timerHideErrorAndMessage = null - } - tvCardID.text = ctx.card!!.cidDescription - - if (ctx.error == null || ctx.error.isEmpty()) { - tvError.visibility = View.GONE - tvError.text = "" - } else { - tvError.visibility = View.VISIBLE - tvError.text = ctx.error - } - if (ctx.message == null || ctx.message.isEmpty()) { - tvMessage.visibility = View.GONE - tvMessage.text = "" - } else { - tvMessage.visibility = View.VISIBLE - tvMessage.text = ctx.message - } - - tvManufacturerInfo.text = ctx.card!!.manufacturer.officialName - - if (ctx.card!!.isManufacturerConfirmed && ctx.card!!.isCardPublicKeyValid) { - tvCardIdentity.setText(R.string.details_attested) - tvCardIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed)) - - } else { - tvCardIdentity.setText(R.string.details_not_confirmed) - tvCardIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed)) - } - - tvIssuer.text = ctx.card!!.issuerDescription - - tvCardRegistredDate.text = DateUtils.formatDateTime(null, ctx.card!!.personalizationDateTime.time, DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NUMERIC_DATE or DateUtils.FORMAT_SHOW_YEAR) - - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(ctx.blockchainName, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(ctx.blockchainName) - tvBlockchain.text = html - - tvValidationNode.text = ctx.coinData!!.validationNodeDescription - - val engine = CoinEngineFactory.create(ctx) - - tvInputs.text = engine!!.unspentInputsDescription - - ivBlockchain.setImageResource(ctx.blockchain.getLogoImageResource(ctx.card!!.tokenSymbol)) - - var s = "" - for (signingM in ctx.card!!.allowedSigningMethod) { - s += if (signingM == ctx.card!!.signingMethod) { - ", ${signingM.description}" - } else { - ", ${signingM.description}" - } - } - s = s.substring(2, s.length) - @Suppress("DEPRECATION") - tvSigningMethod.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(s, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(s) - - - if (ctx.card!!.status == TangemCard.Status.Loaded || ctx.card!!.status == TangemCard.Status.Purged) { - - when { - ctx.card!!.remainingSignatures == 0 -> { - tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed)) - tvRemainingSignatures.setText(R.string.details_none) - } - ctx.card!!.remainingSignatures == 1 -> { - tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed)) - tvRemainingSignatures.setText(R.string.details_last_one) - } - ctx.card!!.remainingSignatures > 1000 -> { - tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed)) - tvRemainingSignatures.setText(R.string.details_unlimited) - } - else -> { - tvRemainingSignatures.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed)) - tvRemainingSignatures.text = ctx.card!!.remainingSignatures.toString() - } - } - tvSignedTx.text = (ctx.card!!.maxSignatures - ctx.card!!.remainingSignatures).toString() - } else { - tvLastSigned.text = "" - tvRemainingSignatures.text = "" - tvSignedTx.text = "" - } - - tvFirmware.text = ctx.card!!.firmwareVersion - - val textIsLinked = if (ctx.card.terminalIsLinked) { - getString(R.string.details_linked_card_to_phone) - } else { - getString(R.string.general_no) - } - tvIsLinked.text = textIsLinked - - if (ctx.card!!.useDevelopersFirmware()!!) { - imgDeveloperVersion.setImageResource(R.drawable.ic_developer_version) - imgDeveloperVersion.visibility = View.VISIBLE - imgDeveloperVersion.setOnClickListener { Toast.makeText(context, R.string.details_unlocked_card, Toast.LENGTH_LONG).show() } - } else - imgDeveloperVersion.visibility = View.INVISIBLE - - if (ctx.card!!.status == TangemCard.Status.Loaded) { - tvWallet.text = ctx.coinData!!.shortWalletString - if (ctx.card!!.isWalletPublicKeyValid) { - tvWalletIdentity.setText(R.string.details_possession_proved) - tvWalletIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed)) - } else { - tvWalletIdentity.setText(R.string.details_possession_not_proved) - tvWalletIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.not_confirmed)) - } - } else { - tvWallet!!.setText(R.string.details_not_available) - tvWalletIdentity.setText(R.string.no_data_string) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - private fun doSetPin() { - requestPIN2Count = 0 - val data = Bundle() - data.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestNewPIN.toString()) - newPIN = "" - newPIN2 = "" - navigateForResult(Constant.REQUEST_CODE_ENTER_NEW_PIN, - R.id.action_verifyCard_to_pinRequestFragment, data) - } - - private fun doResetPin() { - requestPIN2Count = 0 - val data = Bundle() - data.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(data) - newPIN = PINStorage.getDefaultPIN() - newPIN2 = "" - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_verifyCard_to_pinRequestFragment, data) - } - - private fun doResetPin2() { - requestPIN2Count = 0 - val data = Bundle() - data.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(data) - newPIN = "" - newPIN2 = PINStorage.getDefaultPIN2() - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_verifyCard_to_pinRequestFragment, data) - } - - private fun doResetPins() { - requestPIN2Count = 0 - val data = Bundle() - data.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(data) - newPIN = PINStorage.getDefaultPIN() - newPIN2 = PINStorage.getDefaultPIN2() - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_verifyCard_to_pinRequestFragment, data) - } - - private fun doSetPin2() { - requestPIN2Count = 0 - val data = Bundle() - data.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestNewPIN2.toString()) - newPIN = "" - newPIN2 = "" - navigateForResult(Constant.REQUEST_CODE_ENTER_NEW_PIN2, - R.id.action_verifyCard_to_pinRequestFragment, data) - } - - private fun doPurge() { - requestPIN2Count = 0 - val engine = CoinEngineFactory.create(ctx) ?: return - if (!engine.hasBalanceInfo()) { - Toast.makeText(context, R.string.general_error_cannot_erase_wallet_with_non_zero_balance, Toast.LENGTH_LONG).show() - return - } - if (engine.isBalanceNotZero) { - Toast.makeText(context, R.string.general_error_cannot_erase_wallet_with_non_zero_balance, Toast.LENGTH_LONG).show() - return - } else if (engine.awaitingConfirmation()) { - Toast.makeText(context, R.string.general_error_cannot_erase_wallet_with_non_zero_balance, Toast.LENGTH_LONG).show() - return - } - - val data = Bundle() - data.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(data) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE, - R.id.action_verifyCard_to_pinRequestFragment, data) - } - - fun prepareResultIntent(): Intent { - val data = Intent() - ctx.saveToIntent(data) - return data - } - - private fun showMenu(v: View) { - val popup = PopupMenu(activity, v) - val inflater = popup.menuInflater - inflater.inflate(R.menu.menu_loaded_wallet, popup.menu) - - popup.menu.findItem(R.id.action_set_PIN1).isVisible = ctx.card!!.allowSwapPIN()!! - popup.menu.findItem(R.id.action_reset_PIN1).isVisible = ctx.card!!.allowSwapPIN()!! && !ctx.card!!.useDefaultPIN1() - popup.menu.findItem(R.id.action_set_PIN2).isVisible = ctx.card!!.allowSwapPIN2()!! - popup.menu.findItem(R.id.action_reset_PIN2).isVisible = ctx.card!!.allowSwapPIN2()!! && !ctx.card!!.useDefaultPIN2() - popup.menu.findItem(R.id.action_reset_PINs).isVisible = ctx.card!!.allowSwapPIN()!! && ctx.card!!.allowSwapPIN2()!! && !ctx.card!!.useDefaultPIN1() && !ctx.card!!.useDefaultPIN2() - if (!ctx.card!!.isReusable || ctx.card!!.status != TangemCard.Status.Loaded) - popup.menu.findItem(R.id.action_purge).isVisible = false - - popup.setOnMenuItemClickListener { item -> - val id = item.itemId - when (id) { - R.id.action_set_PIN1 -> doSetPin() - R.id.action_reset_PIN1 -> doResetPin() - R.id.action_set_PIN2 -> doSetPin2() - R.id.action_reset_PIN2 -> doResetPin2() - R.id.action_reset_PINs -> doResetPins() - R.id.action_purge -> doPurge() - } - false - } - - if (BuildConfig.DEBUG) { - popup.menu.findItem(R.id.action_set_PIN2).isEnabled = true - popup.menu.findItem(R.id.action_reset_PIN2).isEnabled = true - } - - popup.show() - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/additional/PrepareCryptonitOtherApiWithdrawalFragment.kt b/app/src/main/java/com/tangem/ui/fragment/additional/PrepareCryptonitOtherApiWithdrawalFragment.kt deleted file mode 100644 index f9c5e38416..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/additional/PrepareCryptonitOtherApiWithdrawalFragment.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.tangem.ui.fragment.additional - -import android.app.Activity -import android.graphics.Color -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Bundle -import android.view.View -import com.tangem.Constant -import com.tangem.data.Blockchain -import com.tangem.data.network.CryptonitOtherApi -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.fragment.qr.CameraPermissionManager -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_prepare_cryptonit_other_api_withdrawal.* -import java.io.IOException - -class PrepareCryptonitOtherApiWithdrawalFragment : BaseFragment(), NavigationResultListener, - NfcAdapter.ReaderCallback { - - companion object { - val TAG: String = PrepareCryptonitOtherApiWithdrawalFragment::class.java.simpleName - } - - override val layoutId = R.layout.fragment_prepare_cryptonit_other_api_withdrawal - - private val cameraPermissionManager: CameraPermissionManager by lazy { CameraPermissionManager(this) } - private val ctx: TangemContext by lazy { TangemContext.loadFromBundle(context, arguments) } - private val cryptonit: CryptonitOtherApi by lazy { CryptonitOtherApi(context) } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - tvKey.text = cryptonit.key - tvUserID.text = cryptonit.userId - tvSecret.text = cryptonit.secretDescription - - tvCardID.text = ctx.card!!.cidDescription - tvWallet.text = ctx.coinData!!.wallet - val engine = CoinEngineFactory.create(ctx) - - tvCurrency.text = engine!!.balanceCurrency - - etAmount.setText(engine.convertToAmount(engine.convertToInternalAmount(ctx.card!!.denomination)).toValueString()) - etAmount.filters = engine.amountInputFilters - - // set listeners - btnLoad.setOnClickListener { - try { - val strAmount: String = etAmount.text.toString().replace(",", ".") -// if (!engine.checkAmount(card, strAmount)) -// etAmount.error = getString(R.string.unknown_amount_format) - val dblAmount: Double = strAmount.toDouble() - - rlProgressBar.visibility = View.VISIBLE - tvProgressDescription.text = getString(R.string.cryptonit_request_withdrawal) - - cryptonit.requestCryptoWithdrawal(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet) - } catch (e: Exception) { - etAmount.error = getString(R.string.prepare_transaction_error_unknown_amount_format) - } - - //Toast.makeText(this, strAmount, Toast.LENGTH_LONG).show() -// val balance = engine.getBalanceLong(card)!! / (card!!.blockchain.multiplier / 1000.0) -// if (etAmount.text.toString().replace(",", ".").toDouble() > balance) { -// etAmount.error = getString(R.string.not_enough_funds_on_your_account) -// return@setOnClickListener -// } - - } - ivCameraKey.setOnClickListener { checkPermissionsAndRunCamera() } - - ivCameraSecret.setOnClickListener { checkPermissionsAndRunCamera() } - - ivCameraUserId.setOnClickListener { checkPermissionsAndRunCamera() } - - ivRefreshBalance.setOnClickListener { doRequestBalance() } - - cryptonit.setBalanceListener { response -> - when (ctx.blockchain) { - Blockchain.Ethereum, Blockchain.EthereumTestNet -> { - tvBalance.text = response.eth_available - } - Blockchain.Bitcoin, Blockchain.BitcoinTestNet, Blockchain.BitcoinCash -> { - tvBalance.text = response.btc_available - } - else -> { - } - } - - tvBalanceCurrency.text = ctx.blockchain.currency - tvBalance.setTextColor(Color.BLACK) - rlProgressBar.visibility = View.INVISIBLE - btnLoad.isActivated = true - } - cryptonit.setErrorListener { throwable -> - throwable.printStackTrace() - rlProgressBar.visibility = View.INVISIBLE - tvError.visibility = View.VISIBLE - tvError.text = throwable.message - } - cryptonit.setWithdrawalListener { response -> - rlProgressBar.visibility = View.INVISIBLE - if (response.success != null && response.success!!) { - navigateUp() - } else { - tvError.visibility = View.VISIBLE - tvError.text = response.reason!!.toString() - } - } - btnLoad.isActivated = false - doRequestBalance() - } - - private fun checkPermissionsAndRunCamera() { - if (cameraPermissionManager.isPermissionGranted()) { - navigateForResult(Constant.REQUEST_CODE_SCAN_QR, R.id.action_prepareCryptonitOtherApiWithdrawalFragment_to_qrScanFragment) - } else { - cameraPermissionManager.requirePermission() - } - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - if (resultCode == Activity.RESULT_OK && data != null && data.containsKey("QRCode")) { - when (requestCode) { - Constant.REQUEST_CODE_SCAN_QR_KEY -> { - cryptonit.key = data.getString("QRCode") - tvKey?.text = cryptonit.key - } - Constant.REQUEST_CODE_SCAN_QR_SECRET -> { - cryptonit.secret = data.getString("QRCode") - tvSecret?.text = cryptonit.secretDescription - } - Constant.REQUEST_CODE_SCAN_QR_USER_ID -> { - cryptonit.userId = data.getString("QRCode") - tvUserID?.text = cryptonit.userId - } - } - cryptonit.saveAccountInfo() - doRequestBalance() - } - } - - override fun onTagDiscovered(tag: Tag) { - try { - (activity as MainActivity).nfcManager.ignoreTag(tag) - } catch (e: IOException) { - e.printStackTrace() - } - } - - private fun doRequestBalance() { - if (cryptonit.havaAccountInfo()) { - rlProgressBar.visibility = View.VISIBLE - tvProgressDescription.text = getString(R.string.cryptonit_request_balance) - tvError.visibility = View.INVISIBLE - cryptonit.requestBalance(ctx.blockchain.currency, "USD") - } else { - tvError.visibility = View.VISIBLE - tvError.text = getString(R.string.cryptonit_not_enough_account_data) - } - } - - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - cameraPermissionManager.handleRequestPermissionResult(requestCode, grantResults) { - navigateForResult(Constant.REQUEST_CODE_SCAN_QR, R.id.action_prepareCryptonitOtherApiWithdrawalFragment_to_qrScanFragment) - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/additional/PrepareCryptonitWithdrawalFragment.kt b/app/src/main/java/com/tangem/ui/fragment/additional/PrepareCryptonitWithdrawalFragment.kt deleted file mode 100644 index 3ff76912db..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/additional/PrepareCryptonitWithdrawalFragment.kt +++ /dev/null @@ -1,149 +0,0 @@ -package com.tangem.ui.fragment.additional - -import android.content.Context -import android.graphics.Color -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Bundle -import android.text.InputFilter -import android.view.View -import android.view.inputmethod.EditorInfo -import android.view.inputmethod.InputMethodManager -import android.widget.Toast -import com.tangem.data.Blockchain -import com.tangem.data.network.Cryptonit -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.fragment.BaseFragment -import com.tangem.util.DecimalDigitsInputFilter -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_prepare_cryptonit_withdrawal.* -import java.io.IOException - -class PrepareCryptonitWithdrawalFragment : BaseFragment(), NfcAdapter.ReaderCallback { - - companion object { - val TAG: String = PrepareCryptonitWithdrawalFragment::class.java.simpleName - } - - override val layoutId = R.layout.fragment_prepare_cryptonit_withdrawal - - private val ctx: TangemContext by lazy { TangemContext.loadFromBundle(context, arguments) } - private val cryptonit: Cryptonit by lazy { Cryptonit(context) } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - etUsername.setText(cryptonit.username) - etPassword.setText(cryptonit.password) - etFee.setText(cryptonit.fee) - - tvCardID.text = ctx.card!!.cidDescription - tvWallet.text = ctx.coinData!!.wallet - val engine = CoinEngineFactory.create(ctx) - - tvCurrency.text = engine!!.balanceCurrency - tvFeeCurrency.text = engine.feeCurrency - - etAmount.setText(engine.convertToAmount(engine.convertToInternalAmount(ctx.card!!.denomination)).toValueString()) - etAmount.filters = engine.amountInputFilters - - etAmount.setOnEditorActionListener { lv, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - val imm = lv.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(lv.windowToken, 0) - true - } else - false - } - - when (ctx.blockchain) { - Blockchain.Bitcoin -> { - etAmount.filters = arrayOf(DecimalDigitsInputFilter(5)) - etFee.filters = arrayOf(DecimalDigitsInputFilter(5)) - } - Blockchain.BitcoinCash -> { - etAmount.filters = arrayOf(DecimalDigitsInputFilter(8)) - etFee.filters = arrayOf(DecimalDigitsInputFilter(8)) - } - Blockchain.Ethereum -> { - etAmount.filters = arrayOf(DecimalDigitsInputFilter(18)) - etFee.filters = arrayOf(DecimalDigitsInputFilter(18)) - } - else -> { - } - } - - // set listeners - btnLoad.setOnClickListener { - try { - val strAmount: String = etAmount.text.toString().replace(",", ".") - val strFee: String = etFee.text.toString().replace(",", ".") - val dblAmount: Double = strAmount.toDouble() - cryptonit.fee = strFee - - rlProgressBar.visibility = View.VISIBLE - tvProgressDescription.text = getString(R.string.cryptonit_request_withdrawal) - - cryptonit.requestWithdrawCoins(ctx.blockchain.currency, dblAmount, ctx.coinData!!.wallet) - } catch (e: Exception) { - etAmount.error = getString(R.string.prepare_transaction_error_unknown_amount_format) - } - } - - ivRefreshBalance.setOnClickListener { - cryptonit.username = etUsername.text.toString() - cryptonit.password = etPassword.text.toString() - cryptonit.saveAccountInfo() - doRequestBalance() - } - - cryptonit.setBalanceListener { response -> - tvBalance.text = response.results[0].balance.toString() - tvBalanceCurrency.text = response.results[0].currency // card!!.blockchain.currency - tvBalance.setTextColor(Color.BLACK) - rlProgressBar.visibility = View.INVISIBLE - btnLoad.visibility = View.VISIBLE - } - cryptonit.setErrorListener { throwable -> - throwable.printStackTrace() - rlProgressBar.visibility = View.INVISIBLE - tvError.visibility = View.VISIBLE - tvError.text = throwable.message - } - cryptonit.setWithdrawalListener { response -> - rlProgressBar.visibility = View.INVISIBLE - if (response.success != null && response.success!!) { - Toast.makeText(context, R.string.withdrawal_successful, Toast.LENGTH_LONG).show(); - navigateUp() - } else { - tvError.visibility = View.VISIBLE - tvError.text = response.errors.toString() - } - } - btnLoad.visibility = View.INVISIBLE - doRequestBalance() - } - - override fun onTagDiscovered(tag: Tag) { - try { - (activity as MainActivity).nfcManager.ignoreTag(tag) - } catch (e: IOException) { - e.printStackTrace() - } - } - - private fun doRequestBalance() { - if (cryptonit.haveAccountInfo()) { - rlProgressBar.visibility = View.VISIBLE - tvProgressDescription.text = getString(R.string.cryptonit_request_balance) - tvError.visibility = View.INVISIBLE - cryptonit.requestBalance(ctx.blockchain.currency) - } else { - tvError.visibility = View.VISIBLE - tvError.text = getString(R.string.cryptonit_not_enough_account_data) - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/additional/PrepareKrakenWithdrawalFragment.kt b/app/src/main/java/com/tangem/ui/fragment/additional/PrepareKrakenWithdrawalFragment.kt deleted file mode 100644 index 00685a48df..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/additional/PrepareKrakenWithdrawalFragment.kt +++ /dev/null @@ -1,240 +0,0 @@ -package com.tangem.ui.fragment.additional - -import android.app.Activity -import android.app.AlertDialog -import android.content.Context -import android.content.DialogInterface -import android.graphics.Color -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Bundle -import android.view.View -import android.view.inputmethod.EditorInfo -import android.view.inputmethod.InputMethodManager -import android.widget.Toast -import com.tangem.Constant -import com.tangem.data.Blockchain -import com.tangem.data.network.Kraken -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_prepare_kraken_withdrawal.* -import java.io.IOException -import java.math.BigDecimal -import java.net.URI -import java.util.* - -class PrepareKrakenWithdrawalFragment : BaseFragment(), NavigationResultListener, - NfcAdapter.ReaderCallback { - - companion object { - val TAG: String = PrepareKrakenWithdrawalFragment::class.java.simpleName - } - - override val layoutId = R.layout.fragment_prepare_kraken_withdrawal - - private val ctx: TangemContext by lazy { TangemContext.loadFromBundle(context, arguments) } - private val kraken: Kraken by lazy { Kraken(context) } - - private var fee: BigDecimal? = null - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - tvKey.text = kraken.key - tvSecret.text = kraken.secretDescription - - tvCardID.text = ctx.card!!.cidDescription - tvWallet.text = ctx.coinData!!.wallet - val engine = CoinEngineFactory.create(ctx) - - tvCurrency.text = engine!!.balanceCurrency - - etAmount.setText(engine.convertToAmount(engine.convertToInternalAmount(ctx.card!!.denomination)).toValueString()) - etAmount.filters = engine.amountInputFilters - - etAmount.setOnEditorActionListener { lv, actionId, event -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - val imm = lv.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(lv.windowToken, 0) - lv.clearFocus() - true - } else { - false - } - } - - // set listeners - btnLoad.setOnClickListener { - try { - val strAmount: String = etAmount.text.toString().replace(",", ".") - - var dblAmount: Double = strAmount.toDouble() - rlProgressBar.visibility = View.VISIBLE - tvProgressDescription.text = getString(R.string.kraken_request_withdrawal) - - kraken.requestWithdrawInfo(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet) - } catch (e: Exception) { - etAmount.error = getString(R.string.prepare_transaction_error_unknown_amount_format) - } - - } - -// ivCamera.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR) } - - ivRefreshBalance.setOnClickListener { doRequestBalance() } - - kraken.setBalanceListener { response -> - if (response.error != null && response.error.isNotEmpty()) { - tvError.visibility = View.VISIBLE - tvError.text = Arrays.toString(response.error) - } else { - when (ctx.blockchain) { - Blockchain.Ethereum -> { - tvBalance.text = response.result.XETH.trimEnd('0') - } - Blockchain.Bitcoin -> { - tvBalance.text = response.result.XXBT.trimEnd('0') - } - Blockchain.BitcoinCash -> { - tvBalance.text = response.result.BCH.trimEnd('0') - } - else -> { - tvBalance.text = "???" - } - } - tvBalanceCurrency.text = ctx.blockchain.currency - tvBalance.setTextColor(Color.BLACK) - btnLoad.visibility = View.VISIBLE - } - rlProgressBar.visibility = View.INVISIBLE - } - kraken.setErrorListener { throwable -> - throwable.printStackTrace() - rlProgressBar.visibility = View.INVISIBLE - tvError.visibility = View.VISIBLE - tvError.text = throwable.message - } - kraken.setWithdrawalListener { response -> - rlProgressBar.visibility = View.INVISIBLE - if (response.error != null && response.error.isNotEmpty()) { - tvError.visibility = View.VISIBLE - tvError.text = Arrays.toString(response.error) - } else { - Toast.makeText(context, "Withdrawal successful!", Toast.LENGTH_LONG).show() - navigateUp() - } - } - kraken.setWithdrawalInfoListener { response -> - rlProgressBar.visibility = View.INVISIBLE - if (response.error != null && response.error.isNotEmpty()) { - tvError.visibility = View.VISIBLE - tvError.text = Arrays.toString(response.error) - } else { - fee = BigDecimal(response.result.fee) - showConfirmDialog() - } - } - - btnLoad.visibility = View.INVISIBLE - doRequestBalance() - } - - // Method to show an alert dialog with yes, no and cancel button - private fun showConfirmDialog() { - // Late initialize an alert dialog object - lateinit var dialog: AlertDialog - - - // Initialize a new instance of alert dialog builder object - val builder = AlertDialog.Builder(context) - - // Set a title for alert dialog - builder.setTitle(R.string.kraken_please_confirm_withdraw) - - // Set a message for alert dialog - builder.setMessage(String.format("Continue with fee %s %s?", fee!!.toString().trimEnd('0'), ctx.blockchain.currency)) - - // On click listener for dialog buttons - val dialogClickListener = DialogInterface.OnClickListener { _, which -> - when (which) { - DialogInterface.BUTTON_POSITIVE -> { - try { - val strAmount: String = etAmount.text.toString().replace(",", ".") - - var dblAmount: Double = strAmount.toDouble() - - dblAmount += fee!!.toDouble() - - rlProgressBar.visibility = View.VISIBLE - tvProgressDescription.text = getString(R.string.kraken_request_withdrawal) - - kraken.requestWithdraw(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet) - } catch (e: Exception) { - etAmount.error = getString(R.string.prepare_transaction_error_unknown_amount_format) - } - } - DialogInterface.BUTTON_NEGATIVE -> { - Toast.makeText(context, R.string.kraken_operation_canceled, Toast.LENGTH_LONG).show() - } - } - } - - // Set the alert dialog positive/yes button - builder.setPositiveButton(R.string.general_yes, dialogClickListener) - - // Set the alert dialog negative/no button - builder.setNegativeButton(R.string.general_no, dialogClickListener) - - - // Initialize the AlertDialog using builder object - dialog = builder.create() - - // Finally, display the alert dialog - dialog.show() - } - - private fun doRequestBalance() { - if (kraken!!.haveAccountInfo()) { - rlProgressBar.visibility = View.VISIBLE - tvProgressDescription.text = getString(R.string.kraken_request_balance) - tvError.visibility = View.INVISIBLE - kraken!!.requestBalance() - } else { - tvError.visibility = View.VISIBLE - tvError.text = getString(R.string.kraken_not_enough_account_data) - } - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - if (resultCode == Activity.RESULT_OK && data != null && data.containsKey("QRCode")) { - when (requestCode) { - Constant.REQUEST_CODE_SCAN_QR -> { - val uri = URI(data.getString("QRCode")) - val query = uri.query - val params = query.split("&") - for (param in params) { - if (param.startsWith("key=")) kraken.key = param.substring(4) - else if (param.startsWith("secret=")) kraken.secret = param.substring(7) - } - tvKey!!.text = kraken.key - tvSecret!!.text = kraken.secretDescription - } - } - kraken.saveAccountInfo() - doRequestBalance() - } - } - - override fun onTagDiscovered(tag: Tag) { - try { - (activity as MainActivity).nfcManager.ignoreTag(tag) - } catch (e: IOException) { - e.printStackTrace() - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/additional/TagFragment.kt b/app/src/main/java/com/tangem/ui/fragment/additional/TagFragment.kt deleted file mode 100644 index 8514ccf37c..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/additional/TagFragment.kt +++ /dev/null @@ -1,212 +0,0 @@ -package com.tangem.ui.fragment.additional - -import android.app.Activity -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context -import android.content.Intent -import android.os.Build -import android.os.Bundle -import android.text.Html -import android.view.View -import android.widget.Toast -import androidx.core.content.ContextCompat -import com.tangem.data.network.ServerApiCommon -import com.tangem.server_android.ServerApiTangem -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.fragment.wallet.LoadedWalletFragment -import com.tangem.ui.fragment.wallet.LoadedWalletViewModel -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.util.LOG -import com.tangem.util.UtilHelper -import com.tangem.wallet.* -import com.tangem.wallet.xlmTag.XlmTagEngine -import kotlinx.android.synthetic.main.fr_loaded_wallet.* -import kotlinx.android.synthetic.main.layout_btn_details.* -import kotlinx.android.synthetic.main.layout_tangem_card.* - - -class TagFragment : BaseFragment(), NavigationResultListener { - override val layoutId = R.layout.fragment_tag - private lateinit var viewModel: LoadedWalletViewModel - private lateinit var ctx: TangemContext - private var serverApiCommon: ServerApiCommon = ServerApiCommon() - private var serverApiTangem: ServerApiTangem = ServerApiTangem() - - private var requestCounter: Int = 0 - set(value) { - field = value - LOG.i(LoadedWalletFragment.TAG, "requestCounter, set $field") - if (field <= 0) { - LOG.e(LoadedWalletFragment.TAG, "+++++++++++ FINISH REFRESH") - if (srl != null && srl.isRefreshing) - srl.isRefreshing = false - } else if (srl != null && !srl.isRefreshing) - srl.isRefreshing = true - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val engine = XlmTagEngine(ctx) - - - btnLoad.visibility = View.GONE - btnDetails.visibility = View.GONE - btnExtract.text = getString(R.string.tag_claim) - btnExtract.isEnabled = false //TODO: enable when we implement extraction - btnExtract.backgroundTintList = - ContextCompat.getColorStateList(requireContext(), R.color.btn_dark) - - ivTangemCard.setImageResource(R.drawable.card_tgslix) - - tvBalance.setSingleLine(!engine.needMultipleLinesForBalance()) - tvWallet.text = ctx.coinData.wallet - tvWallet.setOnClickListener { shareWallet() } - btnExplore.setOnClickListener { startActivity(Intent(Intent.ACTION_VIEW, engine.walletExplorerUri)) } - btnCopy.setOnClickListener { shareWallet() } - btnNewScan.setOnClickListener { navigateUp() } - srl?.setOnRefreshListener { refresh(true) } - - requestBalanceAndUnspentTransactions() - } - - - private fun shareWallet() { - val txtShare = ctx.coinData.wallet - val clipboard = activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - clipboard.primaryClip = ClipData.newPlainText(txtShare, txtShare) - Toast.makeText(activity, R.string.loaded_wallet_toast_copied, Toast.LENGTH_LONG).show() - } - - - private fun update() { - ctx.coinData.setIsBalanceEqual(true) - - if (srl.isRefreshing) { - tvBalanceLine1.setTextColor(resources.getColor(R.color.primary)) - tvBalanceLine1.text = getString(R.string.loaded_wallet_verifying_in_blockchain) - tvBalanceLine2.text = "" - tvBalance.text = "" - tvBalanceEquivalent.text = "" - } else { - val validator = BalanceValidator() - validator.check(ctx, false) - context?.let { ContextCompat.getColor(it, validator.color) }?.let { tvBalanceLine1?.setTextColor(it) } - tvBalanceLine1?.text = getString(validator.firstLine) - tvBalanceLine2?.text = getString(validator.getSecondLine(false)) - } - - val engine = CoinEngineFactory.create(ctx) - when { - engine!!.hasBalanceInfo() -> { - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(engine.balanceHTML, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(engine.balanceHTML) - tvBalance.text = html - tvBalanceEquivalent.text = engine.balanceEquivalent - } - - ctx.card?.offlineBalance != null -> { - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(engine.offlineBalanceHTML, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(engine.offlineBalanceHTML) - tvBalance.text = html - } - - else -> tvBalance.text = "" - } - - - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(ctx.blockchainName, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(ctx.blockchainName) - tvBlockchain.text = html - - - } - - private fun requestBalanceAndUnspentTransactions() { - if (UtilHelper.isOnline(context as Activity)) { - val coinEngine = CoinEngineFactory.create(ctx) - requestCounter++ - coinEngine!!.requestBalanceAndUnspentTransactions( - object : CoinEngine.BlockchainRequestsCallbacks { - - override fun onComplete(success: Boolean) { - LOG.i(TAG, "requestBalanceAndUnspentTransactions onComplete: $success, request counter $requestCounter") - if (activity == null) return - requestCounter-- - if (!success) { - LOG.e(TAG, "requestBalanceAndUnspentTransactions ctx.error: " + ctx.error) - } - update() - } - - override fun onProgress() { - if (activity == null) return - LOG.i(TAG, "requestBalanceAndUnspentTransactions onProgress") -// update() - } - - override fun allowAdvance(): Boolean { - return try { - context?.let { UtilHelper.isOnline(it) }!! - } catch (e: KotlinNullPointerException) { - e.printStackTrace() - false - } - } - } - ) - } else { - ctx.error = getString(R.string.general_error_no_connection) - update() - } - } - - private fun refresh(clearData: Boolean = true) { - if (ctx.card == null) return - - // clear all card data and request again - ctx.coinData.clearInfo() - - if (clearData) { - ctx.error = null - ctx.message = null - } - - LOG.w(TAG, "============= START REFRESH") - requestCounter = 0 - srl?.isRefreshing = true - - update() - - ctx.coinData.setIsBalanceEqual(true) - - - requestBalanceAndUnspentTransactions() - - if (requestCounter == 0) { - // if no connection and no requests posted - srl?.isRefreshing = false - update() - } - } - - companion object { - val TAG: String = TagFragment::class.java.simpleName - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/id/CameraFragment.kt b/app/src/main/java/com/tangem/ui/fragment/id/CameraFragment.kt deleted file mode 100644 index 24c6143377..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/id/CameraFragment.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.tangem.ui.fragment.id - -import android.app.Activity -import android.os.Bundle -import android.view.View -import androidx.core.os.bundleOf -import com.otaliastudios.cameraview.CameraListener -import com.otaliastudios.cameraview.PictureResult -import com.otaliastudios.cameraview.controls.Facing -import com.tangem.ui.fragment.BaseFragment -import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_camera.* - - -class CameraFragment : BaseFragment() { - override val layoutId = R.layout.fragment_camera - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - cvCamera?.setLifecycleOwner(viewLifecycleOwner) - - cvCamera?.addCameraListener(object : CameraListener() { - override fun onPictureTaken(result: PictureResult) { // Picture was taken! - - result.toBitmap(200, 200) { - navigateBackWithResult(Activity.RESULT_OK, bundleOf(PHOTO_KEY to it)) - } - } - }) - ivTakePicture?.setOnClickListener { cvCamera?.takePictureSnapshot() } - ivFlipCamera?.setOnClickListener { flipCamera() } - } - - private fun flipCamera() { - if (cvCamera?.facing == Facing.BACK) { - cvCamera?.facing = Facing.FRONT - } else { - cvCamera?.facing = Facing.BACK - } - } - - companion object{ - const val PHOTO_KEY = "photo" - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/id/IdFragment.kt b/app/src/main/java/com/tangem/ui/fragment/id/IdFragment.kt deleted file mode 100644 index f37118f1ba..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/id/IdFragment.kt +++ /dev/null @@ -1,467 +0,0 @@ -package com.tangem.ui.fragment.id - -import android.app.Activity -import android.content.SharedPreferences -import android.graphics.BitmapFactory -import android.media.MediaPlayer -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Bundle -import android.util.Log -import android.view.View -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.ContextCompat -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.data.Blockchain -import com.tangem.data.network.ServerApiCommon -import com.tangem.server_android.ServerApiTangem -import com.tangem.server_android.model.CardVerifyAndGetInfo -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.VerifyCardTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.fragment.BaseFragment -import com.tangem.util.LOG -import com.tangem.util.UtilHelper -import com.tangem.wallet.* -import kotlinx.android.synthetic.main.fragment_id.* -import kotlinx.android.synthetic.main.layout_btn_details.* -import kotlinx.android.synthetic.main.layout_id.* -import kotlinx.android.synthetic.main.layout_tangem_card.* -import kotlinx.android.synthetic.main.layout_tangem_card.rlProgressBar -import net.i2p.crypto.eddsa.Utils -import java.util.* -import kotlin.concurrent.timerTask - -class IdFragment : BaseFragment(), NfcAdapter.ReaderCallback, - CardProtocol.Notifications, SharedPreferences.OnSharedPreferenceChangeListener { - companion object { - val TAG: String = IdFragment::class.java.simpleName - } - - override val layoutId = R.layout.fragment_id - - private lateinit var ctx: TangemContext - private lateinit var mpSecondScanSound: MediaPlayer - private var serverApiCommon: ServerApiCommon = ServerApiCommon() - private var serverApiTangem: ServerApiTangem = ServerApiTangem() - private var lastTag: Tag? = null - private var lastReadSuccess = true - private var verifyCardTask: VerifyCardTask? = null - private var requestPIN2Count = 0 - private var timerHideErrorAndMessage: Timer? = null - private var newPIN = "" - private var newPIN2 = "" - private var photo: ByteArray? = null - private var cardProtocol: CardProtocol? = null - private var refreshAction: Runnable? = null - private var hasIdInfo: Boolean? = null - private var toast: Toast? = null - - private var requestCounter: Int = 0 - set(value) { - field = value - LOG.i(TAG, "requestCounter, set $field") - if (field <= 0) { - LOG.e(TAG, "+++++++++++ FINISH REFRESH") - if (srl != null && srl.isRefreshing) - srl.isRefreshing = false - } else if (srl != null && !srl.isRefreshing) - srl.isRefreshing = true - } - - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - - lastTag = activity?.intent?.getParcelableExtra(Constant.EXTRA_LAST_DISCOVERED_TAG) - - if (arguments?.containsKey(NfcAdapter.EXTRA_TAG) == true) { - val tag = arguments!!.getParcelable(NfcAdapter.EXTRA_TAG) - if (tag != null) onTagDiscovered(tag) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - mpSecondScanSound = MediaPlayer.create(activity, R.raw.scan_card_sound) - - tvIdNumber?.text = "ID # ${Utils.bytesToHex(ctx.card.cid)}" - - if (hasIdInfo == false) rlToolButtons?.visibility = View.VISIBLE - - // set listeners - srl.setOnRefreshListener { refresh() } - - btnDetails.setOnClickListener { - if (cardProtocol != null) { - val bundle = Bundle().apply { ctx.saveToBundle(this) } - navigateForResult(Constant.REQUEST_CODE_VERIFY_CARD, - R.id.action_idFragment_to_verifyCard, bundle) - } else { - (activity as MainActivity).toastHelper - .showSingleToast(context, getString(R.string.general_notification_scan_again_to_verify)) - } - } - - btnIssueNewId?.setOnClickListener { - val bundle = Bundle().apply { ctx.saveToBundle(this) } - navigateToDestination(R.id.action_idFragment_to_issueNewIdFragment, bundle) - } - - if (hasIdInfo == null) tvBalanceLine1?.text = "Reading... Hold the card firmly" - - btnNewScan.setOnClickListener { - navigateUp() - } - - // request card verify and get info listener - val cardVerifyAndGetInfoListener: ServerApiTangem.CardVerifyAndGetInfoListener = object : ServerApiTangem.CardVerifyAndGetInfoListener { - override fun onSuccess(cardVerifyAndGetArtworkResponse: CardVerifyAndGetInfo.Response?) { - LOG.i(TAG, "cardVerifyAndGetInfoListener onSuccess") - if (activity == null || !UtilHelper.isOnline(activity!!)) return - - val result = cardVerifyAndGetArtworkResponse?.results!![0] - if (result.error != null) { - ctx.card!!.isOnlineVerified = false - return - } - ctx.card!!.isOnlineVerified = result.passed - - requestCounter-- - updateViews() - - if (!result.passed) return - - if (App.localStorage.checkBatchInfoChanged(ctx.card!!, result)) { - LOG.w(TAG, "Batch ${result.batch} info changed to '$result'") - ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!)) - App.localStorage.applySubstitution(ctx.card!!) - refresh() - } - } - - override fun onFail(message: String?) { - LOG.i(TAG, "cardVerifyAndGetInfoListener onFail") - if (activity == null || !UtilHelper.isOnline(activity!!)) return - requestCounter-- - updateViews() - } - } - serverApiTangem.setCardVerifyAndGetInfoListener(cardVerifyAndGetInfoListener) - refresh() - startVerify(lastTag) - } - - override fun onPause() { - super.onPause() - if (timerHideErrorAndMessage != null) { - timerHideErrorAndMessage!!.cancel() - timerHideErrorAndMessage = null - } - } - - override fun onStop() { - srl?.removeCallbacks(refreshAction) - toast?.cancel() - super.onStop() - } - - - override fun onTagDiscovered(tag: Tag) { - startVerify(tag) - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar?.visibility = View.VISIBLE } - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - verifyCardTask = null - if (cardProtocol != null) { - if (cardProtocol.error == null) { - rlProgressBar?.post { - rlProgressBar?.visibility = View.GONE - this.cardProtocol = cardProtocol - if (!cardProtocol.card.isWalletPublicKeyValid) - refresh() - else - updateViews() - - if (cardProtocol.card.isIDCard) { - if (cardProtocol.card.hasIDCardData()) { - - ctx.card = cardProtocol.card - - tvBalanceLine1?.visibility = View.VISIBLE - - val idCardData = ctx.card.idCardData - tvFullName.text = idCardData.fullName - tvBirthDate.text = idCardData.birthday - tvGender.text = "Sex: ${idCardData.gender}" - ivPhoto.setImageBitmap(BitmapFactory.decodeByteArray(idCardData.photo, 0, idCardData.photo.size)) - - val inputs = "${idCardData.fullName};${idCardData.birthday}${idCardData.gender}" - val info = inputs.toByteArray() + idCardData.photo - ctx.card.idHash = Util.calculateSHA256(info) - - refresh() - - } else { - rlToolButtons?.visibility = View.VISIBLE - tvBalanceLine1?.text = resources.getString(R.string.id_empty).toUpperCase(Locale.ENGLISH) - tvBalanceLine1?.setTextSize(18F) - tvBalanceLine1?.visibility = View.VISIBLE - hasIdInfo = false - } - } - - mpSecondScanSound.start() - } - } else { - Log.d(this.javaClass.simpleName, - "Error while reading ID card: ${cardProtocol.error.localizedMessage}") - // remove last UIDs because of error and no card read - FirebaseCrashlytics.getInstance().recordException(cardProtocol.error) - rlProgressBar?.post { - lastReadSuccess = false - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) - if (!NoExtendedLengthSupportDialog.allReadyShowed) - activity?.supportFragmentManager?.let { NoExtendedLengthSupportDialog().show(it, NoExtendedLengthSupportDialog.TAG) } - else { - toast = Toast.makeText(activity, R.string.general_notification_scan_again, Toast.LENGTH_SHORT) - toast?.show() - } - } - } - } - - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadCancel() { - verifyCardTask = null - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadWait(msec: Int) { - WaitSecurityDelayDialog.onReadWait(activity as AppCompatActivity?, msec) - } - - override fun onReadBeforeRequest(timeout: Int) { - WaitSecurityDelayDialog.onReadBeforeRequest(activity as AppCompatActivity?, timeout) - } - - override fun onReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(activity) - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - - } - - fun updateViews() { - if (activity == null || this.view == null) return - - if (timerHideErrorAndMessage != null) { - timerHideErrorAndMessage!!.cancel() - timerHideErrorAndMessage = null - } - - if (ctx.card?.idCardData?.photo != null && (photo == null)) { - photo = ctx.card.idCardData.photo - ivPhoto.setImageBitmap(BitmapFactory.decodeByteArray(photo, 0, photo!!.size)) - - } - - if (ctx.hasError()) { - tvError?.visibility = View.VISIBLE - tvError?.text = ctx.error - } else { - tvError?.visibility = View.GONE - tvError?.text = "" - } - - if (ctx.message == null || ctx.message.isEmpty()) { - tvMessage?.text = "" - tvMessage?.visibility = View.GONE - } else { - tvMessage?.text = ctx.message - tvMessage?.visibility = View.VISIBLE - } - - if (tvError?.visibility == View.VISIBLE || tvMessage?.visibility == View.VISIBLE) { - timerHideErrorAndMessage = Timer() - timerHideErrorAndMessage?.schedule( - timerTask { - activity?.runOnUiThread { - tvMessage?.visibility = View.GONE - tvError?.visibility = View.GONE - // clear only already viewed messages - if (tvMessage?.text == ctx.message) ctx.message = null - if (tvError?.text == ctx.error) ctx.error = null - } - }, - 5000) - } - - if (srl.isRefreshing && ctx.card?.hasIDCardData() != false) { - tvBalanceLine1.setTextColor(resources.getColor(R.color.primary)) - tvBalanceLine1.text = getString(R.string.loaded_wallet_verifying_in_blockchain) - tvBalanceLine2.text = "" - } else if (ctx.card?.hasIDCardData() != false) { - - val validator = BalanceValidator() - // TODO why attest=false? - validator.check(ctx, false) - context?.let { ContextCompat.getColor(it, validator.color) }?.let { tvBalanceLine1?.setTextColor(it) } - tvBalanceLine1?.text = getString(validator.firstLine) - tvBalanceLine2?.text = getString(validator.getSecondLine(false)).format(ctx.card.idCardData.trustedAddress) - } - - if (ctx.card.hasIDCardData()) { - val idCardData = ctx.card.idCardData - tvFullName.text = idCardData.fullName - tvBirthDate.text = idCardData.birthday - tvGender.text = "Sex: ${idCardData.gender}" - ivPhoto.setImageBitmap(BitmapFactory.decodeByteArray(idCardData.photo, 0, idCardData.photo.size)) - rlToolButtons?.visibility = View.GONE - } - } - - private fun refresh() { - if (ctx.card == null) return - - // clear all card data and request again - ctx.coinData.clearInfo() - ctx.error = null - ctx.message = null - - LOG.w(TAG, "============= START REFRESH") - requestCounter = 0 - srl?.isRefreshing = true - - updateViews() - - // Bitcoin, Litecoin, BitcoinCash, Stellar - if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet || ctx.blockchain == Blockchain.BitcoinDual || - ctx.blockchain == Blockchain.Litecoin || ctx.blockchain == Blockchain.BitcoinCash || - ctx.blockchain == Blockchain.Stellar || ctx.blockchain == Blockchain.StellarTestNet || ctx.blockchain == Blockchain.StellarAsset) { - ctx.coinData.setIsBalanceEqual(true) - } - - requestVerifyAndGetInfo() - - if (ctx.card.hasIDCardData()) requestBalanceAndUnspentTransactions() - - if (requestCounter == 0) { - // if no connection and no requests posted - srl?.isRefreshing = false - updateViews() - } - } - - private fun requestBalanceAndUnspentTransactions() { - if (UtilHelper.isOnline(context as Activity)) { - val coinEngine = CoinEngineFactory.create(ctx) - coinEngine?.defineWallet() - requestCounter++ - coinEngine!!.requestBalanceAndUnspentTransactions( - object : CoinEngine.BlockchainRequestsCallbacks { - - - override fun onComplete(success: Boolean) { - LOG.i(TAG, "requestBalanceAndUnspentTransactions onComplete: $success, request counter $requestCounter") - if (activity == null) return - requestCounter-- - if (!success) { - LOG.e(TAG, "requestBalanceAndUnspentTransactions ctx.error: " + ctx.error) - } - updateViews() - - } - - override fun onProgress() { - if (activity == null) return - LOG.i(TAG, "requestBalanceAndUnspentTransactions onProgress") - updateViews() - } - - override fun allowAdvance(): Boolean { - return try { - context?.let { UtilHelper.isOnline(it) }!! - } catch (e: KotlinNullPointerException) { - e.printStackTrace() - false - } - } - } - ) - } else { - ctx.error = getString(R.string.general_error_no_connection) - updateViews() - } - } - - private fun requestVerifyAndGetInfo() { - if (UtilHelper.isOnline(context as Activity)) { - if ((ctx.card!!.isOnlineVerified == null || !ctx.card!!.isOnlineVerified)) { - LOG.i(TAG, "requestVerifyAndGetInfo") - requestCounter++ - serverApiTangem.cardVerifyAndGetInfo(ctx.card) - } - } else { - ctx.error = getString(R.string.general_error_no_connection) - updateViews() - } - } - - private fun startVerify(tag: Tag?) { - try { - val isoDep = IsoDep.get(tag) - val uid = tag?.id - val sUID = Util.byteArrayToHexString(uid) - if (ctx.card.uid != sUID || cardProtocol != null) { - (activity as MainActivity).nfcManager.ignoreTag(isoDep.tag) - return - } - - if (lastReadSuccess) - isoDep.timeout = 1000 - else - isoDep.timeout = 65000 - - verifyCardTask = VerifyCardTask(ctx.card, NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, App.firmwaresStorage, this) - verifyCardTask?.start() - } catch (e: Exception) { - e.printStackTrace() - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/id/IssueNewIdFragment.kt b/app/src/main/java/com/tangem/ui/fragment/id/IssueNewIdFragment.kt deleted file mode 100644 index 8418037d86..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/id/IssueNewIdFragment.kt +++ /dev/null @@ -1,258 +0,0 @@ -package com.tangem.ui.fragment.id - -import android.app.Activity -import android.graphics.Bitmap -import android.os.Bundle -import android.os.Parcelable -import android.text.Editable -import android.text.TextWatcher -import android.util.Log -import android.view.View -import android.widget.EditText -import android.widget.RadioButton -import android.widget.Toast -import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf -import com.tangem.tangem_card.util.Util -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import com.tangem.wallet.ethID.EthIdEngine -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_issue_new_id.* -import java.io.ByteArrayOutputStream -import java.text.SimpleDateFormat -import java.util.* - - -class IssueNewIdFragment : BaseFragment(), NavigationResultListener { - lateinit var ctx: TangemContext - private var photo: Bitmap? = null - private var photoInBytes: ByteArray? = null - private var gender: Gender? = null - private var userIdData: UserIdData? = null - - override val layoutId = R.layout.fragment_issue_new_id - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - - ivPhoto?.setOnClickListener { - navigateForResult(GET_PHOTO_REQUEST_CODE, R.id.action_issueNewIdFragment_to_cameraFragment) - } - - if (photo != null) ivPhoto?.setImageBitmap(photo) - - btnConfirm?.setOnClickListener { - if (!checkIfInfoProvided()) { - Toast.makeText(context, "Fill in all data first", Toast.LENGTH_LONG).show() - return@setOnClickListener - } - try { - processData() - } catch (exception: Exception) { - Log.e(this.javaClass.simpleName, - "Exception while processing data: ${exception.localizedMessage}") - Toast.makeText(context, "Check for correctness of data", Toast.LENGTH_LONG).show() - return@setOnClickListener - } - val bundle = bundleOf(USER_ID_DATA to userIdData) - ctx.saveToBundle(bundle) - navigateToDestination(R.id.action_issueNewIdFragment_to_validateIdFragment, bundle) - } - - rbFemale?.setOnClickListener { onRadioButtonClicked(it) } - rbMale?.setOnClickListener { onRadioButtonClicked(it) } - - DateInputMask(etBirthDate).listen() -// etBirthDate?.addTextChangedListener(MaskWatcher("##/##/####")) - - } - - private fun onRadioButtonClicked(view: View) { - if (view is RadioButton) { - when (view.getId()) { - R.id.rbFemale -> - if (view.isChecked) { - gender = Gender.F - } - R.id.rbMale -> - if (view.isChecked) { - gender = Gender.M - } - } - } - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - if (requestCode == GET_PHOTO_REQUEST_CODE) { - if (resultCode == Activity.RESULT_OK) { - photo = data?.getParcelable(CameraFragment.PHOTO_KEY) - ivPhoto?.setImageBitmap(photo) - val out = ByteArrayOutputStream() - photo!!.compress(Bitmap.CompressFormat.JPEG, 100, out) - photoInBytes = out.toByteArray() - } - } - } - - - private fun checkIfInfoProvided(): Boolean { - return (etName.text.isNotBlank() && etSurname.text.isNotBlank() && etBirthDate.text.isNotBlank() && - (photo != null) && (gender != null)) - } - - private fun processData() { - val name = etName.text.toString() - val lastName = etSurname.text.toString() - val birthDate = convertDate(etBirthDate.text) - userIdData = UserIdData(name, lastName, birthDate, gender.toString(), photo!!) - val issuerExpireDate = processIssueExpireDate() - - ctx.card.setTlvIDCardData( - "$name $lastName", - birthDate, - gender.toString(), - photoInBytes, - issuerExpireDate.issueDate, - issuerExpireDate.expireDate, - (CoinEngineFactory.create(ctx) as? EthIdEngine)?.coinData?.approvalAddress - ) - - val inputs = "$name $lastName;$birthDate${gender.toString()}" - val info = inputs.toByteArray() + photoInBytes!! - ctx.card.idHash = Util.calculateSHA256(info) - - Log.d(this.javaClass.simpleName, - "ID info provided: $inputs,\n photo of size ${photoInBytes?.size}") - } - - private fun convertDate(inputDate: CharSequence): String { - val calendar = Calendar.getInstance() - calendar.clear() - val sdf = SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH) - try { - calendar.time = sdf.parse(inputDate.toString()) - } catch (exception: Error) { - etBirthDate.setTextColor(ContextCompat.getColor(requireContext(), R.color.bg_err)) - } - calendar.set(Calendar.HOUR_OF_DAY, 0) - calendar.timeZone = SimpleTimeZone(0, "UTC") - val dateFormat = SimpleDateFormat("yyyy.MM.dd", Locale.ENGLISH) - dateFormat.timeZone = SimpleTimeZone(0, "UTC") - return dateFormat.format(calendar.time) - } - - private fun processIssueExpireDate(): IssuerExpireDate { - val dt = Date() - val issueDate = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(dt) - dt.year = dt.year + 10 - val expireDate = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(dt) - return IssuerExpireDate(issueDate, expireDate) - } - - data class IssuerExpireDate(val issueDate: String, val expireDate: String) - - companion object { - const val SEPARATOR = ";" - const val COMPUTED_PUB_KEY = "ComputedPubKey" - const val GET_PHOTO_REQUEST_CODE = "GetPhoto" - const val USER_ID_DATA = "UserIdData" - } -} - - -enum class Gender { M, F } - -@Parcelize -data class UserIdData( - val firstName: String, - val lastName: String, - val birthDate: String, - val gender: String, - val photo: Bitmap -) : Parcelable - -class DateInputMask(val input: EditText) { - fun listen() { - input.addTextChangedListener(dateEntryWatcher) - } - - private val dateEntryWatcher = object : TextWatcher { - - var edited = false - val dividerCharacter = "/" - - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - if (edited) { - edited = false - return - } - - var working = getEditText() - - working = manageDateDivider(working, 2, start, before) - working = manageDateDivider(working, 5, start, before) - - edited = true - input.setText(working) - input.setSelection(input.text.length) - } - - private fun manageDateDivider(working: String, position: Int, start: Int, before: Int): String { - if (working.length == position) { - return if (before <= position && start < position) - working + dividerCharacter - else - working.dropLast(1) - } - return working - } - - private fun getEditText(): String { - return if (input.text.length >= 10) - input.text.toString().substring(0, 10) - else - input.text.toString() - } - - override fun afterTextChanged(s: Editable) {} - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} - } -} - -class MaskWatcher(private val mask: String) : TextWatcher { - private var isRunning = false - private var isDeleting = false - override fun beforeTextChanged(charSequence: CharSequence, start: Int, count: Int, after: Int) { - isDeleting = count > after - } - - override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) {} - override fun afterTextChanged(editable: Editable) { - if (isRunning || isDeleting) { - return - } - isRunning = true - val editableLength = editable.length - if (editableLength < mask.length) { - if (mask[editableLength] != '#') { - editable.append(mask[editableLength]) - } else if (mask[editableLength - 1] != '#') { - editable.insert(editableLength - 1, mask, editableLength - 1, editableLength) - } - } - if (editableLength > mask.length) editable.delete(editable.lastIndex, editableLength) - isRunning = false - } - - companion object { - fun buildCpf(): MaskWatcher { - return MaskWatcher("###.###.###-##") - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/id/ValidateIdFragment.kt b/app/src/main/java/com/tangem/ui/fragment/id/ValidateIdFragment.kt deleted file mode 100644 index ebbc5c2191..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/id/ValidateIdFragment.kt +++ /dev/null @@ -1,329 +0,0 @@ -package com.tangem.ui.fragment.id - -import android.app.Activity -import android.content.res.ColorStateList -import android.graphics.Color -import android.media.MediaPlayer -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Bundle -import android.util.Log -import android.view.View -import androidx.activity.OnBackPressedCallback -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.OneTouchSignTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.data.PINStorage -import com.tangem.tangem_sdk.android.nfc.NfcDeviceAntennaLocation -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.asBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.util.LOG -import com.tangem.wallet.CoinEngine -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.layout_progress_horizontal.* -import kotlinx.android.synthetic.main.layout_touch_card.* - -class ValidateIdFragment : BaseFragment(), NavigationResultListener, - NfcAdapter.ReaderCallback, CardProtocol.Notifications { - - companion object { - val TAG: String = ValidateIdFragment::class.java.simpleName - } - - override val layoutId = R.layout.fragment_validate_id - - private lateinit var ctx: TangemContext - private lateinit var mpFinishSignSound: MediaPlayer - - private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation - - private var signTransactionTask: OneTouchSignTask? = null - - private lateinit var amount: CoinEngine.Amount - private lateinit var fee: CoinEngine.Amount - private var isIncludeFee = true - private var outAddressStr: String? = null - private var lastReadSuccess = true - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - - val callback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - navigateBackWithResult(Activity.RESULT_CANCELED) - } - } - requireActivity().onBackPressedDispatcher.addCallback(this, callback) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - mpFinishSignSound = MediaPlayer.create(context, R.raw.scan_card_sound) - - // init NFC Antenna - nfcDeviceAntenna = NfcDeviceAntennaLocation(requireContext(), ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc) - nfcDeviceAntenna.init() - - progressBar.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar.visibility = View.INVISIBLE - } - - override fun onPause() { - signTransactionTask?.cancel(true) - super.onPause() - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - if (requestCode == Constant.REQUEST_CODE_SEND_TRANSACTION_) { - navigateBackWithResult(resultCode, data) - } - } - - override fun onTagDiscovered(tag: Tag) { - try { - // get IsoDep handle and run cardReader thread - val isoDep = IsoDep.get(tag) - val uid = tag.id - val sUID = Util.byteArrayToHexString(uid) - - if (lastReadSuccess) - isoDep.timeout = ctx.card.pauseBeforePIN2 + 5000 - else - isoDep.timeout = ctx.card.pauseBeforePIN2 + 65000 - - val coinEngine = CoinEngineFactory.create(ctx) - coinEngine?.defineWallet() - - coinEngine?.setOnNeedSendTransaction { tx -> - if (tx != null) { - val data = Bundle() - ctx.saveToBundle(data) - data.putByteArray(Constant.EXTRA_TX, tx) - - Log.d(this.javaClass.simpleName, - "Transaction is ready to be sent.") - - navigateForResult( - Constant.REQUEST_CODE_SEND_TRANSACTION_, - R.id.action_validateIdFragment_to_writeIdFragment, - data) - } - } - - coinEngine?.requestBalanceAndUnspentTransactions(object : CoinEngine.BlockchainRequestsCallbacks { - override fun onComplete(success: Boolean?) { - val transactionToSign = coinEngine.constructTransaction(null, null, true, null) - - val transaction = object : OneTouchSignTask.TransactionToSign{ - override fun isIssuerCanSignTransaction(card: TangemCard?): Boolean { - return false - } - - override fun isIssuerCanSignData(card: TangemCard?): Boolean { - return false - } - - override fun getHashAlgToSign(card: TangemCard?): String { - return transactionToSign.hashAlgToSign - } - - override fun getRawDataToSign(card: TangemCard?): ByteArray { - return transactionToSign.rawDataToSign - } - - override fun isSigningOnCardSupported(card: TangemCard?): Boolean { - return true - } - - override fun onSignCompleted(card: TangemCard?, signature: ByteArray?) { - transactionToSign.onSignCompleted(signature) - } - - override fun getHashesToSign(card: TangemCard?): Array { - return transactionToSign.hashesToSign - } - - override fun getIssuerTransactionSignature(card: TangemCard?, dataToSignByIssuer: ByteArray?): ByteArray { - return transactionToSign.getIssuerTransactionSignature(dataToSignByIssuer) - } - - } - - PINStorage.setPIN2(PINStorage.getDefaultPIN2()) - Log.d(this.javaClass.simpleName, - "Ready to sing transaction, launching OneTouchSignTask") - signTransactionTask = OneTouchSignTask(NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, this@ValidateIdFragment, transaction) - signTransactionTask?.start() - } - - override fun onProgress() { - } - - override fun allowAdvance(): Boolean { - return true - } - }) - - - } catch (e: CardProtocol.TangemException_WrongAmount) { - try { - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.send_transaction_error_wrong_amount)) - data.putString(EXTRA_TANGEM_CARD_UID, ctx.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, ctx.card.asBundle) - navigateBackWithResult(Activity.RESULT_CANCELED, data) - } catch (e: Exception) { - e.printStackTrace() - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar.visibility = View.VISIBLE } - - progressBar?.post { - progressBar?.visibility = View.VISIBLE - progressBar?.progress = 5 - } - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - progressBar?.post { progressBar?.progress = progress } - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - signTransactionTask = null - if (cardProtocol != null) { - if (cardProtocol.error == null) { - rlProgressBar?.post { rlProgressBar?.visibility = View.GONE } - - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.GREEN) - } - - mpFinishSignSound.start() - } else { - Log.d(this.javaClass.simpleName, - "Error while signing with ID Issuer card: ${cardProtocol.error.localizedMessage}") - FirebaseCrashlytics.getInstance().recordException(cardProtocol.error) - lastReadSuccess = false - if (cardProtocol.error.javaClass == CardProtocol.TangemException_InvalidPIN::class.java) { - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.send_transaction_error_cannot_sign)) - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - navigateBackWithResult(Constant.RESULT_INVALID_PIN_, data) - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } else { - if (cardProtocol.error is CardProtocol.TangemException_WrongAmount) { - try { - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.send_transaction_error_wrong_amount)) - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - navigateBackWithResult(Activity.RESULT_CANCELED, data) - } catch (e: Exception) { - e.printStackTrace() - } - } - progressBar?.post { - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allReadyShowed) { - NoExtendedLengthSupportDialog.message = getText(R.string.dialog_the_nfc_adapter_length_apdu).toString() + "\n" + getText(R.string.dialog_the_nfc_adapter_length_apdu_advice).toString() - NoExtendedLengthSupportDialog().show(requireFragmentManager(), NoExtendedLengthSupportDialog.TAG) - } - } else { - (activity as? MainActivity)?.toastHelper?.showSingleToast( - context, - getString(R.string.general_notification_scan_again) - ) - } - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - } - } - } - - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadCancel() { - signTransactionTask = null - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - - override fun onReadBeforeRequest(timeout: Int) { - LOG.i(TAG, "onReadBeforeRequest timeout $timeout") - activity?.let { WaitSecurityDelayDialog.onReadBeforeRequest(it, timeout) } - } - - override fun onReadAfterRequest() { - LOG.i(TAG, "onReadAfterRequest") - activity?.let { WaitSecurityDelayDialog.onReadAfterRequest(it) } - } - - override fun onReadWait(msec: Int) { - LOG.i(TAG, "onReadWait msec $msec") - activity?.let { WaitSecurityDelayDialog.onReadWait(it, msec) } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/id/WriteIdFragment.kt b/app/src/main/java/com/tangem/ui/fragment/id/WriteIdFragment.kt deleted file mode 100644 index e0baa7b79d..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/id/WriteIdFragment.kt +++ /dev/null @@ -1,295 +0,0 @@ -package com.tangem.ui.fragment.id - -import android.app.Activity -import android.content.res.ColorStateList -import android.graphics.Color -import android.media.MediaPlayer -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Bundle -import android.util.Log -import android.view.View -import androidx.activity.OnBackPressedCallback -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.WriteIDCardTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.nfc.NfcDeviceAntennaLocation -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.asBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.util.LOG -import com.tangem.util.UtilHelper -import com.tangem.wallet.CoinEngine -import com.tangem.wallet.CoinEngineFactory -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.layout_progress_horizontal.* -import kotlinx.android.synthetic.main.layout_touch_card.* -import kotlinx.android.synthetic.tangemAccess.fragment_sign_transaction.* - -class WriteIdFragment : BaseFragment(), NavigationResultListener, - NfcAdapter.ReaderCallback, CardProtocol.Notifications { - - companion object { - val TAG: String = WriteIdFragment::class.java.simpleName - } - - override val layoutId = R.layout.fragment_write_id - - private lateinit var ctx: TangemContext - private lateinit var tx: ByteArray - private lateinit var mpFinishSignSound: MediaPlayer - - private var idWasWritten = false - - private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation - - private var writeIDCardTask: WriteIDCardTask? = null - - private var lastReadSuccess = true - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - tx = arguments?.getByteArray(Constant.EXTRA_TX)!! - - val callback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - navigateBackWithResult(Activity.RESULT_CANCELED) - } - } - requireActivity().onBackPressedDispatcher.addCallback(this, callback) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - mpFinishSignSound = MediaPlayer.create(context, R.raw.scan_card_sound) - - // init NFC Antenna - nfcDeviceAntenna = NfcDeviceAntennaLocation(requireContext(), ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc) - nfcDeviceAntenna.init() - - tvCardID.text = ctx.card!!.cidDescription - progressBar.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar.visibility = View.INVISIBLE - tvProgressBar?.text = "Writing..." - } - - override fun onPause() { - writeIDCardTask?.cancel(true) - super.onPause() - } - - override fun onStop() { - writeIDCardTask?.cancel(true) - super.onStop() - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - if (requestCode == Constant.REQUEST_CODE_SEND_TRANSACTION_) { - navigateBackWithResult(resultCode, data) - } - } - - override fun onTagDiscovered(tag: Tag) { - try { - // get IsoDep handle and run cardReader thread - val isoDep = IsoDep.get(tag) - val uid = tag.id - val sUID = Util.byteArrayToHexString(uid) - - if (sUID == ctx.card.uid || !idWasWritten) { - if (lastReadSuccess) - isoDep.timeout = ctx.card.pauseBeforePIN2 + 5000 - else - isoDep.timeout = ctx.card.pauseBeforePIN2 + 65000 - - writeIDCardTask = WriteIDCardTask(ctx.card, NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, ctx.card.idCardData, ctx.card.issuer.privateDataKey, this) - writeIDCardTask?.start() - } else - (activity as MainActivity).nfcManager.ignoreTag(isoDep.tag) - - } catch (e: CardProtocol.TangemException_WrongAmount) { - try { - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.send_transaction_error_wrong_amount)) - data.putString(EXTRA_TANGEM_CARD_UID, ctx.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, ctx.card.asBundle) - navigateBackWithResult(Activity.RESULT_CANCELED, data) - } catch (e: Exception) { - e.printStackTrace() - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar.visibility = View.VISIBLE } - - progressBar?.post { - progressBar?.visibility = View.VISIBLE - progressBar?.progress = 5 - } - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - progressBar?.post { progressBar?.progress = progress } - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - writeIDCardTask = null - if (cardProtocol != null) { - if (cardProtocol.error == null) { - rlProgressBar?.post { rlProgressBar?.visibility = View.GONE } - - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.GREEN) - } - - mpFinishSignSound.start() - - idWasWritten = true - - val coinEngine = CoinEngineFactory.create(ctx) - - coinEngine!!.requestSendTransaction( - object : CoinEngine.BlockchainRequestsCallbacks { - override fun onComplete(success: Boolean) { - if (success) { - navigateUp(R.id.main) - } else { - navigateUp(R.id.issueNewIdFragment) - } - } - - override fun onProgress() { - } - - override fun allowAdvance(): Boolean { - return UtilHelper.isOnline(requireContext()) - } - }, - tx - ) - - } else { - Log.d(this.javaClass.simpleName, - "Error while writing on ID card: ${cardProtocol.error}") - lastReadSuccess = false - FirebaseCrashlytics.getInstance().recordException(cardProtocol.error) - if (cardProtocol.error.javaClass == CardProtocol.TangemException_InvalidPIN::class.java) { - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.send_transaction_error_cannot_sign)) - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - navigateBackWithResult(Constant.RESULT_INVALID_PIN_, data) - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } else { - if (cardProtocol.error is CardProtocol.TangemException_WrongAmount) { - try { - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.send_transaction_error_wrong_amount)) - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - navigateBackWithResult(Activity.RESULT_CANCELED, data) - } catch (e: Exception) { - e.printStackTrace() - } - } - progressBar?.post { - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allReadyShowed) { - NoExtendedLengthSupportDialog.message = getText(R.string.dialog_the_nfc_adapter_length_apdu).toString() + "\n" + getText(R.string.dialog_the_nfc_adapter_length_apdu_advice).toString() - NoExtendedLengthSupportDialog().show(requireFragmentManager(), NoExtendedLengthSupportDialog.TAG) - } - } else { - if (!idWasWritten) { - (activity as MainActivity).toastHelper.showSingleToast( - context, - getString(R.string.general_notification_scan_again) - ) - } - } - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - } - } - } - - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadCancel() { - writeIDCardTask = null - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - - override fun onReadBeforeRequest(timeout: Int) { - LOG.i(TAG, "onReadBeforeRequest timeout $timeout") - activity?.let { WaitSecurityDelayDialog.onReadBeforeRequest(it, timeout) } - } - - override fun onReadAfterRequest() { - LOG.i(TAG, "onReadAfterRequest") - activity?.let { WaitSecurityDelayDialog.onReadAfterRequest(it) } - } - - override fun onReadWait(msec: Int) { - LOG.i(TAG, "onReadWait msec $msec") - activity?.let { WaitSecurityDelayDialog.onReadWait(it, msec) } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/pin/PinRequestFragment.kt b/app/src/main/java/com/tangem/ui/fragment/pin/PinRequestFragment.kt deleted file mode 100644 index dc4206c2a1..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/pin/PinRequestFragment.kt +++ /dev/null @@ -1,336 +0,0 @@ -package com.tangem.ui.fragment.pin - -import android.Manifest -import android.annotation.SuppressLint -import android.annotation.TargetApi -import android.app.Activity -import android.app.KeyguardManager -import android.content.Context -import android.content.pm.PackageManager -import android.hardware.fingerprint.FingerprintManager -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Build -import android.os.Bundle -import android.text.TextUtils -import android.util.Log -import android.view.View -import android.widget.Button -import androidx.core.app.ActivityCompat -import com.tangem.Constant -import com.tangem.data.fingerprint.FingerprintHelper -import com.tangem.data.fingerprint.StartFingerprintReaderTask -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_sdk.android.data.PINStorage -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.loadFromBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.fragment.BaseFragment -import com.tangem.util.LOG -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_pin_request.* -import kotlinx.android.synthetic.main.layout_pin_buttons.* -import java.io.IOException - -class PinRequestFragment : BaseFragment(), NfcAdapter.ReaderCallback, FingerprintHelper.FingerprintHelperListener { - companion object { - val TAG: String = PinRequestFragment::class.java.simpleName - - fun callingIntent(mode: String): Bundle { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, mode) - return bundle - } - - fun callingIntentRequestPin(mode: String, ctx: TangemContext, newPIN: String): Bundle { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, mode) - bundle.putString(Constant.EXTRA_NEW_PIN, newPIN) - ctx.saveToBundle(bundle) - return bundle - } - - fun callingIntentRequestPin2(mode: String, ctx: TangemContext, newPIN2: String): Bundle { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, mode) - bundle.putString(Constant.EXTRA_NEW_PIN_2, newPIN2) - ctx.saveToBundle(bundle) - return bundle - } - - fun callingIntentRequestPin2(mode: String, ctx: TangemContext): Bundle { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, mode) - ctx.saveToBundle(bundle) - return bundle - } - - fun callingIntentConfirmPin(mode: String, newPIN: String): Bundle { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, mode) - bundle.putString(Constant.EXTRA_NEW_PIN, newPIN) - return bundle - } - - fun callingIntentConfirmPin2(mode: String, newPIN2: String): Bundle { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, mode) - bundle.putString(Constant.EXTRA_NEW_PIN_2, newPIN2) - return bundle - } - } - - override val layoutId = R.layout.fragment_pin_request - - val mode: Mode by lazy { Mode.valueOf(arguments?.getString(Constant.EXTRA_MODE) ?: "") } - - private var allowFingerprint = false - var startFingerprintReaderTask: StartFingerprintReaderTask? = null - private var fingerprintManager: FingerprintManager? = null - private var fingerprintHelper: FingerprintHelper? = null - - enum class Mode { - RequestPIN, RequestPIN2, RequestNewPIN, RequestNewPIN2, ConfirmNewPIN, ConfirmNewPIN2 - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - if (mode == Mode.RequestNewPIN) - if (PINStorage.haveEncryptedPIN()) { - allowFingerprint = true - tvPinPrompt.setText(R.string.pin_request_enter_new_pin_or_use_fingerprint_scanner) - } else - tvPinPrompt.setText(R.string.pin_request_enter_new_pin) - else if (mode == Mode.ConfirmNewPIN) - tvPinPrompt.setText(R.string.pin_request_confirm_new_pin) - else if (mode == Mode.RequestPIN) - if (PINStorage.haveEncryptedPIN()) { - allowFingerprint = true - tvPinPrompt.setText(R.string.pin_request_enter_pin_or_use_fingerprint_scanner) - } else - tvPinPrompt.setText(R.string.pin_request_enter_pin) - else if (mode == Mode.RequestNewPIN2) - if (PINStorage.haveEncryptedPIN2()) { - allowFingerprint = true - tvPinPrompt.setText(R.string.pin_request_prompt_new_pin_2_or_fingerprint) - } else - tvPinPrompt.setText(R.string.pin_request_new_pin_2) - else if (mode == Mode.ConfirmNewPIN2) - tvPinPrompt.setText(R.string.pin_request_confirm_new_pin_2) - else if (mode == Mode.RequestPIN2) { - val uid = arguments?.getString(EXTRA_TANGEM_CARD_UID) - val card = TangemCard(uid) - card.loadFromBundle(arguments?.getBundle(EXTRA_TANGEM_CARD) ?: Bundle()) - - if (card.PIN2 == TangemCard.PIN2_Mode.DefaultPIN2 || card.PIN2 == TangemCard.PIN2_Mode.Unchecked) { - // if we know PIN2 or not try default previously - use it - PINStorage.setPIN2(PINStorage.getDefaultPIN2()) - navigateBackWithResult(Activity.RESULT_OK) - return - } - - if (PINStorage.haveEncryptedPIN2()) { - allowFingerprint = true - tvPinPrompt.setText(R.string.pin_request_enter_pin_2_or_use_fingerprint_scanner) - } else - tvPinPrompt.setText(R.string.pin_request_prompt_enter_pin_2) - } - - if (!allowFingerprint) - tvPinPrompt.visibility = View.GONE - else - tvPinPrompt.visibility = View.VISIBLE - - // set listeners - btn0.setOnClickListener { buttonClick(btn0) } - btn1.setOnClickListener { buttonClick(btn1) } - btn2.setOnClickListener { buttonClick(btn2) } - btn3.setOnClickListener { buttonClick(btn3) } - btn4.setOnClickListener { buttonClick(btn4) } - btn5.setOnClickListener { buttonClick(btn5) } - btn6.setOnClickListener { buttonClick(btn6) } - btn7.setOnClickListener { buttonClick(btn7) } - btn8.setOnClickListener { buttonClick(btn8) } - btn9.setOnClickListener { buttonClick(btn9) } - btnBackspace.setOnClickListener { - val s = tvPin!!.text.toString() - if (s.isNotEmpty()) - tvPin!!.text = s.substring(0, s.length - 1) - } - btnContinue.setOnClickListener { doContinue() } - } - - override fun onPause() { - super.onPause() - fingerprintHelper?.cancel() - - if (startFingerprintReaderTask != null) { - startFingerprintReaderTask!!.cancel(true) - startFingerprintReaderTask = null - } - } - - override fun onStop() { - super.onStop() - fingerprintHelper?.cancel() - - if (startFingerprintReaderTask != null) { - startFingerprintReaderTask!!.cancel(true) - startFingerprintReaderTask = null - } - } - - override fun onResume() { - super.onResume() - if (allowFingerprint) - startFingerprintReader() - } - - override fun onTagDiscovered(tag: Tag) { - try { - Log.w(javaClass.name, "Ignore discovered tag!") - (activity as MainActivity).nfcManager.ignoreTag(tag) - } catch (e: IOException) { - e.printStackTrace() - } - } - - override fun authenticationFailed(error: String) { - LOG.w(TAG, error) - } - - @TargetApi(Build.VERSION_CODES.M) - override fun authenticationSucceeded(result: FingerprintManager.AuthenticationResult) { - LOG.i(TAG, "Authentication succeeded!") - val cipher = result.cryptoObject.cipher - - if (mode == Mode.RequestNewPIN || mode == Mode.ConfirmNewPIN) { - val resultData = Bundle() - val pin = PINStorage.loadEncryptedPIN(cipher) - resultData.putString(Constant.EXTRA_NEW_PIN, pin) - resultData.putString(Constant.EXTRA_CONFIRM_PIN, pin) - navigateBackWithResult(Activity.RESULT_OK, resultData) - } else if (mode == Mode.RequestNewPIN2 || mode == Mode.ConfirmNewPIN2) { - val resultData = Bundle() - val pin = PINStorage.loadEncryptedPIN2(cipher) - resultData.putString(Constant.EXTRA_NEW_PIN_2, pin) - resultData.putString(Constant.EXTRA_CONFIRM_PIN_2, pin) - navigateBackWithResult(Activity.RESULT_OK, resultData) - } else if (mode == Mode.RequestPIN) { - PINStorage.loadEncryptedPIN(cipher) - navigateBackWithResult(Activity.RESULT_OK) - } else if (mode == Mode.RequestPIN2) { - PINStorage.loadEncryptedPIN2(cipher) - navigateBackWithResult(Activity.RESULT_OK) - } - } - - private fun buttonClick(button: Button) { - tvPin.text = tvPin.text.toString() + button.text.toString() - } - - @SuppressLint("NewApi") - private fun testFingerPrintSettings(): Boolean { - LOG.i(TAG, "Testing Fingerprint SettingsFragment") - - val keyguardManager = context?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager - fingerprintManager = context?.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager - - if (!keyguardManager.isKeyguardSecure) { - LOG.i(TAG, "User hasn't enabled Lock Screen") - return false - } - - if (ActivityCompat.checkSelfPermission(context!!, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { - LOG.i(TAG, "User hasn't granted permission to use Fingerprint") - return false - } - - if (!fingerprintManager!!.hasEnrolledFingerprints()) { - LOG.i(TAG, "User hasn't registered any fingerprints") - return false - } - - LOG.i(TAG, "Fingerprint authentication is set.\n") - - return true - } - - private fun startFingerprintReader() { - if (!testFingerPrintSettings()) - return - - if (!allowFingerprint) - return - - fingerprintHelper = FingerprintHelper(this@PinRequestFragment) - startFingerprintReaderTask = StartFingerprintReaderTask( - this@PinRequestFragment, fingerprintManager, fingerprintHelper) - startFingerprintReaderTask!!.execute(null as Void?) - } - - private fun doContinue() { - if (startFingerprintReaderTask != null) - return - - // reset errors. - tvPin!!.error = null - - // store values at the time of the login attempt. - val pin = tvPin!!.text.toString() - - var cancel = false - var focusView: View? = null - - if (mode == Mode.ConfirmNewPIN) { - if (pin != arguments?.getString(Constant.EXTRA_NEW_PIN)) { - tvPin!!.error = getString(R.string.pin_request_error_pin_confirmation_failed) - focusView = tvPin - cancel = true - } - } else if (mode == Mode.ConfirmNewPIN2) { - if (pin != arguments?.getString(Constant.EXTRA_NEW_PIN_2)) { - tvPin!!.error = getString(R.string.pin_request_error_pin_confirmation_failed) - focusView = tvPin - cancel = true - } - } else { - if (TextUtils.isEmpty(pin)) { - tvPin!!.error = getString(R.string.error_empty_pin) - focusView = tvPin - cancel = true - } - } - - if (cancel) - focusView!!.requestFocus() - else { - if (mode == Mode.RequestNewPIN || mode == Mode.ConfirmNewPIN) { - val resultData = Bundle() - resultData.putString(Constant.EXTRA_NEW_PIN, pin) - if (mode == Mode.ConfirmNewPIN) - resultData.putString(Constant.EXTRA_CONFIRM_PIN, pin) - - navigateBackWithResult(Activity.RESULT_OK, resultData) - - } else if (mode == Mode.RequestNewPIN2 || mode == Mode.ConfirmNewPIN2) { - val resultData = Bundle() - resultData.putString(Constant.EXTRA_NEW_PIN_2, pin) - if (mode == Mode.ConfirmNewPIN2) - resultData.putString(Constant.EXTRA_CONFIRM_PIN_2, pin) - navigateBackWithResult(Activity.RESULT_OK, resultData) - - } else if (mode == Mode.RequestPIN) { - PINStorage.setUserPIN(pin) - navigateBackWithResult(Activity.RESULT_OK) - - } else if (mode == Mode.RequestPIN2) { - PINStorage.setPIN2(pin) - navigateBackWithResult(Activity.RESULT_OK) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/pin/PinSaveFragment.kt b/app/src/main/java/com/tangem/ui/fragment/pin/PinSaveFragment.kt deleted file mode 100644 index b1a5fd70d8..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/pin/PinSaveFragment.kt +++ /dev/null @@ -1,372 +0,0 @@ -package com.tangem.ui.fragment.pin - -import android.Manifest -import android.annotation.SuppressLint -import android.annotation.TargetApi -import android.app.Dialog -import android.app.KeyguardManager -import android.content.Context -import android.content.pm.PackageManager -import android.hardware.fingerprint.FingerprintManager -import android.os.Build -import android.os.Bundle -import android.security.keystore.KeyGenParameterSpec -import android.security.keystore.KeyPermanentlyInvalidatedException -import android.security.keystore.KeyProperties -import android.text.TextUtils -import android.view.View -import android.widget.Button -import android.widget.Toast -import androidx.core.app.ActivityCompat -import com.tangem.Constant -import com.tangem.data.fingerprint.ConfirmWithFingerprintTask -import com.tangem.data.fingerprint.FingerprintHelper -import com.tangem.tangem_sdk.android.data.PINStorage -import com.tangem.ui.fragment.BaseFragment -import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_pin_save.* -import kotlinx.android.synthetic.main.layout_pin_buttons.* -import java.io.IOException -import java.security.KeyStore -import java.security.KeyStoreException -import java.security.NoSuchAlgorithmException -import java.security.cert.CertificateException -import javax.crypto.Cipher -import javax.crypto.KeyGenerator -import javax.crypto.NoSuchPaddingException -import javax.crypto.SecretKey -import javax.crypto.spec.IvParameterSpec - -class PinSaveFragment : BaseFragment(), FingerprintHelper.FingerprintHelperListener { - companion object { - val TAG: String = PinSaveFragment::class.java.simpleName - } - - override val layoutId = R.layout.fragment_pin_save - - private var confirmWithFingerprintTask: ConfirmWithFingerprintTask? = null - private var keyStore: KeyStore? = null - private var cipher: Cipher? = null - var fingerprintManager: FingerprintManager? = null - var cryptoObject: FingerprintManager.CryptoObject? = null - var fingerprintHelper: FingerprintHelper? = null - private var usePIN2 = false - private var onConfirmAction: OnConfirmAction? = null - var dFingerPrintConfirmation: Dialog? = null - - private enum class OnConfirmAction { - Save, DeleteEncryptedAndSave, Delete - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - usePIN2 = arguments?.getBoolean(Constant.EXTRA_PIN2, false) ?: false - - if (usePIN2) - tvPinPrompt.text = getString(R.string.pin_save_title_enter_pin2_and_save) - else - tvPinPrompt.text = getString(R.string.pin_save_title_enter_pin_and_save) - - if (usePIN2) { - cbUseFingerprint.isChecked = true - cbUseFingerprint.isEnabled = false - } else { - cbUseFingerprint.isChecked = PINStorage.haveEncryptedPIN() - cbUseFingerprint.isEnabled = true - } - - // set listeners - btn0.setOnClickListener { buttonClick(btn0) } - btn1.setOnClickListener { buttonClick(btn1) } - btn2.setOnClickListener { buttonClick(btn2) } - btn3.setOnClickListener { buttonClick(btn3) } - btn4.setOnClickListener { buttonClick(btn4) } - btn5.setOnClickListener { buttonClick(btn5) } - btn6.setOnClickListener { buttonClick(btn6) } - btn7.setOnClickListener { buttonClick(btn7) } - btn8.setOnClickListener { buttonClick(btn8) } - btn9.setOnClickListener { buttonClick(btn9) } - btnBackspace.setOnClickListener { - val s = tvPin.text.toString() - if (s.isNotEmpty()) - tvPin.text = s.substring(0, s.length - 1) - } - btnSavePIN.setOnClickListener { doSavePIN() } - btnDeletePIN.setOnClickListener { doDeletePIN() } - } - - override fun onPause() { - super.onPause() - if (fingerprintHelper != null) - fingerprintHelper!!.cancel() - - if (confirmWithFingerprintTask != null) - confirmWithFingerprintTask!!.cancel(true) - } - - override fun onStop() { - super.onStop() - if (fingerprintHelper != null) - fingerprintHelper!!.cancel() - - if (confirmWithFingerprintTask != null) - confirmWithFingerprintTask!!.cancel(true) - } - - override fun authenticationFailed(error: String) { - - } - - @TargetApi(Build.VERSION_CODES.M) - override fun authenticationSucceeded(result: FingerprintManager.AuthenticationResult) { - - cipher = result.cryptoObject.cipher - - when (onConfirmAction) { - OnConfirmAction.Save -> { - val textToEncrypt = tvPin.text.toString() - if (usePIN2) { - PINStorage.saveEncryptedPIN2(cipher, textToEncrypt) - } else { - PINStorage.saveEncryptedPIN(cipher, textToEncrypt) - } - } - - OnConfirmAction.Delete -> { - if (usePIN2) { - PINStorage.deleteEncryptedPIN2() - } else { - PINStorage.deleteEncryptedPIN() - PINStorage.deletePIN() - } - tvPin.text = "" - } - - OnConfirmAction.DeleteEncryptedAndSave -> if (usePIN2) { - PINStorage.deleteEncryptedPIN2() - PINStorage.saveEncryptedPIN2(cipher, tvPin.text.toString()) - } else { - PINStorage.deleteEncryptedPIN() - PINStorage.savePIN(tvPin.text.toString()) - } - } - - dFingerPrintConfirmation!!.dismiss() - navigateUp() - } - - fun getKeyStore(): Boolean { - try { - keyStore = KeyStore.getInstance(Constant.KEYSTORE) - // create empty keystore - keyStore!!.load(null) - return true - } catch (e: KeyStoreException) { - e.printStackTrace() - } catch (e: CertificateException) { - e.printStackTrace() - } catch (e: NoSuchAlgorithmException) { - e.printStackTrace() - } catch (e: IOException) { - e.printStackTrace() - } - - return false - } - - @TargetApi(Build.VERSION_CODES.M) - fun createNewKey(forceCreate: Boolean): Boolean { - try { - if (forceCreate) - keyStore!!.deleteEntry(Constant.KEY_ALIAS) - - if (!keyStore!!.containsAlias(Constant.KEY_ALIAS)) { - val generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, Constant.KEYSTORE) - - generator.init(KeyGenParameterSpec.Builder(Constant.KEY_ALIAS, - KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(KeyProperties.BLOCK_MODE_CBC) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) - .setUserAuthenticationRequired(true) - .build() - ) - - generator.generateKey() - } - return true - } catch (e: Exception) { - e.printStackTrace() - } - - return false - } - - @SuppressLint("InlinedApi") - fun getCipher(): Boolean { - try { - cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7) - return true - } catch (e: NoSuchAlgorithmException) { - e.printStackTrace() - } catch (e: NoSuchPaddingException) { - e.printStackTrace() - } - - return false - } - - @TargetApi(Build.VERSION_CODES.M) - fun initCipher(mode: Int): Boolean { - try { - keyStore!!.load(null) - val keySpec = keyStore!!.getKey(Constant.KEY_ALIAS, null) as SecretKey - - if (mode == Cipher.ENCRYPT_MODE) { - cipher!!.init(mode, keySpec) - } else { - val iv = PINStorage.loadEncryptedIV() - val ivSpec = IvParameterSpec(iv) - cipher!!.init(mode, keySpec, ivSpec) - } - - return true - } catch (e: KeyPermanentlyInvalidatedException) { - e.printStackTrace() - // retry after clearing entry - createNewKey(true) - } catch (e: Exception) { - e.printStackTrace() - } - - return false - } - - @TargetApi(Build.VERSION_CODES.M) - fun initCryptObject(): Boolean { - try { - cryptoObject = FingerprintManager.CryptoObject(cipher!!) - return true - } catch (e: Exception) { - e.printStackTrace() - } - - return false - } - - @SuppressLint("SetTextI18n") - private fun buttonClick(button: Button) { - tvPin.text = String.format("%s%s", tvPin.text, button.text) - } - - private fun doSavePIN() { - if (confirmWithFingerprintTask != null) { - return - } - - tvPin.error = null - - val pin = tvPin.text.toString() - - var cancel = false - var focusView: View? = null - - if (TextUtils.isEmpty(pin)) { - tvPin.error = getString(R.string.error_empty_pin) - focusView = tvPin - cancel = true - } - - if (cancel) { - focusView!!.requestFocus() - } else { - if (usePIN2) { - if (!testFingerPrintSettings()) { - tvPin.postDelayed({ navigateUp() }, 2000) - return - } - - onConfirmAction = OnConfirmAction.Save - - confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveFragment) - confirmWithFingerprintTask!!.execute(null as Void?) - - } else { - if (cbUseFingerprint.isChecked || PINStorage.haveEncryptedPIN()) { - if (!testFingerPrintSettings()) { - tvPin.postDelayed({ navigateUp() }, 2000) - return - } - - onConfirmAction = if (cbUseFingerprint.isChecked) { - OnConfirmAction.Save - } else { - OnConfirmAction.DeleteEncryptedAndSave - } - - // show a progress spinner, and kick off a background task to perform the user login attempt - confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveFragment) - confirmWithFingerprintTask!!.execute(null as Void?) - } else { - PINStorage.savePIN(tvPin.text.toString()) - navigateUp() - } - } - } - } - - private fun doDeletePIN() { - if (usePIN2) { - if (PINStorage.haveEncryptedPIN2()) { - if (!testFingerPrintSettings()) { - tvPin.postDelayed({ navigateUp() }, 2000) - return - } - onConfirmAction = OnConfirmAction.Delete - confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveFragment) - confirmWithFingerprintTask!!.execute(null as Void?) - } else { - tvPin.text = "" - navigateUp() - } - } else { - if (cbUseFingerprint.isChecked || PINStorage.haveEncryptedPIN()) { - if (!testFingerPrintSettings()) { - tvPin.postDelayed({ navigateUp() }, 2000) - return - } - onConfirmAction = OnConfirmAction.Delete - confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveFragment) - confirmWithFingerprintTask!!.execute(null as Void?) - } else { - tvPin.text = "" - PINStorage.deletePIN() - navigateUp() - } - } - } - - @SuppressLint("NewApi") - private fun testFingerPrintSettings(): Boolean { - val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager - fingerprintManager = activity?.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager - - if (!keyguardManager.isKeyguardSecure) { - Toast.makeText(context, R.string.pin_save_toast_lock_screen_not_enabled, Toast.LENGTH_LONG).show() - return false - } - - if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(context, R.string.pin_save_toast_no_permission_to_use_fingerprint, Toast.LENGTH_LONG).show() - return false - } - - if (!fingerprintManager!!.hasEnrolledFingerprints()) { - Toast.makeText(context, R.string.pin_save_toast_no_fingerprints_registered, Toast.LENGTH_LONG).show() - return false - } - - return true - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/pin/PinSwapFragment.kt b/app/src/main/java/com/tangem/ui/fragment/pin/PinSwapFragment.kt deleted file mode 100644 index ee846c13ca..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/pin/PinSwapFragment.kt +++ /dev/null @@ -1,202 +0,0 @@ -package com.tangem.ui.fragment.pin - -import android.app.Activity -import android.content.res.ColorStateList -import android.graphics.Color -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Bundle -import android.view.View -import android.widget.ProgressBar -import android.widget.Toast -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.SwapPINTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.asBundle -import com.tangem.tangem_sdk.data.loadFromBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.fragment.BaseFragment -import com.tangem.wallet.R -import kotlinx.android.synthetic.main.fragment_pin_swap.* - -class PinSwapFragment : BaseFragment(), NfcAdapter.ReaderCallback, CardProtocol.Notifications { - companion object { - val TAG: String = PinSwapFragment::class.java.simpleName - - fun callingIntent(newPIN: String, newPIN2: String): Bundle { - val bundle = Bundle() - bundle.putString(Constant.EXTRA_NEW_PIN, newPIN) - bundle.putString(Constant.EXTRA_NEW_PIN_2, newPIN2) - return bundle - } - - const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER - } - - override val layoutId = R.layout.fragment_pin_swap - - private lateinit var card: TangemCard; - private var newPIN: String? = null - private var newPIN2: String? = null - - private var progressBar: ProgressBar? = null - - private var swapPinTask: SwapPINTask? = null - - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - card = TangemCard(arguments?.getString(EXTRA_TANGEM_CARD_UID)) - card.loadFromBundle(arguments?.getBundle(EXTRA_TANGEM_CARD) ?: Bundle()) - - newPIN = arguments?.getString(Constant.EXTRA_NEW_PIN) - newPIN2 = arguments?.getString(Constant.EXTRA_NEW_PIN_2) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - tvCardID.text = card.cidDescription - - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } - - override fun onTagDiscovered(tag: Tag) { - try { - // get IsoDep handle and run cardReader thread - val isoDep = IsoDep.get(tag) - val uid = tag.id - val sUID = Util.byteArrayToHexString(uid) - if (sUID == card.uid) { - isoDep.timeout = card.pauseBeforePIN2 + 65000 - swapPinTask = SwapPINTask(card, NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, this, newPIN, newPIN2) - swapPinTask?.start() - } else { - (activity as MainActivity).nfcManager.ignoreTag(isoDep.tag) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - public override fun onPause() { - swapPinTask?.cancel(true) - super.onPause() - } - - public override fun onStop() { - swapPinTask?.cancel(true) - super.onStop() - } - - override fun onReadStart(cardProtocol: CardProtocol) { - progressBar?.post { - progressBar?.visibility = View.VISIBLE - progressBar?.progress = 5 - } - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - swapPinTask = null - - if (cardProtocol != null) { - cardProtocol.error?.let { FirebaseCrashlytics.getInstance().recordException(it) } - when { - cardProtocol.error == null -> progressBar!!.post { - progressBar!!.progress = 100 - progressBar!!.progressTintList = ColorStateList.valueOf(Color.GREEN) - val data = Bundle() - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - navigateBackWithResult(Activity.RESULT_OK, data) - } - cardProtocol.error is CardProtocol.TangemException_InvalidPIN -> { - progressBar!!.post { - progressBar!!.progress = 100 - progressBar!!.progressTintList = ColorStateList.valueOf(Color.RED) - } - progressBar!!.postDelayed({ - try { - progressBar!!.progress = 0 - progressBar!!.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar!!.visibility = View.INVISIBLE - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, "Cannot change PIN(s). Make sure you enter correct PIN2!") - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - navigateBackWithResult(RESULT_INVALID_PIN, data) - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - else -> progressBar!!.post { - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allReadyShowed) { - NoExtendedLengthSupportDialog().show(activity!!.supportFragmentManager, - NoExtendedLengthSupportDialog.TAG) - } - } else { - Toast.makeText(context, R.string.general_notification_scan_again, Toast.LENGTH_SHORT).show() - } - progressBar!!.progress = 100 - progressBar!!.progressTintList = ColorStateList.valueOf(Color.RED) - } - } - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - progressBar!!.post { progressBar!!.progress = progress } - } - - override fun onReadCancel() { - swapPinTask = null - - progressBar!!.postDelayed({ - try { - progressBar!!.progress = 0 - progressBar!!.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar!!.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadWait(msec: Int) { - WaitSecurityDelayDialog.onReadWait(activity, msec) - } - - override fun onReadBeforeRequest(timeout: Int) { - WaitSecurityDelayDialog.onReadBeforeRequest(activity, timeout) - } - - override fun onReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(activity) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/qr/CameraPermissionManager.kt b/app/src/main/java/com/tangem/ui/fragment/qr/CameraPermissionManager.kt deleted file mode 100644 index 250370d40a..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/qr/CameraPermissionManager.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tangem.ui.fragment.qr - -import android.Manifest -import android.content.pm.PackageManager -import android.widget.Toast -import androidx.core.content.ContextCompat -import androidx.core.content.PermissionChecker -import com.tangem.ui.fragment.BaseFragment -import com.tangem.wallet.R - -class CameraPermissionManager(val fragment: BaseFragment) { - - fun isPermissionGranted(): Boolean { - return ContextCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.CAMERA) == - PermissionChecker.PERMISSION_GRANTED - } - - fun handleRequestPermissionResult(requestCode: Int, grantResults: IntArray, action: () -> Unit) { - when (requestCode) { - 1 -> { - if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(fragment.requireContext(), R.string.general_toast_no_permission, Toast.LENGTH_LONG).show() - } else { - action.invoke() - } - } - } - } - - fun requirePermission() { - fragment.requestPermissions(arrayOf(Manifest.permission.CAMERA), 1) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/qr/QrScanFragment.kt b/app/src/main/java/com/tangem/ui/fragment/qr/QrScanFragment.kt deleted file mode 100644 index 9ee01f8cd9..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/qr/QrScanFragment.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.tangem.ui.fragment.qr - -import android.app.Activity -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.google.zxing.Result -import com.tangem.Constant -import com.tangem.ui.fragment.BaseFragment -import me.dm7.barcodescanner.zxing.ZXingScannerView - -class QrScanFragment : BaseFragment(), ZXingScannerView.ResultHandler { - - override val layoutId = 0 - private var scannerView: ZXingScannerView? = null - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - scannerView = ZXingScannerView(activity) - return scannerView - } - - override fun onPause() { - super.onPause() - scannerView?.stopCamera() - } - - override fun onResume() { - super.onResume() - scannerView?.setResultHandler(this) - scannerView?.startCamera() - } - - override fun handleResult(result: Result) { - val data = Bundle() - data.putString(Constant.EXTRA_QR_CODE, result.text) - navigateBackWithResult(Activity.RESULT_OK, data) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/wallet/CreateNewWalletFragment.kt b/app/src/main/java/com/tangem/ui/fragment/wallet/CreateNewWalletFragment.kt deleted file mode 100644 index 51e9ef4544..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/wallet/CreateNewWalletFragment.kt +++ /dev/null @@ -1,178 +0,0 @@ -package com.tangem.ui.fragment.wallet - -import android.app.Activity -import android.content.res.ColorStateList -import android.graphics.Color -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Bundle -import android.view.View -import android.widget.Toast -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.CreateNewWalletTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.nfc.NfcDeviceAntennaLocation -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.asBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.fragment.BaseFragment -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_create_new_wallet.* -import kotlinx.android.synthetic.main.layout_progress_horizontal.* -import kotlinx.android.synthetic.main.layout_touch_card.* - -class CreateNewWalletFragment : BaseFragment(), NfcAdapter.ReaderCallback, CardProtocol.Notifications { - - override val layoutId = R.layout.fragment_create_new_wallet - - private val ctx: TangemContext by lazy { TangemContext.loadFromBundle(context, arguments) } - - private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation - - private var createNewWalletTask: CreateNewWalletTask? = null - private var lastReadSuccess = true - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - // init NFC Antenna - nfcDeviceAntenna = NfcDeviceAntennaLocation(requireContext(), ivHandCardHorizontal, ivHandCardVertical, llHand, llNfc) - nfcDeviceAntenna.init() - - tvCardId.text = ctx.card!!.cidDescription - progressBar.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar.visibility = View.INVISIBLE - } - - override fun onTagDiscovered(tag: Tag) { - // get IsoDep handle and run cardReader thread - val isoDep = IsoDep.get(tag) - val uid = tag.id - val sUID = Util.byteArrayToHexString(uid) - - if (sUID == ctx.card.uid) { - if (lastReadSuccess) - isoDep.timeout = ctx.card.pauseBeforePIN2 + 5000 - else - isoDep.timeout = ctx.card.pauseBeforePIN2 + 65000 - - createNewWalletTask = CreateNewWalletTask(ctx.card, NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, this) - createNewWalletTask?.start() - } else - (activity as MainActivity).nfcManager.ignoreTag(isoDep.tag) - } - - override fun onPause() { - createNewWalletTask?.cancel(true) - super.onPause() - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar.visibility = View.VISIBLE } - - progressBar?.post { - progressBar?.visibility = View.VISIBLE - progressBar?.progress = 5 - } - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - createNewWalletTask = null - if (cardProtocol != null) { - if (cardProtocol.error == null) { - rlProgressBar.post { rlProgressBar.visibility = View.GONE } - - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.GREEN) - val data = Bundle() - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card.asBundle) - navigateBackWithResult(Activity.RESULT_OK, data) - return@post - } - } else { - FirebaseCrashlytics.getInstance().recordException(cardProtocol.error) - lastReadSuccess = false - if (cardProtocol.error is CardProtocol.TangemException_InvalidPIN) { - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - val data = Bundle() - data.putString(Constant.EXTRA_MESSAGE, getString(R.string.nfc_error_cannot_create_wallet)) - data.putString(EXTRA_TANGEM_CARD_UID, cardProtocol.card.uid) - data.putBundle(EXTRA_TANGEM_CARD, cardProtocol.card!!.asBundle) - navigateBackWithResult(Constant.RESULT_INVALID_PIN, data) - return@postDelayed - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } else { - progressBar?.post { - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allReadyShowed) { - NoExtendedLengthSupportDialog().show(activity!!.supportFragmentManager, NoExtendedLengthSupportDialog.TAG) - } - } else - Toast.makeText(context, R.string.general_notification_scan_again, Toast.LENGTH_SHORT).show() - - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - } - } - } - - rlProgressBar.postDelayed({ rlProgressBar?.visibility = View.GONE }, 500) - - progressBar?.postDelayed({ - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - }, 500) - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - progressBar?.post { progressBar?.progress = progress } - } - - override fun onReadCancel() { - createNewWalletTask = null - - progressBar?.postDelayed({ - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - }, 500) - } - - override fun onReadWait(msec: Int) { - WaitSecurityDelayDialog.onReadWait(activity, msec) - } - - override fun onReadBeforeRequest(timeout: Int) { - WaitSecurityDelayDialog.onReadBeforeRequest(activity, timeout) - } - - override fun onReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(activity) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/wallet/EmptyWalletFragment.kt b/app/src/main/java/com/tangem/ui/fragment/wallet/EmptyWalletFragment.kt deleted file mode 100644 index e8a4cc7542..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/wallet/EmptyWalletFragment.kt +++ /dev/null @@ -1,258 +0,0 @@ -package com.tangem.ui.fragment.wallet - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.content.res.ColorStateList -import android.graphics.Color -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Build -import android.os.Bundle -import android.text.Html -import android.view.View -import android.widget.Toast -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tangem.App -import com.tangem.Constant -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.VerifyCardTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.asBundle -import com.tangem.tangem_sdk.data.loadFromBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.fragment.pin.PinRequestFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext -import kotlinx.android.synthetic.main.fragment_empty_wallet.* -import kotlinx.android.synthetic.main.layout_tangem_card.* - -class EmptyWalletFragment : BaseFragment(), NavigationResultListener, - NfcAdapter.ReaderCallback, CardProtocol.Notifications { - companion object { - val TAG: String = EmptyWalletFragment::class.java.simpleName - fun callingIntent(context: Context, ctx: TangemContext): Intent { - val intent = Intent(context, EmptyWalletFragment::class.java) - ctx.saveToIntent(intent) - return intent - } - } - - override val layoutId = R.layout.fragment_empty_wallet - - private val ctx: TangemContext by lazy { TangemContext.loadFromBundle(context, arguments) } - - private var lastReadSuccess = true - private var verifyCardTask: VerifyCardTask? = null - private var requestPIN2Count = 0 - - private var cardProtocol: CardProtocol? = null - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - tvIssuer.text = ctx.card!!.issuerDescription - - if (ctx.card!!.tokenSymbol.length > 1) { - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(ctx.blockchainName, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(ctx.blockchainName) - tvBlockchain.text = html - } else - tvBlockchain.text = ctx.blockchainName - - tvCardID.text = ctx.card!!.cidDescription - ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card)) - - // set listeners - btnNewWallet.setOnClickListener { - requestPIN2Count = 0 - - val data = Bundle() - data.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - data.putString(EXTRA_TANGEM_CARD_UID, ctx.card!!.uid) - data.putBundle(EXTRA_TANGEM_CARD, ctx.card!!.asBundle) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2, - R.id.action_emptyWalletFragment_to_pinRequestFragment, data) - } - - btnDetails.setOnClickListener { - if (cardProtocol != null) { - val data = Bundle() - ctx.saveToBundle(data) - navigateForResult(Constant.REQUEST_CODE_VERIFY_CARD, - R.id.action_emptyWalletFragment_to_verifyCard, data) - } else { - (activity as MainActivity).toastHelper - .showSingleToast(context, getString(R.string.general_notification_scan_again_to_verify)) - } - } - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - if (requestCode == Constant.REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY) { - if (resultCode == Activity.RESULT_OK) { - if (data != null) { - data.putString(Constant.EXTRA_MODIFICATION, "updateAndViewCard") - data.putInt("updateDelay", 0) - navigateBackWithResult(Activity.RESULT_OK, data) - } - return - } else { - if (data != null && data.containsKey(EXTRA_TANGEM_CARD_UID) && data.containsKey(EXTRA_TANGEM_CARD)) { - val updatedCard = TangemCard(data.getString(EXTRA_TANGEM_CARD_UID)) - updatedCard.loadFromBundle(data.getBundle(EXTRA_TANGEM_CARD)) - ctx.card = updatedCard - } - if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) { - requestPIN2Count++ - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - bundle.putString(EXTRA_TANGEM_CARD_UID, ctx.card!!.uid) - bundle.putBundle(EXTRA_TANGEM_CARD, ctx.card!!.asBundle) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2, - R.id.action_emptyWalletFragment_to_pinRequestFragment, bundle) - return - } - } - navigateBackWithResult(resultCode, data) - return - } else if (requestCode == Constant.REQUEST_CODE_REQUEST_PIN2) { - if (resultCode == Activity.RESULT_OK) { - val bundle = Bundle() - bundle.putString(EXTRA_TANGEM_CARD_UID, ctx.card!!.uid) - bundle.putBundle(EXTRA_TANGEM_CARD, ctx.card!!.asBundle) - navigateForResult(Constant.REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY, - R.id.action_emptyWalletFragment_to_createNewWalletFragment, bundle) - } - } - } - - override fun onTagDiscovered(tag: Tag) { - try { - val isoDep = IsoDep.get(tag) - val uid = tag.id - val sUID = Util.byteArrayToHexString(uid) - if (ctx.card.uid != sUID || cardProtocol != null) { - (activity as MainActivity).nfcManager.ignoreTag(isoDep.tag) - return - } - - if (lastReadSuccess) - isoDep.timeout = 1000 - else - isoDep.timeout = 65000 - - verifyCardTask = VerifyCardTask(ctx.card, NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, App.firmwaresStorage, this) - verifyCardTask?.start() - } catch (e: Exception) { - e.printStackTrace() - } - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar.visibility = View.VISIBLE } - - progressBar?.post { - progressBar?.visibility = View.VISIBLE - progressBar?.progress = 5 - } - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - verifyCardTask = null - if (cardProtocol != null) { - if (cardProtocol.error == null) { - rlProgressBar?.post { rlProgressBar.visibility = View.GONE } - - progressBar?.post { - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.GREEN) - this.cardProtocol = cardProtocol - } - } else { - FirebaseCrashlytics.getInstance().recordException(cardProtocol.error) - // remove last UIDs because of error and no card read - progressBar?.post { - lastReadSuccess = false - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allReadyShowed) - NoExtendedLengthSupportDialog().show(activity!!.supportFragmentManager, NoExtendedLengthSupportDialog.TAG) - } else - Toast.makeText(context, R.string.general_notification_scan_again, Toast.LENGTH_LONG).show() - - progressBar?.progress = 100 - progressBar?.progressTintList = ColorStateList.valueOf(Color.RED) - } - } - } - - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - progressBar?.post { progressBar?.progress = progress } - } - - override fun onReadCancel() { - verifyCardTask = null - - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - - progressBar?.postDelayed({ - try { - progressBar?.progress = 0 - progressBar?.progressTintList = ColorStateList.valueOf(Color.DKGRAY) - progressBar?.visibility = View.INVISIBLE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadWait(msec: Int) { - WaitSecurityDelayDialog.onReadWait(activity, msec) - } - - override fun onReadBeforeRequest(timeout: Int) { - WaitSecurityDelayDialog.onReadBeforeRequest(activity, timeout) - } - - override fun onReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(activity) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/wallet/LoadedWalletFragment.kt b/app/src/main/java/com/tangem/ui/fragment/wallet/LoadedWalletFragment.kt deleted file mode 100644 index b358ddebf5..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/wallet/LoadedWalletFragment.kt +++ /dev/null @@ -1,964 +0,0 @@ -package com.tangem.ui.fragment.wallet - -import android.app.Activity -import android.app.AlertDialog -import android.content.* -import android.content.Context.CLIPBOARD_SERVICE -import android.content.pm.PackageManager -import android.content.res.ColorStateList -import android.media.MediaPlayer -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.nfc.tech.IsoDep -import android.os.Build -import android.os.Bundle -import android.text.Html -import android.view.Gravity -import android.view.LayoutInflater -import android.view.View -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.ContextCompat -import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders -import com.tangem.App -import com.tangem.Constant -import com.tangem.data.Blockchain -import com.tangem.data.dp.PrefsManager -import com.tangem.data.getPayIdNetwork -import com.tangem.data.isPayIdSupported -import com.tangem.server_android.Result -import com.tangem.server_android.ServerApiTangem -import com.tangem.server_android.model.CardVerifyAndGetInfo -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_card.reader.CardProtocol -import com.tangem.tangem_card.tasks.VerifyCardTask -import com.tangem.tangem_card.util.Util -import com.tangem.tangem_sdk.android.reader.NfcReader -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD -import com.tangem.tangem_sdk.data.EXTRA_TANGEM_CARD_UID -import com.tangem.tangem_sdk.data.loadFromBundle -import com.tangem.ui.activity.MainActivity -import com.tangem.ui.dialog.NoExtendedLengthSupportDialog -import com.tangem.ui.dialog.PINSwapWarningDialog -import com.tangem.ui.dialog.ShowQRCodeDialog -import com.tangem.ui.dialog.WaitSecurityDelayDialog -import com.tangem.ui.event.DeletingWalletFinish -import com.tangem.ui.event.TransactionFinishWithSuccess -import com.tangem.ui.fragment.BaseFragment -import com.tangem.ui.fragment.pin.PinRequestFragment -import com.tangem.ui.fragment.pin.PinSwapFragment -import com.tangem.ui.navigation.NavigationResultListener -import com.tangem.util.LOG -import com.tangem.util.UtilHelper -import com.tangem.util.extensions.isStart2CoinCard -import com.tangem.wallet.* -import kotlinx.android.synthetic.main.dialog_pay_id.view.* -import kotlinx.android.synthetic.main.fr_loaded_wallet.* -import kotlinx.android.synthetic.main.layout_btn_details.* -import kotlinx.android.synthetic.main.layout_tangem_card.* -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import retrofit2.HttpException -import java.io.InputStream -import java.util.* -import kotlin.concurrent.timerTask - -class LoadedWalletFragment : BaseFragment(), NavigationResultListener, NfcAdapter.ReaderCallback, - CardProtocol.Notifications, SharedPreferences.OnSharedPreferenceChangeListener { - companion object { - val TAG: String = LoadedWalletFragment::class.java.simpleName - const val PAY_ID_TANGEM = "\$payid.tangem.com" - } - - override val layoutId = R.layout.fr_loaded_wallet - - private lateinit var viewModel: LoadedWalletViewModel - private lateinit var ctx: TangemContext - private lateinit var mpSecondScanSound: MediaPlayer - private var serverApiTangem: ServerApiTangem = ServerApiTangem() - private var lastTag: Tag? = null - private var lastReadSuccess = true - private var verifyCardTask: VerifyCardTask? = null - private var requestPIN2Count = 0 - private var timerHideErrorAndMessage: Timer? = null - private var newPIN = "" - private var newPIN2 = "" - private var cardProtocol: CardProtocol? = null - private var refreshAction: Runnable? = null - private val inactiveColor: ColorStateList by lazy { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - resources.getColorStateList(R.color.btn_dark, activity?.theme) - else - @Suppress("DEPRECATION") - resources.getColorStateList(R.color.btn_dark) - } - private val activeColor: ColorStateList by lazy { - val color = if (ctx.card?.isStart2CoinCard() == true) { - R.color.start2coin_orange - } else { - R.color.colorAccent - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - resources.getColorStateList(color, activity?.theme) - else - @Suppress("DEPRECATION") - resources.getColorStateList(color) - } - private var requestCounter: Int = 0 - set(value) { - field = value - LOG.i(TAG, "requestCounter, set $field") - if (field <= 0) { - LOG.e(TAG, "+++++++++++ FINISH REFRESH") - if (srl != null && srl.isRefreshing) - srl.isRefreshing = false - } else if (srl != null && !srl.isRefreshing) - srl.isRefreshing = true - } - - private var payId: String? = null - private lateinit var btnLoadItems: MutableList - - - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - ctx = TangemContext.loadFromBundle(context, arguments) - - lastTag = activity?.intent?.getParcelableExtra(Constant.EXTRA_LAST_DISCOVERED_TAG) - - if (arguments?.containsKey(NfcAdapter.EXTRA_TAG) == true) { - val tag = requireArguments().getParcelable(NfcAdapter.EXTRA_TAG) - if (tag != null) onTagDiscovered(tag) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel = ViewModelProviders.of(this).get(LoadedWalletViewModel::class.java) - - mpSecondScanSound = MediaPlayer.create(activity, R.raw.scan_card_sound) - - val engine = CoinEngineFactory.create(ctx) - - tvBalance.setSingleLine(!engine!!.needMultipleLinesForBalance()) - - ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card)) - - btnExtract.isEnabled = false - btnExtract.backgroundTintList = inactiveColor - - tvWallet.text = ctx.coinData.wallet - - btnLoadItems = mutableListOf( - getString(R.string.loaded_wallet_load_via_app), - getString(R.string.loaded_wallet_load_via_share_address), - getString(R.string.loaded_wallet_load_via_qr) - ) - - if (ctx.blockchain.isPayIdSupported() && !ctx.card.isStart2CoinCard()) { - ivPayId.visibility = View.VISIBLE - ivPayId.imageAlpha = 100 - ivPayId.setOnClickListener { createPayIdDialog() } - - getPayIdIfApplicable() - } - - - // set listeners - srl.setOnRefreshListener { refresh() } - - tvWallet.setOnClickListener { doShareWallet(false) } - - btnExplore.setOnClickListener { startActivity(Intent(Intent.ACTION_VIEW, engine.walletExplorerUri)) } - - btnCopy.setOnClickListener { doShareWallet(false) } - - - - if (ctx.card?.isStart2CoinCard() == true) { - btnLoad?.visibility = View.GONE - } - - btnLoad.setOnClickListener { - val cw = android.view.ContextThemeWrapper(activity, R.style.AlertDialogTheme) - val dialog = AlertDialog.Builder(cw).setItems(btnLoadItems.toTypedArray() - ) { _, which -> - when (btnLoadItems[which]) { - getString(R.string.loaded_wallet_load_via_app) -> { - try { - val intent = Intent(Intent.ACTION_VIEW, engine.shareWalletUriEx) - intent.addCategory(Intent.CATEGORY_DEFAULT) - startActivity(intent) - } catch (e: ActivityNotFoundException) { - (activity as MainActivity).toastHelper.showSingleToast(context, getString(R.string.loaded_wallet_no_compatible_wallet)) - } - } - - getString(R.string.loaded_wallet_load_via_share_address) -> { - doShareWallet(true) - } - - getString(R.string.loaded_wallet_load_via_qr) -> { - ShowQRCodeDialog.show(activity as AppCompatActivity?, engine.shareWalletUriEx.toString()) - } - payId -> { - if (payId == getString(R.string.loaded_wallet_create_pay_id)) { - createPayIdDialog() - } else { - payId?.let { copyText(it) } - } - } - - else -> { - } - } - } - val dlg = dialog.show() - val wlp = dlg.window.attributes - wlp.gravity = Gravity.BOTTOM - dlg.window.attributes = wlp - } - - btnExtract.setOnClickListener { - if (UtilHelper.isOnline(context as Activity)) - if (!engine.isExtractPossible) { - (activity as MainActivity).toastHelper.showSingleToast(context, ctx.message) - } else if (ctx.card!!.remainingSignatures == 0) { - (activity as MainActivity).toastHelper.showSingleToast(context, getString(R.string.loaded_wallet_warning_no_signature)) - } else { - val bundle = Bundle().apply { ctx.saveToBundle(this) } - navigateForResult(Constant.REQUEST_CODE_SEND_TRANSACTION, - R.id.action_loadedWalletFragment_to_prepareTransactionFragment, bundle) - } - else - Toast.makeText(activity, getString(R.string.general_error_no_connection), Toast.LENGTH_SHORT).show() - } - - btnDetails.setOnClickListener { - if (cardProtocol != null) { - val bundle = Bundle().apply { ctx.saveToBundle(this) } - navigateForResult(Constant.REQUEST_CODE_VERIFY_CARD, - R.id.action_loadedWalletFragment_to_verifyCard, bundle) - } else { - (activity as MainActivity).toastHelper - .showSingleToast(context, getString(R.string.general_notification_scan_again_to_verify)) - } - } - - btnNewScan.setOnClickListener { - // navigateToDestination(R.id.action_loadedWalletFragment_to_main) - navigateUp() - } - - // request card verify and get info listener - val cardVerifyAndGetInfoListener: ServerApiTangem.CardVerifyAndGetInfoListener = object : ServerApiTangem.CardVerifyAndGetInfoListener { - override fun onSuccess(cardVerifyAndGetArtworkResponse: CardVerifyAndGetInfo.Response?) { - LOG.i(TAG, "cardVerifyAndGetInfoListener onSuccess") - if (activity == null || !UtilHelper.isOnline(activity!!)) return - - val result = cardVerifyAndGetArtworkResponse?.results!![0] - if (result.error != null) { - ctx.card!!.isOnlineVerified = false - return - } - ctx.card!!.isOnlineVerified = result.passed - - requestCounter-- - updateViews() - - if (!result.passed) return - - if (App.localStorage.checkBatchInfoChanged(ctx.card!!, result)) { - LOG.w(TAG, "Batch ${result.batch} info changed to '$result'") - ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!)) - App.localStorage.applySubstitution(ctx.card!!) - refresh() - } - if (result.artwork != null && App.localStorage.checkNeedUpdateArtwork(result.artwork)) { - LOG.w(TAG, "Artwork '${result.artwork!!.id}' updated, need download") - requestCounter++ - serverApiTangem.requestArtwork(result.artwork!!.id, result.artwork!!.getUpdateDate(), ctx.card!!) - updateViews() - } - } - - override fun onFail(message: String?) { - LOG.i(TAG, "cardVerifyAndGetInfoListener onFail") - if (activity == null || !UtilHelper.isOnline(activity!!)) return - requestCounter-- - updateViews() - } - } - serverApiTangem.setCardVerifyAndGetInfoListener(cardVerifyAndGetInfoListener) - - // request artwork listener - val artworkListener: ServerApiTangem.ArtworkListener = object : ServerApiTangem.ArtworkListener { - override fun onSuccess(artworkId: String?, inputStream: InputStream?, updateDate: Date?) { - LOG.i(TAG, "artworkListener onSuccess") - if (activity == null || !UtilHelper.isOnline(activity!!)) return - App.localStorage.updateArtwork(artworkId!!, inputStream!!, updateDate!!) - requestCounter-- - ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!)) - updateViews() - } - - override fun onFail(message: String?) { - LOG.i(TAG, "artworkListener onFail") - if (activity == null || !UtilHelper.isOnline(activity!!)) return - requestCounter-- - updateViews() - } - } - serverApiTangem.setArtworkListener(artworkListener) - refresh() - startVerify(lastTag) - - - - // set rate info to CoinData - viewModel.getRateInfo().observe(viewLifecycleOwner, Observer { rate -> - ctx.coinData.rate = rate - ctx.coinData.rateAlter = rate - updateViews() - }) - viewModel.requestRateInfo(ctx) - } - - private fun getPayIdIfApplicable() { - if (ctx.blockchain.isPayIdSupported() && !ctx.card.isStart2CoinCard()) { - viewModel.getPayId( - Util.byteArrayToHexString(ctx.card.cid!!), - Util.byteArrayToHexString(ctx.card.cardPublicKey!!)) - .observe( - viewLifecycleOwner, Observer { result -> - when (result) { - is Result.Success -> { - onPayIdFound(result.data.payId) - } - is Result.Failure -> { - (result.error as? HttpException)?.let { - if (it.code() == 404) { - val createPayId = getString(R.string.loaded_wallet_create_pay_id) - payId = createPayId - if (!btnLoadItems.contains(createPayId)) { - btnLoadItems.add(createPayId) - } - } - } - } - } - }) - } - } - - private fun createPayIdDialog() { - val dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_pay_id, null); - val alertDialogBuilderUserInput = AlertDialog.Builder(context); - alertDialogBuilderUserInput.setView(dialogView); - alertDialogBuilderUserInput - .setCancelable(true) - .setPositiveButton(getString(R.string.create_pay_id_create)) { dialogBox, _ -> - if (dialogView.etPayId.text.isNullOrBlank()) { - Toast.makeText(context, getString(R.string.create_pay_id_empty), Toast.LENGTH_LONG).show() - return@setPositiveButton - } - - dialogBox.cancel() - createPayId("${dialogView.etPayId.text}$PAY_ID_TANGEM") - } - - .setNegativeButton(getString(R.string.general_cancel)){ dialogBox, _ -> - dialogBox.cancel() - } - - alertDialogBuilderUserInput.create().show() - } - - private fun createPayId(payId: String) { - viewModel.setPayId( - Util.byteArrayToHexString(ctx.card.cid!!), - Util.byteArrayToHexString(ctx.card.cardPublicKey!!), - payId, - ctx.coinData.wallet, ctx.blockchain.getPayIdNetwork() - ) - .observe(viewLifecycleOwner, Observer { result -> - when (result) { - is Result.Success -> { - onPayIdFound(payId) - Toast.makeText(context, getString(R.string.create_pay_id_success), Toast.LENGTH_LONG).show() - } - is Result.Failure -> { - Toast.makeText(context, getString(R.string.create_pay_id_error), Toast.LENGTH_LONG).show() - } - } - }) - } - - private fun onPayIdFound(payId: String) { - updateLoadButtonItemsWithNewPayId(payId) - ivPayId.imageAlpha = 255 - this.payId = payId - ivPayId.setOnClickListener { copyText(payId) } - } - - private fun updateLoadButtonItemsWithNewPayId(payId: String) { - val oldPayId = btnLoadItems.firstOrNull { it.contains(PAY_ID_TANGEM) } - btnLoadItems.remove(oldPayId) - btnLoadItems.remove(getString(R.string.loaded_wallet_create_pay_id)) - btnLoadItems.add(payId) - } - - override fun onPause() { - super.onPause() - if (timerHideErrorAndMessage != null) { - timerHideErrorAndMessage!!.cancel() - timerHideErrorAndMessage = null - } - } - - override fun onStart() { - super.onStart() - if (!EventBus.getDefault().isRegistered(this)) - EventBus.getDefault().register(this) - } - - override fun onStop() { - srl?.removeCallbacks(refreshAction) - super.onStop() - } - - override fun onDestroy() { - EventBus.getDefault().unregister(this) - super.onDestroy() - } - - @Subscribe - fun onTransactionFinishWithSuccess(transactionFinishWithSuccess: TransactionFinishWithSuccess) { - refreshAction = Runnable { refresh() } - ctx.card.remainingSignatures -= 1 - srl?.postDelayed(refreshAction, 10000) - } - - @Subscribe - fun onDeleteWalletFinish(deletingWalletFinish: DeletingWalletFinish) { - navigateUp() - } - - override fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle?) { - when (requestCode) { - Constant.REQUEST_CODE_VERIFY_CARD -> - // action after erase wallet - if (resultCode == Activity.RESULT_OK) - navigateUp() - - Constant.REQUEST_CODE_ENTER_NEW_PIN -> if (resultCode == Activity.RESULT_OK) - if (data != null) - if (data.containsKey(Constant.EXTRA_CONFIRM_PIN)) { - val bundle = PinRequestFragment.callingIntentRequestPin( - PinRequestFragment.Mode.RequestPIN.toString(), ctx, - data.getString(Constant.EXTRA_NEW_PIN) ?: "") - - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_loadedWalletFragment_to_pinRequestFragment, - bundle) - } else { - val bundle = PinRequestFragment.callingIntentConfirmPin( - PinRequestFragment.Mode.ConfirmNewPIN.toString(), - data.getString(Constant.EXTRA_NEW_PIN) ?: "") - - navigateForResult(Constant.REQUEST_CODE_ENTER_NEW_PIN, - R.id.action_loadedWalletFragment_to_pinRequestFragment, bundle) - } - - - Constant.REQUEST_CODE_ENTER_NEW_PIN2 -> if (resultCode == Activity.RESULT_OK) - if (data != null) - if (data.containsKey(Constant.EXTRA_CONFIRM_PIN_2)) { - val bundle = PinRequestFragment.callingIntentRequestPin2( - PinRequestFragment.Mode.RequestPIN2.toString(), ctx, - data.getString(Constant.EXTRA_NEW_PIN_2)) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_loadedWalletFragment_to_pinRequestFragment, bundle) - - } else { - val bundle = PinRequestFragment.callingIntentConfirmPin2( - PinRequestFragment.Mode.ConfirmNewPIN2.toString(), - data.getString(Constant.EXTRA_NEW_PIN_2)) - navigateForResult(Constant.REQUEST_CODE_ENTER_NEW_PIN2, - R.id.action_loadedWalletFragment_to_pinRequestFragment, bundle) - } - - Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) { - if (newPIN == "") - newPIN = ctx.card!!.pin - - if (newPIN2 == "") - newPIN2 = App.pinStorage.piN2 - - val pinSwapWarningDialog = PINSwapWarningDialog() - pinSwapWarningDialog.setOnRefreshPage { - val bundle = PinSwapFragment.callingIntent(newPIN, newPIN2) - navigateForResult(Constant.REQUEST_CODE_SWAP_PIN, R.id.pinSwapFragment, bundle) - } - val bundle = Bundle() - if (!CardProtocol.isDefaultPIN(newPIN) || !CardProtocol.isDefaultPIN2(newPIN2)) - bundle.putString(Constant.EXTRA_MESSAGE, getString(R.string.loaded_wallet_warning_dont_forget_pin)) - else - bundle.putString(Constant.EXTRA_MESSAGE, getString(R.string.loaded_wallet_warning_default_pin)) - pinSwapWarningDialog.arguments = bundle - activity?.supportFragmentManager?.let { pinSwapWarningDialog.show(it, PINSwapWarningDialog.TAG) } - } - - Constant.REQUEST_CODE_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) { - if (data == null) { - val resultData = Bundle() - ctx.saveToBundle(resultData) - resultData.putString(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_DELETE) - navigateBackWithResult(Activity.RESULT_OK, resultData) - } else { - data.putString(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_UPDATE) - navigateBackWithResult(Activity.RESULT_OK, data) - } - - } else { - if (data != null && data.containsKey(EXTRA_TANGEM_CARD_UID) && data.containsKey(EXTRA_TANGEM_CARD)) { - val updatedCard = TangemCard(data.getString(EXTRA_TANGEM_CARD_UID)) - updatedCard.loadFromBundle(data.getBundle(EXTRA_TANGEM_CARD)) - ctx.card = updatedCard - } - if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) { - requestPIN2Count++ - val bundle = PinRequestFragment.callingIntentRequestPin2( - PinRequestFragment.Mode.RequestPIN2.toString(), ctx) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN, - R.id.action_loadedWalletFragment_to_pinRequestFragment, bundle) - return - } else { - if (data != null && data.containsKey(Constant.EXTRA_MESSAGE)) { - ctx.error = data.getString(Constant.EXTRA_MESSAGE) - } - } - } - - Constant.REQUEST_CODE_PURGE -> if (resultCode == Activity.RESULT_OK) { - if (data == null) { - val resultData = Bundle() - ctx.saveToBundle(resultData) - resultData.putString(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_DELETE) - navigateBackWithResult(Activity.RESULT_OK, resultData) - } else { - data.putString(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_UPDATE) - navigateBackWithResult(Activity.RESULT_OK, data) - } - - } else { - if (data != null && data.containsKey(EXTRA_TANGEM_CARD_UID) && data.containsKey(EXTRA_TANGEM_CARD)) { - val updatedCard = TangemCard(data.getString(EXTRA_TANGEM_CARD_UID)) - updatedCard.loadFromBundle(data.getBundle(EXTRA_TANGEM_CARD)) - ctx.card = updatedCard - } - if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) { - requestPIN2Count++ - - val bundle = Bundle() - bundle.putString(Constant.EXTRA_MODE, PinRequestFragment.Mode.RequestPIN2.toString()) - ctx.saveToBundle(bundle) - navigateForResult(Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE, - R.id.action_loadedWalletFragment_to_pinRequestFragment, bundle) - - return - } else { - if (data != null && data.containsKey(Constant.EXTRA_MESSAGE)) { - ctx.error = data.getString(Constant.EXTRA_MESSAGE) - } - } - updateViews() - } - - Constant.REQUEST_CODE_SEND_TRANSACTION, Constant.REQUEST_CODE_RECEIVE_TRANSACTION -> { - if (resultCode == Activity.RESULT_OK) { -// ctx.card.remainingSignatures = ctx.card.remainingSignatures - 1 - ctx.coinData?.clearInfo() - srl?.postDelayed({ this.refresh() }, 5000) - srl?.isRefreshing = true - updateViews() - } - - if (data != null) { - if (data.containsKey(EXTRA_TANGEM_CARD_UID) && data.containsKey(EXTRA_TANGEM_CARD)) { - val updatedCard = TangemCard(data.getString(EXTRA_TANGEM_CARD_UID)) - updatedCard.loadFromBundle(data.getBundle(EXTRA_TANGEM_CARD)) - ctx.card = updatedCard - } - } - } - else -> if (data != null && data.containsKey(Constant.EXTRA_MESSAGE)) { - when (resultCode) { - Activity.RESULT_CANCELED -> ctx.error = data.getString(Constant.EXTRA_MESSAGE) - Activity.RESULT_OK -> ctx.message = data.getString(Constant.EXTRA_MESSAGE) - } - updateViews() - } - } - } - - override fun onTagDiscovered(tag: Tag) { - startVerify(tag) - } - - override fun onReadStart(cardProtocol: CardProtocol) { - rlProgressBar?.post { rlProgressBar?.visibility = View.VISIBLE } - } - - override fun onReadProgress(protocol: CardProtocol, progress: Int) { - - } - - override fun onReadFinish(cardProtocol: CardProtocol?) { - verifyCardTask = null - if (cardProtocol != null) { - if (cardProtocol.error == null) { - rlProgressBar?.post { - rlProgressBar?.visibility = View.GONE - this.cardProtocol = cardProtocol - if (!cardProtocol.card.isWalletPublicKeyValid) - refresh() - else - updateViews() - - // TODO - remove, only for test&demo reason! - // TODO - begin - if (cardProtocol.card.isIDCard) { - if (cardProtocol.card.hasIDCardData()) { - Toast.makeText(activity, "ID card: ${cardProtocol.card.idCardData.fullName}", Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(activity, "Empty ID card", Toast.LENGTH_SHORT).show() - } - } - // TODO - end - - mpSecondScanSound.start() - } - } else { - // remove last UIDs because of error and no card read - rlProgressBar?.post { - lastReadSuccess = false - if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported) - if (!NoExtendedLengthSupportDialog.allReadyShowed) - activity?.supportFragmentManager?.let { NoExtendedLengthSupportDialog().show(it, NoExtendedLengthSupportDialog.TAG) } - else - Toast.makeText(activity, R.string.general_notification_scan_again, Toast.LENGTH_SHORT).show() - } - } - } - - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadCancel() { - verifyCardTask = null - rlProgressBar?.postDelayed({ - try { - rlProgressBar?.visibility = View.GONE - } catch (e: Exception) { - e.printStackTrace() - } - }, 500) - } - - override fun onReadWait(msec: Int) { - WaitSecurityDelayDialog.onReadWait(activity as AppCompatActivity?, msec) - } - - override fun onReadBeforeRequest(timeout: Int) { - WaitSecurityDelayDialog.onReadBeforeRequest(activity as AppCompatActivity?, timeout) - } - - override fun onReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(activity) - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - - } - - fun updateViews() { - if (activity == null || this.view == null) return - - if (timerHideErrorAndMessage != null) { - timerHideErrorAndMessage!!.cancel() - timerHideErrorAndMessage = null - } - - if (ctx.hasError()) { - tvError?.visibility = View.VISIBLE - tvError?.text = ctx.error - } else { - tvError?.visibility = View.GONE - tvError?.text = "" - } - - if (ctx.message == null || ctx.message.isEmpty()) { - tvMessage?.text = "" - tvMessage?.visibility = View.GONE - } else { - tvMessage?.text = ctx.message - tvMessage?.visibility = View.VISIBLE - } - - if (tvError?.visibility == View.VISIBLE || tvMessage?.visibility == View.VISIBLE) { - timerHideErrorAndMessage = Timer() - timerHideErrorAndMessage?.schedule( - timerTask { - activity?.runOnUiThread { - tvMessage?.visibility = View.GONE - tvError?.visibility = View.GONE - // clear only already viewed messages - if (tvMessage?.text == ctx.message) ctx.message = null - if (tvError?.text == ctx.error) ctx.error = null - } - }, - 5000) - } - - if (srl.isRefreshing) { - tvBalanceLine1.setTextColor(resources.getColor(R.color.primary)) - tvBalanceLine1.text = getString(R.string.loaded_wallet_verifying_in_blockchain) - tvBalanceLine2.text = "" - tvBalance.text = "" - tvBalanceEquivalent.text = "" - } else { - val validator = BalanceValidator() - // TODO why attest=false? - validator.check(ctx, false) - context?.let { ContextCompat.getColor(it, validator.color) }?.let { tvBalanceLine1?.setTextColor(it) } - tvBalanceLine1?.text = getString(validator.firstLine) - tvBalanceLine2?.text = getString(validator.getSecondLine(false)) - } - - val engine = CoinEngineFactory.create(ctx) - when { - engine!!.hasBalanceInfo() -> { - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(engine.balanceHTML, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(engine.balanceHTML) - tvBalance.text = html - tvBalanceEquivalent.text = engine.balanceEquivalent - } - - ctx.card?.offlineBalance != null -> { - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(engine.offlineBalanceHTML, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(engine.offlineBalanceHTML) - tvBalance.text = html - } - - else -> tvBalance.text = "" - } - - tvWallet.text = ctx.coinData!!.wallet - - if (ctx.card!!.tokenSymbol.length > 1) { - @Suppress("DEPRECATION") val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - Html.fromHtml(ctx.blockchainName, Html.FROM_HTML_MODE_LEGACY) - else - Html.fromHtml(ctx.blockchainName) - tvBlockchain.text = html - } else - tvBlockchain.text = ctx.blockchainName - - if (requestCounter == 0 && engine.hasBalanceInfo()) { - btnExtract.isEnabled = true - btnExtract.backgroundTintList = activeColor - } else { - btnExtract.isEnabled = false - btnExtract.backgroundTintList = inactiveColor - } - - if (engine.isNftToken) { - btnLoad.isEnabled = false - btnLoad.backgroundTintList = inactiveColor - btnExtract.isEnabled = false - btnExtract.backgroundTintList = inactiveColor - } - } - - private fun refresh() { - if (ctx.card == null) return - - // clear all card data and request again - ctx.coinData.clearInfo() - ctx.error = null - ctx.message = null - - LOG.w(TAG, "============= START REFRESH") - requestCounter = 0 - srl?.isRefreshing = true - - if (payId == null || payId == getString(R.string.loaded_wallet_create_pay_id)) { - getPayIdIfApplicable() - } - - updateViews() - - // Bitcoin, Litecoin, BitcoinCash, Stellar - if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet || ctx.blockchain == Blockchain.BitcoinDual || - ctx.blockchain == Blockchain.Litecoin || ctx.blockchain == Blockchain.BitcoinCash || - ctx.blockchain == Blockchain.Stellar || ctx.blockchain == Blockchain.StellarTestNet || ctx.blockchain == Blockchain.StellarAsset) { - ctx.coinData.setIsBalanceEqual(true) - } - - requestVerifyAndGetInfo() - - requestBalanceAndUnspentTransactions() - - if (::viewModel.isInitialized) - viewModel.requestRateInfo(ctx) - - if (requestCounter == 0) { - // if no connection and no requests posted - srl?.isRefreshing = false - updateViews() - } - } - - private fun requestBalanceAndUnspentTransactions() { - if (UtilHelper.isOnline(context as Activity)) { - val coinEngine = CoinEngineFactory.create(ctx) - requestCounter++ - coinEngine!!.requestBalanceAndUnspentTransactions( - object : CoinEngine.BlockchainRequestsCallbacks { - - - override fun onComplete(success: Boolean) { - LOG.i(TAG, "requestBalanceAndUnspentTransactions onComplete: $success, request counter $requestCounter") - if (activity == null) return - requestCounter-- - if (!success) { - LOG.e(TAG, "requestBalanceAndUnspentTransactions ctx.error: " + ctx.error) - } - updateViews() - - if (coinEngine.isBalanceNotZero) showWarningIfPendingTransactionIsPossible() - } - - override fun onProgress() { - if (activity == null) return - LOG.i(TAG, "requestBalanceAndUnspentTransactions onProgress") - updateViews() - } - - override fun allowAdvance(): Boolean { - return try { - context?.let { UtilHelper.isOnline(it) }!! - } catch (e: KotlinNullPointerException) { - e.printStackTrace() - false - } - } - } - ) - } else { - ctx.error = getString(R.string.general_error_no_connection) - updateViews() - } - } - - private fun showWarningIfPendingTransactionIsPossible() { - if (ctx.card.signedHashes > 0 && isNewCid(ctx.card.cidDescription) - && ctx.card.signedHashes != ctx.coinData.sentTransactionsCount) { - AlertDialog.Builder(context) - .setTitle(R.string.dialog_warning) - .setMessage(R.string.loaded_wallet_warning_card_signed_transactions) - .setPositiveButton(R.string.general_ok) { _, _ -> } - .create() - .show() - } - PrefsManager.getInstance().appendCid(ctx.card.cidDescription) - } - - private fun isNewCid(cid: String): Boolean = !PrefsManager.getInstance().getAllCids().contains(cid) - - private fun requestVerifyAndGetInfo() { - if (UtilHelper.isOnline(context as Activity)) { - if ((ctx.card!!.isOnlineVerified == null || !ctx.card!!.isOnlineVerified)) { - LOG.i(TAG, "requestVerifyAndGetInfo") - requestCounter++ - serverApiTangem.cardVerifyAndGetInfo(ctx.card) - } - } else { - ctx.error = getString(R.string.general_error_no_connection) - updateViews() - } - } - - private fun startVerify(tag: Tag?) { - try { - val isoDep = IsoDep.get(tag) - val uid = tag?.id - val sUID = Util.byteArrayToHexString(uid) - if (ctx.card.uid != sUID || cardProtocol != null) { - (activity as? MainActivity)?.nfcManager?.ignoreTag(isoDep.tag) - return - } - - if (lastReadSuccess) - isoDep.timeout = 1000 - else - isoDep.timeout = 65000 - - verifyCardTask = VerifyCardTask(ctx.card, NfcReader((activity as MainActivity).nfcManager, isoDep), - App.localStorage, App.pinStorage, App.firmwaresStorage, this) - verifyCardTask?.start() - } catch (e: Exception) { - e.printStackTrace() - } - } - - private fun doShareWallet(useURI: Boolean) { - if (useURI) { - val txtShare = ctx.coinData.wallet - val intent = Intent(Intent.ACTION_SEND) - intent.type = Constant.INTENT_TYPE_TEXT_PLAIN - intent.putExtra(Intent.EXTRA_SUBJECT, Constant.WALLET_ADDRESS) - intent.putExtra(Intent.EXTRA_TEXT, txtShare) - - val packageManager = activity?.packageManager - val activities = packageManager?.queryIntentActivities(intent, PackageManager.MATCH_ALL) - val isIntentSafe = activities?.size!! > 0 - - if (isIntentSafe) { - // create intent to show chooser - val chooser = Intent.createChooser(intent, getString(R.string.loaded_wallet_chooser_share)) - - // verify the intent will resolve to at least one activity - if (intent.resolveActivity(requireActivity().packageManager) != null) { - startActivity(chooser) - } - } else { - val clipboard = activity?.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager - clipboard.primaryClip = ClipData.newPlainText(txtShare, txtShare) - Toast.makeText(activity, R.string.loaded_wallet_toast_copied, Toast.LENGTH_LONG).show() - } - } else { - copyText(ctx.coinData.wallet) - } - } - - private fun copyText(text: String) { - val clipboard = activity?.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager - clipboard.primaryClip = ClipData.newPlainText(text, text) - Toast.makeText(activity, R.string.loaded_wallet_toast_copied, Toast.LENGTH_LONG).show() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/fragment/wallet/LoadedWalletViewModel.kt b/app/src/main/java/com/tangem/ui/fragment/wallet/LoadedWalletViewModel.kt deleted file mode 100644 index fb1191f6b1..0000000000 --- a/app/src/main/java/com/tangem/ui/fragment/wallet/LoadedWalletViewModel.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.tangem.ui.fragment.wallet - -import androidx.lifecycle.* -import com.tangem.data.network.ServerApiCommon -import com.tangem.data.network.ServerApiCommon.RateInfoListener -import com.tangem.data.network.model.RateInfoResponse -import com.tangem.server_android.PayIdResponse -import com.tangem.server_android.PayIdService -import com.tangem.server_android.Result -import com.tangem.server_android.SetPayIdResponse -import com.tangem.wallet.TangemContext -import kotlinx.coroutines.CoroutineExceptionHandler - -class LoadedWalletViewModel : ViewModel() { - private val serverApiCommon: ServerApiCommon = ServerApiCommon() - private val payIdService = PayIdService() - private lateinit var ctx: TangemContext - private val rate: MutableLiveData by lazy { - MutableLiveData().also { - loadRateInfo() - } - } - - private val scope = viewModelScope.coroutineContext + CoroutineExceptionHandler { _, ex -> - throw ex - } - - fun getRateInfo(): LiveData { - return rate - } - - fun requestRateInfo(ctx: TangemContext) { - this.ctx = ctx - // TODO - move loadRateInfo to CoinEngine - serverApiCommon.requestRateInfo(ctx.blockchain.currency) - } - - private fun loadRateInfo() { - serverApiCommon.setRateInfoListener(object : RateInfoListener { - override fun onSuccess(rateInfoResponse: RateInfoResponse?) { - rate.value = rateInfoResponse!!.data!!.quote!!.usd!!.price - } - - override fun onFail(message: String?) { - ctx.error = message - } - }) - } - - fun getPayId(cardId: String, publicKey: String): LiveData> { - return liveData(viewModelScope.coroutineContext) { - emit( - payIdService.getPayId( - cardId, - publicKey - ) - ) - } - } - - fun setPayId( - cardId: String, - publicKey: String, - payId: String, - address: String, - network: String - ): LiveData> { - return liveData(scope) { - emit( - payIdService.setPayId( - cardId, publicKey, payId, address, network - ) - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/navigation/NavigationResult.kt b/app/src/main/java/com/tangem/ui/navigation/NavigationResult.kt deleted file mode 100644 index ffa42a3976..0000000000 --- a/app/src/main/java/com/tangem/ui/navigation/NavigationResult.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.ui.navigation - -import android.os.Bundle - -data class NavigationResult(val requestCode: String, val resultCode: Int, val data: Bundle? = null) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/ui/navigation/NavigationResultListener.kt b/app/src/main/java/com/tangem/ui/navigation/NavigationResultListener.kt deleted file mode 100644 index f0e1681864..0000000000 --- a/app/src/main/java/com/tangem/ui/navigation/NavigationResultListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.tangem.ui.navigation - -import android.os.Bundle - -interface NavigationResultListener { - fun onNavigationResult(requestCode: String, resultCode: Int, data: Bundle? = null) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/util/Analytics.kt b/app/src/main/java/com/tangem/util/Analytics.kt deleted file mode 100644 index 3885d57da0..0000000000 --- a/app/src/main/java/com/tangem/util/Analytics.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.tangem.util - -import android.content.Context -import android.os.Bundle -import androidx.core.os.bundleOf -import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.google.firebase.perf.FirebasePerformance -import com.tangem.data.dp.PrefsManager -import com.tangem.wallet.BuildConfig -import com.tangem.wallet.R -import com.tangem.wallet.TangemContext - -enum class AnalyticsEvent(val event: String) { - CARD_IS_SCANNED("card_is_scanned"), - TRANSACTION_IS_SENT("transaction_is_sent"), - READY_TO_SCAN("ready_to_scan"), - READY_TO_SIGN("ready_to_sign"), - SIGNED("signed"), - ANALYTICS_TURNED_OFF("analytics_turned_off"), - CARD_TAP_USER_TIMER("CardTapUserTimer"), - ; -} - -enum class AnalyticsParam(val param: String) { - BLOCKCHAIN("blockchain"), - BATCH_ID("batch_id"), - FIRMWARE("firmware"), - ; -} - -class Analytics { - companion object { - fun setCardData(ctx: TangemContext): Bundle { - return bundleOf( - AnalyticsParam.BLOCKCHAIN.param to ctx.blockchainName, - AnalyticsParam.BATCH_ID.param to ctx.card.batch, - AnalyticsParam.FIRMWARE.param to ctx.card.firmwareVersion - ) - } - - fun isEnabled(): Boolean { - return PrefsManager.getInstance().getSettingsBoolean(R.string.pref_analytics, true) - } - - fun setFirebaseEnabled(context: Context, enable: Boolean = isEnabled()) { - FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enable) - FirebaseAnalytics.getInstance(context).setAnalyticsCollectionEnabled( - enable && !BuildConfig.DEBUG - ) - FirebasePerformance.getInstance().isPerformanceCollectionEnabled = enable - } - } -} diff --git a/app/src/main/java/com/tangem/util/ByteUtil.java b/app/src/main/java/com/tangem/util/ByteUtil.java deleted file mode 100644 index 6a55a35daa..0000000000 --- a/app/src/main/java/com/tangem/util/ByteUtil.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.tangem.util; - -public class ByteUtil { - - public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - public static byte[] and(byte[] b1, byte[] b2) { - if (b1.length != b2.length) throw new RuntimeException("Array sizes differ"); - byte[] ret = new byte[b1.length]; - for (int i = 0; i < ret.length; i++) { - ret[i] = (byte) (b1[i] & b2[i]); - } - return ret; - } - - public static byte[] or(byte[] b1, byte[] b2) { - if (b1.length != b2.length) throw new RuntimeException("Array sizes differ"); - byte[] ret = new byte[b1.length]; - for (int i = 0; i < ret.length; i++) { - ret[i] = (byte) (b1[i] | b2[i]); - } - return ret; - } - - public static boolean isNullOrZeroArray(byte[] array){ - return (array == null) || (array.length == 0); - } - - public static boolean isSingleZero(byte[] array){ - return (array.length == 1 && array[0] == 0); - } - - public static int length(byte[]... bytes) { - int result = 0; - for (byte[] array : bytes) { - result += (array == null) ? 0 : array.length; - } - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/util/CommonUtil.java b/app/src/main/java/com/tangem/util/CommonUtil.java deleted file mode 100644 index 613fefd364..0000000000 --- a/app/src/main/java/com/tangem/util/CommonUtil.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.tangem.util; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.util.Log; - -import com.tangem.wallet.R; - -import java.io.File; -import java.util.List; - -public class CommonUtil { - - public static void sendEmail(Context context, File zipFile, String logTag, String subject, String text, File[] fileLocations) { - if (zipFile != null) return; - try { - Intent intent = new Intent(Intent.ACTION_SEND) - //.setData(new Uri.Builder().scheme("mailto").build()) - .setType("text/plain") - .putExtra(Intent.EXTRA_EMAIL, new String[]{"android@tangem.com"}) - .putExtra(Intent.EXTRA_SUBJECT, subject) - .putExtra(Intent.EXTRA_TEXT, text); - - if (fileLocations != null && fileLocations.length > 0) { - String[] fileNames = new String[fileLocations.length]; - for (int i = 0; i < fileLocations.length; i++) - fileNames[i] = fileLocations[i].getAbsolutePath(); - zipFile = File.createTempFile("tangemLogs", ".zip", fileLocations[0].getParentFile()); - Compress compress = new Compress(fileNames, zipFile.getAbsolutePath()); - compress.zip(); - Log.e(logTag, String.format("Send %d bytes zip with logs", zipFile.length())); - Uri attachment = Uri.parse("content://" + context.getString(R.string.log_file_provider_authorities) + "/" + zipFile.getName()); - - intent.putExtra(Intent.EXTRA_STREAM, attachment); - zipFile.deleteOnExit(); - } - - List activities = context.getPackageManager().queryIntentActivities(intent, 0); - boolean isIntentSafe = activities.size() > 0; - - if (isIntentSafe) { - context.startActivity(intent); - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - -} diff --git a/app/src/main/java/com/tangem/util/Compress.java b/app/src/main/java/com/tangem/util/Compress.java deleted file mode 100644 index 20deeefd86..0000000000 --- a/app/src/main/java/com/tangem/util/Compress.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.tangem.util; - -import android.util.Log; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class Compress { - private static final int BUFFER = 2048; - - private String[] _files; - private String _zipFile; - - public Compress(String[] files, String zipFile) { - _files = files; - _zipFile = zipFile; - } - - public void zip() { - try { - BufferedInputStream origin = null; - FileOutputStream dest = new FileOutputStream(_zipFile); - - ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); - - byte data[] = new byte[BUFFER]; - - for (String _file : _files) { - Log.v("Compress", "Adding: " + _file); - FileInputStream fi = new FileInputStream(_file); - origin = new BufferedInputStream(fi, BUFFER); - ZipEntry entry = new ZipEntry(_file.substring(_file.lastIndexOf("/") + 1)); - out.putNextEntry(entry); - int count; - while ((count = origin.read(data, 0, BUFFER)) != -1) { - out.write(data, 0, count); - } - origin.close(); - } - - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - - } -} diff --git a/app/src/main/java/com/tangem/util/CryptoUtil.java b/app/src/main/java/com/tangem/util/CryptoUtil.java deleted file mode 100644 index bc6eb16d42..0000000000 --- a/app/src/main/java/com/tangem/util/CryptoUtil.java +++ /dev/null @@ -1,271 +0,0 @@ -package com.tangem.util; - -import android.util.Log; - -import com.tangem.tangem_card.util.Util; -import com.tangem.wallet.ECDSASignatureETH; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.sec.SECNamedCurves; -import org.bouncycastle.asn1.x9.X9ECParameters; -import org.bouncycastle.asn1.x9.X9IntegerConverter; -import org.bouncycastle.crypto.params.ECDomainParameters; -import org.bouncycastle.crypto.params.ECPrivateKeyParameters; -import org.bouncycastle.crypto.params.ECPublicKeyParameters; -import org.bouncycastle.crypto.signers.ECDSASigner; -import org.bouncycastle.jce.ECNamedCurveTable; -import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; -import org.bouncycastle.jce.spec.ECPublicKeySpec; -import org.bouncycastle.math.ec.ECAlgorithms; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; - -import static org.bitcoinj.core.ECKey.CURVE; -import static org.bitcoinj.core.ECKey.HALF_CURVE_ORDER; - -/** - * Created by Ilia on 15.02.2018. - */ - -public class CryptoUtil { - - public static boolean checkHashSign2(byte[] pub, byte[] hash, BigInteger r, BigInteger s) - { - ECDSASigner signer = new ECDSASigner(); - - ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE); - signer.init(false, params); - return signer.verifySignature(hash, r, s); - } - - public static boolean isCanonical(BigInteger s) { - return s.compareTo(HALF_CURVE_ORDER) <= 0; - } - - public static BigInteger toCanonicalised(BigInteger s) { - - // The order of the curve is the number of valid points that exist on that curve. If S is in the upper - // half of the number of valid points, then bring it back to the lower half. Otherwise, imagine that - // N = 10 - // s = 8, so (-8 % 10 == 2) thus both (r, 8) and (r, 2) are valid solutions. - // 10 - 8 == 2, giving us always the latter solution, which is canonical. - if(!isCanonical(s)) { - BigInteger canon = CURVE.getN().subtract(s); - Log.e("TX_SIGN", "non Canonical S"); - return canon; - } - - return s; - - } - - private static ECPoint decompressKey(BigInteger xBN, boolean yBit) { - X9IntegerConverter x9 = new X9IntegerConverter(); - byte[] compEnc = x9.integerToBytes(xBN, 1 + x9.getByteLength(CURVE.getCurve())); - compEnc[0] = (byte) (yBit ? 0x03 : 0x02); - return CURVE.getCurve().decodePoint(compEnc); - } - - public static byte[] recoverPubBytesFromSignature(int recId, ECDSASignatureETH sig, byte[] messageHash) { - // 1.0 For j from 0 to h (h == recId here and the loop is outside this function) - // 1.1 Let x = r + jn - - X9ECParameters params = SECNamedCurves.getByName("secp256k1"); - ECDomainParameters CURVE2 = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH()); - - BigInteger n = CURVE2.getN(); // Curve order. - BigInteger i = BigInteger.valueOf((long) recId / 2); - BigInteger x = sig.r.add(i.multiply(n)); - // 1.2. Convert the integer x to an octet string X of length mlen using the conversion routine - // specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉. - // 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the - // conversion routine specified in Section 2.3.4. If this conversion routine outputs “invalid”, then - // do another iteration of Step 1. - // - // More concisely, what these points mean is to use X as a compressed public key. - ECCurve.Fp curve = (ECCurve.Fp) CURVE2.getCurve(); - BigInteger prime = curve.getQ(); // Bouncy Castle is not consistent about the letter it uses for the prime. - if (x.compareTo(prime) >= 0) { - // Cannot have point co-ordinates larger than this as everything takes place modulo Q. - return null; - } - // Compressed keys require you to know an extra bit of data about the y-coord as there are two possibilities. - // So it's encoded in the recId. - ECPoint R = decompressKey(x, (recId & 1) == 1); - // 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers responsibility). - if (!R.multiply(n).isInfinity()) - return null; - // 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification. - BigInteger e = new BigInteger(1, messageHash); - // 1.6. For k from 1 to 2 do the following. (loop is outside this function via iterating recId) - // 1.6.1. Compute a candidate public key as: - // Q = mi(r) * (sR - eG) - // - // Where mi(x) is the modular multiplicative inverse. We transform this into the following: - // Q = (mi(r) * s ** R) + (mi(r) * -e ** G) - // Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation - // ** is point multiplication and + is point addition (the EC group operator). - // - // We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive - // inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8. - BigInteger eInv = BigInteger.ZERO.subtract(e).mod(n); - BigInteger rInv = sig.r.modInverse(n); - BigInteger srInv = rInv.multiply(sig.s).mod(n); - BigInteger eInvrInv = rInv.multiply(eInv).mod(n); - ECPoint.Fp q = (ECPoint.Fp) ECAlgorithms.sumOfTwoMultiplies(CURVE2.getG(), eInvrInv, R, srInv); - return q.getEncoded(/* compressed */ false); - } - - public static byte[] calcSign(byte[] priv, byte[] hash) - { - ECDSASigner signer = new ECDSASigner(); - BigInteger d = new BigInteger(priv); - ECPrivateKeyParameters params = new ECPrivateKeyParameters(d, CURVE); - signer.init(true, params); - BigInteger[] rs = signer.generateSignature(hash); - byte[] r = rs[0].toByteArray(); - byte[] s = rs[1].toByteArray(); - byte[] sign = new byte[64]; - for(int i = 0; i < 32; ++i) - { - sign[i] = r[i]; - sign[i+32] = s[i]; - } - return sign; - - } - - public static boolean isEncodingCanonical(byte[] signature) { - // See Bitcoin Core's IsCanonicalSignature, https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 - // A canonical signature exists of: <30> <02> <02> - // Where R and S are not negative (their first byte has its highest bit not set), and not - // excessively padded (do not init with a 0 byte, unless an otherwise negative number follows, - // in which case a single 0 byte is necessary and even required). - if (signature.length < 9 || signature.length > 73) - return false; - - int hashType = (signature[signature.length-1] & 0xff) & ~0x80; // mask the byte to prevent sign-extension hurting us - if (hashType < 1 || hashType > 3) - return false; - - // "wrong type" "wrong length marker" - if ((signature[0] & 0xff) != 0x30 || (signature[1] & 0xff) != signature.length-3) - return false; - - int lenR = signature[3] & 0xff; - if (5 + lenR >= signature.length || lenR == 0) - return false; - int lenS = signature[5+lenR] & 0xff; - if (lenR + lenS + 7 != signature.length || lenS == 0) - return false; - - // R value type mismatch R value negative - if (signature[4-2] != 0x02 || (signature[4] & 0x80) == 0x80) - return false; - if (lenR > 1 && signature[4] == 0x00 && (signature[4+1] & 0x80) != 0x80) - return false; // R value excessively padded - - // S value type mismatch S value negative - if (signature[6 + lenR - 2] != 0x02 || (signature[6 + lenR] & 0x80) == 0x80) - return false; - if (lenS > 1 && signature[6 + lenR] == 0x00 && (signature[6 + lenR + 1] & 0x80) != 0x80) - return false; // S value excessively padded - - return true; - } - - - public static boolean VerifySign(byte[] tlvPublicKey, byte[] data, byte[] tlvSignature) throws IOException, SignatureException, InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { - Signature signature = Signature.getInstance("SHA256withECDSA"); - ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); - KeyFactory factory = KeyFactory.getInstance("EC", "SC"); - - ECPoint p1 = spec.getCurve().decodePoint(tlvPublicKey); - ECPublicKeySpec keySpec = new ECPublicKeySpec(p1, spec); - - PublicKey publicKey = factory.generatePublic(keySpec); - signature.initVerify(publicKey); - signature.update(data); - - ASN1EncodableVector v = new ASN1EncodableVector(); - int size = tlvSignature.length / 2; - v.add(/*r*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(tlvSignature, 0, size)))); - v.add(/*s*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(tlvSignature, size, size * 2)))); - byte[] sigDer = new DERSequence(v).getEncoded(); - - return signature.verify(sigDer); - } - - private static byte[] leaderZero(byte[] s) - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - if (s[0] > 0x7f) { - baos.write((byte) 0x00); - } - for(int i = 0; i < 32; ++i) - baos.write(s[i]); - - return baos.toByteArray(); - } - public static boolean checkHashSign(byte[] pub, byte[] hash, byte[] sign) - { - byte[] rtmp = new byte[32]; - byte[] stmp = new byte[32]; - - for(int i = 0; i< 32; ++i) - { - rtmp[i] = sign[i]; - stmp[i] = sign[i+32]; - } - - leaderZero(rtmp); - byte[] r2 = leaderZero(rtmp); - byte[] s2 = leaderZero(stmp); - - BigInteger r = new BigInteger(r2); - BigInteger s = new BigInteger(s2); - ECDSASigner signer = new ECDSASigner(); - - ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE); - signer.init(false, params); - return signer.verifySignature(hash, r, s); - } - public static byte[] doubleSha256(byte[] bytes) { - try { - MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); - return sha256.digest(sha256.digest(bytes)); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - public static byte[] sha256ripemd160(byte[] publicKey) { - try { - MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); - byte[] sha256hash = sha256.digest(publicKey); - byte[] hashedPublicKey = Util.calculateRIPEMD160(sha256hash); - return hashedPublicKey; - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } catch (NoSuchProviderException e) { - e.printStackTrace(); - } - return null; - } -} diff --git a/app/src/main/java/com/tangem/util/DecimalDigitsInputFilter.java b/app/src/main/java/com/tangem/util/DecimalDigitsInputFilter.java deleted file mode 100644 index d3c456c747..0000000000 --- a/app/src/main/java/com/tangem/util/DecimalDigitsInputFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.tangem.util; - -import android.text.InputFilter; -import android.text.Spanned; - -public class DecimalDigitsInputFilter implements InputFilter { - private final int decimalDigits; - - /** - * Constructor. - * - * @param decimalDigits maximum decimal digits - */ - public DecimalDigitsInputFilter(int decimalDigits) { - this.decimalDigits = decimalDigits; - } - - @Override - public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { - int dotPos = -1; - int len = dest.length(); - for (int i = 0; i < len; i++) { - char c = dest.charAt(i); - if (c == '.' || c == ',') { - dotPos = i; - break; - } - } - - if (dotPos >= 0) { - // protects against many dots - if (source.equals(".") || source.equals(",")) { - return ""; - } - - // if the text is entered before the dot - if (dend <= dotPos) { - return null; - } - - if (len - dotPos > decimalDigits) { - return ""; - } - } - - return null; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/util/DerEncodingUtil.java b/app/src/main/java/com/tangem/util/DerEncodingUtil.java deleted file mode 100644 index f3a88131df..0000000000 --- a/app/src/main/java/com/tangem/util/DerEncodingUtil.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.tangem.util; - -import com.tangem.wallet.btc.BitcoinOutputStream; - -import org.spongycastle.asn1.ASN1Integer; -import org.spongycastle.asn1.DERSequenceGenerator; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; - -/** - * Created by Ilia on 15.02.2018. - */ - -public class DerEncodingUtil { - - public static byte[] PackInteger(byte[] s) - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - baos.write((byte)0x02); - - byte length = (byte)s.length; - if (s[0] > 0x7f) { - baos.write((byte)(length+1)); - baos.write((byte) 0x00); - } - else { - baos.write((byte)length); - } - - for(int i = 0; i < length; ++i) - baos.write(s[i]); - - return baos.toByteArray(); - } - - public static byte[] packSignDer(BigInteger r, BigInteger s, byte[] pubKey) throws IOException - { - byte[] signDer = DerEncoding(r, s); - BitcoinOutputStream packKey = new BitcoinOutputStream(); - - packKey.write((byte)0x41); - packKey.write(pubKey); - - byte[] keyArray = packKey.toByteArray(); - - BitcoinOutputStream result = new BitcoinOutputStream(); - result.write((byte)(signDer.length+1)); - result.write(signDer); - result.write((byte)0x1); - - result.write(keyArray); - - return result.toByteArray(); - - } - - public static byte[] packSignDerBitcoinCash(BigInteger r, BigInteger s, byte[] pubKey) throws IOException - { - byte[] signDer = DerEncoding(r, s); - BitcoinOutputStream packKey = new BitcoinOutputStream(); - - packKey.write((byte)0x21); //compress key - packKey.write(pubKey); - - byte[] keyArray = packKey.toByteArray(); - - BitcoinOutputStream result = new BitcoinOutputStream(); - result.write((byte)(signDer.length+1)); - result.write(signDer); - result.write((byte)0x41); - - result.write(keyArray); - - return result.toByteArray(); - - } - - - public static byte[] DerEncoding(BigInteger r, BigInteger s) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(72); - DERSequenceGenerator seq = new DERSequenceGenerator(bos); - seq.addObject(new ASN1Integer(r)); - seq.addObject(new ASN1Integer(s)); - seq.close(); - return bos.toByteArray(); - } - -// public static byte[] DerEncoding(byte[] sign) -// { -// byte[] r = sign; -// byte[] s = new byte[32]; -// for(int i =0; i < 32; ++i) -// { -// s[i] = sign[i+32]; -// } -// -// byte[] newR = PackInteger(r); -// byte[] newS = PackInteger(s); -// -// ByteArrayOutputStream baos = new ByteArrayOutputStream(); -// baos.write((byte)(newR.length+newS.length+2)); -// baos.write((byte)newR.length); -// baos.write(newR, 0, newR.length); -// baos.write((byte)newS.length); -// baos.write(newS, 0, newS.length); -// -// return baos.toByteArray(); -// } -// -// public static byte[] DerEncodingBI(BigInteger[] sign) -// { -// byte[] r = sign[0].toByteArray(); -// byte[] s = sign[1].toByteArray(); -// -// byte[] newR = PackInteger(r); -// byte[] newS = PackInteger(s); -// -// ByteArrayOutputStream baos = new ByteArrayOutputStream(); -// -// baos.write((byte)(newR.length+newS.length+2)); -// -// baos.write((byte)newR.length); -// baos.write(newR, 0, newR.length); -// -// baos.write((byte)newS.length); -// baos.write(newS, 0, newS.length); -// -// return baos.toByteArray(); -// } -} diff --git a/app/src/main/java/com/tangem/util/DeviceName.java b/app/src/main/java/com/tangem/util/DeviceName.java deleted file mode 100644 index f577dd16bb..0000000000 --- a/app/src/main/java/com/tangem/util/DeviceName.java +++ /dev/null @@ -1,2091 +0,0 @@ -package com.tangem.util; - -/** - * Created by Ilia on 20.04.2018. - */ -/* - * Copyright (C) 2017 Jared Rummler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - import android.Manifest; - import android.content.Context; - import android.content.SharedPreferences; - import android.content.pm.PackageManager; - import android.net.ConnectivityManager; - import android.net.NetworkInfo; - import android.os.Build; - import android.os.Handler; - import android.os.Looper; - import androidx.annotation.WorkerThread; - import android.text.TextUtils; - import java.io.BufferedReader; - import java.io.IOException; - import java.io.InputStreamReader; - import java.net.HttpURLConnection; - import java.net.URL; - import java.util.Locale; - import org.json.JSONArray; - import org.json.JSONException; - import org.json.JSONObject; - -// @formatter:off -/** - *

Get the consumer friendly name of an Android device.

- * - *

On many popular devices the market name of the device is not available. For example, on the - * Samsung Galaxy S6 the value of {@link Build#MODEL} could be "SM-G920F", "SM-G920I", "SM-G920W8", - * etc.

- * - *

See the usages below to get the consumer friends name of a device:

- * - *

Get the name of the current device:

- * - *
- * String deviceName = DeviceName.getDeviceName();
- * 
- * - *

The above code will get the correct device name for the top 600 Android devices. If the - * device is unrecognized, then Build.MODEL is returned.

- * - *

Get the name of a device using the device's codename:

- * - *
- * // Retruns "Moto X Style"
- * DeviceName.getDeviceName("clark", "Unknown device");
- * 
- * - *

Get information about the device:

- * - *
- * DeviceName.with(context).request(new DeviceName.Callback() {
- *
- *   @Override public void onFinished(DeviceName.DeviceInfo info, Exception error) {
- *     String manufacturer = info.manufacturer;  // "Samsung"
- *     String name = info.marketName;            // "Galaxy S6 Edge"
- *     String model = info.model;                // "SM-G925I"
- *     String codename = info.codename;          // "zerolte"
- *     String deviceName = info.getName();       // "Galaxy S6 Edge"
- *     // FYI: We are on the UI thread.
- *   }
- * });
- * 
- * - *

The above code loads JSON from a generated list of device names based on Google's maintained - * list. It will be up-to-date with Google's supported device list so that you will get the correct - * name for new or unknown devices. This supports over 10,000 devices.

- * - *

This will only make a network call once. The value is saved to SharedPreferences for future - * calls.

- */ - -public class DeviceName { - - // @formatter:on - - // JSON which is derived from Google's PDF document which contains all devices on Google Play. - // To get the URL to the JSON file which contains information about the device name: - // String url = String.format(DEVICE_JSON_URL, Build.DEVICE); - private static final String DEVICE_JSON_URL = - "https://raw.githubusercontent.com/jaredrummler/AndroidDeviceNames/master/json/devices/%s.json"; - - // Preference filename for storing device info so we don't need to download it again. - private static final String SHARED_PREF_NAME = "device_names"; - - /** - * Create a new request to get information about a device. - * - * @param context - * the application context - * @return a new Request instance. - */ - public static Request with(Context context) { - return new Request(context.getApplicationContext()); - } - - /** - * Get the consumer friendly name of the device. - * - * @return the market name of the current device. - * @see #getDeviceName(String, String) - */ - public static String getDeviceName() { - return getDeviceName(Build.DEVICE, Build.MODEL, capitalize(Build.MODEL)); - } - - /** - * Get the consumer friendly name of a device. - * - * @param codename - * the value of the system property "ro.product.device" ({@link Build#DEVICE}) - * or - * the value of the system property "ro.product.model" ({@link Build#MODEL}) - * @param fallback - * the fallback name if the device is unknown. Usually the value of the system property - * "ro.product.model" ({@link Build#MODEL}) - * @return the market name of a device or {@code fallback} if the device is unknown. - */ - public static String getDeviceName(String codename, String fallback) { - return getDeviceName(codename, codename, fallback); - } - - /** - * Get the consumer friendly name of a device. - * - * @param codename - * the value of the system property "ro.product.device" ({@link Build#DEVICE}). - * @param model - * the value of the system property "ro.product.model" ({@link Build#MODEL}). - * @param fallback - * the fallback name if the device is unknown. Usually the value of the system property - * "ro.product.model" ({@link Build#MODEL}) - * @return the market name of a device or {@code fallback} if the device is unknown. - */ - public static String getDeviceName(String codename, String model, String fallback) { - // ---------------------------------------------------------------------------- - // Acer - if ((codename != null && codename.equals("acer_S57")) - || (model != null && model.equals("S57"))) { - return "Liquid Jade Z"; - } - if ((codename != null && codename.equals("acer_t08")) - || (model != null && model.equals("T08"))) { - return "Liquid Zest Plus"; - } - // ---------------------------------------------------------------------------- - // Asus - if ((codename != null && (codename.equals("grouper") - || codename.equals("tilapia")))) { - return "Nexus 7 (2012)"; - } - if ((codename != null && (codename.equals("deb") - || codename.equals("flo")))) { - return "Nexus 7 (2013)"; - } - // ---------------------------------------------------------------------------- - // Google - if ((codename != null && codename.equals("sailfish"))) { - return "Pixel"; - } - if ((codename != null && codename.equals("walleye"))) { - return "Pixel 2"; - } - if ((codename != null && codename.equals("taimen"))) { - return "Pixel 2 XL"; - } - if ((codename != null && codename.equals("dragon"))) { - return "Pixel C"; - } - if ((codename != null && codename.equals("marlin"))) { - return "Pixel XL"; - } - // ---------------------------------------------------------------------------- - // HTC - if ((codename != null && codename.equals("flounder"))) { - return "Nexus 9"; - } - // ---------------------------------------------------------------------------- - // Huawei - if ((codename != null && (codename.equals("HWBND-H"))) - || (model != null && (model.equals("BND-L21") - || model.equals("BND-L24")))) { - return "Honor 7X"; - } - if (model != null && model.contains("WAS-LX")) { - return "P10 lite"; - } - if ((codename != null && codename.equals("HWBKL")) - || (model != null && model.equals("BKL-L09"))) { - return "Honor View 10"; - } - if ((codename != null && (codename.equals("HWALP"))) - || (model != null && (model.equals("ALP-AL00") - || model.equals("ALP-L09") - || model.equals("ALP-L29") - || model.equals("ALP-TL00")))) { - return "Mate 10"; - } - if ((codename != null && (codename.equals("HWMHA"))) - || (model != null && (model.equals("MHA-AL00") - || model.equals("MHA-L09") - || model.equals("MHA-L29") - || model.equals("MHA-TL00")))) { - return "Mate 9"; - } - if ((codename != null && codename.equals("angler"))) { - return "Nexus 6P"; - } - // ---------------------------------------------------------------------------- - // LGE - if ((codename != null && (codename.equals("g2"))) - || (model != null && (model.equals("LG-D800") - || model.equals("LG-D801") - || model.equals("LG-D802") - || model.equals("LG-D802T") - || model.equals("LG-D802TR") - || model.equals("LG-D803") - || model.equals("LG-D805") - || model.equals("LG-D806") - || model.equals("LG-F320K") - || model.equals("LG-F320L") - || model.equals("LG-F320S") - || model.equals("LG-LS980") - || model.equals("VS980 4G")))) { - return "LG G2"; - } - if ((codename != null && (codename.equals("g3"))) - || (model != null && (model.equals("AS985") - || model.equals("LG-AS990") - || model.equals("LG-D850") - || model.equals("LG-D851") - || model.equals("LG-D852") - || model.equals("LG-D852G") - || model.equals("LG-D855") - || model.equals("LG-D856") - || model.equals("LG-D857") - || model.equals("LG-D858") - || model.equals("LG-D858HK") - || model.equals("LG-D859") - || model.equals("LG-F400K") - || model.equals("LG-F400L") - || model.equals("LG-F400S") - || model.equals("LGL24") - || model.equals("LGLS990") - || model.equals("LGUS990") - || model.equals("LGV31") - || model.equals("VS985 4G")))) { - return "LG G3"; - } - if ((codename != null && (codename.equals("p1"))) - || (model != null && (model.equals("AS986") - || model.equals("LG-AS811") - || model.equals("LG-AS991") - || model.equals("LG-F500K") - || model.equals("LG-F500L") - || model.equals("LG-F500S") - || model.equals("LG-H810") - || model.equals("LG-H811") - || model.equals("LG-H812") - || model.equals("LG-H815") - || model.equals("LG-H818") - || model.equals("LG-H819") - || model.equals("LGLS991") - || model.equals("LGUS991") - || model.equals("LGV32") - || model.equals("VS986")))) { - return "LG G4"; - } - if ((codename != null && (codename.equals("h1"))) - || (model != null && (model.equals("LG-F700K") - || model.equals("LG-F700L") - || model.equals("LG-F700S") - || model.equals("LG-H820") - || model.equals("LG-H820PR") - || model.equals("LG-H830") - || model.equals("LG-H831") - || model.equals("LG-H850") - || model.equals("LG-H858") - || model.equals("LG-H860") - || model.equals("LG-H868") - || model.equals("LGAS992") - || model.equals("LGLS992") - || model.equals("LGUS992") - || model.equals("RS988") - || model.equals("VS987")))) { - return "LG G5"; - } - if ((codename != null && (codename.equals("lucye"))) - || (model != null && (model.equals("LG-AS993") - || model.equals("LG-H870") - || model.equals("LG-H870AR") - || model.equals("LG-H870DS") - || model.equals("LG-H870I") - || model.equals("LG-H870S") - || model.equals("LG-H871") - || model.equals("LG-H872") - || model.equals("LG-H872PR") - || model.equals("LG-H873") - || model.equals("LG-LS993") - || model.equals("LGM-G600K") - || model.equals("LGM-G600L") - || model.equals("LGM-G600S") - || model.equals("LGUS997") - || model.equals("VS988")))) { - return "LG G6"; - } - if ((codename != null && codename.equals("mako"))) { - return "Nexus 4"; - } - if ((codename != null && codename.equals("hammerhead"))) { - return "Nexus 5"; - } - if ((codename != null && codename.equals("bullhead"))) { - return "Nexus 5X"; - } - // ---------------------------------------------------------------------------- - // Motorola - if ((codename != null && codename.equals("shamu"))) { - return "Nexus 6"; - } - // ---------------------------------------------------------------------------- - // OnePlus - if ((codename != null && codename.equals("OnePlus3")) - || (model != null && model.equals("ONEPLUS A3000"))) { - return "OnePlus3"; - } - if ((codename != null && codename.equals("OnePlus3T")) - || (model != null && model.equals("ONEPLUS A3000"))) { - return "OnePlus3T"; - } - if ((codename != null && codename.equals("OnePlus5")) - || (model != null && model.equals("ONEPLUS A5000"))) { - return "OnePlus5"; - } - if ((codename != null && codename.equals("OnePlus5T")) - || (model != null && model.equals("ONEPLUS A5010"))) { - return "OnePlus5T"; - } - // ---------------------------------------------------------------------------- - // Samsung - if ((codename != null && (codename.equals("a53g") - || codename.equals("a5lte") - || codename.equals("a5ltechn") - || codename.equals("a5ltectc") - || codename.equals("a5ltezh") - || codename.equals("a5ltezt") - || codename.equals("a5ulte") - || codename.equals("a5ultebmc") - || codename.equals("a5ultektt") - || codename.equals("a5ultelgt") - || codename.equals("a5ulteskt"))) - || (model != null && (model.equals("SM-A5000") - || model.equals("SM-A5009") - || model.equals("SM-A500F") - || model.equals("SM-A500F1") - || model.equals("SM-A500FU") - || model.equals("SM-A500G") - || model.equals("SM-A500H") - || model.equals("SM-A500K") - || model.equals("SM-A500L") - || model.equals("SM-A500M") - || model.equals("SM-A500S") - || model.equals("SM-A500W") - || model.equals("SM-A500X") - || model.equals("SM-A500XZ") - || model.equals("SM-A500Y") - || model.equals("SM-A500YZ")))) { - return "Galaxy A5"; - } - if ((codename != null && (codename.equals("vivaltods5m"))) - || (model != null && (model.equals("SM-G313HU") - || model.equals("SM-G313HY") - || model.equals("SM-G313M") - || model.equals("SM-G313MY")))) { - return "Galaxy Ace 4"; - } - if ((codename != null && (codename.equals("GT-S6352") - || codename.equals("GT-S6802") - || codename.equals("GT-S6802B") - || codename.equals("SCH-I579") - || codename.equals("SCH-I589") - || codename.equals("SCH-i579") - || codename.equals("SCH-i589"))) - || (model != null && (model.equals("GT-S6352") - || model.equals("GT-S6802") - || model.equals("GT-S6802B") - || model.equals("SCH-I589") - || model.equals("SCH-i579") - || model.equals("SCH-i589")))) { - return "Galaxy Ace Duos"; - } - if ((codename != null && (codename.equals("GT-S7500") - || codename.equals("GT-S7500L") - || codename.equals("GT-S7500T") - || codename.equals("GT-S7500W") - || codename.equals("GT-S7508"))) - || (model != null && (model.equals("GT-S7500") - || model.equals("GT-S7500L") - || model.equals("GT-S7500T") - || model.equals("GT-S7500W") - || model.equals("GT-S7508")))) { - return "Galaxy Ace Plus"; - } - if ((codename != null && (codename.equals("heat3gtfnvzw") - || codename.equals("heatnfc3g") - || codename.equals("heatqlte"))) - || (model != null && (model.equals("SM-G310HN") - || model.equals("SM-G357FZ") - || model.equals("SM-S765C") - || model.equals("SM-S766C")))) { - return "Galaxy Ace Style"; - } - if ((codename != null && (codename.equals("vivalto3g") - || codename.equals("vivalto3mve3g") - || codename.equals("vivalto5mve3g") - || codename.equals("vivaltolte") - || codename.equals("vivaltonfc3g"))) - || (model != null && (model.equals("SM-G313F") - || model.equals("SM-G313HN") - || model.equals("SM-G313ML") - || model.equals("SM-G313MU") - || model.equals("SM-G316H") - || model.equals("SM-G316HU") - || model.equals("SM-G316M") - || model.equals("SM-G316MY")))) { - return "Galaxy Ace4"; - } - if ((codename != null && (codename.equals("core33g") - || codename.equals("coreprimelte") - || codename.equals("coreprimelteaio") - || codename.equals("coreprimeltelra") - || codename.equals("coreprimeltespr") - || codename.equals("coreprimeltetfnvzw") - || codename.equals("coreprimeltevzw") - || codename.equals("coreprimeve3g") - || codename.equals("coreprimevelte") - || codename.equals("cprimeltemtr") - || codename.equals("cprimeltetmo") - || codename.equals("rossalte") - || codename.equals("rossaltectc") - || codename.equals("rossaltexsa"))) - || (model != null && (model.equals("SAMSUNG-SM-G360AZ") - || model.equals("SM-G3606") - || model.equals("SM-G3608") - || model.equals("SM-G3609") - || model.equals("SM-G360F") - || model.equals("SM-G360FY") - || model.equals("SM-G360GY") - || model.equals("SM-G360H") - || model.equals("SM-G360HU") - || model.equals("SM-G360M") - || model.equals("SM-G360P") - || model.equals("SM-G360R6") - || model.equals("SM-G360T") - || model.equals("SM-G360T1") - || model.equals("SM-G360V") - || model.equals("SM-G361F") - || model.equals("SM-G361H") - || model.equals("SM-G361HU") - || model.equals("SM-G361M") - || model.equals("SM-S820L")))) { - return "Galaxy Core Prime"; - } - if ((codename != null && (codename.equals("kanas") - || codename.equals("kanas3g") - || codename.equals("kanas3gcmcc") - || codename.equals("kanas3gctc") - || codename.equals("kanas3gnfc"))) - || (model != null && (model.equals("SM-G3556D") - || model.equals("SM-G3558") - || model.equals("SM-G3559") - || model.equals("SM-G355H") - || model.equals("SM-G355HN") - || model.equals("SM-G355HQ") - || model.equals("SM-G355M")))) { - return "Galaxy Core2"; - } - if ((codename != null && (codename.equals("e53g") - || codename.equals("e5lte") - || codename.equals("e5ltetfnvzw") - || codename.equals("e5ltetw"))) - || (model != null && (model.equals("SM-E500F") - || model.equals("SM-E500H") - || model.equals("SM-E500M") - || model.equals("SM-E500YZ") - || model.equals("SM-S978L")))) { - return "Galaxy E5"; - } - if ((codename != null && (codename.equals("e73g") - || codename.equals("e7lte") - || codename.equals("e7ltechn") - || codename.equals("e7ltectc") - || codename.equals("e7ltehktw"))) - || (model != null && (model.equals("SM-E7000") - || model.equals("SM-E7009") - || model.equals("SM-E700F") - || model.equals("SM-E700H") - || model.equals("SM-E700M")))) { - return "Galaxy E7"; - } - if ((codename != null && (codename.equals("SCH-I629") - || codename.equals("nevis") - || codename.equals("nevis3g") - || codename.equals("nevis3gcmcc") - || codename.equals("nevisds") - || codename.equals("nevisnvess") - || codename.equals("nevisp") - || codename.equals("nevisvess") - || codename.equals("nevisw"))) - || (model != null && (model.equals("GT-S6790") - || model.equals("GT-S6790E") - || model.equals("GT-S6790L") - || model.equals("GT-S6790N") - || model.equals("GT-S6810") - || model.equals("GT-S6810B") - || model.equals("GT-S6810E") - || model.equals("GT-S6810L") - || model.equals("GT-S6810M") - || model.equals("GT-S6810P") - || model.equals("GT-S6812") - || model.equals("GT-S6812B") - || model.equals("GT-S6812C") - || model.equals("GT-S6812i") - || model.equals("GT-S6818") - || model.equals("GT-S6818V") - || model.equals("SCH-I629")))) { - return "Galaxy Fame"; - } - if ((codename != null && codename.equals("grandprimelteatt")) - || (model != null && model.equals("SAMSUNG-SM-G530A"))) { - return "Galaxy Go Prime"; - } - if ((codename != null && (codename.equals("baffinlite") - || codename.equals("baffinlitedtv") - || codename.equals("baffinq3g"))) - || (model != null && (model.equals("GT-I9060") - || model.equals("GT-I9060L") - || model.equals("GT-I9063T") - || model.equals("GT-I9082C") - || model.equals("GT-I9168") - || model.equals("GT-I9168I")))) { - return "Galaxy Grand Neo"; - } - if ((codename != null && (codename.equals("fortuna3g") - || codename.equals("fortuna3gdtv") - || codename.equals("fortunalte") - || codename.equals("fortunaltectc") - || codename.equals("fortunaltezh") - || codename.equals("fortunaltezt") - || codename.equals("fortunave3g") - || codename.equals("gprimelteacg") - || codename.equals("gprimeltecan") - || codename.equals("gprimeltemtr") - || codename.equals("gprimeltespr") - || codename.equals("gprimeltetfnvzw") - || codename.equals("gprimeltetmo") - || codename.equals("gprimelteusc") - || codename.equals("grandprimelte") - || codename.equals("grandprimelteaio") - || codename.equals("grandprimeve3g") - || codename.equals("grandprimeve3gdtv") - || codename.equals("grandprimevelte") - || codename.equals("grandprimevelteltn") - || codename.equals("grandprimeveltezt"))) - || (model != null && (model.equals("SAMSUNG-SM-G530AZ") - || model.equals("SM-G5306W") - || model.equals("SM-G5308W") - || model.equals("SM-G5309W") - || model.equals("SM-G530BT") - || model.equals("SM-G530F") - || model.equals("SM-G530FZ") - || model.equals("SM-G530H") - || model.equals("SM-G530M") - || model.equals("SM-G530MU") - || model.equals("SM-G530P") - || model.equals("SM-G530R4") - || model.equals("SM-G530R7") - || model.equals("SM-G530T") - || model.equals("SM-G530T1") - || model.equals("SM-G530W") - || model.equals("SM-G530Y") - || model.equals("SM-G531BT") - || model.equals("SM-G531F") - || model.equals("SM-G531H") - || model.equals("SM-G531M") - || model.equals("SM-G531Y") - || model.equals("SM-S920L") - || model.equals("gprimelteacg")))) { - return "Galaxy Grand Prime"; - } - if ((codename != null && (codename.equals("ms013g") - || codename.equals("ms013gdtv") - || codename.equals("ms013gss") - || codename.equals("ms01lte") - || codename.equals("ms01ltektt") - || codename.equals("ms01ltelgt") - || codename.equals("ms01lteskt"))) - || (model != null && (model.equals("SM-G710") - || model.equals("SM-G7102") - || model.equals("SM-G7102T") - || model.equals("SM-G7105") - || model.equals("SM-G7105H") - || model.equals("SM-G7105L") - || model.equals("SM-G7106") - || model.equals("SM-G7108") - || model.equals("SM-G7109") - || model.equals("SM-G710K") - || model.equals("SM-G710L") - || model.equals("SM-G710S")))) { - return "Galaxy Grand2"; - } - if ((codename != null && (codename.equals("j13g") - || codename.equals("j13gtfnvzw") - || codename.equals("j1lte") - || codename.equals("j1nlte") - || codename.equals("j1qltevzw") - || codename.equals("j1xlte") - || codename.equals("j1xlteaio") - || codename.equals("j1xlteatt") - || codename.equals("j1xltecan") - || codename.equals("j1xqltespr") - || codename.equals("j1xqltetfnvzw"))) - || (model != null && (model.equals("SAMSUNG-SM-J120A") - || model.equals("SAMSUNG-SM-J120AZ") - || model.equals("SM-J100F") - || model.equals("SM-J100FN") - || model.equals("SM-J100G") - || model.equals("SM-J100H") - || model.equals("SM-J100M") - || model.equals("SM-J100ML") - || model.equals("SM-J100MU") - || model.equals("SM-J100VPP") - || model.equals("SM-J100Y") - || model.equals("SM-J120F") - || model.equals("SM-J120FN") - || model.equals("SM-J120M") - || model.equals("SM-J120P") - || model.equals("SM-J120W") - || model.equals("SM-S120VL") - || model.equals("SM-S777C")))) { - return "Galaxy J1"; - } - if ((codename != null && (codename.equals("j1acelte") - || codename.equals("j1acelteltn") - || codename.equals("j1acevelte") - || codename.equals("j1pop3g"))) - || (model != null && (model.equals("SM-J110F") - || model.equals("SM-J110G") - || model.equals("SM-J110H") - || model.equals("SM-J110L") - || model.equals("SM-J110M") - || model.equals("SM-J111F") - || model.equals("SM-J111M")))) { - return "Galaxy J1 Ace"; - } - if ((codename != null && (codename.equals("j53g") - || codename.equals("j5lte") - || codename.equals("j5ltechn") - || codename.equals("j5ltekx") - || codename.equals("j5nlte") - || codename.equals("j5ylte"))) - || (model != null && (model.equals("SM-J5007") - || model.equals("SM-J5008") - || model.equals("SM-J500F") - || model.equals("SM-J500FN") - || model.equals("SM-J500G") - || model.equals("SM-J500H") - || model.equals("SM-J500M") - || model.equals("SM-J500N0") - || model.equals("SM-J500Y")))) { - return "Galaxy J5"; - } - if ((codename != null && (codename.equals("j75ltektt") - || codename.equals("j7e3g") - || codename.equals("j7elte") - || codename.equals("j7ltechn"))) - || (model != null && (model.equals("SM-J7008") - || model.equals("SM-J700F") - || model.equals("SM-J700H") - || model.equals("SM-J700K") - || model.equals("SM-J700M")))) { - return "Galaxy J7"; - } - if ((codename != null && (codename.equals("maguro") - || codename.equals("toro") - || codename.equals("toroplus"))) - || (model != null && (model.equals("Galaxy X")))) { - return "Galaxy Nexus"; - } - if ((codename != null && (codename.equals("lt033g") - || codename.equals("lt03ltektt") - || codename.equals("lt03ltelgt") - || codename.equals("lt03lteskt") - || codename.equals("p4notelte") - || codename.equals("p4noteltektt") - || codename.equals("p4noteltelgt") - || codename.equals("p4notelteskt") - || codename.equals("p4noteltespr") - || codename.equals("p4notelteusc") - || codename.equals("p4noteltevzw") - || codename.equals("p4noterf") - || codename.equals("p4noterfktt") - || codename.equals("p4notewifi") - || codename.equals("p4notewifi43241any") - || codename.equals("p4notewifiany") - || codename.equals("p4notewifiktt") - || codename.equals("p4notewifiww"))) - || (model != null && (model.equals("GT-N8000") - || model.equals("GT-N8005") - || model.equals("GT-N8010") - || model.equals("GT-N8013") - || model.equals("GT-N8020") - || model.equals("SCH-I925") - || model.equals("SCH-I925U") - || model.equals("SHV-E230K") - || model.equals("SHV-E230L") - || model.equals("SHV-E230S") - || model.equals("SHW-M480K") - || model.equals("SHW-M480W") - || model.equals("SHW-M485W") - || model.equals("SHW-M486W") - || model.equals("SM-P601") - || model.equals("SM-P602") - || model.equals("SM-P605K") - || model.equals("SM-P605L") - || model.equals("SM-P605S") - || model.equals("SPH-P600")))) { - return "Galaxy Note 10.1"; - } - if ((codename != null && (codename.equals("SC-01G") - || codename.equals("SCL24") - || codename.equals("tbeltektt") - || codename.equals("tbeltelgt") - || codename.equals("tbelteskt") - || codename.equals("tblte") - || codename.equals("tblteatt") - || codename.equals("tbltecan") - || codename.equals("tbltechn") - || codename.equals("tbltespr") - || codename.equals("tbltetmo") - || codename.equals("tblteusc") - || codename.equals("tbltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-N915A") - || model.equals("SC-01G") - || model.equals("SCL24") - || model.equals("SM-N9150") - || model.equals("SM-N915F") - || model.equals("SM-N915FY") - || model.equals("SM-N915G") - || model.equals("SM-N915K") - || model.equals("SM-N915L") - || model.equals("SM-N915P") - || model.equals("SM-N915R4") - || model.equals("SM-N915S") - || model.equals("SM-N915T") - || model.equals("SM-N915T3") - || model.equals("SM-N915V") - || model.equals("SM-N915W8") - || model.equals("SM-N915X")))) { - return "Galaxy Note Edge"; - } - if ((codename != null && (codename.equals("v1a3g") - || codename.equals("v1awifi") - || codename.equals("v1awifikx") - || codename.equals("viennalte") - || codename.equals("viennalteatt") - || codename.equals("viennaltekx") - || codename.equals("viennaltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-P907A") - || model.equals("SM-P900") - || model.equals("SM-P901") - || model.equals("SM-P905") - || model.equals("SM-P905F0") - || model.equals("SM-P905M") - || model.equals("SM-P905V")))) { - return "Galaxy Note Pro 12.2"; - } - if ((codename != null && (codename.equals("tre3caltektt") - || codename.equals("tre3caltelgt") - || codename.equals("tre3calteskt") - || codename.equals("tre3g") - || codename.equals("trelte") - || codename.equals("treltektt") - || codename.equals("treltelgt") - || codename.equals("trelteskt") - || codename.equals("trhplte") - || codename.equals("trlte") - || codename.equals("trlteatt") - || codename.equals("trltecan") - || codename.equals("trltechn") - || codename.equals("trltechnzh") - || codename.equals("trltespr") - || codename.equals("trltetmo") - || codename.equals("trlteusc") - || codename.equals("trltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-N910A") - || model.equals("SM-N9100") - || model.equals("SM-N9106W") - || model.equals("SM-N9108V") - || model.equals("SM-N9109W") - || model.equals("SM-N910C") - || model.equals("SM-N910F") - || model.equals("SM-N910G") - || model.equals("SM-N910H") - || model.equals("SM-N910K") - || model.equals("SM-N910L") - || model.equals("SM-N910P") - || model.equals("SM-N910R4") - || model.equals("SM-N910S") - || model.equals("SM-N910T") - || model.equals("SM-N910T2") - || model.equals("SM-N910T3") - || model.equals("SM-N910U") - || model.equals("SM-N910V") - || model.equals("SM-N910W8") - || model.equals("SM-N910X") - || model.equals("SM-N916K") - || model.equals("SM-N916L") - || model.equals("SM-N916S")))) { - return "Galaxy Note4"; - } - if ((codename != null && (codename.equals("noblelte") - || codename.equals("noblelteacg") - || codename.equals("noblelteatt") - || codename.equals("nobleltebmc") - || codename.equals("nobleltechn") - || codename.equals("nobleltecmcc") - || codename.equals("nobleltehk") - || codename.equals("nobleltektt") - || codename.equals("nobleltelgt") - || codename.equals("nobleltelra") - || codename.equals("noblelteskt") - || codename.equals("nobleltespr") - || codename.equals("nobleltetmo") - || codename.equals("noblelteusc") - || codename.equals("nobleltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-N920A") - || model.equals("SM-N9200") - || model.equals("SM-N9208") - || model.equals("SM-N920C") - || model.equals("SM-N920F") - || model.equals("SM-N920G") - || model.equals("SM-N920I") - || model.equals("SM-N920K") - || model.equals("SM-N920L") - || model.equals("SM-N920P") - || model.equals("SM-N920R4") - || model.equals("SM-N920R6") - || model.equals("SM-N920R7") - || model.equals("SM-N920S") - || model.equals("SM-N920T") - || model.equals("SM-N920V") - || model.equals("SM-N920W8") - || model.equals("SM-N920X")))) { - return "Galaxy Note5"; - } - if ((codename != null && (codename.equals("SC-01J") - || codename.equals("SCV34") - || codename.equals("gracelte") - || codename.equals("graceltektt") - || codename.equals("graceltelgt") - || codename.equals("gracelteskt") - || codename.equals("graceqlteacg") - || codename.equals("graceqlteatt") - || codename.equals("graceqltebmc") - || codename.equals("graceqltechn") - || codename.equals("graceqltedcm") - || codename.equals("graceqltelra") - || codename.equals("graceqltespr") - || codename.equals("graceqltetfnvzw") - || codename.equals("graceqltetmo") - || codename.equals("graceqlteue") - || codename.equals("graceqlteusc") - || codename.equals("graceqltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-N930A") - || model.equals("SC-01J") - || model.equals("SCV34") - || model.equals("SGH-N037") - || model.equals("SM-N9300") - || model.equals("SM-N930F") - || model.equals("SM-N930K") - || model.equals("SM-N930L") - || model.equals("SM-N930P") - || model.equals("SM-N930R4") - || model.equals("SM-N930R6") - || model.equals("SM-N930R7") - || model.equals("SM-N930S") - || model.equals("SM-N930T") - || model.equals("SM-N930U") - || model.equals("SM-N930V") - || model.equals("SM-N930VL") - || model.equals("SM-N930W8") - || model.equals("SM-N930X")))) { - return "Galaxy Note7"; - } - if ((codename != null && (codename.equals("SC-01K") - || codename.equals("SCV37") - || codename.equals("greatlte") - || codename.equals("greatlteks") - || codename.equals("greatqlte") - || codename.equals("greatqltechn") - || codename.equals("greatqltecmcc") - || codename.equals("greatqltecs") - || codename.equals("greatqlteue"))) - || (model != null && (model.equals("SC-01K") - || model.equals("SCV37") - || model.equals("SM-N9500") - || model.equals("SM-N9508") - || model.equals("SM-N950F") - || model.equals("SM-N950N") - || model.equals("SM-N950U") - || model.equals("SM-N950U1") - || model.equals("SM-N950W") - || model.equals("SM-N950XN")))) { - return "Galaxy Note8"; - } - if ((codename != null && (codename.equals("o5lte") - || codename.equals("o5ltechn") - || codename.equals("o5prolte") - || codename.equals("on5ltemtr") - || codename.equals("on5ltetfntmo") - || codename.equals("on5ltetmo"))) - || (model != null && (model.equals("SM-G5500") - || model.equals("SM-G550FY") - || model.equals("SM-G550T") - || model.equals("SM-G550T1") - || model.equals("SM-G550T2") - || model.equals("SM-S550TL")))) { - return "Galaxy On5"; - } - if ((codename != null && (codename.equals("o7lte") - || codename.equals("o7ltechn") - || codename.equals("on7elte"))) - || (model != null && (model.equals("SM-G6000") - || model.equals("SM-G600F") - || model.equals("SM-G600FY")))) { - return "Galaxy On7"; - } - if ((codename != null && (codename.equals("GT-I9000") - || codename.equals("GT-I9000B") - || codename.equals("GT-I9000M") - || codename.equals("GT-I9000T") - || codename.equals("GT-I9003") - || codename.equals("GT-I9003L") - || codename.equals("GT-I9008L") - || codename.equals("GT-I9010") - || codename.equals("GT-I9018") - || codename.equals("GT-I9050") - || codename.equals("SC-02B") - || codename.equals("SCH-I500") - || codename.equals("SCH-S950C") - || codename.equals("SCH-i909") - || codename.equals("SGH-I897") - || codename.equals("SGH-T959V") - || codename.equals("SGH-T959W") - || codename.equals("SHW-M110S") - || codename.equals("SHW-M190S") - || codename.equals("SPH-D700") - || codename.equals("loganlte"))) - || (model != null && (model.equals("GT-I9000") - || model.equals("GT-I9000B") - || model.equals("GT-I9000M") - || model.equals("GT-I9000T") - || model.equals("GT-I9003") - || model.equals("GT-I9003L") - || model.equals("GT-I9008L") - || model.equals("GT-I9010") - || model.equals("GT-I9018") - || model.equals("GT-I9050") - || model.equals("GT-S7275") - || model.equals("SAMSUNG-SGH-I897") - || model.equals("SC-02B") - || model.equals("SCH-I500") - || model.equals("SCH-S950C") - || model.equals("SCH-i909") - || model.equals("SGH-T959V") - || model.equals("SGH-T959W") - || model.equals("SHW-M110S") - || model.equals("SHW-M190S") - || model.equals("SPH-D700")))) { - return "Galaxy S"; - } - if ((codename != null && (codename.equals("kylechn") - || codename.equals("kyleopen") - || codename.equals("kyletdcmcc"))) - || (model != null && (model.equals("GT-S7562") - || model.equals("GT-S7568")))) { - return "Galaxy S Duos"; - } - if ((codename != null && (codename.equals("kyleprods"))) - || (model != null && (model.equals("GT-S7582") - || model.equals("GT-S7582L")))) { - return "Galaxy S Duos2"; - } - if ((codename != null && codename.equals("vivalto3gvn")) - || (model != null && model.equals("SM-G313HZ"))) { - return "Galaxy S Duos3"; - } - if ((codename != null && (codename.equals("SC-03E") - || codename.equals("c1att") - || codename.equals("c1ktt") - || codename.equals("c1lgt") - || codename.equals("c1skt") - || codename.equals("d2att") - || codename.equals("d2can") - || codename.equals("d2cri") - || codename.equals("d2dcm") - || codename.equals("d2lteMetroPCS") - || codename.equals("d2lterefreshspr") - || codename.equals("d2ltetmo") - || codename.equals("d2mtr") - || codename.equals("d2spi") - || codename.equals("d2spr") - || codename.equals("d2tfnspr") - || codename.equals("d2tfnvzw") - || codename.equals("d2tmo") - || codename.equals("d2usc") - || codename.equals("d2vmu") - || codename.equals("d2vzw") - || codename.equals("d2xar") - || codename.equals("m0") - || codename.equals("m0apt") - || codename.equals("m0chn") - || codename.equals("m0cmcc") - || codename.equals("m0ctc") - || codename.equals("m0ctcduos") - || codename.equals("m0skt") - || codename.equals("m3") - || codename.equals("m3dcm"))) - || (model != null && (model.equals("GT-I9300") - || model.equals("GT-I9300T") - || model.equals("GT-I9305") - || model.equals("GT-I9305N") - || model.equals("GT-I9305T") - || model.equals("GT-I9308") - || model.equals("Gravity") - || model.equals("GravityQuad") - || model.equals("SAMSUNG-SGH-I747") - || model.equals("SC-03E") - || model.equals("SC-06D") - || model.equals("SCH-I535") - || model.equals("SCH-I535PP") - || model.equals("SCH-I939") - || model.equals("SCH-I939D") - || model.equals("SCH-L710") - || model.equals("SCH-R530C") - || model.equals("SCH-R530M") - || model.equals("SCH-R530U") - || model.equals("SCH-R530X") - || model.equals("SCH-S960L") - || model.equals("SCH-S968C") - || model.equals("SGH-I747M") - || model.equals("SGH-I748") - || model.equals("SGH-T999") - || model.equals("SGH-T999L") - || model.equals("SGH-T999N") - || model.equals("SGH-T999V") - || model.equals("SHV-E210K") - || model.equals("SHV-E210L") - || model.equals("SHV-E210S") - || model.equals("SHW-M440S") - || model.equals("SPH-L710") - || model.equals("SPH-L710T")))) { - return "Galaxy S3"; - } - if ((codename != null && (codename.equals("golden") - || codename.equals("goldenlteatt") - || codename.equals("goldenltebmc") - || codename.equals("goldenltevzw") - || codename.equals("goldenve3g"))) - || (model != null && (model.equals("GT-I8190") - || model.equals("GT-I8190L") - || model.equals("GT-I8190N") - || model.equals("GT-I8190T") - || model.equals("GT-I8200L") - || model.equals("SAMSUNG-SM-G730A") - || model.equals("SM-G730V") - || model.equals("SM-G730W8")))) { - return "Galaxy S3 Mini"; - } - if ((codename != null && (codename.equals("goldenve3g") - || codename.equals("goldenvess3g"))) - || (model != null && (model.equals("GT-I8200") - || model.equals("GT-I8200N") - || model.equals("GT-I8200Q")))) { - return "Galaxy S3 Mini Value Edition"; - } - if ((codename != null && (codename.equals("s3ve3g") - || codename.equals("s3ve3gdd") - || codename.equals("s3ve3gds") - || codename.equals("s3ve3gdsdd"))) - || (model != null && (model.equals("GT-I9300I") - || model.equals("GT-I9301I") - || model.equals("GT-I9301Q")))) { - return "Galaxy S3 Neo"; - } - if ((codename != null && (codename.equals("SC-04E") - || codename.equals("ja3g") - || codename.equals("ja3gduosctc") - || codename.equals("jaltektt") - || codename.equals("jaltelgt") - || codename.equals("jalteskt") - || codename.equals("jflte") - || codename.equals("jflteMetroPCS") - || codename.equals("jflteaio") - || codename.equals("jflteatt") - || codename.equals("jfltecan") - || codename.equals("jfltecri") - || codename.equals("jfltecsp") - || codename.equals("jfltelra") - || codename.equals("jflterefreshspr") - || codename.equals("jfltespr") - || codename.equals("jfltetfnatt") - || codename.equals("jfltetfntmo") - || codename.equals("jfltetmo") - || codename.equals("jflteusc") - || codename.equals("jfltevzw") - || codename.equals("jfltevzwpp") - || codename.equals("jftdd") - || codename.equals("jfvelte") - || codename.equals("jfwifi") - || codename.equals("jsglte") - || codename.equals("ks01lte") - || codename.equals("ks01ltektt") - || codename.equals("ks01ltelgt"))) - || (model != null && (model.equals("GT-I9500") - || model.equals("GT-I9505") - || model.equals("GT-I9505X") - || model.equals("GT-I9506") - || model.equals("GT-I9507") - || model.equals("GT-I9507V") - || model.equals("GT-I9508") - || model.equals("GT-I9508C") - || model.equals("GT-I9508V") - || model.equals("GT-I9515") - || model.equals("GT-I9515L") - || model.equals("SAMSUNG-SGH-I337") - || model.equals("SAMSUNG-SGH-I337Z") - || model.equals("SC-04E") - || model.equals("SCH-I545") - || model.equals("SCH-I545L") - || model.equals("SCH-I545PP") - || model.equals("SCH-I959") - || model.equals("SCH-R970") - || model.equals("SCH-R970C") - || model.equals("SCH-R970X") - || model.equals("SGH-I337M") - || model.equals("SGH-M919") - || model.equals("SGH-M919N") - || model.equals("SGH-M919V") - || model.equals("SGH-S970G") - || model.equals("SHV-E300K") - || model.equals("SHV-E300L") - || model.equals("SHV-E300S") - || model.equals("SHV-E330K") - || model.equals("SHV-E330L") - || model.equals("SM-S975L") - || model.equals("SPH-L720") - || model.equals("SPH-L720T")))) { - return "Galaxy S4"; - } - if ((codename != null && (codename.equals("serrano3g") - || codename.equals("serranods") - || codename.equals("serranolte") - || codename.equals("serranoltebmc") - || codename.equals("serranoltektt") - || codename.equals("serranoltekx") - || codename.equals("serranoltelra") - || codename.equals("serranoltespr") - || codename.equals("serranolteusc") - || codename.equals("serranoltevzw") - || codename.equals("serranove3g") - || codename.equals("serranovelte") - || codename.equals("serranovolteatt"))) - || (model != null && (model.equals("GT-I9190") - || model.equals("GT-I9192") - || model.equals("GT-I9192I") - || model.equals("GT-I9195") - || model.equals("GT-I9195I") - || model.equals("GT-I9195L") - || model.equals("GT-I9195T") - || model.equals("GT-I9195X") - || model.equals("GT-I9197") - || model.equals("SAMSUNG-SGH-I257") - || model.equals("SCH-I435") - || model.equals("SCH-I435L") - || model.equals("SCH-R890") - || model.equals("SGH-I257M") - || model.equals("SHV-E370D") - || model.equals("SHV-E370K") - || model.equals("SPH-L520")))) { - return "Galaxy S4 Mini"; - } - if ((codename != null && (codename.equals("SC-04F") - || codename.equals("SCL23") - || codename.equals("k3g") - || codename.equals("klte") - || codename.equals("klteMetroPCS") - || codename.equals("klteacg") - || codename.equals("klteaio") - || codename.equals("klteatt") - || codename.equals("kltecan") - || codename.equals("klteduoszn") - || codename.equals("kltektt") - || codename.equals("kltelgt") - || codename.equals("kltelra") - || codename.equals("klteskt") - || codename.equals("kltespr") - || codename.equals("kltetfnvzw") - || codename.equals("kltetmo") - || codename.equals("klteusc") - || codename.equals("kltevzw") - || codename.equals("kwifi") - || codename.equals("lentisltektt") - || codename.equals("lentisltelgt") - || codename.equals("lentislteskt"))) - || (model != null && (model.equals("SAMSUNG-SM-G900A") - || model.equals("SAMSUNG-SM-G900AZ") - || model.equals("SC-04F") - || model.equals("SCL23") - || model.equals("SM-G9006W") - || model.equals("SM-G9008W") - || model.equals("SM-G9009W") - || model.equals("SM-G900F") - || model.equals("SM-G900FQ") - || model.equals("SM-G900H") - || model.equals("SM-G900I") - || model.equals("SM-G900K") - || model.equals("SM-G900L") - || model.equals("SM-G900M") - || model.equals("SM-G900MD") - || model.equals("SM-G900P") - || model.equals("SM-G900R4") - || model.equals("SM-G900R6") - || model.equals("SM-G900R7") - || model.equals("SM-G900S") - || model.equals("SM-G900T") - || model.equals("SM-G900T1") - || model.equals("SM-G900T3") - || model.equals("SM-G900T4") - || model.equals("SM-G900V") - || model.equals("SM-G900W8") - || model.equals("SM-G900X") - || model.equals("SM-G906K") - || model.equals("SM-G906L") - || model.equals("SM-G906S") - || model.equals("SM-S903VL")))) { - return "Galaxy S5"; - } - if ((codename != null && (codename.equals("s5neolte") - || codename.equals("s5neoltecan"))) - || (model != null && (model.equals("SM-G903F") - || model.equals("SM-G903M") - || model.equals("SM-G903W")))) { - return "Galaxy S5 Neo"; - } - if ((codename != null && (codename.equals("SC-05G") - || codename.equals("zeroflte") - || codename.equals("zeroflteacg") - || codename.equals("zeroflteaio") - || codename.equals("zeroflteatt") - || codename.equals("zerofltebmc") - || codename.equals("zerofltechn") - || codename.equals("zerofltectc") - || codename.equals("zerofltektt") - || codename.equals("zerofltelgt") - || codename.equals("zerofltelra") - || codename.equals("zerofltemtr") - || codename.equals("zeroflteskt") - || codename.equals("zerofltespr") - || codename.equals("zerofltetfnvzw") - || codename.equals("zerofltetmo") - || codename.equals("zeroflteusc") - || codename.equals("zerofltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-G920A") - || model.equals("SAMSUNG-SM-G920AZ") - || model.equals("SC-05G") - || model.equals("SM-G9200") - || model.equals("SM-G9208") - || model.equals("SM-G9209") - || model.equals("SM-G920F") - || model.equals("SM-G920I") - || model.equals("SM-G920K") - || model.equals("SM-G920L") - || model.equals("SM-G920P") - || model.equals("SM-G920R4") - || model.equals("SM-G920R6") - || model.equals("SM-G920R7") - || model.equals("SM-G920S") - || model.equals("SM-G920T") - || model.equals("SM-G920T1") - || model.equals("SM-G920V") - || model.equals("SM-G920W8") - || model.equals("SM-G920X") - || model.equals("SM-S906L") - || model.equals("SM-S907VL")))) { - return "Galaxy S6"; - } - if ((codename != null && (codename.equals("404SC") - || codename.equals("SC-04G") - || codename.equals("SCV31") - || codename.equals("zerolte") - || codename.equals("zerolteacg") - || codename.equals("zerolteatt") - || codename.equals("zeroltebmc") - || codename.equals("zeroltechn") - || codename.equals("zeroltektt") - || codename.equals("zeroltelgt") - || codename.equals("zeroltelra") - || codename.equals("zerolteskt") - || codename.equals("zeroltespr") - || codename.equals("zeroltetmo") - || codename.equals("zerolteusc") - || codename.equals("zeroltevzw"))) - || (model != null && (model.equals("404SC") - || model.equals("SAMSUNG-SM-G925A") - || model.equals("SC-04G") - || model.equals("SCV31") - || model.equals("SM-G9250") - || model.equals("SM-G925F") - || model.equals("SM-G925I") - || model.equals("SM-G925K") - || model.equals("SM-G925L") - || model.equals("SM-G925P") - || model.equals("SM-G925R4") - || model.equals("SM-G925R6") - || model.equals("SM-G925R7") - || model.equals("SM-G925S") - || model.equals("SM-G925T") - || model.equals("SM-G925V") - || model.equals("SM-G925W8") - || model.equals("SM-G925X")))) { - return "Galaxy S6 Edge"; - } - if ((codename != null && (codename.equals("zenlte") - || codename.equals("zenlteatt") - || codename.equals("zenltebmc") - || codename.equals("zenltechn") - || codename.equals("zenltektt") - || codename.equals("zenltekx") - || codename.equals("zenltelgt") - || codename.equals("zenlteskt") - || codename.equals("zenltespr") - || codename.equals("zenltetmo") - || codename.equals("zenlteusc") - || codename.equals("zenltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-G928A") - || model.equals("SM-G9280") - || model.equals("SM-G9287") - || model.equals("SM-G9287C") - || model.equals("SM-G928C") - || model.equals("SM-G928F") - || model.equals("SM-G928G") - || model.equals("SM-G928I") - || model.equals("SM-G928K") - || model.equals("SM-G928L") - || model.equals("SM-G928N0") - || model.equals("SM-G928P") - || model.equals("SM-G928R4") - || model.equals("SM-G928S") - || model.equals("SM-G928T") - || model.equals("SM-G928V") - || model.equals("SM-G928W8") - || model.equals("SM-G928X")))) { - return "Galaxy S6 Edge+"; - } - if ((codename != null && (codename.equals("herolte") - || codename.equals("heroltebmc") - || codename.equals("heroltektt") - || codename.equals("heroltelgt") - || codename.equals("herolteskt") - || codename.equals("heroqlteacg") - || codename.equals("heroqlteaio") - || codename.equals("heroqlteatt") - || codename.equals("heroqltecctvzw") - || codename.equals("heroqltechn") - || codename.equals("heroqltelra") - || codename.equals("heroqltemtr") - || codename.equals("heroqltespr") - || codename.equals("heroqltetfnvzw") - || codename.equals("heroqltetmo") - || codename.equals("heroqlteue") - || codename.equals("heroqlteusc") - || codename.equals("heroqltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-G930A") - || model.equals("SAMSUNG-SM-G930AZ") - || model.equals("SM-G9300") - || model.equals("SM-G9308") - || model.equals("SM-G930F") - || model.equals("SM-G930K") - || model.equals("SM-G930L") - || model.equals("SM-G930P") - || model.equals("SM-G930R4") - || model.equals("SM-G930R6") - || model.equals("SM-G930R7") - || model.equals("SM-G930S") - || model.equals("SM-G930T") - || model.equals("SM-G930T1") - || model.equals("SM-G930U") - || model.equals("SM-G930V") - || model.equals("SM-G930VC") - || model.equals("SM-G930VL") - || model.equals("SM-G930W8") - || model.equals("SM-G930X")))) { - return "Galaxy S7"; - } - if ((codename != null && (codename.equals("SC-02H") - || codename.equals("SCV33") - || codename.equals("hero2lte") - || codename.equals("hero2ltebmc") - || codename.equals("hero2ltektt") - || codename.equals("hero2ltelgt") - || codename.equals("hero2lteskt") - || codename.equals("hero2qlteatt") - || codename.equals("hero2qltecctvzw") - || codename.equals("hero2qltechn") - || codename.equals("hero2qltespr") - || codename.equals("hero2qltetmo") - || codename.equals("hero2qlteue") - || codename.equals("hero2qlteusc") - || codename.equals("hero2qltevzw"))) - || (model != null && (model.equals("SAMSUNG-SM-G935A") - || model.equals("SC-02H") - || model.equals("SCV33") - || model.equals("SM-G9350") - || model.equals("SM-G935F") - || model.equals("SM-G935K") - || model.equals("SM-G935L") - || model.equals("SM-G935P") - || model.equals("SM-G935R4") - || model.equals("SM-G935S") - || model.equals("SM-G935T") - || model.equals("SM-G935U") - || model.equals("SM-G935V") - || model.equals("SM-G935VC") - || model.equals("SM-G935W8") - || model.equals("SM-G935X")))) { - return "Galaxy S7 Edge"; - } - if ((codename != null && (codename.equals("SC-02J") - || codename.equals("SCV36") - || codename.equals("dreamlte") - || codename.equals("dreamlteks") - || codename.equals("dreamqltecan") - || codename.equals("dreamqltechn") - || codename.equals("dreamqltecmcc") - || codename.equals("dreamqltesq") - || codename.equals("dreamqlteue"))) - || (model != null && (model.equals("SC-02J") - || model.equals("SCV36") - || model.equals("SM-G9500") - || model.equals("SM-G9508") - || model.equals("SM-G950F") - || model.equals("SM-G950N") - || model.equals("SM-G950U") - || model.equals("SM-G950U1") - || model.equals("SM-G950W")))) { - return "Galaxy S8"; - } - if ((codename != null && (codename.equals("SC-03J") - || codename.equals("SCV35") - || codename.equals("dream2lte") - || codename.equals("dream2lteks") - || codename.equals("dream2qltecan") - || codename.equals("dream2qltechn") - || codename.equals("dream2qltesq") - || codename.equals("dream2qlteue"))) - || (model != null && (model.equals("SC-03J") - || model.equals("SCV35") - || model.equals("SM-G9550") - || model.equals("SM-G955F") - || model.equals("SM-G955N") - || model.equals("SM-G955U") - || model.equals("SM-G955U1") - || model.equals("SM-G955W")))) { - return "Galaxy S8+"; - } - if ((codename != null && (codename.equals("starlte") - || codename.equals("starlteks") - || codename.equals("starqltechn") - || codename.equals("starqltecmcc") - || codename.equals("starqltecs") - || codename.equals("starqltesq") - || codename.equals("starqlteue"))) - || (model != null && (model.equals("SM-G9600") - || model.equals("SM-G9608") - || model.equals("SM-G960F") - || model.equals("SM-G960N") - || model.equals("SM-G960U") - || model.equals("SM-G960U1") - || model.equals("SM-G960W")))) { - return "Galaxy S9"; - } - if ((codename != null && (codename.equals("star2lte") - || codename.equals("star2lteks") - || codename.equals("star2qltechn") - || codename.equals("star2qltecs") - || codename.equals("star2qltesq") - || codename.equals("star2qlteue"))) - || (model != null && (model.equals("SM-G9650") - || model.equals("SM-G965F") - || model.equals("SM-G965N") - || model.equals("SM-G965U") - || model.equals("SM-G965U1") - || model.equals("SM-G965W")))) { - return "Galaxy S9+"; - } - if ((codename != null && (codename.equals("GT-P7500") - || codename.equals("GT-P7500D") - || codename.equals("GT-P7503") - || codename.equals("GT-P7510") - || codename.equals("SC-01D") - || codename.equals("SCH-I905") - || codename.equals("SGH-T859") - || codename.equals("SHW-M300W") - || codename.equals("SHW-M380K") - || codename.equals("SHW-M380S") - || codename.equals("SHW-M380W"))) - || (model != null && (model.equals("GT-P7500") - || model.equals("GT-P7500D") - || model.equals("GT-P7503") - || model.equals("GT-P7510") - || model.equals("SC-01D") - || model.equals("SCH-I905") - || model.equals("SGH-T859") - || model.equals("SHW-M300W") - || model.equals("SHW-M380K") - || model.equals("SHW-M380S") - || model.equals("SHW-M380W")))) { - return "Galaxy Tab 10.1"; - } - if ((codename != null && (codename.equals("GT-P6200") - || codename.equals("GT-P6200L") - || codename.equals("GT-P6201") - || codename.equals("GT-P6210") - || codename.equals("GT-P6211") - || codename.equals("SC-02D") - || codename.equals("SGH-T869") - || codename.equals("SHW-M430W"))) - || (model != null && (model.equals("GT-P6200") - || model.equals("GT-P6200L") - || model.equals("GT-P6201") - || model.equals("GT-P6210") - || model.equals("GT-P6211") - || model.equals("SC-02D") - || model.equals("SGH-T869") - || model.equals("SHW-M430W")))) { - return "Galaxy Tab 7.0 Plus"; - } - if ((codename != null && (codename.equals("gteslteatt") - || codename.equals("gtesltebmc") - || codename.equals("gtesltelgt") - || codename.equals("gteslteskt") - || codename.equals("gtesltetmo") - || codename.equals("gtesltetw") - || codename.equals("gtesltevzw") - || codename.equals("gtesqltespr") - || codename.equals("gtesqlteusc"))) - || (model != null && (model.equals("SAMSUNG-SM-T377A") - || model.equals("SM-T375L") - || model.equals("SM-T375S") - || model.equals("SM-T3777") - || model.equals("SM-T377P") - || model.equals("SM-T377R4") - || model.equals("SM-T377T") - || model.equals("SM-T377V") - || model.equals("SM-T377W")))) { - return "Galaxy Tab E 8.0"; - } - if ((codename != null && (codename.equals("gtel3g") - || codename.equals("gtelltevzw") - || codename.equals("gtelwifi") - || codename.equals("gtelwifichn") - || codename.equals("gtelwifiue"))) - || (model != null && (model.equals("SM-T560") - || model.equals("SM-T560NU") - || model.equals("SM-T561") - || model.equals("SM-T561M") - || model.equals("SM-T561Y") - || model.equals("SM-T562") - || model.equals("SM-T567V")))) { - return "Galaxy Tab E 9.6"; - } - if ((codename != null && (codename.equals("403SC") - || codename.equals("degas2wifi") - || codename.equals("degas2wifibmwchn") - || codename.equals("degas3g") - || codename.equals("degaslte") - || codename.equals("degasltespr") - || codename.equals("degasltevzw") - || codename.equals("degasvelte") - || codename.equals("degasveltechn") - || codename.equals("degaswifi") - || codename.equals("degaswifibmwzc") - || codename.equals("degaswifidtv") - || codename.equals("degaswifiopenbnn") - || codename.equals("degaswifiue"))) - || (model != null && (model.equals("403SC") - || model.equals("SM-T230") - || model.equals("SM-T230NT") - || model.equals("SM-T230NU") - || model.equals("SM-T230NW") - || model.equals("SM-T230NY") - || model.equals("SM-T230X") - || model.equals("SM-T231") - || model.equals("SM-T232") - || model.equals("SM-T235") - || model.equals("SM-T235Y") - || model.equals("SM-T237P") - || model.equals("SM-T237V") - || model.equals("SM-T239") - || model.equals("SM-T2397") - || model.equals("SM-T239C") - || model.equals("SM-T239M")))) { - return "Galaxy Tab4 7.0"; - } - if ((codename != null && (codename.equals("gvlte") - || codename.equals("gvlteatt") - || codename.equals("gvltevzw") - || codename.equals("gvltexsp") - || codename.equals("gvwifijpn") - || codename.equals("gvwifiue"))) - || (model != null && (model.equals("SAMSUNG-SM-T677A") - || model.equals("SM-T670") - || model.equals("SM-T677") - || model.equals("SM-T677V")))) { - return "Galaxy View"; - } - if ((codename != null && codename.equals("manta"))) { - return "Nexus 10"; - } - // ---------------------------------------------------------------------------- - // Sony - if ((codename != null && (codename.equals("D2104") - || codename.equals("D2105"))) - || (model != null && (model.equals("D2104") - || model.equals("D2105")))) { - return "Xperia E1 dual"; - } - if ((codename != null && (codename.equals("D2202") - || codename.equals("D2203") - || codename.equals("D2206") - || codename.equals("D2243"))) - || (model != null && (model.equals("D2202") - || model.equals("D2203") - || model.equals("D2206") - || model.equals("D2243")))) { - return "Xperia E3"; - } - if ((codename != null && (codename.equals("E5603") - || codename.equals("E5606") - || codename.equals("E5653"))) - || (model != null && (model.equals("E5603") - || model.equals("E5606") - || model.equals("E5653")))) { - return "Xperia M5"; - } - if ((codename != null && (codename.equals("E5633") - || codename.equals("E5643") - || codename.equals("E5663"))) - || (model != null && (model.equals("E5633") - || model.equals("E5643") - || model.equals("E5663")))) { - return "Xperia M5 Dual"; - } - if ((codename != null && codename.equals("LT26i")) - || (model != null && model.equals("LT26i"))) { - return "Xperia S"; - } - if ((codename != null && (codename.equals("D5303") - || codename.equals("D5306") - || codename.equals("D5316") - || codename.equals("D5316N") - || codename.equals("D5322"))) - || (model != null && (model.equals("D5303") - || model.equals("D5306") - || model.equals("D5316") - || model.equals("D5316N") - || model.equals("D5322")))) { - return "Xperia T2 Ultra"; - } - if ((codename != null && (codename.equals("txs03"))) - || (model != null && (model.equals("SGPT12") - || model.equals("SGPT13")))) { - return "Xperia Tablet S"; - } - if ((codename != null && (codename.equals("SGP311") - || codename.equals("SGP312") - || codename.equals("SGP321") - || codename.equals("SGP351"))) - || (model != null && (model.equals("SGP311") - || model.equals("SGP312") - || model.equals("SGP321") - || model.equals("SGP351")))) { - return "Xperia Tablet Z"; - } - if ((codename != null && (codename.equals("D6502") - || codename.equals("D6503") - || codename.equals("D6543") - || codename.equals("SO-03F"))) - || (model != null && (model.equals("D6502") - || model.equals("D6503") - || model.equals("D6543") - || model.equals("SO-03F")))) { - return "Xperia Z2"; - } - if ((codename != null && (codename.equals("401SO") - || codename.equals("D6603") - || codename.equals("D6616") - || codename.equals("D6643") - || codename.equals("D6646") - || codename.equals("D6653") - || codename.equals("SO-01G") - || codename.equals("SOL26") - || codename.equals("leo"))) - || (model != null && (model.equals("401SO") - || model.equals("D6603") - || model.equals("D6616") - || model.equals("D6643") - || model.equals("D6646") - || model.equals("D6653") - || model.equals("SO-01G") - || model.equals("SOL26")))) { - return "Xperia Z3"; - } - if ((codename != null && (codename.equals("402SO") - || codename.equals("SO-03G") - || codename.equals("SOV31"))) - || (model != null && (model.equals("402SO") - || model.equals("SO-03G") - || model.equals("SOV31")))) { - return "Xperia Z4"; - } - if ((codename != null && (codename.equals("E5803") - || codename.equals("E5823") - || codename.equals("SO-02H"))) - || (model != null && (model.equals("E5803") - || model.equals("E5823") - || model.equals("SO-02H")))) { - return "Xperia Z5 Compact"; - } - // ---------------------------------------------------------------------------- - // Sony Ericsson - if ((codename != null && (codename.equals("LT26i") - || codename.equals("SO-02D"))) - || (model != null && (model.equals("LT26i") - || model.equals("SO-02D")))) { - return "Xperia S"; - } - if ((codename != null && (codename.equals("SGP311") - || codename.equals("SGP321") - || codename.equals("SGP341") - || codename.equals("SO-03E"))) - || (model != null && (model.equals("SGP311") - || model.equals("SGP321") - || model.equals("SGP341") - || model.equals("SO-03E")))) { - return "Xperia Tablet Z"; - } - return fallback; - } - - /** - * Get the {@link DeviceInfo} for the current device. Do not run on the UI thread, as this may - * download JSON to retrieve the {@link DeviceInfo}. JSON is only downloaded once and then - * stored to {@link SharedPreferences}. - * - * @param context - * the application context. - * @return {@link DeviceInfo} for the current device. - */ - @WorkerThread - public static DeviceInfo getDeviceInfo(Context context) { - return getDeviceInfo(context.getApplicationContext(), Build.DEVICE, Build.MODEL); - } - - /** - * Get the {@link DeviceInfo} for the current device. Do not run on the UI thread, as this may - * download JSON to retrieve the {@link DeviceInfo}. JSON is only downloaded once and then - * stored to {@link SharedPreferences}. - * - * @param context - * the application context. - * @param codename - * the codename of the device - * @return {@link DeviceInfo} for the current device. - */ - @WorkerThread - public static DeviceInfo getDeviceInfo(Context context, String codename) { - return getDeviceInfo(context, codename, null); - } - - /** - * Get the {@link DeviceInfo} for the current device. Do not run on the UI thread, as this may - * download JSON to retrieve the {@link DeviceInfo}. JSON is only downloaded once and then - * stored to {@link SharedPreferences}. - * - * @param context - * the application context. - * @param codename - * the codename of the device - * @param model - * the model of the device - * @return {@link DeviceInfo} for the current device. - */ - @WorkerThread - public static DeviceInfo getDeviceInfo(Context context, String codename, String model) { - SharedPreferences prefs = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE); - String key = String.format("%s:%s", codename, model); - String savedJson = prefs.getString(key, null); - if (savedJson != null) { - try { - return new DeviceInfo(new JSONObject(savedJson)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - // check if we have an internet connection - int ret = context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE); - boolean isConnectedToNetwork = false; - if (ret == PackageManager.PERMISSION_GRANTED) { - ConnectivityManager connMgr = (ConnectivityManager) - context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); - if (networkInfo != null && networkInfo.isConnected()) { - isConnectedToNetwork = true; - } - } else { - // assume we are connected. - isConnectedToNetwork = true; - } - - if (isConnectedToNetwork) { - try { - // Get the device name from the generated JSON files created from Google's device list. - String url = String.format(DEVICE_JSON_URL, codename.toLowerCase(Locale.ENGLISH)); - String jsonString = downloadJson(url); - JSONArray jsonArray = new JSONArray(jsonString); - for (int i = 0, len = jsonArray.length(); i < len; i++) { - JSONObject json = jsonArray.getJSONObject(i); - DeviceInfo info = new DeviceInfo(json); - if ((codename.equalsIgnoreCase(info.codename) && model == null) - || codename.equalsIgnoreCase(info.codename) && model.equalsIgnoreCase(info.model)) { - // Save to SharedPreferences so we don't need to make another request. - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(key, json.toString()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - editor.apply(); - } else { - editor.commit(); - } - return info; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (codename.equals(Build.DEVICE) && model.equals(Build.MODEL)) { - return new DeviceInfo(Build.MANUFACTURER, getDeviceName(), codename, model); // current device - } - - return new DeviceInfo(null, null, codename, model); // unknown device - } - - /** - *

Capitalizes getAllProcesses the whitespace separated words in a String. Only the first - * letter of each word is changed.

- * - * Whitespace is defined by {@link Character#isWhitespace(char)}. - * - * @param str - * the String to capitalize - * @return capitalized The capitalized String - */ - private static String capitalize(String str) { - if (TextUtils.isEmpty(str)) { - return str; - } - char[] arr = str.toCharArray(); - boolean capitalizeNext = true; - String phrase = ""; - for (char c : arr) { - if (capitalizeNext && Character.isLetter(c)) { - phrase += Character.toUpperCase(c); - capitalizeNext = false; - continue; - } else if (Character.isWhitespace(c)) { - capitalizeNext = true; - } - phrase += c; - } - return phrase; - } - - /** Download URL to String */ - @WorkerThread - private static String downloadJson(String myurl) throws IOException { - StringBuilder sb = new StringBuilder(); - BufferedReader reader = null; - try { - URL url = new URL(myurl); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setReadTimeout(10000); - conn.setConnectTimeout(15000); - conn.setRequestMethod("GET"); - conn.setDoInput(true); - conn.connect(); - if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line; - while ((line = reader.readLine()) != null) { - sb.append(line).append('\n'); - } - } - return sb.toString(); - } finally { - if (reader != null) { - reader.close(); - } - } - } - - public static final class Request { - - final Context context; - final Handler handler; - String codename; - String model; - - private Request(Context ctx) { - context = ctx; - handler = new Handler(ctx.getMainLooper()); - } - - /** - * Set the device codename to query. You should also set the model. - * - * @param codename - * the value of the system property "ro.product.device" - * @return This Request object to allow for chaining of calls to set methods. - * @see Build#DEVICE - */ - public Request setCodename(String codename) { - this.codename = codename; - return this; - } - - /** - * Set the device model to query. You should also set the codename. - * - * @param model - * the value of the system property "ro.product.model" - * @return This Request object to allow for chaining of calls to set methods. - * @see Build#MODEL - */ - public Request setModel(String model) { - this.model = model; - return this; - } - - /** - * Download information about the device. This saves the results in shared-preferences so - * future requests will not need a network connection. - * - * @param callback - * the callback to retrieve the {@link DeviceInfo} - */ - public void request(Callback callback) { - if (codename == null && model == null) { - codename = Build.DEVICE; - model = Build.MODEL; - } - GetDeviceRunnable runnable = new GetDeviceRunnable(callback); - if (Looper.myLooper() == Looper.getMainLooper()) { - new Thread(runnable).start(); - } else { - runnable.run(); // already running in background thread. - } - } - - private final class GetDeviceRunnable implements Runnable { - - final Callback callback; - DeviceInfo deviceInfo; - Exception error; - - public GetDeviceRunnable(Callback callback) { - this.callback = callback; - } - - @Override public void run() { - try { - deviceInfo = getDeviceInfo(context, codename, model); - } catch (Exception e) { - error = e; - } - handler.post(new Runnable() { - - @Override public void run() { - callback.onFinished(deviceInfo, error); - } - }); - } - } - - } - - /** - * Callback which is invoked when the {@link DeviceInfo} is finished loading. - */ - public interface Callback { - - /** - * Callback to get the device info. This is run on the UI thread. - * - * @param info - * the requested {@link DeviceInfo} - * @param error - * {@code null} if nothing went wrong. - */ - void onFinished(DeviceInfo info, Exception error); - } - - /** - * Device information based on - * Google's maintained list. - */ - public static final class DeviceInfo { - - /** Retail branding */ - public final String manufacturer; - - /** Marketing name */ - public final String marketName; - - /** the value of the system property "ro.product.device" */ - public final String codename; - - /** the value of the system property "ro.product.model" */ - public final String model; - - public DeviceInfo(String manufacturer, String marketName, String codename, String model) { - this.manufacturer = manufacturer; - this.marketName = marketName; - this.codename = codename; - this.model = model; - } - - private DeviceInfo(JSONObject jsonObject) throws JSONException { - manufacturer = jsonObject.getString("manufacturer"); - marketName = jsonObject.getString("market_name"); - codename = jsonObject.getString("codename"); - model = jsonObject.getString("model"); - } - - /** - * @return the consumer friendly name of the device. - */ - public String getName() { - if (!TextUtils.isEmpty(marketName)) { - return marketName; - } - return capitalize(model); - } - } - -} - diff --git a/app/src/main/java/com/tangem/util/FormatUtil.java b/app/src/main/java/com/tangem/util/FormatUtil.java deleted file mode 100644 index 5196d2bbaf..0000000000 --- a/app/src/main/java/com/tangem/util/FormatUtil.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.tangem.util; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Locale; - -/** - * Created by Ilia on 15.02.2018. - */ - -public class FormatUtil { - public static long parseValue(String valueStr) throws NumberFormatException { - return new BigDecimal(valueStr).multiply(BigDecimal.valueOf(1_0000_0000)).setScale(0, BigDecimal.ROUND_HALF_DOWN).longValueExact(); - } - - public static String DoubleToString(double amount) { - DecimalFormat myFormatter = GetDecimalFormat(); - String output = myFormatter.format(amount); - return output; - } - - public static DecimalFormat GetDecimalFormat() { - DecimalFormatSymbols symbols = new DecimalFormatSymbols(); - symbols.setDecimalSeparator('.'); - - String pattern = "#0.########"; -// DecimalFormat myFormatter = new DecimalFormat(pattern, symbols); - DecimalFormat myFormatter = new DecimalFormat(pattern); - - myFormatter.setParseBigDecimal(true); - - return myFormatter; - } - - public static BigDecimal stringToBigDecimal(final String formattedString, - final Locale locale) - { - final DecimalFormatSymbols symbols; - final char groupSeparatorChar; - final String groupSeparator; - final char decimalSeparatorChar; - final String decimalSeparator; - String fixedString; - final BigDecimal number; - - symbols = new DecimalFormatSymbols(locale); - groupSeparatorChar = symbols.getGroupingSeparator(); - decimalSeparatorChar = symbols.getDecimalSeparator(); - - if(groupSeparatorChar == '.') - { - groupSeparator = "\\" + groupSeparatorChar; - } - else - { - groupSeparator = Character.toString(groupSeparatorChar); - } - - if(decimalSeparatorChar == '.') - { - decimalSeparator = "\\" + decimalSeparatorChar; - } - else - { - decimalSeparator = Character.toString(decimalSeparatorChar); - } - - fixedString = formattedString.replaceAll(groupSeparator , ""); - fixedString = fixedString.replaceAll(decimalSeparator , "."); - number = new BigDecimal(fixedString); - - return (number); - } - - public static long ConvertStringToLong(String caption) throws Exception { -// BigDecimal d = new BigDecimal(caption); - BigDecimal d = stringToBigDecimal(caption,Locale.US); - d = d.multiply(new BigDecimal(100000000)); - d = d.setScale(5); - BigInteger b = d.toBigInteger(); - long l = b.longValue(); - return l; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/util/LOG.java b/app/src/main/java/com/tangem/util/LOG.java deleted file mode 100644 index 387c3f90b1..0000000000 --- a/app/src/main/java/com/tangem/util/LOG.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.tangem.util; - -import android.util.Log; - -import com.tangem.wallet.BuildConfig; - -public final class LOG { - public static String TAG = "com.tangem.wallet"; - - public static void d(String msg) { - d(null, msg); - } - - public static void e(String msg) { - e(null, msg); - } - - public static void d(String tag, String msg) { - if (BuildConfig.DEBUG) - Log.d(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), msg); - } - - public static void d(String tag, int msg) { - if (BuildConfig.DEBUG) - Log.d(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), String.valueOf(msg)); - } - - public static void i(String tag, String msg) { - if (BuildConfig.DEBUG) - Log.i(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), msg); - } - - public static void i(String tag, int msg) { - if (BuildConfig.DEBUG) - Log.i(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), String.valueOf(msg)); - } - - public static void w(String tag, String msg) { - if (BuildConfig.DEBUG) - Log.w(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), msg); - } - - public static void w(String tag, int msg) { - if (BuildConfig.DEBUG) - Log.w(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), String.valueOf(msg)); - } - - public static void e(String tag, String msg) { - if (BuildConfig.DEBUG) - Log.e(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), msg); - } - - public static void e(String tag, int msg) { - if (BuildConfig.DEBUG) - Log.d(TAG + (tag != null && !tag.equals("") ? "." + tag : ""), String.valueOf(msg)); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/util/UtilHelper.kt b/app/src/main/java/com/tangem/util/UtilHelper.kt deleted file mode 100644 index 914520d6e2..0000000000 --- a/app/src/main/java/com/tangem/util/UtilHelper.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.tangem.util - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.Color -import android.net.ConnectivityManager -import android.net.NetworkInfo -import android.os.Build -import android.widget.Toast -import com.google.zxing.BarcodeFormat -import com.google.zxing.EncodeHintType -import com.google.zxing.WriterException -import com.google.zxing.qrcode.QRCodeWriter -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel -import java.util.* - -object UtilHelper { - - @Throws(WriterException::class) - fun generateQrCode(myCodeText: String): Bitmap { - val hintMap = Hashtable() - hintMap[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M // H = 30% damage - hintMap[EncodeHintType.MARGIN] = 2 - - val qrCodeWriter = QRCodeWriter() - - val size = 256 - - val bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hintMap) - val width = bitMatrix.width - val bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565) - for (x in 0 until width) { - for (y in 0 until width) { - bmp.setPixel(y, x, if (bitMatrix.get(x, y)) Color.BLACK else Color.WHITE) - } - } - return bmp - } - - fun isOnline(context: Context): Boolean { - return try { - val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager - val netInfo: NetworkInfo? - netInfo = cm.activeNetworkInfo - netInfo != null && netInfo.isConnected - } catch (e: NullPointerException) { - e.printStackTrace() - false - } - } - - fun getDeviceInfo(): String { - return "----------------------------------------\n" + - "MODEL: " + Build.MODEL + "\n" + - "ID: " + Build.ID + "\n" + - "Manufacturer: " + Build.MANUFACTURER + "\n" + - "Brand: " + Build.BRAND + "\n" + - "Hardware: " + Build.HARDWARE + "\n" + - "Version: " + Build.VERSION.RELEASE + ", " + Build.VERSION.INCREMENTAL + "\n" + - "OS: " + Build.VERSION.BASE_OS + "\n" + - "SDK: " + Build.VERSION.SDK_INT + "\n" + - "BOARD: " + Build.BOARD + "\n" + - "FINGERPRINT: " + Build.FINGERPRINT + "\n" + - "----------------------------------------\n" - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/util/extensions/Context.kt b/app/src/main/java/com/tangem/util/extensions/Context.kt deleted file mode 100644 index f138f41bb7..0000000000 --- a/app/src/main/java/com/tangem/util/extensions/Context.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.tangem.util.extensions - -import android.content.Context -import androidx.annotation.ColorRes -import androidx.core.content.ContextCompat - -fun Context.colorFrom(@ColorRes colorId: Int) = ContextCompat.getColor(this, colorId) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/util/extensions/TangemCard.kt b/app/src/main/java/com/tangem/util/extensions/TangemCard.kt deleted file mode 100644 index 4e3cc50e4b..0000000000 --- a/app/src/main/java/com/tangem/util/extensions/TangemCard.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.util.extensions - -import com.tangem.tangem_card.data.TangemCard -import com.tangem.tangem_card.util.Util - -fun TangemCard.isStart2CoinCard(): Boolean = (Util.bytesToHex(this.cid).startsWith("1")) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/BCHUtils.java b/app/src/main/java/com/tangem/wallet/BCHUtils.java deleted file mode 100644 index 8264d849d0..0000000000 --- a/app/src/main/java/com/tangem/wallet/BCHUtils.java +++ /dev/null @@ -1,345 +0,0 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 29.09.2017. - */ - -import android.util.Log; - -import com.tangem.tangem_card.util.Util; -import com.tangem.util.CryptoUtil; -import com.tangem.util.FormatUtil; -import com.tangem.wallet.btc.BitcoinException; -import com.tangem.wallet.btc.BitcoinOutputStream; -import com.tangem.wallet.btc.BtcData; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@SuppressWarnings({"WeakerAccess", "TryWithIdenticalCatches", "unused"}) -public final class BCHUtils { - static final BigInteger LARGEST_PRIVATE_KEY = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);//SECP256K1_N - public static final long MIN_FEE_PER_KB = 10000; - public static final long MAX_ALLOWED_FEE = FormatUtil.parseValue("0.1"); - public static final long MIN_PRIORITY_FOR_NO_FEE = 57600000; - public static final long MIN_MIN_OUTPUT_VALUE_FOR_NO_FEE = 10000000L; - public static final int MAX_TX_LEN_FOR_NO_FEE = 10000; - public static final float EXPECTED_BLOCKS_PER_DAY = 144.0f;//(expected confirmations per day) - - public static String toHex(byte[] bytes) { - if (bytes == null) { - return ""; - } - final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - char[] hexChars = new char[bytes.length * 2]; - int v; - for (int j = 0; j < bytes.length; j++) { - v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - - public static byte[] buildTXForSign(String myAddress, String outputAddress, String changeAddress, ArrayList unspentOutputs, int currentInputPos, long amount, long change) throws BitcoinException, IOException { - - int inputPos = currentInputPos; - byte[] tx = buildPreimage(outputAddress, changeAddress, unspentOutputs, inputPos, amount, change); - return tx; - } - - public static byte[] buildTXForSend(String outputAddress, String changeAddress, ArrayList unspentOutputs, long amount, long change) throws BitcoinException, IOException { - - int inputPos = -1; - byte[] tx = buildBodyTX(outputAddress, changeAddress, unspentOutputs, inputPos, amount, change); - return tx; - } - - //BIP 143 as reference + script length added - public static byte[] buildPreimage(String outputAddress, String changeAddress, ArrayList unspentOutputs, int inputPos, long amount, long change) throws BitcoinException, IOException { - - //nVersion of the transaction (4-byte little endian) - BitcoinOutputStream forSign = new BitcoinOutputStream(); - //forSign.writeInt32(0x01); - forSign.write(new byte[]{0x02, 0x00, 0x00, 0x00}); // version - - //inputCount - byte inputCount = (byte) unspentOutputs.size(); - - //hashPrevouts (32-byte hash) - ByteArrayOutputStream prevouts = new ByteArrayOutputStream(); - for (int i = 0; i < inputCount; ++i) { - UnspentOutputInfo outPut = unspentOutputs.get(i); - byte[] txHash = BCHUtils.reverse(Util.hexToBytes(outPut.txHashForBuild));//Little-endian txID - byte[] txIndex = BCHUtils.reverse(Util.intToByteArray4(outPut.outputIndex));//Little-endian outputIndex - prevouts.write(txHash); - prevouts.write(txIndex); - } - byte[] hashPrevouts = CryptoUtil.doubleSha256(prevouts.toByteArray()); - forSign.write(hashPrevouts); - - //hashSequence (32-byte hash), ffffffff only - ByteArrayOutputStream sequences = new ByteArrayOutputStream(); - for (int i = 0; i < inputCount; ++i) { - sequences.write(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}); - } - byte[] hashSequence = CryptoUtil.doubleSha256(sequences.toByteArray()); - forSign.write(hashSequence); - - //outpoint (32-byte hash + 4-byte little endian) - UnspentOutputInfo outPut = unspentOutputs.get(inputPos); - byte[] txHash = BCHUtils.reverse(Util.hexToBytes(outPut.txHashForBuild));//Little-endian txID - byte[] txIndex = BCHUtils.reverse(Util.intToByteArray4(outPut.outputIndex));//Little-endian outputIndex - forSign.write(txHash); - forSign.write(txIndex); - - //scriptCode of the input (serialized as scripts inside CTxOuts) - byte[] scriptCode = Transaction.Script.buildOutput(changeAddress).bytes; //build change out - byte[] scriptLength = Util.intToByteArray(scriptCode.length); - forSign.write(scriptLength); - forSign.write(scriptCode); - - //value of the output spent by this input (8-byte little endian) - byte[] outValue = BCHUtils.reverse(Util.longToByteArray8(outPut.value)); - forSign.write(outValue); - - //nSequence of the input (4-byte little endian), ffffffff only - forSign.write(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}); - - //hashOutputs (32-byte hash) - ByteArrayOutputStream outputs = new ByteArrayOutputStream(); - byte[] sendAmount = BCHUtils.reverse(Util.longToByteArray8(amount)); - byte[] sendScript = Transaction.Script.buildOutput(outputAddress).bytes; // build out - byte[] sendLength = Util.intToByteArray(sendScript.length); - outputs.write(sendAmount); - outputs.write(sendLength); - outputs.write(sendScript); - //output for change (if any) - if (change != 0) { - byte[] changeAmount = BCHUtils.reverse(Util.longToByteArray8(change)); - byte[] changeScript = Transaction.Script.buildOutput(changeAddress).bytes; //build change out - byte[] changeLength = Util.intToByteArray(changeScript.length); - outputs.write(changeAmount); - outputs.write(changeLength); - outputs.write(changeScript); - } - byte[] hashOutputs = CryptoUtil.doubleSha256(outputs.toByteArray()); - forSign.write(hashOutputs); - - //nLocktime of the transaction (4-byte little endian) - forSign.write(new byte[]{0x00, 0x00, 0x00, 0x00}); - - //sighash type of the signature (4-byte little endian) - forSign.write(new byte[]{0x41, 0x00, 0x00, 0x00}); - - byte[] rawData = forSign.toByteArray(); - - Log.e("Sign_TX_Body", BCHUtils.toHex(rawData)); - - return rawData; - - } - public static byte[] buildBodyTX(String outputAddress, String changeAddress, ArrayList unspentOutputs, int inputPos, long amount, long change) throws BitcoinException, IOException { - - //0200000000 - BitcoinOutputStream forSign = new BitcoinOutputStream(); - //forSign.writeInt32(0x01); - forSign.write(new byte[]{0x02, 0x00, 0x00, 0x00}); // version - - //01 - byte inputCount = (byte) unspentOutputs.size(); - forSign.write(inputCount); // input count - //hex str hash prev btc - - for (int i = 0; i < inputCount; ++i) { - UnspentOutputInfo outPut = unspentOutputs.get(i); - int outputIndex = outPut.outputIndex; - byte[] txHash = BCHUtils.reverse(Util.hexToBytes(outPut.txHashForBuild));//Sha256Hash.hash(rawTxByte); - forSign.write(txHash); - forSign.writeInt32(outputIndex); //output index in prev tx - if (inputPos == -1 || i == inputPos) { - // hex str 1976a914....88ac - forSign.write((byte) outPut.scriptForBuild.length); - forSign.write(outPut.scriptForBuild); - } else { - forSign.write(0x00); - } - //ffffffff - forSign.write(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}); // sequence - } - - - //02 - byte outputCount = (byte) ((change == 0) ? 1 : 2); // outputCount - forSign.write(outputCount); - - //8 bytes - - forSign.writeInt64(amount); //amount - byte[] sendScript = Transaction.Script.buildOutput(outputAddress).bytes; // build out - //hex str 1976a914....88ac - forSign.write((byte) sendScript.length); - forSign.write(sendScript); - - if (change != 0) { - //8 bytes - forSign.writeInt64(change); // change - //hex str 1976a914....88ac - byte[] chancheScript = Transaction.Script.buildOutput(changeAddress).bytes; //build out - forSign.write((byte) chancheScript.length); - forSign.write(chancheScript); - - } - - //00000000 - forSign.write(new byte[]{0x00, 0x00, 0x00, 0x00}); - - //forSign.write(new byte[]{0x01, 0x00, 0x00, 0x00}); - - byte[] rawData = forSign.toByteArray(); - - Log.e("Sign_TX_Body", BCHUtils.toHex(rawData)); - - return rawData; - } - - public static byte[] buildBodyTX(String outputAddress, String changeAddress, int outputIndex, String prevID, long amount, long change, byte[] script) throws BitcoinException, IOException { - - //0200000000 - BitcoinOutputStream forSign = new BitcoinOutputStream(); - forSign.writeInt32(0x01);//write(new byte[]{0x02, 0x00, 0x00, 0x00}); // version - - //01 - byte inputCount = 1; - forSign.write(inputCount); // input count - //hex str hash prev btc - byte[] txHash = BCHUtils.reverse(Util.hexToBytes(prevID));//Sha256Hash.hash(rawTxByte); - forSign.write(txHash); //previos tx hash - - //00000000 - //byte indexOutput = outputIndex; - forSign.writeInt32(outputIndex/*indexOutput*/); //output index in prev tx - //forSign.write(0x00); - - // hex str 1976a914....88ac - forSign.write((byte) script.length); - forSign.write(script); - - //ffffffff - forSign.write(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}); // sequence - - //02 - byte outputCount = (byte) ((change == 0) ? 1 : 2); // outputCount - forSign.write(outputCount); - - //8 bytes - - forSign.writeInt64(amount); //amount - byte[] sendScript = Transaction.Script.buildOutput(outputAddress).bytes; // build out - //hex str 1976a914....88ac - forSign.write((byte) sendScript.length); - forSign.write(sendScript); - - if (change != 0) { - //8 bytes - forSign.writeInt64(change); // change - //hex str 1976a914....88ac - byte[] chancheScript = Transaction.Script.buildOutput(changeAddress).bytes; //build out - forSign.write((byte) chancheScript.length); - forSign.write(chancheScript); - - } - - //00000000 - forSign.write(new byte[]{0x00, 0x00, 0x00, 0x00}); - - byte[] rawData = forSign.toByteArray(); - - //Log.e("Sign_TX_Body", BCHUtils.toHex(rawData)); - return rawData; - } - - public static ArrayList getOutputs(List rawTxList, byte[] outputScriptWeAreAbleToSpend) throws BitcoinException { - ArrayList unspentOutputs = new ArrayList<>(); - - for (BtcData.UnspentTransaction current : rawTxList) { - byte[] rawTxByte = BCHUtils.fromHex(current.script); - if (rawTxByte == null || current.script.isEmpty()) { - continue; - } - - Transaction baseTx = new Transaction(rawTxByte); - - if (baseTx.inputs.length == 0 || baseTx.outputs.length == 0) - throw new IllegalArgumentException("Unable to decode given transaction"); - - byte[] txHash = BCHUtils.reverse(CryptoUtil.doubleSha256(rawTxByte)); - String txHashForBuild = current.txID; - byte[] sign = null; - - for (int outputIndex = 0; outputIndex < baseTx.outputs.length; outputIndex++) { - Transaction.Output output = baseTx.outputs[outputIndex]; - - // find outputs - if (Arrays.equals(outputScriptWeAreAbleToSpend, output.script.bytes)) { - unspentOutputs.add(new UnspentOutputInfo(txHash, output.script, output.value, outputIndex, -1, txHashForBuild, sign)); - } - } - - } - - return unspentOutputs; - } - - public static byte[] fromHex(String s) { - if (s != null) { - try { - StringBuilder sb = new StringBuilder(s.length()); - for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); - if (!Character.isWhitespace(ch)) { - sb.append(ch); - } - } - s = sb.toString(); - int len = s.length(); - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - int hi = (Character.digit(s.charAt(i), 16) << 4); - int low = Character.digit(s.charAt(i + 1), 16); - if (hi >= 256 || low < 0 || low >= 16) { - return null; - } - data[i / 2] = (byte) (hi | low); - } - return data; - } catch (Exception ignored) { - } - } - return null; - } - - public static byte[] reverse(byte[] bytes) { - byte[] result = new byte[bytes.length]; - for (int i = 0; i < bytes.length; i++) { - result[i] = bytes[bytes.length - i - 1]; - } - return result; - } - - public static byte[] reverseInPlace(byte[] bytes) { - int len = bytes.length / 2; - for (int i = 0; i < len; i++) { - byte t = bytes[i]; - bytes[i] = bytes[bytes.length - i - 1]; - bytes[bytes.length - i - 1] = t; - } - return bytes; - } - -} - diff --git a/app/src/main/java/com/tangem/wallet/BTCUtils.java b/app/src/main/java/com/tangem/wallet/BTCUtils.java deleted file mode 100644 index 1b3c8fe894..0000000000 --- a/app/src/main/java/com/tangem/wallet/BTCUtils.java +++ /dev/null @@ -1,280 +0,0 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 29.09.2017. - */ - -import android.util.Log; - -import com.tangem.tangem_card.util.Util; -import com.tangem.util.CryptoUtil; -import com.tangem.util.FormatUtil; -import com.tangem.wallet.btc.BitcoinException; -import com.tangem.wallet.btc.BitcoinOutputStream; -import com.tangem.wallet.btc.BtcData; - -import org.bitcoinj.core.Address; -import org.bitcoinj.core.SegwitAddress; -import org.bitcoinj.script.ScriptBuilder; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@SuppressWarnings({"WeakerAccess", "TryWithIdenticalCatches", "unused"}) -public final class BTCUtils { - static final BigInteger LARGEST_PRIVATE_KEY = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);//SECP256K1_N - public static final long MIN_FEE_PER_KB = 10000; - public static final long MAX_ALLOWED_FEE = FormatUtil.parseValue("0.1"); - public static final long MIN_PRIORITY_FOR_NO_FEE = 57600000; - public static final long MIN_MIN_OUTPUT_VALUE_FOR_NO_FEE = 10000000L; - public static final int MAX_TX_LEN_FOR_NO_FEE = 10000; - public static final float EXPECTED_BLOCKS_PER_DAY = 144.0f;//(expected confirmations per day) - - public static String toHex(byte[] bytes) { - if (bytes == null) { - return ""; - } - final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - char[] hexChars = new char[bytes.length * 2]; - int v; - for (int j = 0; j < bytes.length; j++) { - v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - - public static byte[] buildTXForSign(String myAddress, String outputAddress, String changeAddress, ArrayList unspentOutputs, int currentInputPos, long amount, long change) throws BitcoinException, IOException { - byte[] myScript = Transaction.Script.buildOutput(myAddress).bytes; - unspentOutputs.get(currentInputPos).scriptForBuild = myScript; - int inputPos = currentInputPos; - byte[] body = buildBodyTX(outputAddress, changeAddress, unspentOutputs, inputPos, amount, change); - - ByteArrayOutputStream os = new ByteArrayOutputStream(); - os.write(body); - os.write(new byte[]{0x01, 0x00, 0x00, 0x00}); - byte[] tx = os.toByteArray(); - return tx; - } - - public static byte[] buildTXForSend(String outputAddress, String changeAddress, ArrayList unspentOutputs, long amount, long change) throws BitcoinException, IOException { - int inputPos = -1; - byte[] body = buildBodyTX(outputAddress, changeAddress, unspentOutputs, inputPos, amount, change); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - os.write(body); - byte[] tx = os.toByteArray(); - return tx; - } - - public static byte[] buildBodyTX(String outputAddress, String changeAddress, ArrayList unspentOutputs, int inputPos, long amount, long change) throws BitcoinException, IOException { - - //0200000000 - BitcoinOutputStream forSign = new BitcoinOutputStream(); - forSign.writeInt32(0x01);//write(new byte[]{0x02, 0x00, 0x00, 0x00}); // version - - //01 - byte inputCount = (byte) unspentOutputs.size(); - forSign.write(inputCount); // input count - //hex str hash prev btc - - for (int i = 0; i < inputCount; ++i) { - UnspentOutputInfo outPut = unspentOutputs.get(i); - int outputIndex = outPut.outputIndex; - byte[] txHash = BTCUtils.reverse(Util.hexToBytes(outPut.txHashForBuild));//Sha256Hash.hash(rawTxByte); - forSign.write(txHash); - forSign.writeInt32(outputIndex); //output index in prev tx - if (inputPos == -1 || i == inputPos) { - // hex str 1976a914....88ac - forSign.write((byte) outPut.scriptForBuild.length); - forSign.write(outPut.scriptForBuild); - } else { - forSign.write(0x00); - } - //ffffffff - forSign.write(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}); // sequence - } - - - //02 - byte outputCount = (byte) ((change == 0) ? 1 : 2); // outputCount - forSign.write(outputCount); - - //8 bytes - - forSign.writeInt64(amount); //amount - - byte[] sendScript; - if (outputAddress.startsWith("bc1") || outputAddress.startsWith("tb1")) { - Address address = SegwitAddress.fromBech32(null, outputAddress); - sendScript = ScriptBuilder.createOutputScript(address).getProgram(); - } else { - sendScript = Transaction.Script.buildOutput(outputAddress).bytes; // build out - } - - //hex str 1976a914....88ac - forSign.write((byte) sendScript.length); - forSign.write(sendScript); - - if (change != 0) { - //8 bytes - forSign.writeInt64(change); // change - //hex str 1976a914....88ac - byte[] chancheScript = Transaction.Script.buildOutput(changeAddress).bytes; //build out - forSign.write((byte) chancheScript.length); - forSign.write(chancheScript); - - } - - //00000000 - forSign.write(new byte[]{0x00, 0x00, 0x00, 0x00}); - - //forSign.write(new byte[]{0x01, 0x00, 0x00, 0x00}); - - byte[] rawData = forSign.toByteArray(); - - Log.e("Sign_TX_Body", BTCUtils.toHex(rawData)); - - return rawData; - } - - public static byte[] buildBodyTX(String outputAddress, String changeAddress, int outputIndex, String prevID, long amount, long change, byte[] script) throws BitcoinException, IOException { - - //0200000000 - BitcoinOutputStream forSign = new BitcoinOutputStream(); - forSign.writeInt32(0x01);//write(new byte[]{0x02, 0x00, 0x00, 0x00}); // version - - //01 - byte inputCount = 1; - forSign.write(inputCount); // input count - //hex str hash prev btc - byte[] txHash = BTCUtils.reverse(Util.hexToBytes(prevID));//Sha256Hash.hash(rawTxByte); - forSign.write(txHash); //previos tx hash - - //00000000 - //byte indexOutput = outputIndex; - forSign.writeInt32(outputIndex/*indexOutput*/); //output index in prev tx - //forSign.write(0x00); - - // hex str 1976a914....88ac - forSign.write((byte) script.length); - forSign.write(script); - - //ffffffff - forSign.write(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}); // sequence - - //02 - byte outputCount = (byte) ((change == 0) ? 1 : 2); // outputCount - forSign.write(outputCount); - - //8 bytes - - forSign.writeInt64(amount); //amount - byte[] sendScript = Transaction.Script.buildOutput(outputAddress).bytes; // build out - //hex str 1976a914....88ac - forSign.write((byte) sendScript.length); - forSign.write(sendScript); - - if (change != 0) { - //8 bytes - forSign.writeInt64(change); // change - //hex str 1976a914....88ac - byte[] chancheScript = Transaction.Script.buildOutput(changeAddress).bytes; //build out - forSign.write((byte) chancheScript.length); - forSign.write(chancheScript); - - } - - //00000000 - forSign.write(new byte[]{0x00, 0x00, 0x00, 0x00}); - - byte[] rawData = forSign.toByteArray(); - - //Log.e("Sign_TX_Body", BTCUtils.toHex(rawData)); - return rawData; - } - - public static ArrayList getOutputs(List rawTxList, byte[] outputScriptWeAreAbleToSpend) throws BitcoinException { - ArrayList unspentOutputs = new ArrayList<>(); - - for (BtcData.UnspentTransaction current : rawTxList) { - byte[] rawTxByte = BTCUtils.fromHex(current.script); - if (rawTxByte == null || current.script.isEmpty()) { - continue; - } - - Transaction baseTx = new Transaction(rawTxByte); - - if (baseTx.inputs.length == 0 || baseTx.outputs.length == 0) - throw new IllegalArgumentException("Unable to decode given transaction"); - - byte[] txHash = BTCUtils.reverse(CryptoUtil.doubleSha256(rawTxByte)); - String txHashForBuild = current.txID; - byte[] sign = null; - - for (int outputIndex = 0; outputIndex < baseTx.outputs.length; outputIndex++) { - Transaction.Output output = baseTx.outputs[outputIndex]; - - // find outputs - if (Arrays.equals(outputScriptWeAreAbleToSpend, output.script.bytes)) { - unspentOutputs.add(new UnspentOutputInfo(txHash, output.script, output.value, outputIndex, -1, txHashForBuild, sign)); - } - } - - } - - return unspentOutputs; - } - - public static byte[] fromHex(String s) { - if (s != null) { - try { - StringBuilder sb = new StringBuilder(s.length()); - for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); - if (!Character.isWhitespace(ch)) { - sb.append(ch); - } - } - s = sb.toString(); - int len = s.length(); - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - int hi = (Character.digit(s.charAt(i), 16) << 4); - int low = Character.digit(s.charAt(i + 1), 16); - if (hi >= 256 || low < 0 || low >= 16) { - return null; - } - data[i / 2] = (byte) (hi | low); - } - return data; - } catch (Exception ignored) { - } - } - return null; - } - - public static byte[] reverse(byte[] bytes) { - byte[] result = new byte[bytes.length]; - for (int i = 0; i < bytes.length; i++) { - result[i] = bytes[bytes.length - i - 1]; - } - return result; - } - - public static byte[] reverseInPlace(byte[] bytes) { - int len = bytes.length / 2; - for (int i = 0; i < len; i++) { - byte t = bytes[i]; - bytes[i] = bytes[bytes.length - i - 1]; - bytes[bytes.length - i - 1] = t; - } - return bytes; - } - -} - diff --git a/app/src/main/java/com/tangem/wallet/BalanceValidator.java b/app/src/main/java/com/tangem/wallet/BalanceValidator.java deleted file mode 100644 index 9457557164..0000000000 --- a/app/src/main/java/com/tangem/wallet/BalanceValidator.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.tangem.wallet; - -import androidx.annotation.StringRes; - -import com.tangem.App; -import com.tangem.tangem_card.data.TangemCard; - -public class BalanceValidator { - private @StringRes int firstLine; - private @StringRes int secondLine; - private int score; - private boolean hasPending; - - public @StringRes int getFirstLine() { - return firstLine; - } - - public void setFirstLine(@StringRes int value) { - firstLine = value; - } - - public @StringRes int getSecondLine(Boolean recommend) { -// if (!recommend) - return secondLine; - -// if (score > 89) { -// return "Safe to accept. " + secondLine; -// } else if (score > 74) { -// return "Not fully safe to accept. " + secondLine; -// } else if (score > 30) { -// return "Not safe to accept. " + secondLine; -// } else { -// return "Do not accept! " + secondLine; -// } - } - - public void setSecondLine(@StringRes int value) { - secondLine = value; - } - - public void setScore(int score) { - this.score = score; - } - - public int getColor() { - if( hasPending ) - { - return R.color.primary_dark; - } - if (score > 89) { - return R.color.confirmed; - } else if (score > 74) { - return android.R.color.holo_orange_light; - } else if (score > 0) { - return android.R.color.holo_orange_dark; - } else { - return android.R.color.holo_red_light; - } - } - - public void check(TangemContext ctx, Boolean attest) { - firstLine = R.string.balance_validator_first_line_verification_failed; - secondLine = R.string.empty_string; - TangemCard card = ctx.getCard(); - CoinEngine engine = CoinEngineFactory.INSTANCE.create(ctx); - - if (!engine.validateBalance(this)) return; - - hasPending=App.pendingTransactionsStorage.hasTransactions(card); - - if( hasPending ) - { - firstLine = R.string.balance_validator_first_line_pending_transaction; - secondLine = R.string.balance_validator_second_line_swipe_to_refresh; - return; - } - - // Verify card? - if (attest) { - - if (!card.isWalletPublicKeyValid()) { - score = 0; - firstLine = R.string.balance_validator_first_line_verification_failed; - secondLine = R.string.balance_validator_second_line_verification_failed; - return; - } - - if (card.isOnlineVerified() != null && !card.isOnlineVerified()) { - score = 0; - firstLine = R.string.balance_validator_first_line_not_genuine; - secondLine = R.string.balance_validator_second_line_failed_attestation; - return; - } - - if (card.isCodeConfirmed() != null && !card.isCodeConfirmed()) { - score = 0; - firstLine = R.string.balance_validator_first_line_not_genuine; - secondLine = R.string.balance_validator_second_line_failed_binary_code_verification; - return; - } - - if (card.PIN2 == TangemCard.PIN2_Mode.CustomPIN2) { - score = 0; - firstLine = R.string.balance_validator_first_line_locked_pin2; - secondLine = R.string.balance_validator_second_line_disable_pin_2; - return; - } - - // rule 2.b - if (card.isOnlineVerified()) { - secondLine += R.string.balance_validator_first_line_verify_identity; - } else { - score = 80; - secondLine += R.string.balance_validator_second_line_identity_not_verified; - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/Base58.java b/app/src/main/java/com/tangem/wallet/Base58.java deleted file mode 100644 index 0948e420fc..0000000000 --- a/app/src/main/java/com/tangem/wallet/Base58.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.tangem.wallet; - -import java.math.BigInteger; - -/** - * Created by Ilia on 15.02.2018. - */ - -public class Base58 { - private static final char[] BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); - - private static final int BASE58_CHUNK_DIGITS = 10;//how many base 58 digits fits in long - private static final BigInteger BASE58_CHUNK_MOD = BigInteger.valueOf(0x5fa8624c7fba400L); //58^BASE58_CHUNK_DIGITS - private static final byte[] BASE58_VALUES = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, - -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, - -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; - - public static byte[] decodeBase58(String input) { - if (input == null) { - return null; - } - input = input.trim(); - if (input.length() == 0) { - return new byte[0]; - } - BigInteger resultNum = BigInteger.ZERO; - int nLeadingZeros = 0; - while (nLeadingZeros < input.length() && input.charAt(nLeadingZeros) == BASE58[0]) { - nLeadingZeros++; - } - long acc = 0; - int nDigits = 0; - int p = nLeadingZeros; - while (p < input.length()) { - int v = BASE58_VALUES[input.charAt(p) & 0xff]; - if (v >= 0) { - acc *= 58; - acc += v; - nDigits++; - if (nDigits == BASE58_CHUNK_DIGITS) { - resultNum = resultNum.multiply(BASE58_CHUNK_MOD).add(BigInteger.valueOf(acc)); - acc = 0; - nDigits = 0; - } - p++; - } else { - break; - } - } - if (nDigits > 0) { - long mul = 58; - while (--nDigits > 0) { - mul *= 58; - } - resultNum = resultNum.multiply(BigInteger.valueOf(mul)).add(BigInteger.valueOf(acc)); - } - final int BASE58_SPACE = -2; - while (p < input.length() && BASE58_VALUES[input.charAt(p) & 0xff] == BASE58_SPACE) { - p++; - } - if (p < input.length()) { - return null; - } - byte[] plainNumber = resultNum.toByteArray(); - int plainNumbersOffs = plainNumber[0] == 0 ? 1 : 0; - byte[] result = new byte[nLeadingZeros + plainNumber.length - plainNumbersOffs]; - System.arraycopy(plainNumber, plainNumbersOffs, result, nLeadingZeros, plainNumber.length - plainNumbersOffs); - return result; - } - - public static String encodeBase58(byte[] input) { - if (input == null) { - return null; - } - StringBuilder str = new StringBuilder((input.length * 350) / 256 + 1); - BigInteger bn = new BigInteger(1, input); - long rem; - while (true) { - BigInteger[] divideAndRemainder = bn.divideAndRemainder(BASE58_CHUNK_MOD); - bn = divideAndRemainder[0]; - rem = divideAndRemainder[1].longValue(); - if (bn.compareTo(BigInteger.ZERO) == 0) { - break; - } - for (int i = 0; i < BASE58_CHUNK_DIGITS; i++) { - str.append(BASE58[(int) (rem % 58)]); - rem /= 58; - } - } - while (rem != 0) { - str.append(BASE58[(int) (rem % 58)]); - rem /= 58; - } - str.reverse(); - int nLeadingZeros = 0; - while (nLeadingZeros < input.length && input[nLeadingZeros] == 0) { - str.insert(0, BASE58[0]); - nLeadingZeros++; - } - return str.toString(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/CoinData.java b/app/src/main/java/com/tangem/wallet/CoinData.java deleted file mode 100644 index 67dba01d34..0000000000 --- a/app/src/main/java/com/tangem/wallet/CoinData.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.tangem.wallet; - -import android.os.Bundle; -import android.util.Log; - -import com.tangem.data.Blockchain; - -public abstract class CoinData { - - public CoinData() { - } - - private String wallet; - - public void setWallet(String wallet) { - this.wallet = wallet; - } - - public String getWallet() { - return wallet; - } - - public String getShortWalletString() { - if (wallet.length() < 22) { - return wallet; - } else { - return wallet.substring(0, 10) + "......" + wallet.substring(wallet.length() - 10, wallet.length()); - } - } - - public boolean isBalanceReceived() { - return balanceReceived; - } - - private boolean balanceReceived = false; - - public void setBalanceReceived(boolean value) { - balanceReceived = value; - } - - public void loadFromBundle(Bundle B) { - wallet = B.getString("Wallet"); - - if (B.containsKey("balanceReceived")) setBalanceReceived(B.getBoolean("balanceReceived")); - - validationNodeDescription = B.getString("validationNodeDescription"); - -// if (B.containsKey("FailedBalance")) -// failedBalanceRequestCounter = new AtomicInteger(B.getInt("FailedBalance")); - - if (B.containsKey("isBalanceEqual")) setIsBalanceEqual(B.getBoolean("isBalanceEqual")); - - if (B.containsKey("rate")) - rate = B.getFloat("rate"); - if (B.containsKey("rateAlter")) - rateAlter = B.getFloat("rateAlter"); - - if (B.containsKey("sentTransactionsCount")) { - sentTransactionsCount = B.getInt("sentTransactionsCount"); - } - - if (B.containsKey("ResolvedPayIdAddress")) resolvedPayIdAddress = B.getString("ResolvedPayIdAddress"); - else resolvedPayIdAddress = null; - } - - public void saveToBundle(Bundle B) { - try { - B.putString("Wallet", wallet); - - if (balanceEqual != null) B.putBoolean("isBalanceEqual", balanceEqual); - -// if (failedBalanceRequestCounter != null) -// B.putInt("FailedBalance", failedBalanceRequestCounter.get()); - - B.putFloat("rate", rate); - B.putFloat("rateAlter", rateAlter); - - B.putBoolean("balanceReceived", balanceReceived); - B.putString("validationNodeDescription", validationNodeDescription); - - B.putInt("sentTransactionsCount", sentTransactionsCount); - - if (resolvedPayIdAddress != null) B.putString("ResolvedPayIdAddress", resolvedPayIdAddress); - } catch (Exception e) { - Log.e("Can't save to bundle ", e.getMessage()); - } - - } - - public Bundle asBundle() { - Bundle bundle = new Bundle(); - saveToBundle(bundle); - return bundle; - } - - public static CoinData fromBundle(Blockchain blockchain, Bundle bundle) { - CoinEngine engine = CoinEngineFactory.INSTANCE.create(blockchain); - if (engine == null) return null; - CoinData result = engine.createCoinData(); - result.loadFromBundle(bundle); - return result; - } - - //TODO - move all to special engines - private float rate = 0; - private float rateAlter = 0; - - public float getRate() { - return rate; - } - - public float getRateAlter() { - return rateAlter; - } - - public void setRate(float rate) { - this.rate = rate; - } - - public void setRateAlter(float rate) { - this.rateAlter = rate; - } - -// public Double amountFromInternalUnits(Long internalAmount) { -// // TODO java.lang.NullPointerException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference -// return ((double) internalAmount) / -// getBlockchain().getMultiplier(); -// } -// -// public Double amountFromInternalUnits(Integer internalAmount) { -// return ((double) internalAmount) / getBlockchain().getMultiplier(); -// } -// -// // TODO разобраться с балансами, привести к единому интерфейсу -// public Long internalUnitsFromString(String caption) { -// try { -// return FormatUtil.ConvertStringToLong(caption); -// } catch (Exception e) { -// return null; -// } -// } -// -// public String getAmountDescription(Double amount) { -// String output = FormatUtil.DoubleToString(amount); -// return output + " " + getBlockchain().getCurrency(); -// } - - public boolean getAmountEquivalentDescriptionAvailable() { - return rate > 0; - } - - - public void clearInfo() { - setIsBalanceEqual(false); - setBalanceReceived(false); - setValidationNodeDescription(""); - minFee = null; - maxFee = null; - normalFee = null; - rate = 0f; - rateAlter = 0f; - sentTransactionsCount = 0; - resolvedPayIdAddress = null; - } - -// private AtomicInteger failedBalanceRequestCounter; -// -// public int incFailedBalanceRequestCounter() { -// if (failedBalanceRequestCounter == null) -// failedBalanceRequestCounter = new AtomicInteger(0); -// return failedBalanceRequestCounter.incrementAndGet(); -// } -// -// public void resetFailedBalanceRequestCounter() { -// failedBalanceRequestCounter = new AtomicInteger(0); -// } -// -// public int getFailedBalanceRequestCounter() { -// if (failedBalanceRequestCounter == null) -// return 0; -// return failedBalanceRequestCounter.get(); -// } - - private Boolean balanceEqual; - - public Boolean isBalanceEqual() { - return balanceEqual; - } - - public void setIsBalanceEqual(boolean isEqual) { - balanceEqual = isEqual; - } - - private String validationNodeDescription = ""; - - public String getValidationNodeDescription() { - return validationNodeDescription; - } - - public void setValidationNodeDescription(String validationNodeDescription) { - this.validationNodeDescription = validationNodeDescription; - } - - public CoinEngine.Amount minFee = null; - public CoinEngine.Amount normalFee = null; - public CoinEngine.Amount maxFee = null; - - private int sentTransactionsCount = 0; - - public int getSentTransactionsCount() { - return sentTransactionsCount; - } - - public void setSentTransactionsCount(int sentTransactionsCount) { - this.sentTransactionsCount = sentTransactionsCount; - } - - public void incSentTransactionsCount() { - sentTransactionsCount++; - } - - private String resolvedPayIdAddress = null; - - public String getResolvedPayIdAddress() { - return resolvedPayIdAddress; - } - - public void setResolvedPayIdAddress(String resolvedPayIdAddress) { - this.resolvedPayIdAddress = resolvedPayIdAddress; - } - -} diff --git a/app/src/main/java/com/tangem/wallet/CoinEngine.java b/app/src/main/java/com/tangem/wallet/CoinEngine.java deleted file mode 100644 index 9e30d2df6f..0000000000 --- a/app/src/main/java/com/tangem/wallet/CoinEngine.java +++ /dev/null @@ -1,410 +0,0 @@ -package com.tangem.wallet; - -import android.net.Uri; -import android.text.InputFilter; - -import com.tangem.data.Blockchain; -import com.tangem.tangem_card.reader.CardProtocol; -import com.tangem.tangem_card.tasks.SignTask; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.RoundingMode; -import java.net.URL; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Locale; - -import co.nstant.in.cbor.CborException; - -/** - * Created by Ilia on 15.02.2018. - */ - -public abstract class CoinEngine { - - public static class InternalAmount extends BigDecimal { - private String currency; - - public InternalAmount() { - super(0); - currency = ""; - } - - public InternalAmount(String amountString, String currency) { - super(amountString.replace(',', '.')); - this.currency = currency; - } - - public InternalAmount(long amount, String currency) { - super(amount); - this.currency = currency; - } - - public InternalAmount(BigDecimal amount, String currency) { - super(amount.unscaledValue(), amount.scale()); - this.currency = currency; - } - - public InternalAmount(BigInteger amount, String currency) { - super(new BigDecimal(amount).unscaledValue(), new BigDecimal(amount).scale()); - this.currency = currency; - } - - public boolean notZero() { - return compareTo(BigDecimal.ZERO) > 0; - } - - public boolean isZero() { - return compareTo(BigDecimal.ZERO) == 0; - } - - public String getCurrency() { - return currency; - } - - public String toValueString(int decimals) { - DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US); - symbols.setDecimalSeparator('.'); - DecimalFormat df = new DecimalFormat(); - df.setDecimalFormatSymbols(symbols); - df.setMaximumFractionDigits(decimals); - - df.setMinimumFractionDigits(0); - - df.setGroupingUsed(false); - - BigDecimal bd = new BigDecimal(unscaledValue(), scale()); - bd.setScale(decimals, ROUND_DOWN); - return df.format(bd); - } - - public String toValueString() { - return toValueString(scale()); - } - - @Override - public String toString() { - return super.toString(); - } - - } - - public static class Amount extends BigDecimal { - private String currency; - - public Amount() { - super(0); - currency = ""; - } - - public Amount(String amountString, String currency) { - super(amountString.replace(',', '.')); - this.currency = currency; - } - - public Amount(Long amount, String currency) { - super(amount); - this.currency = currency; - } - - public Amount(BigDecimal amount, String currency) { - super(amount.unscaledValue(), amount.scale()); - this.currency = currency; - } - - public String getCurrency() { - return currency; - } - - @Override - public String toString() { - return super.toString() + " " + currency; - } - - public boolean notZero() { - return compareTo(BigDecimal.ZERO) > 0; - } - - public String toDescriptionString(int decimals) { - return toValueString(decimals) + " " + currency; - } - - public String toValueString(int decimals) { - DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US); - symbols.setDecimalSeparator('.'); - DecimalFormat df = new DecimalFormat(); - df.setDecimalFormatSymbols(symbols); - df.setMaximumFractionDigits(decimals); - - df.setMinimumFractionDigits(0); - - df.setGroupingUsed(false); - - BigDecimal bd = new BigDecimal(unscaledValue(), scale()); - bd.setScale(decimals, ROUND_DOWN); - return df.format(bd); - } - - public String toValueString() { - return toValueString(scale()); - } - - public String toEquivalentString(double rateValue) { - if (rateValue > 0) { - BigDecimal biRate = new BigDecimal(rateValue); - BigDecimal exchangeCurs = biRate.multiply(this); - exchangeCurs = exchangeCurs.setScale(2, RoundingMode.DOWN); - return "≈ USD  " + exchangeCurs.toString(); - } else { - return ""; - } - } - - public boolean isZero() { - return compareTo(BigDecimal.ZERO) == 0; - } - - @Override - public Amount setScale(int newScale) { - return new Amount(super.setScale(newScale), currency); - } - } - - protected TangemContext ctx; - - public CoinEngine() { - - } - - public CoinEngine(TangemContext ctx) { - this.ctx = ctx; - } - - public abstract boolean awaitingConfirmation(); - - public abstract boolean hasBalanceInfo(); - - public abstract boolean isBalanceNotZero(); - - // TODO - return string message - public abstract boolean isExtractPossible(); - - public abstract Uri getWalletExplorerUri(); - - public abstract Uri getShareWalletUri(); - - public Uri getShareWalletUriEx(){ - String scheme = ctx.getBlockchain().getUriScheme(); - if (scheme != null) - return Uri.parse(scheme + ":" + getShareWalletUri()); - else - return getShareWalletUri(); - } - - public abstract boolean checkNewTransactionAmount(Amount amount); - - public abstract boolean checkNewTransactionAmountAndFee(Amount amount, Amount fee, Boolean isFeeIncluded); - - public abstract boolean validateBalance(BalanceValidator balanceValidator); - - public abstract Amount getBalance(); - - public abstract String getBalanceHTML(); - - public abstract String getBalanceCurrency(); - - public abstract InputFilter[] getAmountInputFilters(); - - public abstract String evaluateFeeEquivalent(String fee); - - public abstract String getFeeCurrency(); - - public abstract boolean isNeedCheckNode(); - - public abstract String getBalanceEquivalent(); - - public abstract boolean validateAddress(String address); - - public abstract String calculateAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException, CborException, IOException, Exception; - - public abstract Amount convertToAmount(InternalAmount internalAmount) throws Exception; - - public abstract Amount convertToAmount(String strAmount, String currency); - - public abstract InternalAmount convertToInternalAmount(Amount amount) throws Exception; - - public abstract InternalAmount convertToInternalAmount(byte[] bytes) throws Exception; - - public abstract byte[] convertToByteArray(InternalAmount internalAmount) throws Exception; - - public abstract CoinData createCoinData(); - - public abstract String getUnspentInputsDescription(); - - public String getOfflineBalanceHTML() { - return ""; - } - -// public String getOfflineBalanceHTML() { -// InternalAmount offlineInternalAmount = convertToInternalAmount(ctx.getCard().getOfflineBalance()); -// Amount offlineAmount = convertToAmount(offlineInternalAmount); -// return offlineAmount.toDescriptionString(getDecimals()); -// } - - public void defineWallet() throws CardProtocol.TangemException { - try { - String wallet = calculateAddress(ctx.getCard().getWalletPublicKey()); - ctx.getCoinData().setWallet(wallet); - } catch (Exception e) { - ctx.getCoinData().setWallet("ERROR"); - throw new CardProtocol.TangemException("Can't define wallet address"); - } - - } - - /** - * Create instance of {@link SignTask.TransactionToSign} used for transaction signing and sending - * - * Transaction processing sequence: - * 1. User enter transaction attributes - * 2. Application create instance of {@link SignTask.TransactionToSign} by call {@see constructTransaction} - * 3. Application set notification when transaction were prepared {@see setOnNeedSendTransaction} and init {@link SignTask} - * 4. User tap card and card sign transaction - * 5. Application receive {@link OnNeedSendTransaction} notification with prepared raw transaction - * 6. Application show user information that transaction ready for sending and init sending procedure by call {@see requestSendTransaction} - * 7. Application receive notification of sending result through {@link CoinEngine.BlockchainRequestsCallbacks} and show result to user - * - * @param amountValue - amount of desired transaction - * @param feeValue - fee amount of desired transaction - * @param IncFee - true if fee amount is included in amountValue (amountValue is total amount of transaction) - * @param targetAddress - target address of transaction - * @return instance of {@link SignTask.TransactionToSign} - * @throws Exception if something goes wrong - */ - public abstract SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception; - - /** - * Interface used to notify main application when new transaction is prepared to send - */ - public interface OnNeedSendTransaction { - void onTransactionPrepared(byte[] txForSend); - } - - protected OnNeedSendTransaction onNeedSendTransaction; - - - /** - * Set notification callback when new transaction is prepared to send - */ - public void setOnNeedSendTransaction(OnNeedSendTransaction onNeedSendTransaction) { - this.onNeedSendTransaction = onNeedSendTransaction; - } - - protected void notifyOnNeedSendTransaction(byte[] txForSend) throws Exception { - if (onNeedSendTransaction == null) - throw new Exception("Transaction was signed but no callback defined to send!"); - onNeedSendTransaction.onTransactionPrepared(txForSend); - } - - /** - * Interface used to notify/querying application during processing sequence of request to blockchain nodes/servers - */ - public interface BlockchainRequestsCallbacks { - /** - * Notification that the all requests in sequence completed - * Call after a last request completed - * If occurred error return in {@link TangemContext} {@see TangemContext.getError()} - * - * @param success -* - */ - void onComplete(Boolean success); - - /** - * Notification that a new part of data received and it's possible to update view - * May call when some request in the sequence completed but there are still a few requests left - */ - void onProgress(); - - /** - * Return flag that allow to add new or re-requests in the sequence - * Call between requests or when request fail and before re-request - * - * @return true if not need terminate (e.g. activity is online) - */ - boolean allowAdvance(); - } - - /** - * Start sequence of request to blockchain nodes needed to get balance and other information (for example unspent transaction) needed to - * show current state of wallet and prepare new withdrawal transaction - * Save result in {@link CoinData} - * If occurred error can be get at onComplete callback in {@link TangemContext}.getError() - * @param blockchainRequestsCallbacks - notifications - * @throws Exception if something goes wrong - */ - public abstract void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) throws Exception; - - /** - * Start sequence of request to blockchain nodes needed to get fee amount for a new transaction - * Save result in {@link CoinData} minFee, maxFee, normalFee - * @param blockchainRequestsCallbacks - notifications - * @throws Exception if something goes wrong - */ - public abstract void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception; - - /** - * Start sequence of request to blockchain nodes needed to send new transaction - * If occurred error can be get at onComplete callback in {@link TangemContext}.getError() - * @param blockchainRequestsCallbacks - notifications - * @throws Exception if something goes wrong - */ - public abstract void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) throws Exception; - - - /** - * @return true if blockchain need multiple lines to show balance (e.g. need show additional balance information, Token count for example) - */ - public boolean needMultipleLinesForBalance() { - return false; - } - - /** - * @return true to allow user select fee level - min, normal or priority - */ - public boolean allowSelectFeeLevel() { - return true; - } - - /** - * @return true to allow user select include or exclude fee - */ - public boolean allowSelectFeeInclusion() { - return true; - } - - public boolean isNftToken() { - return false; - } - - - public int pendingTransactionTimeoutInSeconds() { return 30; } - - protected boolean validatePayId(String payId) { - String[] addressParts = payId.split("\\$"); - - if (addressParts.length != 2) { - return false; - } - String addressURL = "https://" + addressParts[1] + "/" + addressParts[0]; - try { - new URL(addressURL).toURI(); - return true; - } catch (Exception e) { - return false; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/CoinEngineFactory.kt b/app/src/main/java/com/tangem/wallet/CoinEngineFactory.kt deleted file mode 100644 index 0cf887e769..0000000000 --- a/app/src/main/java/com/tangem/wallet/CoinEngineFactory.kt +++ /dev/null @@ -1,150 +0,0 @@ -package com.tangem.wallet - -import android.util.Log -import com.tangem.data.Blockchain -import com.tangem.wallet.bch.BtcCashEngine -import com.tangem.wallet.binance.BinanceAssetEngine -import com.tangem.wallet.binance.BinanceEngine -import com.tangem.wallet.btc.BtcEngine -import com.tangem.wallet.btcmultisig.BtcMultisigEngine -import com.tangem.wallet.cardano.CardanoData -import com.tangem.wallet.cardano.CardanoEngine -import com.tangem.wallet.ducatus.DucatusEngine -import com.tangem.wallet.eos.EosEngine -import com.tangem.wallet.eth.EthEngine -import com.tangem.wallet.ethID.EthIdEngine -import com.tangem.wallet.flowDemo.FlowDemoEngine -import com.tangem.wallet.ltc.LtcEngine -import com.tangem.wallet.matic.MaticTokenEngine -import com.tangem.wallet.nftToken.NftTokenEngine -import com.tangem.wallet.rsk.RskEngine -import com.tangem.wallet.rsk.RskTokenEngine -import com.tangem.wallet.token.TokenEngine -import com.tangem.wallet.tezos.TezosEngine -import com.tangem.wallet.tokenEmv.TokenEmvEngine -import com.tangem.wallet.xlm.XlmAssetEngine -import com.tangem.wallet.xlm.XlmEngine -import com.tangem.wallet.xlmTag.XlmTagEngine -import com.tangem.wallet.xrp.XrpEngine - -/** - * Factory for create specific engine - * - * @param - * Blockchain - * @param TangemContext - * - */ - -object CoinEngineFactory { - private val TAG = CoinEngineFactory::class.java.simpleName - - fun create(blockchain: Blockchain): CoinEngine? { - return when (blockchain) { - Blockchain.Bitcoin, Blockchain.BitcoinTestNet -> BtcEngine() - Blockchain.BitcoinCash -> BtcCashEngine() - Blockchain.Ethereum, Blockchain.EthereumTestNet -> EthEngine() - Blockchain.EthereumId -> EthIdEngine() - Blockchain.Token -> TokenEngine() - Blockchain.NftToken -> NftTokenEngine() - Blockchain.Litecoin -> LtcEngine() - Blockchain.Rootstock -> RskEngine() - Blockchain.RootstockToken -> RskTokenEngine() - Blockchain.Cardano -> CardanoEngine() - Blockchain.Ripple -> XrpEngine() - Blockchain.Binance, Blockchain.BinanceTestNet -> BinanceEngine() - Blockchain.BinanceAsset -> BinanceAssetEngine() - Blockchain.Matic, Blockchain.MaticTestNet -> MaticTokenEngine() - Blockchain.StellarTestNet, Blockchain.Stellar -> XlmEngine() - Blockchain.StellarAsset -> XlmAssetEngine() - Blockchain.StellarTag -> XlmTagEngine() - Blockchain.Eos -> EosEngine() - Blockchain.Ducatus -> DucatusEngine() - Blockchain.Tezos -> TezosEngine() - Blockchain.BitcoinDual -> BtcMultisigEngine() - Blockchain.FlowDemo -> FlowDemoEngine() - Blockchain.TokenEmv -> TokenEmvEngine() - else -> null - } - } - - fun create(context: TangemContext): CoinEngine? { - var result: CoinEngine? - try { - result = if (Blockchain.BitcoinCash == context.blockchain) - BtcCashEngine(context) - else if (Blockchain.Bitcoin == context.blockchain || Blockchain.BitcoinTestNet == context.blockchain) - BtcEngine(context) - else if (Blockchain.Ethereum == context.blockchain || Blockchain.EthereumTestNet == context.blockchain) - EthEngine(context) - else if (Blockchain.EthereumId == context.blockchain) - EthIdEngine(context) - else if (Blockchain.Token == context.blockchain) - TokenEngine(context) - else if (Blockchain.NftToken == context.blockchain) - NftTokenEngine(context) - else if (Blockchain.Litecoin == context.blockchain) - LtcEngine(context) - else if (Blockchain.Rootstock == context.blockchain) - RskEngine(context) - else if (Blockchain.RootstockToken == context.blockchain) - RskTokenEngine(context) - else if (Blockchain.Cardano == context.blockchain) - CardanoEngine(context) - else if (Blockchain.Ripple == context.blockchain) - XrpEngine(context) - else if (Blockchain.Binance == context.blockchain || Blockchain.BinanceTestNet == context.blockchain) - BinanceEngine(context) - else if (Blockchain.BinanceAsset == context.blockchain) - BinanceAssetEngine(context) - else if (Blockchain.Matic == context.blockchain || Blockchain.MaticTestNet == context.blockchain) - MaticTokenEngine(context) - else if (Blockchain.Stellar == context.blockchain || Blockchain.StellarTestNet == context.blockchain) - XlmEngine(context) - else if (Blockchain.StellarAsset == context.blockchain) - XlmAssetEngine(context) - else if (Blockchain.StellarTag == context.blockchain) - XlmTagEngine(context) - else if (Blockchain.Eos == context.blockchain) - EosEngine(context) - else if (Blockchain.Ducatus == context.blockchain) - DucatusEngine(context) - else if (Blockchain.Tezos == context.blockchain) - TezosEngine(context) - else if (Blockchain.BitcoinDual == context.blockchain) - BtcMultisigEngine(context) - else if (Blockchain.FlowDemo == context.blockchain) - FlowDemoEngine(context) - else if (Blockchain.TokenEmv == context.blockchain) - TokenEmvEngine(context) - else - return null - } catch (e: Exception) { - e.printStackTrace() - result = null - Log.e(TAG, "Can't create CoinEngine!") - } - return result - } - - fun createCardano(context: TangemContext): CoinEngine? { - var result: CoinEngine? - try { - result = CardanoEngine(context)//EthEngine(context)// - - } catch (e: Exception) { - e.printStackTrace() - result = null - Log.e(TAG, "Can't create Cardano CoinEngine!") - } - return result - } - - fun createCardanoData(): CoinData? { - return CardanoData()//EthData()// CardanoData() - } - - fun isCardano(blockchainID: String): Boolean { - return blockchainID==Blockchain.Cardano.id//Ethereum.id - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/Digest.java b/app/src/main/java/com/tangem/wallet/Digest.java deleted file mode 100644 index b3924d61c7..0000000000 --- a/app/src/main/java/com/tangem/wallet/Digest.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 18.12.2017. - */ - -public interface Digest{ - - /** - * Insert one more input data byte. - * - * @param in the input byte - */ - void update(byte in); - - /** - * Insert some more bytes. - * - * @param inbuf the data bytes - */ - void update(byte[] inbuf); - - /** - * Insert some more bytes. - * - * @param inbuf the data buffer - * @param off the data offset in {@code inbuf} - * @param len the data length (in bytes) - */ - void update(byte[] inbuf, int off, int len); - - /** - * Finalize the current hash computation and return the hash value - * in a newly-allocated array. The object is resetted. - * - * @return the hash output - */ - byte[] digest(); - - /** - * Input some bytes, then finalize the current hash computation - * and return the hash value in a newly-allocated array. The object - * is resetted. - * - * @param inbuf the input data - * @return the hash output - */ - byte[] digest(byte[] inbuf); - - /** - * Finalize the current hash computation and store the hash value - * in the provided output buffer. The {@code len} parameter - * contains the maximum number of bytes that should be written; - * no more bytes than the natural hash function output length will - * be produced. If {@code len} is smaller than the natural - * hash output length, the hash output is truncated to its first - * {@code len} bytes. The object is resetted. - * - * @param outbuf the output buffer - * @param off the output offset within {@code outbuf} - * @param len the requested hash output length (in bytes) - * @return the number of bytes actually written in {@code outbuf} - */ - int digest(byte[] outbuf, int off, int len); - - /** - * Get the natural hash function output length (in bytes). - * - * @return the digest output length (in bytes) - */ - int getDigestLength(); - - /** - * Reset the object: this makes it suitable for a new hash - * computation. The current computation, if any, is discarded. - */ - void reset(); - - /** - * Clone the current state. The returned object evolves independantly - * of this object. - * - * @return the clone - */ - Digest copy(); - - /** - *

Return the "block length" for the hash function. This - * value is naturally defined for iterated hash functions - * (Merkle-Damgard). It is used in HMAC (that's what the - * HMAC specification - * names the "{@code B}" parameter).

- * - *

If the function is "block-less" then this function may - * return {@code -n} where {@code n} is an integer such that the - * block length for HMAC ("{@code B}") will be inferred from the - * key length, by selecting the smallest multiple of {@code n} - * which is no smaller than the key length. For instance, for - * the Fugue-xxx hash functions, this function returns -4: the - * virtual block length B is the HMAC key length, rounded up to - * the next multiple of 4.

- * - * @return the internal block length (in bytes), or {@code -n} - */ - int getBlockLength(); - - /** - *

Get the display name for this function (e.g. {@code "SHA-1"} - * for SHA-1).

- * - * @see Object - */ - String toString(); -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/DigestEngine.java b/app/src/main/java/com/tangem/wallet/DigestEngine.java deleted file mode 100644 index 8dd130353d..0000000000 --- a/app/src/main/java/com/tangem/wallet/DigestEngine.java +++ /dev/null @@ -1,220 +0,0 @@ -package com.tangem.wallet; - - -import java.security.MessageDigest; - -/** - * Created by Ilia on 18.12.2017. - */ - -public abstract class DigestEngine extends MessageDigest implements Digest { - - /** - * Reset the hash algorithm state. - */ - protected abstract void engineReset(); - - /** - * Process one block of data. - * - * @param data the data block - */ - protected abstract void processBlock(byte[] data); - - /** - * Perform the final padding and store the result in the - * provided buffer. This method shall call {@link #flush} - * and then {@link #update} with the appropriate padding - * data in order to get the full input data. - * - * @param buf the output buffer - * @param off the output offset - */ - protected abstract void doPadding(byte[] buf, int off); - - /** - * This function is called at object creation time; the - * implementation should use it to perform initialization tasks. - * After this method is called, the implementation should be ready - * to process data or meaningfully honour calls such as - * {@link #engineGetDigestLength} - */ - protected abstract void doInit(); - - private int digestLen, blockLen, inputLen; - private byte[] inputBuf, outputBuf; - private long blockCount; - - /** - * Instantiate the engine. - */ - public DigestEngine(String alg) - { - super(alg); - doInit(); - digestLen = engineGetDigestLength(); - blockLen = getInternalBlockLength(); - inputBuf = new byte[blockLen]; - outputBuf = new byte[digestLen]; - inputLen = 0; - blockCount = 0; - } - - private void adjustDigestLen() - { - if (digestLen == 0) { - digestLen = engineGetDigestLength(); - outputBuf = new byte[digestLen]; - } - } - - public byte[] digest() - { - adjustDigestLen(); - byte[] result = new byte[digestLen]; - digest(result, 0, digestLen); - return result; - } - - public byte[] digest(byte[] input) - { - update(input, 0, input.length); - return digest(); - } - - public int digest(byte[] buf, int offset, int len) - { - adjustDigestLen(); - if (len >= digestLen) { - doPadding(buf, offset); - reset(); - return digestLen; - } else { - doPadding(outputBuf, 0); - System.arraycopy(outputBuf, 0, buf, offset, len); - reset(); - return len; - } - } - - public void reset() - { - engineReset(); - inputLen = 0; - blockCount = 0; - } - - public void update(byte input) - { - inputBuf[inputLen ++] = (byte)input; - if (inputLen == blockLen) { - processBlock(inputBuf); - blockCount ++; - inputLen = 0; - } - } - - public void update(byte[] input) - { - update(input, 0, input.length); - } - - public void update(byte[] input, int offset, int len) - { - while (len > 0) { - int copyLen = blockLen - inputLen; - if (copyLen > len) - copyLen = len; - System.arraycopy(input, offset, inputBuf, inputLen, - copyLen); - offset += copyLen; - inputLen += copyLen; - len -= copyLen; - if (inputLen == blockLen) { - processBlock(inputBuf); - blockCount ++; - inputLen = 0; - } - } - } - - /** - * Get the internal block length. This is the length (in - * bytes) of the array which will be passed as parameter to - * {@link #processBlock}. The default implementation of this - * method calls {@link #getBlockLength} and returns the same - * value. Overriding this method is useful when the advertised - * block length (which is used, for instance, by HMAC) is - * suboptimal with regards to internal buffering needs. - * - * @return the internal block length (in bytes) - */ - protected int getInternalBlockLength() - { - return getBlockLength(); - } - - /** - * Flush internal buffers, so that less than a block of data - * may at most be upheld. - * - * @return the number of bytes still unprocessed after the flush - */ - protected final int flush() - { - return inputLen; - } - - /** - * Get a reference to an internal buffer with the same size - * than a block. The contents of that buffer are defined only - * immediately after a call to {@link #flush()}: if - * {@link #flush()} return the value {@code n}, then the - * first {@code n} bytes of the array returned by this method - * are the {@code n} bytes of input data which are still - * unprocessed. The values of the remaining bytes are - * undefined and may be altered at will. - * - * @return a block-sized internal buffer - */ - protected final byte[] getBlockBuffer() - { - return inputBuf; - } - - /** - * Get the "block count": this is the number of times the - * {@link #processBlock} method has been invoked for the - * current hash operation. That counter is incremented - * after the call to {@link #processBlock}. - * - * @return the block count - */ - protected long getBlockCount() - { - return blockCount; - } - - /** - * This function copies the internal buffering state to some - * other instance of a class extending {@code DigestEngine}. - * It returns a reference to the copy. This method is intended - * to be called by the implementation of the {@link #copy} - * method. - * - * @param dest the copy - * @return the value {@code dest} - */ - protected Digest copyState(DigestEngine dest) - { - dest.inputLen = inputLen; - dest.blockCount = blockCount; - System.arraycopy(inputBuf, 0, dest.inputBuf, 0, - inputBuf.length); - adjustDigestLen(); - dest.adjustDigestLen(); - System.arraycopy(outputBuf, 0, dest.outputBuf, 0, - outputBuf.length); - return dest; - } -} diff --git a/app/src/main/java/com/tangem/wallet/ECDSASignatureETH.java b/app/src/main/java/com/tangem/wallet/ECDSASignatureETH.java deleted file mode 100644 index a4b9741a1d..0000000000 --- a/app/src/main/java/com/tangem/wallet/ECDSASignatureETH.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.tangem.wallet; - -import java.math.BigInteger; - -/** - * Created by Ilia on 07.01.2018. - */ - -public class ECDSASignatureETH { - /** - * The two components of the signature. - */ - public final BigInteger r, s; - public byte v; - - /** - * Constructs a signature with the given components. Does NOT automatically canonicalise the signature. - * - * @param r - - * @param s - - */ - public ECDSASignatureETH(BigInteger r, BigInteger s) { - this.r = r; - this.s = s; - } - - /** - *t - * @param r - * @param s - * @return - - */ - private static ECDSASignatureETH fromComponents(byte[] r, byte[] s) { - return new ECDSASignatureETH(new BigInteger(1, r), new BigInteger(1, s)); - } - - /** - * - * @param r - - * @param s - - * @param v - - * @return - - */ - public static ECDSASignatureETH fromComponents(byte[] r, byte[] s, byte v) { - ECDSASignatureETH signature = fromComponents(r, s); - signature.v = v; - return signature; - } - - -} - diff --git a/app/src/main/java/com/tangem/wallet/EthTransaction.java b/app/src/main/java/com/tangem/wallet/EthTransaction.java deleted file mode 100644 index 48e86ecf6a..0000000000 --- a/app/src/main/java/com/tangem/wallet/EthTransaction.java +++ /dev/null @@ -1,225 +0,0 @@ -package com.tangem.wallet; - -import android.util.Log; - -import com.tangem.util.ByteUtil; -import com.tangem.util.CryptoUtil; - -import org.bitcoinj.core.ECKey; -import org.bitcoinj.core.Sha256Hash; -import org.spongycastle.util.BigIntegers; -import org.spongycastle.util.encoders.Hex; - -import java.math.BigInteger; -import java.util.Arrays; - -import static com.tangem.util.ByteUtil.EMPTY_BYTE_ARRAY; - -/** - * Created by Ilia on 07.01.2018. - */ - -public class EthTransaction { - byte[] nonce; - byte[] gasPrice; - byte[] gasLimit; - byte[] receiveAddress; - byte[] value; - byte[] data; - Integer chainId; - byte[] rlpRaw; - public ECDSASignatureETH signature; - byte[] rlpEncoded; - - private static final int CHAIN_ID_INC = 35; - private static final int LOWER_REAL_V = 27; - - public static EthTransaction create(String to, BigInteger amount, BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, Integer chainId) { - return new EthTransaction(BigIntegers.asUnsignedByteArray(nonce), - BigIntegers.asUnsignedByteArray(gasPrice), - BigIntegers.asUnsignedByteArray(gasLimit), - Hex.decode(to), - BigIntegers.asUnsignedByteArray(amount), - null, - chainId); - } - - public static EthTransaction create(String to, BigInteger amount, BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, Integer chainId, byte[] data) { - return new EthTransaction(BigIntegers.asUnsignedByteArray(nonce), - BigIntegers.asUnsignedByteArray(gasPrice), - BigIntegers.asUnsignedByteArray(gasLimit), - Hex.decode(to), - BigIntegers.asUnsignedByteArray(amount), - data, - chainId); - } - - public EthTransaction(byte[] nonce, byte[] gasPrice, byte[] gasLimit, byte[] receiveAddress, byte[] value, byte[] data, Integer chainId) { - this.nonce = nonce; - this.gasPrice = gasPrice; - this.gasLimit = gasLimit; - this.receiveAddress = receiveAddress; - if (ByteUtil.isSingleZero(value)) { - this.value = EMPTY_BYTE_ARRAY; - } else { - this.value = value; - } - this.data = data; - this.chainId = chainId; - - if (receiveAddress == null) { - this.receiveAddress = ByteUtil.EMPTY_BYTE_ARRAY; - } - } - - public enum ChainEnum { - Mainnet(1), - Morden(2), - Ropsten(3), - Rinkeby(4), - Rootstock_mainnet(30), - Rootstock_testnet(31), - Kovan(42), - Ethereum_Classic_mainnet(61), - Ethereum_Classic_testnet(62), - Geth_private_chains(1337), - Matic_Testnet(8995); - - private int value; - - ChainEnum(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - } - - public byte[] getRawHash() { - - byte[] plainMsg = this.getEncodedRaw(); - Keccak256 kec = new Keccak256(); - return kec.digest(plainMsg); - } - - public byte[] getHash() { - - byte[] plainMsg = this.getEncoded(); - Keccak256 kec = new Keccak256(); - return kec.digest(plainMsg); - } - - public static int BruteRecoveryID2(ECDSASignatureETH sig, byte[] messageHash, byte[] thisKey) { - Log.e("ETH_KZ", BTCUtils.toHex(thisKey)); - int recId = -1; - for (int i = 0; i < 4; i++) { - byte[] recK = CryptoUtil.recoverPubBytesFromSignature(i, sig, messageHash); - - if (recK == null) { - continue; - } - - Log.e("ETH_k " + String.valueOf(i), BTCUtils.toHex(recK)); - if (Arrays.equals(recK, thisKey)) { - recId = i; - recId += 27; - break; - } - } - return recId; - } - - public int BruteRecoveryID(ECKey.ECDSASignature sig, Sha256Hash messageHash, byte[] thisKey) { - Log.e("ETH_KZ", BTCUtils.toHex(thisKey)); - int recId = -1; - for (int i = 0; i < 4; i++) { - ECKey k = ECKey.recoverFromSignature(i, sig, messageHash, false); - - if (k == null) - continue; - byte[] recK = k.getPubKey(); - Log.e("ETH_k " + String.valueOf(i), BTCUtils.toHex(recK)); - if (k != null && Arrays.equals(recK, thisKey)) { - recId = i; - break; - } - } - return recId; - } - - // signed TX - public byte[] getEncoded() { - - // parse null as 0 for nonce - byte[] nonce = null; - if (this.nonce == null || this.nonce.length == 1 && this.nonce[0] == 0) { - nonce = RLP.encodeElement(null); - } else { - nonce = RLP.encodeElement(this.nonce); - } - byte[] gasPrice = RLP.encodeElement(this.gasPrice); - byte[] gasLimit = RLP.encodeElement(this.gasLimit); - byte[] receiveAddress = RLP.encodeElement(this.receiveAddress); - byte[] value = RLP.encodeElement(this.value); - byte[] data = RLP.encodeElement(this.data); - - byte[] v, r, s; - - if (signature != null) { - int encodeV; - if (chainId == null) { - encodeV = signature.v; - } else { - encodeV = signature.v - LOWER_REAL_V; - encodeV += chainId * 2 + CHAIN_ID_INC; - } - v = RLP.encodeInt(encodeV); - r = RLP.encodeElement(BigIntegers.asUnsignedByteArray(signature.r)); - s = RLP.encodeElement(BigIntegers.asUnsignedByteArray(signature.s)); - } else { - // Since EIP-155 use chainId for v - v = chainId == null ? RLP.encodeElement(EMPTY_BYTE_ARRAY) : RLP.encodeInt(chainId); - r = RLP.encodeElement(EMPTY_BYTE_ARRAY); - s = RLP.encodeElement(EMPTY_BYTE_ARRAY); - } - - this.rlpEncoded = RLP.encodeList(nonce, gasPrice, gasLimit, - receiveAddress, value, data, v, r, s); - - //this.hash = this.getHash(); - - return rlpEncoded; - } - - // unsigned TX - public byte[] getEncodedRaw() { - // parse null as 0 for nonce - byte[] nonce = null; - if (this.nonce == null || this.nonce.length == 1 && this.nonce[0] == 0) { - nonce = RLP.encodeElement(null); - } else { - nonce = RLP.encodeElement(this.nonce); - } - byte[] gasPrice = RLP.encodeElement(this.gasPrice); - byte[] gasLimit = RLP.encodeElement(this.gasLimit); - byte[] receiveAddress = RLP.encodeElement(this.receiveAddress); - byte[] value = RLP.encodeElement(this.value); - byte[] data = RLP.encodeElement(this.data); - - // Since EIP-155 use chainId for v - if (chainId == null) { - rlpRaw = RLP.encodeList(nonce, gasPrice, gasLimit, receiveAddress, - value, data); - } else { - byte[] v, r, s; - v = RLP.encodeInt(chainId); - r = RLP.encodeElement(EMPTY_BYTE_ARRAY); - s = RLP.encodeElement(EMPTY_BYTE_ARRAY); - rlpRaw = RLP.encodeList(nonce, gasPrice, gasLimit, receiveAddress, - value, data, v, r, s); - } - return rlpRaw; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/Keccak256.java b/app/src/main/java/com/tangem/wallet/Keccak256.java deleted file mode 100644 index bd8c2b5ded..0000000000 --- a/app/src/main/java/com/tangem/wallet/Keccak256.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 18.12.2017. - */ - -public class Keccak256 extends KeccakCore { - - /** - * Create the engine. - */ - public Keccak256() - { - super("eth-keccak-256"); - } - - public Digest copy() - { - return copyState(new Keccak256()); - } - - public int engineGetDigestLength() - { - return 32; - } - - @Override - protected byte[] engineDigest() { - return null; - } - - @Override - protected void engineUpdate(byte arg0) { - } - - @Override - protected void engineUpdate(byte[] arg0, int arg1, int arg2) { - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/KeccakCore.java b/app/src/main/java/com/tangem/wallet/KeccakCore.java deleted file mode 100644 index 015b33bb49..0000000000 --- a/app/src/main/java/com/tangem/wallet/KeccakCore.java +++ /dev/null @@ -1,546 +0,0 @@ -package com.tangem.wallet; - - -/** - * Created by Ilia on 18.12.2017. - */ -abstract class KeccakCore extends DigestEngine { - KeccakCore(String alg) - { - super(alg); - } - - private long[] A; - private byte[] tmpOut; - - private static final long[] RC = { - 0x0000000000000001L, 0x0000000000008082L, - 0x800000000000808AL, 0x8000000080008000L, - 0x000000000000808BL, 0x0000000080000001L, - 0x8000000080008081L, 0x8000000000008009L, - 0x000000000000008AL, 0x0000000000000088L, - 0x0000000080008009L, 0x000000008000000AL, - 0x000000008000808BL, 0x800000000000008BL, - 0x8000000000008089L, 0x8000000000008003L, - 0x8000000000008002L, 0x8000000000000080L, - 0x000000000000800AL, 0x800000008000000AL, - 0x8000000080008081L, 0x8000000000008080L, - 0x0000000080000001L, 0x8000000080008008L - }; - - /** - * Encode the 64-bit word {@code val} into the array - * {@code buf} at offset {@code off}, in little-endian - * convention (least significant byte first). - * - * @param val the value to encode - * @param buf the destination buffer - * @param off the destination offset - */ - private static void encodeLELong(long val, byte[] buf, int off) - { - buf[off + 0] = (byte)val; - buf[off + 1] = (byte)(val >>> 8); - buf[off + 2] = (byte)(val >>> 16); - buf[off + 3] = (byte)(val >>> 24); - buf[off + 4] = (byte)(val >>> 32); - buf[off + 5] = (byte)(val >>> 40); - buf[off + 6] = (byte)(val >>> 48); - buf[off + 7] = (byte)(val >>> 56); - } - - /** - * Decode a 64-bit little-endian word from the array {@code buf} - * at offset {@code off}. - * - * @param buf the source buffer - * @param off the source offset - * @return the decoded value - */ - private static long decodeLELong(byte[] buf, int off) - { - return (buf[off + 0] & 0xFFL) - | ((buf[off + 1] & 0xFFL) << 8) - | ((buf[off + 2] & 0xFFL) << 16) - | ((buf[off + 3] & 0xFFL) << 24) - | ((buf[off + 4] & 0xFFL) << 32) - | ((buf[off + 5] & 0xFFL) << 40) - | ((buf[off + 6] & 0xFFL) << 48) - | ((buf[off + 7] & 0xFFL) << 56); - } - - protected void engineReset() - { - doReset(); - } - - protected void processBlock(byte[] data) - { - /* Input block */ - for (int i = 0; i < data.length; i += 8) - A[i >>> 3] ^= decodeLELong(data, i); - - long t0, t1, t2, t3, t4; - long tt0, tt1, tt2, tt3, tt4; - long t, kt; - long c0, c1, c2, c3, c4, bnn; - - /* - * Unrolling four rounds kills performance big time - * on Intel x86 Core2, in both 32-bit and 64-bit modes - * (less than 1 MB/s instead of 55 MB/s on x86-64). - * Unrolling two rounds appears to be fine. - */ - for (int j = 0; j < 24; j += 2) { - - tt0 = A[ 1] ^ A[ 6]; - tt1 = A[11] ^ A[16]; - tt0 ^= A[21] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[ 4] ^ A[ 9]; - tt3 = A[14] ^ A[19]; - tt0 ^= A[24]; - tt2 ^= tt3; - t0 = tt0 ^ tt2; - - tt0 = A[ 2] ^ A[ 7]; - tt1 = A[12] ^ A[17]; - tt0 ^= A[22] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[ 0] ^ A[ 5]; - tt3 = A[10] ^ A[15]; - tt0 ^= A[20]; - tt2 ^= tt3; - t1 = tt0 ^ tt2; - - tt0 = A[ 3] ^ A[ 8]; - tt1 = A[13] ^ A[18]; - tt0 ^= A[23] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[ 1] ^ A[ 6]; - tt3 = A[11] ^ A[16]; - tt0 ^= A[21]; - tt2 ^= tt3; - t2 = tt0 ^ tt2; - - tt0 = A[ 4] ^ A[ 9]; - tt1 = A[14] ^ A[19]; - tt0 ^= A[24] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[ 2] ^ A[ 7]; - tt3 = A[12] ^ A[17]; - tt0 ^= A[22]; - tt2 ^= tt3; - t3 = tt0 ^ tt2; - - tt0 = A[ 0] ^ A[ 5]; - tt1 = A[10] ^ A[15]; - tt0 ^= A[20] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[ 3] ^ A[ 8]; - tt3 = A[13] ^ A[18]; - tt0 ^= A[23]; - tt2 ^= tt3; - t4 = tt0 ^ tt2; - - A[ 0] = A[ 0] ^ t0; - A[ 5] = A[ 5] ^ t0; - A[10] = A[10] ^ t0; - A[15] = A[15] ^ t0; - A[20] = A[20] ^ t0; - A[ 1] = A[ 1] ^ t1; - A[ 6] = A[ 6] ^ t1; - A[11] = A[11] ^ t1; - A[16] = A[16] ^ t1; - A[21] = A[21] ^ t1; - A[ 2] = A[ 2] ^ t2; - A[ 7] = A[ 7] ^ t2; - A[12] = A[12] ^ t2; - A[17] = A[17] ^ t2; - A[22] = A[22] ^ t2; - A[ 3] = A[ 3] ^ t3; - A[ 8] = A[ 8] ^ t3; - A[13] = A[13] ^ t3; - A[18] = A[18] ^ t3; - A[23] = A[23] ^ t3; - A[ 4] = A[ 4] ^ t4; - A[ 9] = A[ 9] ^ t4; - A[14] = A[14] ^ t4; - A[19] = A[19] ^ t4; - A[24] = A[24] ^ t4; - A[ 5] = (A[ 5] << 36) | (A[ 5] >>> (64 - 36)); - A[10] = (A[10] << 3) | (A[10] >>> (64 - 3)); - A[15] = (A[15] << 41) | (A[15] >>> (64 - 41)); - A[20] = (A[20] << 18) | (A[20] >>> (64 - 18)); - A[ 1] = (A[ 1] << 1) | (A[ 1] >>> (64 - 1)); - A[ 6] = (A[ 6] << 44) | (A[ 6] >>> (64 - 44)); - A[11] = (A[11] << 10) | (A[11] >>> (64 - 10)); - A[16] = (A[16] << 45) | (A[16] >>> (64 - 45)); - A[21] = (A[21] << 2) | (A[21] >>> (64 - 2)); - A[ 2] = (A[ 2] << 62) | (A[ 2] >>> (64 - 62)); - A[ 7] = (A[ 7] << 6) | (A[ 7] >>> (64 - 6)); - A[12] = (A[12] << 43) | (A[12] >>> (64 - 43)); - A[17] = (A[17] << 15) | (A[17] >>> (64 - 15)); - A[22] = (A[22] << 61) | (A[22] >>> (64 - 61)); - A[ 3] = (A[ 3] << 28) | (A[ 3] >>> (64 - 28)); - A[ 8] = (A[ 8] << 55) | (A[ 8] >>> (64 - 55)); - A[13] = (A[13] << 25) | (A[13] >>> (64 - 25)); - A[18] = (A[18] << 21) | (A[18] >>> (64 - 21)); - A[23] = (A[23] << 56) | (A[23] >>> (64 - 56)); - A[ 4] = (A[ 4] << 27) | (A[ 4] >>> (64 - 27)); - A[ 9] = (A[ 9] << 20) | (A[ 9] >>> (64 - 20)); - A[14] = (A[14] << 39) | (A[14] >>> (64 - 39)); - A[19] = (A[19] << 8) | (A[19] >>> (64 - 8)); - A[24] = (A[24] << 14) | (A[24] >>> (64 - 14)); - bnn = ~A[12]; - kt = A[ 6] | A[12]; - c0 = A[ 0] ^ kt; - kt = bnn | A[18]; - c1 = A[ 6] ^ kt; - kt = A[18] & A[24]; - c2 = A[12] ^ kt; - kt = A[24] | A[ 0]; - c3 = A[18] ^ kt; - kt = A[ 0] & A[ 6]; - c4 = A[24] ^ kt; - A[ 0] = c0; - A[ 6] = c1; - A[12] = c2; - A[18] = c3; - A[24] = c4; - bnn = ~A[22]; - kt = A[ 9] | A[10]; - c0 = A[ 3] ^ kt; - kt = A[10] & A[16]; - c1 = A[ 9] ^ kt; - kt = A[16] | bnn; - c2 = A[10] ^ kt; - kt = A[22] | A[ 3]; - c3 = A[16] ^ kt; - kt = A[ 3] & A[ 9]; - c4 = A[22] ^ kt; - A[ 3] = c0; - A[ 9] = c1; - A[10] = c2; - A[16] = c3; - A[22] = c4; - bnn = ~A[19]; - kt = A[ 7] | A[13]; - c0 = A[ 1] ^ kt; - kt = A[13] & A[19]; - c1 = A[ 7] ^ kt; - kt = bnn & A[20]; - c2 = A[13] ^ kt; - kt = A[20] | A[ 1]; - c3 = bnn ^ kt; - kt = A[ 1] & A[ 7]; - c4 = A[20] ^ kt; - A[ 1] = c0; - A[ 7] = c1; - A[13] = c2; - A[19] = c3; - A[20] = c4; - bnn = ~A[17]; - kt = A[ 5] & A[11]; - c0 = A[ 4] ^ kt; - kt = A[11] | A[17]; - c1 = A[ 5] ^ kt; - kt = bnn | A[23]; - c2 = A[11] ^ kt; - kt = A[23] & A[ 4]; - c3 = bnn ^ kt; - kt = A[ 4] | A[ 5]; - c4 = A[23] ^ kt; - A[ 4] = c0; - A[ 5] = c1; - A[11] = c2; - A[17] = c3; - A[23] = c4; - bnn = ~A[ 8]; - kt = bnn & A[14]; - c0 = A[ 2] ^ kt; - kt = A[14] | A[15]; - c1 = bnn ^ kt; - kt = A[15] & A[21]; - c2 = A[14] ^ kt; - kt = A[21] | A[ 2]; - c3 = A[15] ^ kt; - kt = A[ 2] & A[ 8]; - c4 = A[21] ^ kt; - A[ 2] = c0; - A[ 8] = c1; - A[14] = c2; - A[15] = c3; - A[21] = c4; - A[ 0] = A[ 0] ^ RC[j + 0]; - - tt0 = A[ 6] ^ A[ 9]; - tt1 = A[ 7] ^ A[ 5]; - tt0 ^= A[ 8] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[24] ^ A[22]; - tt3 = A[20] ^ A[23]; - tt0 ^= A[21]; - tt2 ^= tt3; - t0 = tt0 ^ tt2; - - tt0 = A[12] ^ A[10]; - tt1 = A[13] ^ A[11]; - tt0 ^= A[14] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[ 0] ^ A[ 3]; - tt3 = A[ 1] ^ A[ 4]; - tt0 ^= A[ 2]; - tt2 ^= tt3; - t1 = tt0 ^ tt2; - - tt0 = A[18] ^ A[16]; - tt1 = A[19] ^ A[17]; - tt0 ^= A[15] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[ 6] ^ A[ 9]; - tt3 = A[ 7] ^ A[ 5]; - tt0 ^= A[ 8]; - tt2 ^= tt3; - t2 = tt0 ^ tt2; - - tt0 = A[24] ^ A[22]; - tt1 = A[20] ^ A[23]; - tt0 ^= A[21] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[12] ^ A[10]; - tt3 = A[13] ^ A[11]; - tt0 ^= A[14]; - tt2 ^= tt3; - t3 = tt0 ^ tt2; - - tt0 = A[ 0] ^ A[ 3]; - tt1 = A[ 1] ^ A[ 4]; - tt0 ^= A[ 2] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[18] ^ A[16]; - tt3 = A[19] ^ A[17]; - tt0 ^= A[15]; - tt2 ^= tt3; - t4 = tt0 ^ tt2; - - A[ 0] = A[ 0] ^ t0; - A[ 3] = A[ 3] ^ t0; - A[ 1] = A[ 1] ^ t0; - A[ 4] = A[ 4] ^ t0; - A[ 2] = A[ 2] ^ t0; - A[ 6] = A[ 6] ^ t1; - A[ 9] = A[ 9] ^ t1; - A[ 7] = A[ 7] ^ t1; - A[ 5] = A[ 5] ^ t1; - A[ 8] = A[ 8] ^ t1; - A[12] = A[12] ^ t2; - A[10] = A[10] ^ t2; - A[13] = A[13] ^ t2; - A[11] = A[11] ^ t2; - A[14] = A[14] ^ t2; - A[18] = A[18] ^ t3; - A[16] = A[16] ^ t3; - A[19] = A[19] ^ t3; - A[17] = A[17] ^ t3; - A[15] = A[15] ^ t3; - A[24] = A[24] ^ t4; - A[22] = A[22] ^ t4; - A[20] = A[20] ^ t4; - A[23] = A[23] ^ t4; - A[21] = A[21] ^ t4; - A[ 3] = (A[ 3] << 36) | (A[ 3] >>> (64 - 36)); - A[ 1] = (A[ 1] << 3) | (A[ 1] >>> (64 - 3)); - A[ 4] = (A[ 4] << 41) | (A[ 4] >>> (64 - 41)); - A[ 2] = (A[ 2] << 18) | (A[ 2] >>> (64 - 18)); - A[ 6] = (A[ 6] << 1) | (A[ 6] >>> (64 - 1)); - A[ 9] = (A[ 9] << 44) | (A[ 9] >>> (64 - 44)); - A[ 7] = (A[ 7] << 10) | (A[ 7] >>> (64 - 10)); - A[ 5] = (A[ 5] << 45) | (A[ 5] >>> (64 - 45)); - A[ 8] = (A[ 8] << 2) | (A[ 8] >>> (64 - 2)); - A[12] = (A[12] << 62) | (A[12] >>> (64 - 62)); - A[10] = (A[10] << 6) | (A[10] >>> (64 - 6)); - A[13] = (A[13] << 43) | (A[13] >>> (64 - 43)); - A[11] = (A[11] << 15) | (A[11] >>> (64 - 15)); - A[14] = (A[14] << 61) | (A[14] >>> (64 - 61)); - A[18] = (A[18] << 28) | (A[18] >>> (64 - 28)); - A[16] = (A[16] << 55) | (A[16] >>> (64 - 55)); - A[19] = (A[19] << 25) | (A[19] >>> (64 - 25)); - A[17] = (A[17] << 21) | (A[17] >>> (64 - 21)); - A[15] = (A[15] << 56) | (A[15] >>> (64 - 56)); - A[24] = (A[24] << 27) | (A[24] >>> (64 - 27)); - A[22] = (A[22] << 20) | (A[22] >>> (64 - 20)); - A[20] = (A[20] << 39) | (A[20] >>> (64 - 39)); - A[23] = (A[23] << 8) | (A[23] >>> (64 - 8)); - A[21] = (A[21] << 14) | (A[21] >>> (64 - 14)); - bnn = ~A[13]; - kt = A[ 9] | A[13]; - c0 = A[ 0] ^ kt; - kt = bnn | A[17]; - c1 = A[ 9] ^ kt; - kt = A[17] & A[21]; - c2 = A[13] ^ kt; - kt = A[21] | A[ 0]; - c3 = A[17] ^ kt; - kt = A[ 0] & A[ 9]; - c4 = A[21] ^ kt; - A[ 0] = c0; - A[ 9] = c1; - A[13] = c2; - A[17] = c3; - A[21] = c4; - bnn = ~A[14]; - kt = A[22] | A[ 1]; - c0 = A[18] ^ kt; - kt = A[ 1] & A[ 5]; - c1 = A[22] ^ kt; - kt = A[ 5] | bnn; - c2 = A[ 1] ^ kt; - kt = A[14] | A[18]; - c3 = A[ 5] ^ kt; - kt = A[18] & A[22]; - c4 = A[14] ^ kt; - A[18] = c0; - A[22] = c1; - A[ 1] = c2; - A[ 5] = c3; - A[14] = c4; - bnn = ~A[23]; - kt = A[10] | A[19]; - c0 = A[ 6] ^ kt; - kt = A[19] & A[23]; - c1 = A[10] ^ kt; - kt = bnn & A[ 2]; - c2 = A[19] ^ kt; - kt = A[ 2] | A[ 6]; - c3 = bnn ^ kt; - kt = A[ 6] & A[10]; - c4 = A[ 2] ^ kt; - A[ 6] = c0; - A[10] = c1; - A[19] = c2; - A[23] = c3; - A[ 2] = c4; - bnn = ~A[11]; - kt = A[ 3] & A[ 7]; - c0 = A[24] ^ kt; - kt = A[ 7] | A[11]; - c1 = A[ 3] ^ kt; - kt = bnn | A[15]; - c2 = A[ 7] ^ kt; - kt = A[15] & A[24]; - c3 = bnn ^ kt; - kt = A[24] | A[ 3]; - c4 = A[15] ^ kt; - A[24] = c0; - A[ 3] = c1; - A[ 7] = c2; - A[11] = c3; - A[15] = c4; - bnn = ~A[16]; - kt = bnn & A[20]; - c0 = A[12] ^ kt; - kt = A[20] | A[ 4]; - c1 = bnn ^ kt; - kt = A[ 4] & A[ 8]; - c2 = A[20] ^ kt; - kt = A[ 8] | A[12]; - c3 = A[ 4] ^ kt; - kt = A[12] & A[16]; - c4 = A[ 8] ^ kt; - A[12] = c0; - A[16] = c1; - A[20] = c2; - A[ 4] = c3; - A[ 8] = c4; - A[ 0] = A[ 0] ^ RC[j + 1]; - t = A[ 5]; - A[ 5] = A[18]; - A[18] = A[11]; - A[11] = A[10]; - A[10] = A[ 6]; - A[ 6] = A[22]; - A[22] = A[20]; - A[20] = A[12]; - A[12] = A[19]; - A[19] = A[15]; - A[15] = A[24]; - A[24] = A[ 8]; - A[ 8] = t; - t = A[ 1]; - A[ 1] = A[ 9]; - A[ 9] = A[14]; - A[14] = A[ 2]; - A[ 2] = A[13]; - A[13] = A[23]; - A[23] = A[ 4]; - A[ 4] = A[21]; - A[21] = A[16]; - A[16] = A[ 3]; - A[ 3] = A[17]; - A[17] = A[ 7]; - A[ 7] = t; - } - } - - protected void doPadding(byte[] out, int off) - { - int ptr = flush(); - byte[] buf = getBlockBuffer(); - if ((ptr + 1) == buf.length) { - buf[ptr] = (byte)0x81; - } else { - buf[ptr] = (byte)0x01; - for (int i = ptr + 1; i < (buf.length - 1); i ++) - buf[i] = 0; - buf[buf.length - 1] = (byte)0x80; - } - processBlock(buf); - A[ 1] = ~A[ 1]; - A[ 2] = ~A[ 2]; - A[ 8] = ~A[ 8]; - A[12] = ~A[12]; - A[17] = ~A[17]; - A[20] = ~A[20]; - int dlen = engineGetDigestLength(); - for (int i = 0; i < dlen; i += 8) - encodeLELong(A[i >>> 3], tmpOut, i); - System.arraycopy(tmpOut, 0, out, off, dlen); - } - - protected void doInit() - { - A = new long[25]; - tmpOut = new byte[(engineGetDigestLength() + 7) & ~7]; - doReset(); - } - - public int getBlockLength() - { - return 200 - 2 * engineGetDigestLength(); - } - - private final void doReset() - { - for (int i = 0; i < 25; i ++) - A[i] = 0; - A[ 1] = 0xFFFFFFFFFFFFFFFFL; - A[ 2] = 0xFFFFFFFFFFFFFFFFL; - A[ 8] = 0xFFFFFFFFFFFFFFFFL; - A[12] = 0xFFFFFFFFFFFFFFFFL; - A[17] = 0xFFFFFFFFFFFFFFFFL; - A[20] = 0xFFFFFFFFFFFFFFFFL; - } - - - protected Digest copyState(KeccakCore dst) - { - System.arraycopy(A, 0, dst.A, 0, 25); - return super.copyState(dst); - } - - public String toString() - { - return "Keccak-" + (engineGetDigestLength() << 3); - } -} diff --git a/app/src/main/java/com/tangem/wallet/RLP.java b/app/src/main/java/com/tangem/wallet/RLP.java deleted file mode 100644 index 7ec159ead9..0000000000 --- a/app/src/main/java/com/tangem/wallet/RLP.java +++ /dev/null @@ -1,228 +0,0 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 07.01.2018. - */ - -import java.util.Arrays; - -import static com.tangem.util.ByteUtil.isNullOrZeroArray; -import static com.tangem.util.ByteUtil.isSingleZero; - -public class RLP { - public static final byte[] EMPTY_ELEMENT_RLP = encodeElement(new byte[0]); - - /** - * Allow for content up to size of 2^64 bytes * - */ - private static final double MAX_ITEM_LENGTH = Math.pow(256, 8); - - /** - * Reason for threshold according to Vitalik Buterin: - * - 56 bytes maximizes the benefit of both options - * - if we went with 60 then we would have only had 4 slots for long strings - * so RLP would not have been able to store objects above 4gb - * - if we went with 48 then RLP would be fine for 2^128 space, but that's way too much - * - so 56 and 2^64 space seems like the right place to put the cutoff - * - also, that's where Bitcoin's varint does the cutof - */ - private static final int SIZE_THRESHOLD = 56; - - /** RLP encoding rules are defined as follows: */ - - /* - * For a single byte whose value is in the [0x00, 0x7f] range, that byte is - * its own RLP encoding. - */ - - /** - * [0x80] - * If a string is 0-55 bytes long, the RLP encoding consists of a single - * byte with value 0x80 plus the length of the string followed by the - * string. The range of the first byte is thus [0x80, 0xb7]. - */ - private static final int OFFSET_SHORT_ITEM = 0x80; - - /** - * [0xb7] - * If a string is more than 55 bytes long, the RLP encoding consists of a - * single byte with value 0xb7 plus the length of the length of the string - * in binary form, followed by the length of the string, followed by the - * string. For example, a length-1024 string would be encoded as - * \xb9\x04\x00 followed by the string. The range of the first byte is thus - * [0xb8, 0xbf]. - */ - private static final int OFFSET_LONG_ITEM = 0xb7; - - /** - * [0xc0] - * If the total payload of a list (i.e. the combined length of all its - * items) is 0-55 bytes long, the RLP encoding consists of a single byte - * with value 0xc0 plus the length of the list followed by the concatenation - * of the RLP encodings of the items. The range of the first byte is thus - * [0xc0, 0xf7]. - */ - private static final int OFFSET_SHORT_LIST = 0xc0; - - public static byte[] encodeByte(byte singleByte) { - if ((singleByte & 0xFF) == 0) { - return new byte[]{(byte) OFFSET_SHORT_ITEM}; - } else if ((singleByte & 0xFF) <= 0x7F) { - return new byte[]{singleByte}; - } else { - return new byte[]{(byte) (OFFSET_SHORT_ITEM + 1), singleByte}; - } - } - - public static byte[] encodeShort(short singleShort) { - if ((singleShort & 0xFF) == singleShort) - return encodeByte((byte) singleShort); - else { - return new byte[]{(byte) (OFFSET_SHORT_ITEM + 2), - (byte) (singleShort >> 8 & 0xFF), - (byte) (singleShort >> 0 & 0xFF)}; - } - } - - public static byte[] encodeInt(int singleInt) { - if ((singleInt & 0xFF) == singleInt) - return encodeByte((byte) singleInt); - else if ((singleInt & 0xFFFF) == singleInt) - return encodeShort((short) singleInt); - else if ((singleInt & 0xFFFFFF) == singleInt) - return new byte[]{(byte) (OFFSET_SHORT_ITEM + 3), - (byte) (singleInt >>> 16), - (byte) (singleInt >>> 8), - (byte) singleInt}; - else { - return new byte[]{(byte) (OFFSET_SHORT_ITEM + 4), - (byte) (singleInt >>> 24), - (byte) (singleInt >>> 16), - (byte) (singleInt >>> 8), - (byte) singleInt}; - } - } - - private static final int OFFSET_LONG_LIST = 0xf7; - - public static byte[] encodeElement2(byte[] srcData) { - if (srcData == null) - return new byte[]{(byte) OFFSET_SHORT_ITEM}; - else if (srcData.length == 1 && (srcData[0] & 0xFF) < 0x80) { - return srcData; - } else if (srcData.length < SIZE_THRESHOLD) { - // length = 8X - byte length = (byte) (OFFSET_SHORT_ITEM + srcData.length); - byte[] data = Arrays.copyOf(srcData, srcData.length + 1); - System.arraycopy(data, 0, data, 1, srcData.length); - data[0] = length; - - return data; - } else { - // length of length = BX - // prefix = [BX, [length]] - int tmpLength = srcData.length; - byte byteNum = 0; - while (tmpLength != 0) { - ++byteNum; - tmpLength = tmpLength >> 8; - } - byte[] lenBytes = new byte[byteNum]; - for (int i = 0; i < byteNum; ++i) { - lenBytes[byteNum - 1 - i] = (byte) ((srcData.length >> (8 * i)) & 0xFF); - } - // first byte = F7 + bytes.length - byte[] data = Arrays.copyOf(srcData, srcData.length + 1 + byteNum); - System.arraycopy(data, 0, data, 1 + byteNum, srcData.length); - data[0] = (byte) (OFFSET_LONG_ITEM + byteNum); - System.arraycopy(lenBytes, 0, data, 1, lenBytes.length); - - return data; - } - } - public static byte[] encodeElement(byte[] srcData) { - - if (isNullOrZeroArray(srcData)) - return new byte[]{(byte) OFFSET_SHORT_ITEM}; - else if (isSingleZero(srcData)) - return srcData; - else if (srcData.length == 1 && (srcData[0] & 0xFF) < 0x80) { - return srcData; - } else if (srcData.length < SIZE_THRESHOLD) { - // length = 8X - byte length = (byte) (OFFSET_SHORT_ITEM + srcData.length); - byte[] data = Arrays.copyOf(srcData, srcData.length + 1); - System.arraycopy(data, 0, data, 1, srcData.length); - data[0] = length; - - return data; - } else { - // length of length = BX - // prefix = [BX, [length]] - int tmpLength = srcData.length; - byte byteNum = 0; - while (tmpLength != 0) { - ++byteNum; - tmpLength = tmpLength >> 8; - } - byte[] lenBytes = new byte[byteNum]; - for (int i = 0; i < byteNum; ++i) { - lenBytes[byteNum - 1 - i] = (byte) ((srcData.length >> (8 * i)) & 0xFF); - } - // first byte = F7 + bytes.length - byte[] data = Arrays.copyOf(srcData, srcData.length + 1 + byteNum); - System.arraycopy(data, 0, data, 1 + byteNum, srcData.length); - data[0] = (byte) (OFFSET_LONG_ITEM + byteNum); - System.arraycopy(lenBytes, 0, data, 1, lenBytes.length); - - return data; - } - } - - - public static byte[] encodeList(byte[]... elements) { - - if (elements == null) { - return new byte[]{(byte) OFFSET_SHORT_LIST}; - } - - int totalLength = 0; - for (byte[] element1 : elements) { - totalLength += element1.length; - } - - byte[] data; - int copyPos; - if (totalLength < SIZE_THRESHOLD) { - - data = new byte[1 + totalLength]; - data[0] = (byte) (OFFSET_SHORT_LIST + totalLength); - copyPos = 1; - } else { - // length of length = BX - // prefix = [BX, [length]] - int tmpLength = totalLength; - byte byteNum = 0; - while (tmpLength != 0) { - ++byteNum; - tmpLength = tmpLength >> 8; - } - tmpLength = totalLength; - byte[] lenBytes = new byte[byteNum]; - for (int i = 0; i < byteNum; ++i) { - lenBytes[byteNum - 1 - i] = (byte) ((tmpLength >> (8 * i)) & 0xFF); - } - // first byte = F7 + bytes.length - data = new byte[1 + lenBytes.length + totalLength]; - data[0] = (byte) (OFFSET_LONG_LIST + byteNum); - System.arraycopy(lenBytes, 0, data, 1, lenBytes.length); - - copyPos = lenBytes.length + 1; - } - for (byte[] element : elements) { - System.arraycopy(element, 0, data, copyPos, element.length); - copyPos += element.length; - } - return data; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/RLPElement.java b/app/src/main/java/com/tangem/wallet/RLPElement.java deleted file mode 100644 index ae82526c2d..0000000000 --- a/app/src/main/java/com/tangem/wallet/RLPElement.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.wallet; - -import java.io.Serializable; - -/** - * Created by Ilia on 07.01.2018. - */ - -public interface RLPElement extends Serializable { - - byte[] getRLPData(); -} diff --git a/app/src/main/java/com/tangem/wallet/RLPList.java b/app/src/main/java/com/tangem/wallet/RLPList.java deleted file mode 100644 index 14164502b3..0000000000 --- a/app/src/main/java/com/tangem/wallet/RLPList.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.tangem.wallet; - -import java.util.ArrayList; - -/** - * Created by Ilia on 07.01.2018. - */ - -public class RLPList extends ArrayList implements RLPElement { - - byte[] rlpData; - - public void setRLPData(byte[] rlpData) { - this.rlpData = rlpData; - } - - public byte[] getRLPData() { - return rlpData; - } - - public static void recursivePrint(RLPElement element) { - - if (element == null) - throw new RuntimeException("RLPElement object can't be null"); - if (element instanceof RLPList) { - - RLPList rlpList = (RLPList) element; - System.out.print("["); - for (RLPElement singleElement : rlpList) - recursivePrint(singleElement); - System.out.print("]"); - } else { - String hex = BTCUtils.toHex(element.getRLPData()); - System.out.print(hex + ", "); - } - } -} diff --git a/app/src/main/java/com/tangem/wallet/TangemContext.java b/app/src/main/java/com/tangem/wallet/TangemContext.java deleted file mode 100644 index 9d3c4d5194..0000000000 --- a/app/src/main/java/com/tangem/wallet/TangemContext.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.tangem.wallet; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; - -import com.google.firebase.crashlytics.FirebaseCrashlytics; -import com.tangem.Constant; -import com.tangem.data.Blockchain; -import com.tangem.tangem_card.data.TangemCard; -import com.tangem.tangem_sdk.data.TangemCardExtensionsKt; -import com.tangem.util.AnalyticsParam; - -public class TangemContext { - // public static final String EXTRA_BLOCKCHAIN_DATA = "BLOCKCHAIN_DATA"; - private Context context; - private TangemCard card; - private CoinData coinData; - private String error; - private String message; - - public TangemContext() { - - } - - public TangemContext(TangemCard card) { - - this.card = card; - } - - public Blockchain getBlockchain() { - if (card == null) return Blockchain.Unknown; - Blockchain blockchain = Blockchain.fromId(card.getBlockchainID()); - if ((blockchain == Blockchain.Ethereum || blockchain == Blockchain.EthereumTestNet) && card.isToken()) { - if (card.getTokenSymbol().startsWith("NFT:")) { - return Blockchain.NftToken; - } else { - return Blockchain.Token; - } - } - if (blockchain == Blockchain.Ethereum && card.isIDCard()) { - return Blockchain.EthereumId; - } - if ((blockchain == Blockchain.Rootstock) && card.isToken()) { - return Blockchain.RootstockToken; - } - if (blockchain == Blockchain.Stellar && card.isToken()) { - return Blockchain.StellarAsset; - } - if (blockchain == Blockchain.Binance && card.isToken()) { - return Blockchain.BinanceAsset; - } - return blockchain; - } - -// public void setBlockchain(Blockchain blockchain) { -// if (card == null) return; -// card.setBlockchainID(blockchain.getID()); -// } - -// private String blockchainName = ""; - - public String getBlockchainName() { - Blockchain blockchain = getBlockchain(); - if (blockchain == Blockchain.Token || blockchain == Blockchain.RootstockToken) { - return card.getTokenSymbol() + "
" + getBlockchain().getOfficialName() + " smart contract token"; - } - if (blockchain == Blockchain.NftToken) { - return card.getTokenSymbol().substring(4) + "
" + getBlockchain().getOfficialName() + " non-fungible token"; - } - if (blockchain == Blockchain.StellarAsset || blockchain == Blockchain.BinanceAsset) { - return card.getTokenSymbol() + "
" + getBlockchain().getOfficialName() + " asset"; - } - if (blockchain == Blockchain.StellarTag) { - return "TANGEM TAG
" + getBlockchain().getOfficialName() + " non-fungible token "; - } - return blockchain.getOfficialName(); - } - - public Context getContext() { - return context; - } - - public void setContext(Context context) { - this.context = context; - } - - public TangemCard getCard() { - return card; - } - - public void setCard(TangemCard card) { - this.card = card; - } - - public CoinData getCoinData() { - return coinData; - } - - public void setCoinData(CoinData coinData) { - this.coinData = coinData; - } - - public void setError(String error) { - if (error != null) { - FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance(); - crashlytics.setCustomKey(AnalyticsParam.BLOCKCHAIN.getParam(), getBlockchainName()); - crashlytics.recordException(new Exception(error)); - } - this.error = error; - } - - public void setError(int valueId) { - this.error = getString(valueId); - } - - public String getError() { - return error; - } - - public boolean hasError() { - return error != null && !error.isEmpty(); - } - - public void setMessage(String value) { - this.message = value; - } - - public void setMessage(int valueId) { - this.message = getString(valueId); - } - - public String getMessage() { - return message; - } - - - public static TangemContext loadFromBundle(Context context, Bundle bundle) { - TangemContext tangemContext = new TangemContext(); - tangemContext.setContext(context); - - if (bundle.containsKey(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID)) { - tangemContext.card = new TangemCard(bundle.getString(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID)); - TangemCardExtensionsKt.loadFromBundle(tangemContext.card, bundle.getBundle(TangemCardExtensionsKt.EXTRA_TANGEM_CARD)); - } - - if (tangemContext.getBlockchain() != null) { - if (bundle.containsKey(Constant.EXTRA_BLOCKCHAIN_DATA)) { - tangemContext.coinData = CoinData.fromBundle(tangemContext.getBlockchain(), bundle.getBundle(Constant.EXTRA_BLOCKCHAIN_DATA)); - } else { - tangemContext.coinData = CoinEngineFactory.INSTANCE.create(tangemContext).createCoinData(); - } - } - tangemContext.error = bundle.getString("Error"); - tangemContext.message = bundle.getString("Message"); - - return tangemContext; - } - - public void saveToBundle(Bundle intent) { - - if (card != null) { - intent.putString(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID, card.getUID()); - intent.putBundle(TangemCardExtensionsKt.EXTRA_TANGEM_CARD, TangemCardExtensionsKt.getAsBundle(card)); - } - - if (coinData != null) { - intent.putBundle(Constant.EXTRA_BLOCKCHAIN_DATA, coinData.asBundle()); - } - - intent.putString("Error", error); - intent.putString("Message", message); - } - - public void saveToIntent(Intent intent) { - - if (card != null) { - intent.putExtra(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID, card.getUID()); - intent.putExtra(TangemCardExtensionsKt.EXTRA_TANGEM_CARD, TangemCardExtensionsKt.getAsBundle(card)); - } - - if (coinData != null) { - intent.putExtra(Constant.EXTRA_BLOCKCHAIN_DATA, coinData.asBundle()); - } - - intent.putExtra("Error", error); - intent.putExtra("Message", message); - } - - public String getString(int stringId) { - if (context != null) return getContext().getResources().getString(stringId); - return "context.resources.string[" + stringId + "]"; - } - - public void setDenomination(byte[] denomination) { - try { - CoinEngine engine = CoinEngineFactory.INSTANCE.create(getBlockchain()); - CoinEngine.InternalAmount internalAmount = engine.convertToInternalAmount(denomination); - CoinEngine.Amount amount = engine.convertToAmount(internalAmount); - card.setDenomination(denomination, amount.toString()); - } catch (Exception e) { - e.printStackTrace(); - card.setDenomination(denomination, "N/A"); - } - } - -} diff --git a/app/src/main/java/com/tangem/wallet/Transaction.java b/app/src/main/java/com/tangem/wallet/Transaction.java deleted file mode 100644 index 07dc9b42e5..0000000000 --- a/app/src/main/java/com/tangem/wallet/Transaction.java +++ /dev/null @@ -1,635 +0,0 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 29.09.2017. - */ - -import com.tangem.wallet.btc.BitcoinException; -import com.tangem.wallet.btc.BitcoinInputStream; -import com.tangem.wallet.btc.BitcoinOutputStream; -import com.tangem.util.CryptoUtil; - -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Stack; - -@SuppressWarnings("WeakerAccess") -public final class Transaction { - public final int version; - public final Input[] inputs; - public final Output[] outputs; - public final int lockTime; - - public Transaction(byte[] rawBytes) throws BitcoinException { - if (rawBytes == null) { - throw new BitcoinException(BitcoinException.ERR_NO_INPUT, "empty input"); - } - BitcoinInputStream bais = null; - try { - bais = new BitcoinInputStream(rawBytes); - version = bais.readInt32(); - if (version != 1 && version != 2 && version != 3 && version != -1273714314) { - throw new BitcoinException(BitcoinException.ERR_UNSUPPORTED, "Unsupported TX version", version); - } - - - int inputsCount = 0; - int first = bais.readByte(); - if(first == 0) - { - int skip = bais.readByte(); - inputsCount = bais.readByte(); - } - else - { - inputsCount = first; - } - //int inputsCount = (int) bais.readVarInt(); TODO: - inputs = new Input[inputsCount]; - for (int i = 0; i < inputsCount; i++) { - OutPoint outPoint = new OutPoint(BTCUtils.reverse(bais.readChars(32)), bais.readInt32()); - byte[] script = bais.readChars((int) bais.readVarInt()); - int sequence = bais.readInt32(); - inputs[i] = new Input(outPoint, new Script(script), sequence); - } - int outputsCount = (int) bais.readVarInt(); - outputs = new Output[outputsCount]; - for (int i = 0; i < outputsCount; i++) { - long value = bais.readInt64(); - long scriptSize = bais.readVarInt(); - if (scriptSize < 0 || scriptSize > 10_000_000) { - throw new BitcoinException(BitcoinException.ERR_BAD_FORMAT, "Script size for output " + i + - " is strange (" + scriptSize + " bytes)."); - } - byte[] script = bais.readChars((int) scriptSize); - outputs[i] = new Output(value, new Script(script)); - } - lockTime = bais.readInt32(); - } catch (EOFException e) { - throw new BitcoinException(BitcoinException.ERR_BAD_FORMAT, "TX incomplete"); - } catch (IOException e) { - throw new IllegalArgumentException("Unable to read TX"); - } catch (Error e) { - throw new IllegalArgumentException("Unable to read TX: " + e); - } finally { - if (bais != null) { - try { - bais.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - public Transaction(Input[] inputs, Output[] outputs, int lockTime) { - this.version = 1; - this.inputs = inputs; - this.outputs = outputs; - this.lockTime = lockTime; - } - - public byte[] getBytes() { - BitcoinOutputStream baos = new BitcoinOutputStream(); - try { - baos.writeInt32(version); - baos.writeVarInt(inputs.length); - for (Input input : inputs) { - baos.write(BTCUtils.reverse(input.outPoint.hash)); - baos.writeInt32(input.outPoint.index); - int scriptLen = input.script == null ? 0 : input.script.bytes.length; - baos.writeVarInt(scriptLen); - if (scriptLen > 0) { - baos.write(input.script.bytes); - } - baos.writeInt32(input.sequence); - } - baos.writeVarInt(outputs.length); - for (Output output : outputs) { - baos.writeInt64(output.value); - int scriptLen = output.script == null ? 0 : output.script.bytes.length; - baos.writeVarInt(scriptLen); - if (scriptLen > 0) { - baos.write(output.script.bytes); - } - } - baos.writeInt32(lockTime); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - baos.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return baos.toByteArray(); - - } - - @Override - public String toString() { - return "{" + - "\n\"inputs\":\n" + printAsJsonArray(inputs) + - ",\n\"outputs\":\n" + printAsJsonArray(outputs) + - ",\n\"lockTime\":\"" + lockTime + "\"}\n"; - } - - private String printAsJsonArray(Object[] a) { - if (a == null) { - return "null"; - } - if (a.length == 0) { - return "[]"; - } - int iMax = a.length - 1; - StringBuilder sb = new StringBuilder(); - sb.append('['); - for (int i = 0; ; i++) { - sb.append(String.valueOf(a[i])); - if (i == iMax) - return sb.append(']').toString(); - sb.append(",\n"); - } - } - - public static class Input { - public final OutPoint outPoint; - public final Script script; - public final int sequence; - - public Input(OutPoint outPoint, Script script, int sequence) { - this.outPoint = outPoint; - this.script = script; - this.sequence = sequence; - } - - @Override - public String toString() { - return "{\n\"outPoint\":" + outPoint + ",\n\"script\":\"" + script + "\",\n\"sequence\":\"" + Integer.toHexString(sequence) + "\"\n}\n"; - } - } - - public static class OutPoint { - public final byte[] hash;//32-byte hash of the transaction from which we want to redeem an output - public final int index;//Four-byte field denoting the output index we want to redeem from the transaction with the above hash (output number 2 = output index 1) - - public OutPoint(byte[] hash, int index) { - this.hash = hash; - this.index = index; - } - - @Override - public String toString() { - return "{" + "\"hash\":\"" + BTCUtils.toHex(hash) + "\", \"index\":\"" + index + "\"}"; - } - } - - public static class Output { - public final long value; - public final Script script; - - public Output(long value, Script script) { - this.value = value; - this.script = script; - } - - @Override - public String toString() { - return "{\n\"value\":\"" + value * 1e-8 + "\",\"script\":\"" + script + "\"\n}"; - } - } - - public static final class Script { - - public static class ScriptInvalidException extends Exception { - public ScriptInvalidException() { - } - - public ScriptInvalidException(String s) { - super(s); - } - } - - public static final byte OP_FALSE = 0; - public static final byte OP_TRUE = 0x51; - public static final byte OP_PUSHDATA1 = 0x4c; - public static final byte OP_PUSHDATA2 = 0x4d; - public static final byte OP_PUSHDATA4 = 0x4e; - public static final byte OP_DUP = 0x76;//Duplicates the top stack item. - public static final byte OP_DROP = 0x75; - public static final byte OP_HASH160 = (byte) 0xA9;//The input is hashed twice: first with SHA-256 and then with RIPEMD-160. - public static final byte OP_VERIFY = 0x69;//Marks transaction as invalid if top stack value is not true. True is removed, but false is not. - public static final byte OP_EQUAL = (byte) 0x87;//Returns 1 if the inputs are exactly equal, 0 otherwise. - public static final byte OP_EQUALVERIFY = (byte) 0x88;//Same as OP_EQUAL, but runs OP_VERIFY afterward. - public static final byte OP_CHECKSIG = (byte) 0xAC;//The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. - public static final byte OP_CHECKSIGVERIFY = (byte) 0xAD; - public static final byte OP_NOP = 0x61; - - public static final byte SIGHASH_ALL = 1; - - public final byte[] bytes; - - public Script(byte[] rawBytes) { - bytes = rawBytes; - } - - public Script(byte[] data1, byte[] data2) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(data1.length + data2.length + 2); - try { - writeBytes(data1, baos); - writeBytes(data2, baos); - baos.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - bytes = baos.toByteArray(); - } - - private static void writeBytes(byte[] data, ByteArrayOutputStream baos) throws IOException { - if (data.length < OP_PUSHDATA1) { - baos.write(data.length); - } else if (data.length < 0xff) { - baos.write(OP_PUSHDATA1); - baos.write(data.length); - } else if (data.length < 0xffff) { - baos.write(OP_PUSHDATA2); - baos.write(data.length & 0xff); - baos.write((data.length >> 8) & 0xff); - } else { - baos.write(OP_PUSHDATA4); - baos.write(data.length & 0xff); - baos.write((data.length >> 8) & 0xff); - baos.write((data.length >> 16) & 0xff); - baos.write((data.length >>> 24) & 0xff); - } - baos.write(data); - } - - public void run(Stack stack) throws ScriptInvalidException { - run(0, null, stack); - } - - public void run(int inputIndex, Transaction tx, Stack stack) throws ScriptInvalidException { - for (int pos = 0; pos < bytes.length; pos++) { - switch (bytes[pos]) { - case OP_NOP: - break; - case OP_DROP: - if (stack.isEmpty()) { - throw new IllegalArgumentException("stack empty on OP_DROP"); - } - stack.pop(); - break; - case OP_DUP: - if (stack.isEmpty()) { - throw new IllegalArgumentException("stack empty on OP_DUP"); - } - stack.push(stack.peek()); - break; - case OP_HASH160: - if (stack.isEmpty()) { - throw new IllegalArgumentException("stack empty on OP_HASH160"); - } - stack.push(CryptoUtil.sha256ripemd160(stack.pop())); - break; - case OP_EQUAL: - case OP_EQUALVERIFY: - if (stack.size() < 2) { - throw new IllegalArgumentException("not enough elements to perform OP_EQUAL"); - } - stack.push(new byte[]{(byte) (Arrays.equals(stack.pop(), stack.pop()) ? 1 : 0)}); - if (bytes[pos] == OP_EQUALVERIFY) { - if (verifyFails(stack)) { - throw new ScriptInvalidException("wrong address"); - } - } - break; - case OP_VERIFY: - if (verifyFails(stack)) { - throw new ScriptInvalidException(); - } - break; - case OP_CHECKSIG: - case OP_CHECKSIGVERIFY: - byte[] publicKey = stack.pop(); - byte[] signatureAndHashType = stack.pop(); - if (signatureAndHashType[signatureAndHashType.length - 1] != SIGHASH_ALL) { - throw new IllegalArgumentException("I cannot check this sig type: " + signatureAndHashType[signatureAndHashType.length - 1]); - } - byte[] signature = new byte[signatureAndHashType.length - 1]; - System.arraycopy(signatureAndHashType, 0, signature, 0, signature.length); - byte[] hash = hashTransaction(inputIndex, bytes, tx); - //boolean valid = BTCUtils.verify(publicKey, signature, hash); - if (bytes[pos] == OP_CHECKSIG) { - stack.push(new byte[]{(byte) (1)}); - } else { - if (verifyFails(stack)) { - throw new ScriptInvalidException("Bad signature"); - } - if (!stack.empty()) { - throw new ScriptInvalidException("Bad signature - superfluous scriptSig operations"); - } - } - break; - case OP_FALSE: - stack.push(new byte[]{0}); - break; - case OP_TRUE: - stack.push(new byte[]{1}); - break; - default: - int op = bytes[pos] & 0xff; - int len; - if (op < OP_PUSHDATA1) { - len = op; - byte[] data = new byte[len]; - System.arraycopy(bytes, pos + 1, data, 0, len); - stack.push(data); - pos += data.length; - } else if (op == OP_PUSHDATA1) { - len = bytes[pos + 1] & 0xff; - byte[] data = new byte[len]; - System.arraycopy(bytes, pos + 1, data, 0, len); - stack.push(data); - pos += 1 + data.length; - } else { - throw new IllegalArgumentException("I cannot read this data: " + Integer.toHexString(bytes[pos])); - } - break; - } - } - } - - public static byte[] hashTransaction(int inputIndex, byte[] subscript, Transaction tx) { - Input[] unsignedInputs = new Input[tx.inputs.length]; - for (int i = 0; i < tx.inputs.length; i++) { - Input txInput = tx.inputs[i]; - if (i == inputIndex) { - unsignedInputs[i] = new Input(txInput.outPoint, new Script(subscript), txInput.sequence); - } else { - unsignedInputs[i] = new Input(txInput.outPoint, new Script(new byte[0]), txInput.sequence); - } - } - Transaction unsignedTransaction = new Transaction(unsignedInputs, tx.outputs, tx.lockTime); - return hashTransactionForSigning(unsignedTransaction); - } - - public static byte[] hashTransactionForSigning(Transaction unsignedTransaction) { - byte[] txUnsignedBytes = unsignedTransaction.getBytes(); - BitcoinOutputStream baos = new BitcoinOutputStream(); - try { - baos.write(txUnsignedBytes); - baos.writeInt32(Script.SIGHASH_ALL); - baos.close(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return CryptoUtil.doubleSha256(baos.toByteArray()); - } - - public static boolean verifyFails(Stack stack) { - byte[] input; - boolean valid; - input = stack.pop(); - if (input.length == 0 || (input.length == 1 && input[0] == OP_FALSE)) { - //false - stack.push(new byte[]{OP_FALSE}); - valid = false; - } else { - //true - valid = true; - } - return !valid; - } - - - @Override - public String toString() { - return convertBytesToReadableString(bytes); - } - - //converts something like "OP_DUP OP_HASH160 ba507bae8f1643d2556000ca26b9301b9069dc6b OP_EQUALVERIFY OP_CHECKSIG" into bytes - public static byte[] convertReadableStringToBytes(String readableString) { - String[] tokens = readableString.trim().split("\\s+"); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - for (String token : tokens) { - switch (token) { - case "OP_NOP": - os.write(OP_NOP); - break; - case "OP_DROP": - os.write(OP_DROP); - break; - case "OP_DUP": - os.write(OP_DUP); - break; - case "OP_HASH160": - os.write(OP_HASH160); - break; - case "OP_EQUAL": - os.write(OP_EQUAL); - break; - case "OP_EQUALVERIFY": - os.write(OP_EQUALVERIFY); - break; - case "OP_VERIFY": - os.write(OP_VERIFY); - break; - case "OP_CHECKSIG": - os.write(OP_CHECKSIG); - break; - case "OP_CHECKSIGVERIFY": - os.write(OP_CHECKSIGVERIFY); - break; - case "OP_FALSE": - os.write(OP_FALSE); - break; - case "OP_TRUE": - os.write(OP_TRUE); - break; - default: - if (token.startsWith("OP_")) { - throw new IllegalArgumentException("I don't know this operation: " + token); - } - byte[] data = BTCUtils.fromHex(token); - if (data == null) { - throw new IllegalArgumentException("I don't know what's this: " + token); - } - if (data.length < OP_PUSHDATA1) { - os.write(data.length); - try { - os.write(data); - } catch (IOException e) { - throw new RuntimeException("ByteArrayOutputStream behaves weird: " + e); - } - } else if (data.length <= 255) { - os.write(OP_PUSHDATA1); - os.write(data.length); - try { - os.write(data); - } catch (IOException e) { - throw new RuntimeException("ByteArrayOutputStream behaves weird: " + e); - } - } else { - throw new IllegalArgumentException("OP_PUSHDATA2 & OP_PUSHDATA4 are not supported"); - } - break; - } - } - try { - os.close(); - } catch (IOException e) { - e.printStackTrace(); - } - return os.toByteArray(); - } - - public static String convertBytesToReadableString(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - for (int pos = 0; pos < bytes.length; pos++) { - if (sb.length() > 0) { - sb.append(' '); - } - switch (bytes[pos]) { - case OP_NOP: - sb.append("OP_NOP"); - break; - case OP_DROP: - sb.append("OP_DROP"); - break; - case OP_DUP: - sb.append("OP_DUP"); - break; - case OP_HASH160: - sb.append("OP_HASH160"); - break; - case OP_EQUAL: - sb.append("OP_EQUAL"); - break; - case OP_EQUALVERIFY: - sb.append("OP_EQUALVERIFY"); - break; - case OP_VERIFY: - sb.append("OP_VERIFY"); - break; - case OP_CHECKSIG: - sb.append("OP_CHECKSIG"); - break; - case OP_CHECKSIGVERIFY: - sb.append("OP_CHECKSIGVERIFY"); - break; - case OP_FALSE: - sb.append("OP_FALSE"); - break; - case OP_TRUE: - sb.append("OP_TRUE"); - break; - default: - int op = bytes[pos] & 0xff; - int len; - if (op < OP_PUSHDATA1) { - len = op; - byte[] data = new byte[len]; - System.arraycopy(bytes, pos + 1, data, 0, len); - sb.append(BTCUtils.toHex(data)); - pos += data.length; - } else if (op == OP_PUSHDATA1) { - len = bytes[pos + 1] & 0xff; - byte[] data = new byte[len]; - System.arraycopy(bytes, pos + 1, data, 0, len);//FIXME I suspect there is off by one error... - sb.append(BTCUtils.toHex(data)); - pos += 1 + data.length; - } else { - throw new IllegalArgumentException("I cannot read this data: " + Integer.toHexString(bytes[pos]) + " at " + pos); - } - break; - } - } - return sb.toString(); - } - - @Override - public boolean equals(Object o) { - return this == o || !(o == null || getClass() != o.getClass()) && Arrays.equals(bytes, ((Script) o).bytes); - } - - @Override - public int hashCode() { - return Arrays.hashCode(bytes); - } - - public static Script buildOutput(String address) throws BitcoinException { - //noinspection TryWithIdenticalCatches - byte[] addressWithCheckSumAndNetworkCode = Base58.decodeBase58(address); - if (addressWithCheckSumAndNetworkCode[0] == 0 || addressWithCheckSumAndNetworkCode[0] == 111 || addressWithCheckSumAndNetworkCode[0] == 48 || addressWithCheckSumAndNetworkCode[0] == 49) { //0 for BTC/BCH 1 address | 48 for LTC L address | 49 for Ducatus - return buildOutputP2H(address); - } - - if(addressWithCheckSumAndNetworkCode[0] == 5 || addressWithCheckSumAndNetworkCode[0] == (byte)0xc4 || addressWithCheckSumAndNetworkCode[0] == 50) { //5 for BTC/BCH/LTC 3 address | 50 for LTC M address - return buildOutputP2SH(address); - } - - throw new BitcoinException(BitcoinException.ERR_UNSUPPORTED, "Unknown address type", address); - } - public static Script buildOutputP2SH(String address) throws BitcoinException { - try { - byte[] addressWithCheckSumAndNetworkCode = Base58.decodeBase58(address); - if (addressWithCheckSumAndNetworkCode[0] != 5 && addressWithCheckSumAndNetworkCode[0] != (byte)0xc4 && addressWithCheckSumAndNetworkCode[0] != 50) { - throw new BitcoinException(BitcoinException.ERR_UNSUPPORTED, "Unknown address type", address); - } - - byte[] bareAddress = new byte[20]; - System.arraycopy(addressWithCheckSumAndNetworkCode, 1, bareAddress, 0, bareAddress.length); - - ByteArrayOutputStream buf = new ByteArrayOutputStream(23); - buf.write(OP_HASH160); - writeBytes(bareAddress, buf); - buf.write(OP_EQUAL); - return new Script(buf.toByteArray()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - - public static Script buildOutputP2H(String address) throws BitcoinException { - //noinspection TryWithIdenticalCatches - try { - byte[] addressWithCheckSumAndNetworkCode = Base58.decodeBase58(address); - if (addressWithCheckSumAndNetworkCode[0] != 0 && addressWithCheckSumAndNetworkCode[0] != 111 && addressWithCheckSumAndNetworkCode[0] != 48 && addressWithCheckSumAndNetworkCode[0] != 49) { - throw new BitcoinException(BitcoinException.ERR_UNSUPPORTED, "Unknown address type", address); - } - - byte[] bareAddress = new byte[20]; - System.arraycopy(addressWithCheckSumAndNetworkCode, 1, bareAddress, 0, bareAddress.length); - - MessageDigest digestSha = MessageDigest.getInstance("SHA-256"); - digestSha.update(addressWithCheckSumAndNetworkCode, 0, addressWithCheckSumAndNetworkCode.length - 4); - - byte[] calculatedDigest = digestSha.digest(digestSha.digest()); - for (int i = 0; i < 4; i++) { - if (calculatedDigest[i] != addressWithCheckSumAndNetworkCode[addressWithCheckSumAndNetworkCode.length - 4 + i]) { - throw new BitcoinException(BitcoinException.ERR_BAD_FORMAT, "Bad address", address); - } - } - - ByteArrayOutputStream buf = new ByteArrayOutputStream(25); - buf.write(OP_DUP); - buf.write(OP_HASH160); - writeBytes(bareAddress, buf); - buf.write(OP_EQUALVERIFY); - buf.write(OP_CHECKSIG); - return new Script(buf.toByteArray()); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } -} diff --git a/app/src/main/java/com/tangem/wallet/UnspentOutputInfo.java b/app/src/main/java/com/tangem/wallet/UnspentOutputInfo.java deleted file mode 100644 index d2f790b24e..0000000000 --- a/app/src/main/java/com/tangem/wallet/UnspentOutputInfo.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 29.09.2017. - */ - -@SuppressWarnings("WeakerAccess") -public class UnspentOutputInfo { - public final byte[] txHash; - public final Transaction.Script script; - public final long value; - public final int outputIndex; - public final long confirmations; - public String txHashForBuild; - public byte[] scriptForBuild; - - public UnspentOutputInfo(byte[] txHash, Transaction.Script script, long value, int outputIndex, long confirmations, String hashForBuild, byte[] sign) { - this.txHash = txHash; - this.script = script; - this.value = value; - this.outputIndex = outputIndex; - this.confirmations = confirmations; - this.txHashForBuild = hashForBuild; - this.scriptForBuild = sign; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashAddressDecodedParts.java b/app/src/main/java/com/tangem/wallet/bch/BitcoinCashAddressDecodedParts.java deleted file mode 100644 index 104c19c31f..0000000000 --- a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashAddressDecodedParts.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.tangem.wallet.bch; - -// Helper class for CashAddr - -public class BitcoinCashAddressDecodedParts { - - String prefix; - - BitcoinCashAddressType addressType; - - byte[] hash; - - public String getPrefix() { - return prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - public BitcoinCashAddressType getAddressType() { - return addressType; - } - - public void setAddressType(BitcoinCashAddressType addressType) { - this.addressType = addressType; - } - - public byte[] getHash() { - return hash; - } - - public void setHash(byte[] hash) { - this.hash = hash; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashAddressType.java b/app/src/main/java/com/tangem/wallet/bch/BitcoinCashAddressType.java deleted file mode 100644 index 1beab277b6..0000000000 --- a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashAddressType.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.wallet.bch; - - -/** - * Copyright (c) 2018 Tobias Brandt - * - * Distributed under the MIT software license, see the accompanying file LICENSE - * or http://www.opensource.org/licenses/mit-license.php. - */ -public enum BitcoinCashAddressType { - - P2PKH((byte) 0), P2SH((byte) 8); - - private final byte versionByte; - - BitcoinCashAddressType(byte versionByte) { - this.versionByte = versionByte; - } - - public byte getVersionByte() { - return versionByte; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashBase32.java b/app/src/main/java/com/tangem/wallet/bch/BitcoinCashBase32.java deleted file mode 100644 index 5e1a6a8c5d..0000000000 --- a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashBase32.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.tangem.wallet.bch; - -import java.util.HashMap; -import java.util.Map; - -/** - * Copyright (c) 2018 Tobias Brandt - * - * Distributed under the MIT software license, see the accompanying file LICENSE - * or http://www.opensource.org/licenses/mit-license.php. - */ -public class BitcoinCashBase32 { - - public static final String CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - - private static final char[] CHARS = CHARSET.toCharArray(); - - private static Map charPositionMap; - static { - charPositionMap = new HashMap<>(); - for (int i = 0; i < CHARS.length; i++) { - charPositionMap.put(CHARS[i], i); - } - if (charPositionMap.size() != 32) { - throw new RuntimeException("The charset must contain 32 unique characters."); - } - } - - /** - * Encode a byte array as base32 string. This method assumes that all bytes - * are only from 0-31 - * - * @param byteArray - * @return - */ - public static String encode(byte[] byteArray) { - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < byteArray.length; i++) { - int val = (int) byteArray[i]; - - if (val < 0 || val > 31) { - throw new RuntimeException("This method assumes that all bytes are only from 0-31. Was: " + val); - } - - sb.append(CHARS[val]); - } - - return sb.toString(); - } - - /** - * Decode a base32 string back to the byte array representation - * - * @param base32String - * @return - */ - public static byte[] decode(String base32String) { - byte[] bytes = new byte[base32String.length()]; - - char[] charArray = base32String.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - Integer position = charPositionMap.get(charArray[i]); - if (position == null) { - throw new RuntimeException("There seems to be an invalid char: " + charArray[i]); - } - bytes[i] = (byte) ((int) position); - } - - return bytes; - } -} - - \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashBitArrayConverter.java b/app/src/main/java/com/tangem/wallet/bch/BitcoinCashBitArrayConverter.java deleted file mode 100644 index 3f92f9445c..0000000000 --- a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashBitArrayConverter.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.tangem.wallet.bch; -/** - * Copyright (c) 2018 Tobias Brandt - * - * Copyright (c) 2017 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ -public class BitcoinCashBitArrayConverter { - - public static byte[] convertBits(byte[] bytes8Bits, int from, int to, boolean strictMode) { - int length = (int) (strictMode ? Math.floor((double) bytes8Bits.length * from / to) - : Math.ceil((double) bytes8Bits.length * from / to)); - int mask = ((1 << to) - 1) & 0xff; - byte[] result = new byte[length]; - int index = 0; - int accumulator = 0; - int bits = 0; - for (int i = 0; i < bytes8Bits.length; i++) { - byte value = bytes8Bits[i]; - accumulator = (((accumulator & 0xff) << from) | (value & 0xff)); - bits += from; - while (bits >= to) { - bits -= to; - result[index] = (byte) ((accumulator >> bits) & mask); - ++index; - } - } - if (!strictMode) { - if (bits > 0) { - result[index] = (byte) ((accumulator << (to - bits)) & mask); - ++index; - } - } else { - if (!(bits < from && ((accumulator << (to - bits)) & mask) == 0)) { - throw new RuntimeException("Strict mode was used but input couldn't be converted without padding"); - } - } - - return result; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashNode.kt b/app/src/main/java/com/tangem/wallet/bch/BitcoinCashNode.kt deleted file mode 100644 index 3355580efe..0000000000 --- a/app/src/main/java/com/tangem/wallet/bch/BitcoinCashNode.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.tangem.wallet.bch - -enum class BitcoinCashNode(val host: String, val port: Int, val proto: String) { - N_001("electrumx.hillsideinternet.com", 50002, "ssl"), - N_002("blackie.c3-soft.com", 50002, "ssl"), - N_003("electrum.imaginary.cash", 50002, "ssl"), -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java b/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java deleted file mode 100644 index 5694d0ad4a..0000000000 --- a/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java +++ /dev/null @@ -1,730 +0,0 @@ -package com.tangem.wallet.bch; - -import android.net.Uri; -import android.text.InputFilter; -import android.util.Log; - -import com.tangem.App; -import com.tangem.data.network.ServerApiBlockchair; -import com.tangem.data.network.ServerApiPayId; -import com.tangem.data.network.model.BlockchairAddressData; -import com.tangem.data.network.model.BlockchairAddressResponse; -import com.tangem.data.network.model.BlockchairStatsResponse; -import com.tangem.data.network.model.BlockchairTransactionResponse; -import com.tangem.data.network.model.BlockchairUnspentOutput; -import com.tangem.data.network.model.PayIdAddress; -import com.tangem.data.network.model.PayIdResponse; -import com.tangem.tangem_card.data.TangemCard; -import com.tangem.tangem_card.reader.CardProtocol; -import com.tangem.tangem_card.tasks.SignTask; -import com.tangem.tangem_card.util.Util; -import com.tangem.util.CryptoUtil; -import com.tangem.util.DecimalDigitsInputFilter; -import com.tangem.util.DerEncodingUtil; -import com.tangem.wallet.BCHUtils; -import com.tangem.wallet.BTCUtils; -import com.tangem.wallet.BalanceValidator; -import com.tangem.wallet.CoinData; -import com.tangem.wallet.CoinEngine; -import com.tangem.wallet.R; -import com.tangem.wallet.TangemContext; -import com.tangem.wallet.Transaction; -import com.tangem.wallet.UnspentOutputInfo; -import com.tangem.wallet.btc.BtcData; -import com.tangem.wallet.btc.Unspents; - -import java.io.ByteArrayOutputStream; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.RoundingMode; -import java.nio.ByteBuffer; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.ArrayList; -import java.util.Arrays; - -import io.reactivex.CompletableObserver; -import io.reactivex.SingleObserver; -import io.reactivex.observers.DisposableCompletableObserver; -import io.reactivex.observers.DisposableSingleObserver; - -public class BtcCashEngine extends CoinEngine { - - private static final String TAG = BtcCashEngine.class.getSimpleName(); - public BtcData coinData = null; - - public BtcCashEngine(TangemContext context) throws Exception { - super(context); - if (context.getCoinData() == null) { - coinData = new BtcData(); - context.setCoinData(coinData); - } else if (context.getCoinData() instanceof BtcData) { - coinData = (BtcData) context.getCoinData(); - } else { - throw new Exception("Invalid type of Blockchain data for BtcEngine"); - } - } - - public BtcCashEngine() { - } - - private static int getDecimals() { - return 8; - } - - private void checkBlockchainDataExists() throws Exception { - if (coinData == null) throw new Exception("No blockchain data"); - } - - @Override - public boolean awaitingConfirmation() { - if (coinData == null) return false; - return coinData.getBalanceUnconfirmed() != 0 || coinData.isHasUnconfirmed() || App.pendingTransactionsStorage.hasTransactions(ctx.getCard()); - } - - @Override - public String getBalanceHTML() { - Amount balance = getBalance(); - if (balance != null) { - return balance.toDescriptionString(getDecimals()); - } else { - return ""; - } - } - - @Override - public String getBalanceCurrency() { - return "BCH"; - } - - @Override - public boolean isBalanceNotZero() { - if (coinData == null) return false; - if (coinData.getBalanceInInternalUnits() == null) return false; - return coinData.getBalanceInInternalUnits().notZero(); - } - - @Override - public boolean hasBalanceInfo() { - if (coinData == null) return false; - return coinData.hasBalanceInfo(); - } - - @Override - public boolean isExtractPossible() { - if (!hasBalanceInfo()) { - ctx.setMessage(R.string.loaded_wallet_error_obtaining_blockchain_data); - } else if (!isBalanceNotZero()) { - ctx.setMessage(R.string.general_wallet_empty); - } else if (awaitingConfirmation()) { - ctx.setMessage(R.string.loaded_wallet_message_wait); - } else if (coinData.getUnspentTransactions().size() == 0) { - ctx.setMessage(R.string.loaded_wallet_message_refresh); - } else { - return true; - } - return false; - } - - @Override - public String getFeeCurrency() { - return "BCH"; - } - - @Override - public boolean validateAddress(String address) { - if (address != null && address.contains("$")) { // PayID - return validatePayId(address); - } - - return CashAddr.isValidCashAddress(address); - } - - @Override - public boolean isNeedCheckNode() { - return true; - } - - @Override - public Uri getWalletExplorerUri() { - return Uri.parse("https://blockchair.com/bitcoin-cash/address/" + ctx.getCoinData().getWallet()); - } - - @Override - public Uri getShareWalletUri() { - return Uri.parse(ctx.getCoinData().getWallet()); - } - - @Override - public InputFilter[] getAmountInputFilters() { - return new InputFilter[]{new DecimalDigitsInputFilter(getDecimals())}; - } - - @Override - public boolean checkNewTransactionAmount(Amount amount) { - if (coinData == null) return false; - if (amount.compareTo(convertToAmount(coinData.getBalanceInInternalUnits())) > 0) { - return false; - } - return true; - } - - @Override - public boolean checkNewTransactionAmountAndFee(Amount amountValue, Amount feeValue, Boolean isIncludeFee) { - InternalAmount fee; - InternalAmount amount; - - try { - checkBlockchainDataExists(); - amount = convertToInternalAmount(amountValue); - fee = convertToInternalAmount(feeValue); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - - if (fee == null || amount == null) - return false; - - if (fee.isZero() || amount.isZero()) - return false; - - if (isIncludeFee && (amount.compareTo(coinData.getBalanceInInternalUnits()) > 0 || amount.compareTo(fee) < 0)) - return false; - - if (!isIncludeFee && amount.add(fee).compareTo(coinData.getBalanceInInternalUnits()) > 0) - return false; - - return true; - } - - @Override - public boolean validateBalance(BalanceValidator balanceValidator) { - if (((ctx.getCard().getOfflineBalance() == null) && !ctx.getCoinData().isBalanceReceived()) || (!ctx.getCoinData().isBalanceReceived() && (ctx.getCard().getRemainingSignatures() != ctx.getCard().getMaxSignatures()))) { - balanceValidator.setScore(0); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_unknown_balance); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_unverified_balance); - return false; - } - - if (coinData.getBalanceUnconfirmed() != 0 || coinData.isHasUnconfirmed()) { - balanceValidator.setScore(0); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_transaction_in_progress); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_wait_for_confirmation); - return false; - } - - if (coinData.isBalanceReceived() && coinData.isBalanceEqual()) { - balanceValidator.setScore(100); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_verified_balance); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_confirmed_in_blockchain); - if (coinData.getBalanceInInternalUnits().isZero()) { - balanceValidator.setFirstLine(R.string.balance_validator_first_line_empty_wallet); - balanceValidator.setSecondLine(R.string.empty_string); - } - } - return true; - } - - @Override - public Amount getBalance() { - return convertToAmount(coinData.getBalanceInInternalUnits()); - } - - @Override - public String evaluateFeeEquivalent(String fee) { - if (!coinData.getAmountEquivalentDescriptionAvailable()) return ""; - try { - Amount feeAmount = new Amount(fee, getFeeCurrency()); - return feeAmount.toEquivalentString(coinData.getRate()); - } catch (Exception e) { - return ""; - } - } - - @Override - public String getBalanceEquivalent() { - if (coinData == null || !coinData.getAmountEquivalentDescriptionAvailable()) return ""; - Amount balance = getBalance(); - if (balance == null) return ""; - return balance.toEquivalentString(coinData.getRate()); - } - - @Override - public String calculateAddress(byte[] pubKey) throws NoSuchProviderException, NoSuchAlgorithmException { - - // CashAddr format - byte hash1[] = Util.calculateSHA256(pubKey); - byte hash2[] = Util.calculateRIPEMD160(hash1); - return CashAddr.toCashAddress(BitcoinCashAddressType.P2PKH, hash2); - - } - - public String calculateLegacyAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException { - - // Legacy format (BTC) - byte netSelectionByte = (byte) 0x00; - - byte hash1[] = Util.calculateSHA256(pkUncompressed); - byte hash2[] = Util.calculateRIPEMD160(hash1); - - ByteBuffer BB = ByteBuffer.allocate(hash2.length + 1); - - BB.put(netSelectionByte); - BB.put(hash2); - - byte hash3[] = Util.calculateSHA256(BB.array()); - byte hash4[] = Util.calculateSHA256(hash3); - - BB = ByteBuffer.allocate(hash2.length + 5); - BB.put(netSelectionByte); - BB.put(hash2); - BB.put(hash4[0]); - BB.put(hash4[1]); - BB.put(hash4[2]); - BB.put(hash4[3]); - - return org.bitcoinj.core.Base58.encode(BB.array()); - } - - public String convertToLegacyAddress(String cashAddr) throws NoSuchProviderException, NoSuchAlgorithmException { - - BitcoinCashAddressDecodedParts bcadp = CashAddr.decodeCashAddress(cashAddr); - byte netSelectionByte = (byte) 0x00; - byte hash2[] = bcadp.hash; - - ByteBuffer BB = ByteBuffer.allocate(hash2.length + 1); - - BB.put(netSelectionByte); - BB.put(hash2); - - byte hash3[] = Util.calculateSHA256(BB.array()); - byte hash4[] = Util.calculateSHA256(hash3); - - BB = ByteBuffer.allocate(hash2.length + 5); - BB.put(netSelectionByte); - BB.put(hash2); - BB.put(hash4[0]); - BB.put(hash4[1]); - BB.put(hash4[2]); - BB.put(hash4[3]); - - return org.bitcoinj.core.Base58.encode(BB.array()); - } - - @Override - public Amount convertToAmount(InternalAmount internalAmount) { - BigDecimal d = internalAmount.divide(new BigDecimal("100000000")); - return new Amount(d, getBalanceCurrency()); - } - - @Override - public Amount convertToAmount(String strAmount, String currency) { - return new Amount(strAmount, currency); - } - - @Override - public InternalAmount convertToInternalAmount(Amount amount) throws Exception { - BigDecimal d = amount.multiply(new BigDecimal("100000000")); - return new InternalAmount(d, getBalanceCurrency()); - } - - @Override - public InternalAmount convertToInternalAmount(byte[] bytes) { - if (bytes == null) return null; - byte[] reversed = new byte[bytes.length]; - for (int i = 0; i < bytes.length; i++) reversed[i] = bytes[bytes.length - i - 1]; - return new InternalAmount(Util.byteArrayToLong(reversed), "Satoshi"); - } - - @Override - public byte[] convertToByteArray(InternalAmount internalAmount) throws Exception { - byte[] bytes = Util.longToByteArray(internalAmount.longValueExact()); - byte[] reversed = new byte[bytes.length]; - for (int i = 0; i < bytes.length; i++) reversed[i] = bytes[bytes.length - i - 1]; - return reversed; - } - - @Override - public CoinData createCoinData() { - return new BtcData(); - } - - @Override - public String getUnspentInputsDescription() { - Unspents unspents = coinData.getUnspentInputsDescription(); - if (unspents == null) { - return ""; - } else { - return String.format( - ctx.getContext().getString(R.string.details_unspents_number), - unspents.getUnspetns(), - unspents.getGatheredUnspents()); - } - } - - @Override - public void defineWallet() throws CardProtocol.TangemException { - try { - String wallet = calculateAddress(ctx.getCard().getWalletPublicKeyRar()); - ctx.getCoinData().setWallet(wallet); - } catch (Exception e) { - ctx.getCoinData().setWallet("ERROR"); - throw new CardProtocol.TangemException("Can't define wallet address"); - } - - } - - - @Override - public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception { - checkBlockchainDataExists(); - - String destination; - //PayID - if (coinData.getResolvedPayIdAddress() != null) { - destination = coinData.getResolvedPayIdAddress(); - } else { - destination = targetAddress; - } - - String srcLegacyAddress = convertToLegacyAddress(ctx.getCoinData().getWallet()); - String destLegacyAddress = convertToLegacyAddress(destination); - byte[] pbKey = ctx.getCard().getWalletPublicKeyRar(); //ALWAYS USING COMPRESS KEY - - final ArrayList unspentOutputs = new ArrayList<>(); - for (BtcData.UnspentTransaction utxo : coinData.getUnspentTransactions()) { - unspentOutputs.add(new UnspentOutputInfo(BTCUtils.fromHex(utxo.txID), new Transaction.Script(BTCUtils.fromHex(utxo.script)), utxo.amount, utxo.outputN, -1, utxo.txID, null)); - } - - long fullAmount = 0; - for (int i = 0; i < unspentOutputs.size(); ++i) { - fullAmount += unspentOutputs.get(i).value; - } - - - long fees = convertToInternalAmount(feeValue).longValueExact(); - long amount = convertToInternalAmount(amountValue).longValueExact(); - long change = fullAmount - amount; - if (IncFee) { - amount = amount - fees; - } else { - change = change - fees; - } - - if (amount + fees > fullAmount) { - throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < change (%d) + amount (%d)", fullAmount, change, amount)); - } - - final long amountFinal = amount; - final long changeFinal = change; - - byte[][] txForSign = new byte[unspentOutputs.size()][]; - byte[][] bodyHash = new byte[unspentOutputs.size()][]; - byte[][] bodyDoubleHash = new byte[unspentOutputs.size()][]; - - for (int i = 0; i < unspentOutputs.size(); ++i) { - txForSign[i] = BCHUtils.buildTXForSign(srcLegacyAddress, destLegacyAddress, srcLegacyAddress, unspentOutputs, i, amount, change); - bodyHash[i] = Util.calculateSHA256(txForSign[i]); - bodyDoubleHash[i] = Util.calculateSHA256(bodyHash[i]); - } - - return new SignTask.TransactionToSign() { - - @Override - public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) { - return signingMethod == TangemCard.SigningMethod.Sign_Hash || signingMethod == TangemCard.SigningMethod.Sign_Raw; - } - - @Override - public byte[][] getHashesToSign() throws Exception { - byte[][] dataForSign = new byte[unspentOutputs.size()][]; - for (int i = 0; i < unspentOutputs.size(); ++i) { - dataForSign[i] = bodyDoubleHash[i]; - } - return dataForSign; - } - - @Override - public byte[] getRawDataToSign() throws Exception { - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - for (int i = 0; i < txForSign.length; i++) { - if (i != 0 && txForSign[0].length != txForSign[i].length) - throw new Exception("Hashes length must be identical!"); - bs.write(txForSign[i]); - } - - return bs.toByteArray(); - } - - @Override - public String getHashAlgToSign() { - return "sha-256x2"; - } - - @Override - public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception { - throw new Exception("Transaction validation by issuer not supported in this version!"); - } - - @Override - public byte[] onSignCompleted(byte[] signFromCard) throws Exception { - for (int i = 0; i < unspentOutputs.size(); ++i) { - BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, i * 64, 32 + i * 64)); - BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32 + i * 64, 64 + i * 64)); - s = CryptoUtil.toCanonicalised(s); - - unspentOutputs.get(i).scriptForBuild = DerEncodingUtil.packSignDerBitcoinCash(r, s, pbKey); - } - - byte[] txForSend = BCHUtils.buildTXForSend(destLegacyAddress, srcLegacyAddress, unspentOutputs, amountFinal, changeFinal); - - notifyOnNeedSendTransaction(txForSend); - return txForSend; - } - }; - } - - @Override - public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) throws Exception { - final ServerApiBlockchair serverApiBlockchair = new ServerApiBlockchair(ctx.getBlockchain()); - - SingleObserver addressObserver = new DisposableSingleObserver() { - @Override - public void onSuccess(BlockchairAddressResponse addressResponse) { - try { - BlockchairAddressData addressData = addressResponse.getData().get(coinData.getWallet()); - - coinData.setBalanceConfirmed(addressData.getAddress().getBalance()); - coinData.setBalanceUnconfirmed(0L); - coinData.setBalanceReceived(true); - coinData.setValidationNodeDescription(serverApiBlockchair.getUrl()); - coinData.setSentTransactionsCount(addressData.getAddress().getOutputCount() - addressData.getAddress().getUnspentOutputCount()); - - for (BlockchairUnspentOutput utxo : addressData.getUnspentOutputs()) { - if (utxo.getBlock() != -1) { - BtcData.UnspentTransaction unspentTx = new BtcData.UnspentTransaction(); - unspentTx.txID = utxo.getTransactionHash(); - unspentTx.amount = utxo.getAmount(); - unspentTx.outputN = utxo.getIndex(); - coinData.getUnspentTransactions().add(unspentTx); - } else { - coinData.setHasUnconfirmed(true); - } - } - - if (addressData.getAddress().getBalance() != 0) { - blockchainRequestsCallbacks.onComplete(true); - } else { //check if there is an unconfirmed tx, which spent all funds - if (addressData.getTransactions().isEmpty()) { - blockchainRequestsCallbacks.onComplete(true); - } else { - requestIsTransactionConfirmed(addressData.getTransactions().get(0), blockchainRequestsCallbacks); - } - } - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "FAIL getAddress Exception"); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - @Override - public void onError(Throwable e) { - e.printStackTrace(); - Log.e(TAG, "FAIL getAddress Exception"); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBlockchair.getAddress(coinData.getWallet(), addressObserver); - } - - private void requestIsTransactionConfirmed(String transaction, BlockchainRequestsCallbacks blockchainRequestsCallbacks) { - final ServerApiBlockchair serverApiBlockchair = new ServerApiBlockchair(ctx.getBlockchain()); - - SingleObserver transactionObserver = new DisposableSingleObserver() { - @Override - public void onSuccess(BlockchairTransactionResponse transactionResponse) { - if (transactionResponse.getData().get(transaction).getTransaction().getBlock() == -1) { - coinData.setHasUnconfirmed(true); - } - blockchainRequestsCallbacks.onComplete(true); - } - - @Override - public void onError(Throwable e) { - e.printStackTrace(); - Log.e(TAG, "FAIL getTransaction Exception"); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBlockchair.getTransaction(transaction, transactionObserver); - } - - private Integer calculateEstimatedTransactionSize(String outputAddress, String outAmount) { - try { - SignTask.TransactionToSign ps = constructTransaction(new Amount(outAmount, getBalanceCurrency()), new Amount("0.00", getFeeCurrency()), true, outputAddress); - OnNeedSendTransaction onNeedSendTransactionBackup = onNeedSendTransaction; - onNeedSendTransaction = (tx) -> { - }; // empty function to bypass exception - - byte[][] hashesToSign = ps.getHashesToSign(); - byte[] signFromCard = new byte[64 * hashesToSign.length]; - Arrays.fill(signFromCard, (byte) 0x01); - byte[] txForSend = ps.onSignCompleted(signFromCard); - onNeedSendTransaction = onNeedSendTransactionBackup; - Log.e(TAG, "txForSend.length=" + String.valueOf(txForSend.length)); - return txForSend.length + 1; - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "Can't calculate transaction size -> use default!"); - return 256; - } - } - - private final static BigDecimal relayFee = new BigDecimal(0.00001); - - @Override - public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception { - - CompletableObserver payIdObserver = new DisposableCompletableObserver() { - @Override - public void onComplete() { - int calcSize = calculateEstimatedTransactionSize(coinData.getResolvedPayIdAddress(), amount.toValueString()); - Log.e(TAG, String.format("Estimated tx size %d", calcSize)); - - checkFee(blockchainRequestsCallbacks, calcSize); - - blockchainRequestsCallbacks.onComplete(true); - } - - @Override - public void onError(Throwable e) { - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - if (targetAddress.contains("$")) { // PayID - resolvePayID(targetAddress, payIdObserver); - } else { - int calcSize = calculateEstimatedTransactionSize(targetAddress, amount.toValueString()); - Log.e(TAG, String.format("Estimated tx size %d", calcSize)); - - checkFee(blockchainRequestsCallbacks, calcSize); - - blockchainRequestsCallbacks.onComplete(true); - } - } - - private void checkFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, int calcSize) { - coinData.minFee = null; - coinData.maxFee = null; - coinData.normalFee = null; - - final ServerApiBlockchair serverApiBlockchair = new ServerApiBlockchair(ctx.getBlockchain()); - - SingleObserver statsObserver = new DisposableSingleObserver() { - @Override - public void onSuccess(BlockchairStatsResponse blockchairStatsResponse) { - try { - int feeSatoshi = blockchairStatsResponse.getData().getFeePerByte() * calcSize; - BigDecimal fee = BigDecimal.valueOf(feeSatoshi).movePointLeft(getDecimals()); - if (fee.compareTo(relayFee) < 0) { - fee = relayFee; - } - Amount feeAmount = new Amount(fee.setScale(getDecimals(), RoundingMode.DOWN), getFeeCurrency()); - coinData.minFee = feeAmount; - coinData.normalFee = feeAmount; - coinData.maxFee = feeAmount; - blockchainRequestsCallbacks.onComplete(true); - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "FAIL getStats Exception"); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - @Override - public void onError(Throwable e) { - e.printStackTrace(); - Log.e(TAG, "FAIL getStats Exception"); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBlockchair.getStats(statsObserver); - } - - private void resolvePayID(String targetAddress, CompletableObserver observer) { - final ServerApiPayId serverApiPayId = new ServerApiPayId(); - - SingleObserver payIdObserver = new DisposableSingleObserver() { - @Override - public void onSuccess(PayIdResponse payIdResponse) { - try { - String resolvedAddress = null; - for (PayIdAddress address : payIdResponse.getAddresses()) { - if (address.getPaymentNetwork().equals(ctx.getBlockchain().getCurrency()) && - address.getEnvironment().equals("MAINNET")) { - resolvedAddress = address.getAddressDetails().getAddress(); - break; - } - } - if (validateAddress(resolvedAddress)) { - if (!resolvedAddress.equals(coinData.getWallet())) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); - } else { - observer.onError(new Exception("Resolved PayID address equals source address")); - } - } else { - observer.onError(new Exception("Unknown address format in PayID response")); - } - } catch (Exception e) { - observer.onError(new Exception("Unknown response format on PayID request")); - } - } - - @Override - public void onError(Throwable e) { - Log.i(TAG, "onFail: " + "payID" + " " + e.getMessage()); - observer.onError(new Exception("PayID error:" + e.getMessage())); - } - }; - - serverApiPayId.getAddress(targetAddress, ctx.getBlockchain(), payIdObserver); - } - - @Override - public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) throws Exception { - final ServerApiBlockchair serverApiBlockchair = new ServerApiBlockchair(ctx.getBlockchain()); - - CompletableObserver sendObserver = new DisposableCompletableObserver() { - @Override - public void onComplete() { - blockchainRequestsCallbacks.onComplete(true); - } - - @Override - public void onError(Throwable e) { - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBlockchair.sendTransaction(Util.byteArrayToHexString(txForSend), sendObserver); - } - - @Override - public boolean allowSelectFeeLevel() { - return false; - } -} diff --git a/app/src/main/java/com/tangem/wallet/bch/CashAddr.java b/app/src/main/java/com/tangem/wallet/bch/CashAddr.java deleted file mode 100644 index 25c6851c16..0000000000 --- a/app/src/main/java/com/tangem/wallet/bch/CashAddr.java +++ /dev/null @@ -1,225 +0,0 @@ -package com.tangem.wallet.bch; - -import java.math.BigInteger; -import java.util.Arrays; - - -/** - * Copyright (c) 2018 Tobias Brandt - * - * Distributed under the MIT software license, see the accompanying file LICENSE - * or http://www.opensource.org/licenses/mit-license.php. - */ - - -public class CashAddr { - - public static final String CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - - private static final char[] CHARS = CHARSET.toCharArray(); - - - public static final String SEPARATOR = ":"; - - public static final String MAIN_NET_PREFIX = "bitcoincash"; - - public static final String TEST_NET_PREFIX = "bchtest"; - - public static final String ASSUMED_DEFAULT_PREFIX = MAIN_NET_PREFIX; - - private static final BigInteger[] POLYMOD_GENERATORS = new BigInteger[] { new BigInteger("98f2bc8e61", 16), - new BigInteger("79b76d99e2", 16), new BigInteger("f33e5fb3c4", 16), new BigInteger("ae2eabe2a8", 16), - new BigInteger("1e4f43e470", 16) }; - - private static final BigInteger POLYMOD_AND_CONSTANT = new BigInteger("07ffffffff", 16); - - public static String toCashAddress(BitcoinCashAddressType addressType, byte[] hash) { - String prefixString = MAIN_NET_PREFIX; - byte[] prefixBytes = getPrefixBytes(prefixString); - byte[] payloadBytes = concatenateByteArrays(new byte[] { addressType.getVersionByte() }, hash); - payloadBytes = convertBits(payloadBytes, 8, 5, false); - byte[] allChecksumInput = concatenateByteArrays( - concatenateByteArrays(concatenateByteArrays(prefixBytes, new byte[] { 0 }), payloadBytes), - new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); - byte[] checksumBytes = calculateChecksumBytesPolymod(allChecksumInput); - checksumBytes = convertBits(checksumBytes, 8, 5, true); - String cashAddress = BitcoinCashBase32.encode(concatenateByteArrays(payloadBytes, checksumBytes)); - return prefixString + SEPARATOR + cashAddress; - } - - public static BitcoinCashAddressDecodedParts decodeCashAddress(String bitcoinCashAddress) { - if (!isValidCashAddress(bitcoinCashAddress)) { - throw new RuntimeException("Address wasn't valid: " + bitcoinCashAddress); - } - - BitcoinCashAddressDecodedParts decoded = new BitcoinCashAddressDecodedParts(); - String[] addressParts = bitcoinCashAddress.split(SEPARATOR); - if (addressParts.length == 2) { - decoded.setPrefix(addressParts[0]); - } else { - decoded.setPrefix(MAIN_NET_PREFIX); - } - - byte[] addressData = BitcoinCashBase32.decode(addressParts[addressParts.length - 1]); - addressData = Arrays.copyOfRange(addressData, 0, addressData.length - 8); - addressData = BitcoinCashBitArrayConverter.convertBits(addressData, 5, 8, true); - byte versionByte = addressData[0]; - byte[] hash = Arrays.copyOfRange(addressData, 1, addressData.length); - - decoded.setAddressType(getAddressTypeFromVersionByte(versionByte)); - decoded.setHash(hash); - - return decoded; - } - - private static BitcoinCashAddressType getAddressTypeFromVersionByte(byte versionByte) { - for (BitcoinCashAddressType addressType : BitcoinCashAddressType.values()) { - if (addressType.getVersionByte() == versionByte) { - return addressType; - } - } - - throw new RuntimeException("Unknown version byte: " + versionByte); - } - - - - public static boolean isValidCashAddress(String bitcoinCashAddress ) { - try { - if (!isSingleCase(bitcoinCashAddress)) - return false; - - bitcoinCashAddress = bitcoinCashAddress.toLowerCase(); - String prefix; - - if (bitcoinCashAddress.contains(SEPARATOR)) { - String[] split = bitcoinCashAddress.split(SEPARATOR); - prefix = split[0]; - if (!prefix.equals(MAIN_NET_PREFIX)) {return false;} //for now we use main net only - bitcoinCashAddress = split[1]; - } else { - prefix = MAIN_NET_PREFIX; - } - if (!bitcoinCashAddress.startsWith("q")) {return false;} //for now we use P2PKH addresses only - - byte[] checksumData = concatenateByteArrays( - concatenateByteArrays(getPrefixBytes(prefix ), new byte[] { 0x00 }), - BitcoinCashBase32.decode(bitcoinCashAddress)); - - byte[] calculateChecksumBytesPolymod = calculateChecksumBytesPolymod(checksumData); - return new BigInteger(calculateChecksumBytesPolymod).compareTo(BigInteger.ZERO) == 0; - } catch (RuntimeException re) { - return false; - } - } - - - - private static boolean isSingleCase(String bitcoinCashAddress) { - if (bitcoinCashAddress.equals(bitcoinCashAddress.toLowerCase())) { - return true; - } - if (bitcoinCashAddress.equals(bitcoinCashAddress.toUpperCase())) { - return true; - } - - return false; - } - - /** - * @param checksumInput - * @return Returns a 40 bits checksum in form of 5 8-bit arrays. This still has - * to me mapped to 5-bit array representation - */ - private static byte[] calculateChecksumBytesPolymod(byte[] checksumInput) { - BigInteger c = BigInteger.ONE; - - for (int i = 0; i < checksumInput.length; i++) { - byte c0 = c.shiftRight(35).byteValue(); - c = c.and(POLYMOD_AND_CONSTANT).shiftLeft(5) - .xor(new BigInteger(String.format("%02x", checksumInput[i]), 16)); - - if ((c0 & 0x01) != 0) - c = c.xor(POLYMOD_GENERATORS[0]); - if ((c0 & 0x02) != 0) - c = c.xor(POLYMOD_GENERATORS[1]); - if ((c0 & 0x04) != 0) - c = c.xor(POLYMOD_GENERATORS[2]); - if ((c0 & 0x08) != 0) - c = c.xor(POLYMOD_GENERATORS[3]); - if ((c0 & 0x10) != 0) - c = c.xor(POLYMOD_GENERATORS[4]); - } - - byte[] checksum = c.xor(BigInteger.ONE).toByteArray(); - if (checksum.length == 5) { - return checksum; - } else { - byte[] newChecksumArray = new byte[5]; - - System.arraycopy(checksum, Math.max(0, checksum.length - 5), newChecksumArray, - Math.max(0, 5 - checksum.length), Math.min(5, checksum.length)); - - return newChecksumArray; - } - - } - - private static byte[] getPrefixBytes(String prefixString ) { - byte[] prefixBytes = new byte[prefixString.length()]; - - char[] charArray = prefixString.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - prefixBytes[i] = (byte) (charArray[i] & 0x1f); - } - - return prefixBytes; - } - - private static byte[] concatenateByteArrays(byte[] first, byte[] second) { - byte[] concatenatedBytes = new byte[first.length + second.length]; - - System.arraycopy(first, 0, concatenatedBytes, 0, first.length); - System.arraycopy(second, 0, concatenatedBytes, first.length, second.length); - - return concatenatedBytes; - } - - private static byte[] convertBits(byte[] bytes8Bits, int from, int to, boolean strictMode) { - //Copyright (c) 2017 Pieter Wuille - - int length = (int) (strictMode ? Math.floor((double) bytes8Bits.length * from / to) - : Math.ceil((double) bytes8Bits.length * from / to)); - int mask = ((1 << to) - 1) & 0xff; - byte[] result = new byte[length]; - int index = 0; - int accumulator = 0; - int bits = 0; - for (int i = 0; i < bytes8Bits.length; i++) { - byte value = bytes8Bits[i]; - accumulator = (((accumulator & 0xff) << from) | (value & 0xff)); - bits += from; - while (bits >= to) { - bits -= to; - result[index] = (byte) ((accumulator >> bits) & mask); - ++index; - } - } - if (!strictMode) { - if (bits > 0) { - result[index] = (byte) ((accumulator << (to - bits)) & mask); - ++index; - } - } else { - if (!(bits < from && ((accumulator << (to - bits)) & mask) == 0)) { - throw new RuntimeException("Strict mode was used but input couldn't be converted without padding"); - } - } - - return result; - } - - - - -} diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetData.java b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetData.java deleted file mode 100644 index 6c06d4dd75..0000000000 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetData.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.tangem.wallet.binance; - -import android.os.Bundle; -import android.util.Log; - -import com.tangem.wallet.CoinEngine; - -public class BinanceAssetData extends BinanceData { - private String assetBalance; - private String assetSymbol; - - @Override - public void loadFromBundle(Bundle B) { - super.loadFromBundle(B); - - if (B.containsKey("AssetBalance")) assetBalance = B.getString("AssetBalance"); - else assetBalance = null; - if (B.containsKey("AssetSymbol")) assetSymbol = B.getString("AssetSymbol"); - else assetSymbol = null; - } - - @Override - public void saveToBundle(Bundle B) { - super.saveToBundle(B); - try { - if (assetBalance != null) B.putString("AssetBalance", assetBalance); - if (assetSymbol != null) B.putString("AssetSymbol", assetSymbol); - } catch (Exception e) { - Log.e("Can't save to bundle ", e.getMessage()); - } - } - - @Override - public void clearInfo() { - super.clearInfo(); - assetBalance = null; - } - - @Override - public boolean hasBalanceInfo() { - return super.hasBalanceInfo() || assetBalance != null; - } - - public CoinEngine.Amount getAssetBalance() { - return assetBalance == null ? null : new CoinEngine.Amount(assetBalance, assetSymbol); - } - - public void setAssetBalance(String assetBalance) { - this.assetBalance = assetBalance; - } - - public void setAssetSymbol(String assetSymbol) { - this.assetSymbol = assetSymbol; - } -} diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java deleted file mode 100644 index 71953fc5cf..0000000000 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java +++ /dev/null @@ -1,666 +0,0 @@ -package com.tangem.wallet.binance; - -import android.net.Uri; -import android.text.InputFilter; -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.data.network.BinanceApi; -import com.tangem.data.network.Server; -import com.tangem.data.network.ServerApiBinance; -import com.tangem.data.network.ServerApiPayId; -import com.tangem.data.network.model.BinanceFees; -import com.tangem.data.network.model.PayIdAddress; -import com.tangem.data.network.model.PayIdResponse; -import com.tangem.tangem_card.data.TangemCard; -import com.tangem.tangem_card.reader.CardProtocol; -import com.tangem.tangem_card.tasks.SignTask; -import com.tangem.tangem_card.util.Util; -import com.tangem.util.CryptoUtil; -import com.tangem.util.DecimalDigitsInputFilter; -import com.tangem.wallet.BalanceValidator; -import com.tangem.wallet.CoinData; -import com.tangem.wallet.CoinEngine; -import com.tangem.wallet.R; -import com.tangem.wallet.TangemContext; -import com.tangem.wallet.binance.client.BinanceDexApiClientFactory; -import com.tangem.wallet.binance.client.BinanceDexApiRestClient; -import com.tangem.wallet.binance.client.BinanceDexEnvironment; -import com.tangem.wallet.binance.client.domain.broadcast.TransactionOption; -import com.tangem.wallet.binance.client.domain.broadcast.Transfer; -import com.tangem.wallet.binance.client.encoding.Bech32; -import com.tangem.wallet.binance.client.encoding.Crypto; -import com.tangem.wallet.binance.client.encoding.message.MessageType; -import com.tangem.wallet.binance.client.encoding.message.TransactionRequestAssemblerExtSign; -import com.tangem.wallet.binance.client.encoding.message.TransferMessage; - -import org.bitcoinj.core.Utils; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.RoundingMode; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.List; - -import io.reactivex.CompletableObserver; -import io.reactivex.SingleObserver; -import io.reactivex.observers.DisposableCompletableObserver; -import io.reactivex.observers.DisposableSingleObserver; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -public class BinanceAssetEngine extends CoinEngine { - private static final String TAG = BinanceAssetEngine.class.getSimpleName(); - - public BinanceAssetData coinData = null; - private BinanceDexApiRestClient client = null; - - public BinanceAssetEngine(TangemContext context) throws Exception { - super(context); - if (context.getCoinData() == null) { - coinData = new BinanceAssetData(); - context.setCoinData(coinData); - } else if (context.getCoinData() instanceof BinanceAssetData) { - coinData = (BinanceAssetData) context.getCoinData(); - } else { - throw new Exception("Invalid type of Blockchain data for " + TAG); - } - client = BinanceDexApiClientFactory.newInstance().newRestClient(BinanceDexEnvironment.PROD.getBaseUrl()); - coinData.setChainId("Binance-Chain-Tigris"); - } - - public BinanceAssetEngine() { - super(); - } - - private static int getDecimals() { - return 8; - } - - private void checkBlockchainDataExists() throws Exception { - if (coinData == null) throw new Exception("No blockchain data"); - } - - @Override - public boolean awaitingConfirmation() { - return App.pendingTransactionsStorage.hasTransactions(ctx.getCard()); - } - - @Override - public String getBalanceHTML() { - Amount balance = coinData.getBalance(); - Amount assetBalance = coinData.getAssetBalance(); - if (balance != null) { - if (assetBalance != null) { - return assetBalance.toDescriptionString(getDecimals()) + "
+ " + balance.toDescriptionString(getDecimals()) + " for fee"; - } - return new Amount(BigDecimal.ZERO, ctx.getCard().tokenSymbol).toDescriptionString(getDecimals()) + "
+ " + balance.toDescriptionString(getDecimals()) + " for fee"; - } else { - return ""; - } - } - - @Override - public String getBalanceCurrency() { - if (hasBalanceInfo()) { - if (coinData.getAssetBalance() != null) { - return ctx.getCard().tokenSymbol; - } else { - return getFeeCurrency(); - } - } else { - return getFeeCurrency(); - } - } - - @Override - public boolean isBalanceNotZero() { - if (!hasBalanceInfo()) - return false; - return (coinData.getBalance() != null && coinData.getBalance().notZero()) || - (coinData.getAssetBalance() != null && coinData.getAssetBalance().notZero()); - } - - @Override - public boolean hasBalanceInfo() { - if (coinData == null) return false; - return coinData.hasBalanceInfo() || coinData.isError404(); - } - - public boolean isExtractPossible() { - if (!hasBalanceInfo()) { - ctx.setMessage(R.string.loaded_wallet_error_obtaining_blockchain_data); - } else if (!isBalanceNotZero()) { - ctx.setMessage(R.string.general_wallet_empty); - } else if (awaitingConfirmation()) { - ctx.setMessage(R.string.loaded_wallet_message_wait); - } else if (coinData.getBalance() == null || coinData.getBalance().isZero()) { - ctx.setMessage(ctx.getString(R.string.confirm_transaction_error_not_enough_bnb_for_fee)); - } else { - return true; - } - return false; - } - - @Override - public String getFeeCurrency() { - return "BNB"; - } - - @Override - public boolean validateAddress(String address) { - if (address == null || address.isEmpty()) { - return false; - } - - if (address.contains("$")) { // PayID - return validatePayId(address); - } - - try { - Crypto.decodeAddress(address); - } catch (Exception e) { - return false; - } - - if (ctx.getBlockchain() == Blockchain.Binance && !address.startsWith("bnb1")) { - return false; - } - - if (ctx.getBlockchain() == Blockchain.BinanceTestNet && !address.startsWith("tbnb1")) { - return false; - } - - return true; - } - - @Override - public boolean isNeedCheckNode() { - return true; - } - - @Override - public Uri getWalletExplorerUri() { - if (ctx.getBlockchain() == Blockchain.Binance) { - return Uri.parse("https://explorer.binance.org/address/" + ctx.getCoinData().getWallet()); - } else if (ctx.getBlockchain() == Blockchain.BinanceTestNet) { - return Uri.parse("https://testnet-explorer.binance.org/address/" + ctx.getCoinData().getWallet()); - } else { - Log.e(TAG, "Invalid blockchain for BinanceEngine"); - return Uri.parse("https://explorer.binance.org/address/" + ctx.getCoinData().getWallet()); - } - } - - public Uri getShareWalletUri() { - return Uri.parse(ctx.getCoinData().getWallet()); - } - - @Override - public InputFilter[] getAmountInputFilters() { - return new InputFilter[]{new DecimalDigitsInputFilter(getDecimals())}; - } - - @Override - public boolean checkNewTransactionAmount(Amount amount) { - if (!hasBalanceInfo()) return false; - Amount balance; - try { - if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) { - balance = coinData.getAssetBalance(); - } else if (amount.getCurrency().equals(getFeeCurrency())) { - balance = coinData.getBalance(); - } else { - return false; - } - } catch (Exception e) { - e.printStackTrace(); - return false; - } - return amount.compareTo(balance) <= 0; - } - - @Override - public boolean checkNewTransactionAmountAndFee(Amount amount, Amount fee, Boolean isFeeIncluded) { - if (!hasBalanceInfo()) return false; - - try { - Amount balance = coinData.getBalance(); - - if (fee == null || amount == null || fee.isZero() || amount.isZero()) - return false; - - - if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) { - // token transaction - if (fee.compareTo(balance) > 0) - return false; - } else if (amount.getCurrency().equals(getFeeCurrency())) { - // standard ETH transaction - if (isFeeIncluded && (amount.compareTo(balance) > 0 || fee.compareTo(balance) > 0)) - return false; - - if (!isFeeIncluded && amount.add(fee).compareTo(balance) > 0) - return false; - } else { - return false; - } - } catch (Exception e) { - e.printStackTrace(); - return false; - } - - return true; - } - - @Override - public boolean validateBalance(BalanceValidator balanceValidator) { - try { - if (((ctx.getCard().getOfflineBalance() == null) && !ctx.getCoinData().isBalanceReceived()) || (!ctx.getCoinData().isBalanceReceived() && (ctx.getCard().getRemainingSignatures() != ctx.getCard().getMaxSignatures()))) { - - if (coinData.isError404()) { - balanceValidator.setScore(0); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_no_account); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_create_account); - } else { - balanceValidator.setScore(0); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_unknown_balance); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_unverified_balance); - return false; - } - } - - if (coinData.isBalanceReceived()) { - balanceValidator.setScore(100); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_verified_balance); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_confirmed_in_blockchain); - if (coinData.getBalance().isZero() && (coinData.getAssetBalance() == null || coinData.getAssetBalance().isZero())) { - balanceValidator.setFirstLine(R.string.balance_validator_first_line_empty_wallet); - balanceValidator.setSecondLine(R.string.empty_string); - } - } - - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - @Override - public Amount getBalance() { - if (!hasBalanceInfo()) return null; - if (coinData.getAssetBalance() != null) { - return coinData.getAssetBalance(); - } else { - return coinData.getBalance(); - } - } - - @Override - public String evaluateFeeEquivalent(String fee) { - if (!coinData.getAmountEquivalentDescriptionAvailable()) return ""; - try { - Amount feeAmount = new Amount(fee, getFeeCurrency()); - return feeAmount.toEquivalentString(coinData.getRate()); - } catch (Exception e) { - return ""; - } - } - - @Override - public String getBalanceEquivalent() { - if (!hasBalanceInfo()) { - return ""; - } - try { - if (coinData.getAssetBalance().notZero()) { - return ""; - } else { - return coinData.getBalance().toEquivalentString(coinData.getRateAlter()); - } - } catch (Exception e) { - e.printStackTrace(); - return ""; - } - } - - public String calculateAddress(byte[] pkCompressed) throws Exception { - byte[] pubKeyHash = Utils.sha256hash160(pkCompressed); - return Bech32.encode("bnb", Crypto.convertBits(pubKeyHash, 0, pubKeyHash.length, 8, 5, false)); - } - - @Override - public Amount convertToAmount(InternalAmount internalAmount) { - return new Amount(internalAmount, getBalanceCurrency()); - } - - @Override - public Amount convertToAmount(String strAmount, String currency) { - return new Amount(strAmount, currency); - } - - @Override - public InternalAmount convertToInternalAmount(Amount amount) { - return new InternalAmount(amount, getBalanceCurrency()); - } - - @Override - public InternalAmount convertToInternalAmount(byte[] bytes) { - if (bytes == null) return null; - byte[] reversed = new byte[bytes.length]; - for (int i = 0; i < bytes.length; i++) reversed[i] = bytes[bytes.length - i - 1]; - return new InternalAmount(Util.byteArrayToLong(reversed), getBalanceCurrency()); - } - - @Override - public byte[] convertToByteArray(InternalAmount internalAmount) { - return Util.longToByteArray(internalAmount.longValueExact()); - } - - @Override - public CoinData createCoinData() { - return new BinanceAssetData(); - } - - @Override - public String getUnspentInputsDescription() { - return ""; - } - - @Override - public void defineWallet() throws CardProtocol.TangemException { - try { - String wallet = calculateAddress(ctx.getCard().getWalletPublicKeyRar()); - ctx.getCoinData().setWallet(wallet); - coinData.setAssetSymbol(ctx.getCard().tokenSymbol); - } catch (Exception e) { - ctx.getCoinData().setWallet("ERROR"); - throw new CardProtocol.TangemException("Can't define wallet address"); - } - } - - @Override - public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception { - checkBlockchainDataExists(); - - String destination; - //PayID - if (coinData.getResolvedPayIdAddress() != null) { - destination = coinData.getResolvedPayIdAddress(); - } else { - destination = targetAddress; - } - - String amount; - - if (IncFee && amountValue.getCurrency().equals(getFeeCurrency())) { //Coin transfer only - amount = amountValue.subtract(feeValue).setScale(getDecimals(), RoundingMode.DOWN).toPlainString(); - } else { - amount = amountValue.setScale(getDecimals(), RoundingMode.DOWN).toPlainString(); - } - - byte[] pubKey = ctx.getCard().getWalletPublicKeyRar(); - byte[] pubKeyPrefix = MessageType.PubKey.getTypePrefixBytes(); - byte[] pubKeyForSign = new byte[pubKey.length + pubKeyPrefix.length + 1]; - System.arraycopy(pubKeyPrefix, 0, pubKeyForSign, 0, pubKeyPrefix.length); - pubKeyForSign[pubKeyPrefix.length] = (byte) 33; - System.arraycopy(pubKey, 0, pubKeyForSign, pubKeyPrefix.length + 1, pubKey.length); - - Transfer transfer = new Transfer(); - transfer.setCoin(amountValue.getCurrency().equals(getFeeCurrency()) ? getFeeCurrency() : ctx.getCard().getContractAddress()); - transfer.setFromAddress(ctx.getCoinData().getWallet()); - transfer.setToAddress(destination); - transfer.setAmount(amount); - - TransactionOption options = TransactionOption.DEFAULT_INSTANCE; - - TransactionRequestAssemblerExtSign txAssembler = client.prepareTransfer(transfer, coinData, pubKeyForSign, options, true); - // TransactionRequestAssembler.buildTransfer as reference - TransferMessage msgBean = txAssembler.createTransferMessage(transfer); - byte[] msg = txAssembler.encodeTransferMessage(msgBean); - byte[] dataForSign = txAssembler.prepareForSign(msgBean); - - return new SignTask.TransactionToSign() { - - @Override - public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) { - return signingMethod == TangemCard.SigningMethod.Sign_Hash || signingMethod == TangemCard.SigningMethod.Sign_Raw; - } - - @Override - public byte[][] getHashesToSign() throws NoSuchAlgorithmException { - byte[][] hashForSign = new byte[1][]; - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - hashForSign[0] = digest.digest(dataForSign); - return hashForSign; - } - - @Override - public byte[] getRawDataToSign() { - return dataForSign; - } - - @Override - public String getHashAlgToSign() { - return "sha-256"; - } - - @Override - public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception { - throw new Exception("Transaction validation by issuer not supported in this version"); - } - - @Override - public byte[] onSignCompleted(byte[] signFromCard) throws Exception { - int size = signFromCard.length / 2; - BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, size)); - BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, size, size * 2)); - s = CryptoUtil.toCanonicalised(s); - - byte[] resultSig = new byte[64]; - System.arraycopy(Utils.bigIntegerToBytes(r, 32), 0, resultSig, 0, 32); - System.arraycopy(Utils.bigIntegerToBytes(s, 32), 0, resultSig, 32, 32); - - // TransactionRequestAssembler.buildTransfer as reference - byte[] signature = txAssembler.encodeSignature(resultSig); - byte[] txForSend = txAssembler.encodeStdTx(msg, signature); - - notifyOnNeedSendTransaction(txForSend); - return txForSend; - } - }; - } - - public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) { - try { - ServerApiBinance serverApiBinance = new ServerApiBinance(); - - ServerApiBinance.ResponseListener responseListener = new ServerApiBinance.ResponseListener() { - @Override - public void onSuccess() { - blockchainRequestsCallbacks.onComplete(true); - } - - @Override - public void onFail() { - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBinance.setResponseListener(responseListener); - serverApiBinance.getBalance(ctx, client); - - coinData.setValidationNodeDescription(Server.ApiBinance.URL_BINANCE); - - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "FAIL Binance balance exception"); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) { - CompletableObserver payIdObserver = new DisposableCompletableObserver() { - @Override - public void onComplete() { - checkFee(blockchainRequestsCallbacks); - } - - @Override - public void onError(Throwable e) { - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - if (targetAddress.contains("$")) { // PayID - resolvePayID(targetAddress, payIdObserver); - } else { - checkFee(blockchainRequestsCallbacks); - } - } - - private void checkFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks) { - try { - String baseUrl = Server.ApiBinance.Method.API_V1; - - Retrofit retrofitBinance = new Retrofit.Builder() - .baseUrl(baseUrl) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - - BinanceApi binanceApi = retrofitBinance.create(BinanceApi.class); - Call> call = binanceApi.binanceFees(); - call.enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.code() == 200) { - for (BinanceFees fee : response.body()) { - if (fee.getFixed_fee_params() != null) { - Long longFee = Long.valueOf(fee.getFixed_fee_params().getFee()); - Amount feeAmount = new Amount(BigDecimal.valueOf(longFee).divide(BigDecimal.valueOf(100000000)).setScale(8, RoundingMode.DOWN), getFeeCurrency()); - coinData.minFee = coinData.normalFee = coinData.maxFee = feeAmount; - Log.i(TAG, "requestFee onResponse " + response.code()); - blockchainRequestsCallbacks.onComplete(true); - } - } - } else { - ctx.setError(response.code()); - Log.e(TAG, "requestFee onResponse " + response.code()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - ctx.setError(t.getMessage()); - Log.e(TAG, "requestFee onFailure " + t.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }); - } catch (Exception e) { - ctx.setError(e.getMessage()); - e.printStackTrace(); - Log.e(TAG, "FAIL Binance fee exception"); - blockchainRequestsCallbacks.onComplete(false); - } - } - - private void resolvePayID(String targetAddress, CompletableObserver observer) { - final ServerApiPayId serverApiPayId = new ServerApiPayId(); - - SingleObserver payIdObserver = new DisposableSingleObserver() { - @Override - public void onSuccess(PayIdResponse payIdResponse) { - try { - String resolvedAddress = null; - for (PayIdAddress address : payIdResponse.getAddresses()) { - if (address.getPaymentNetwork().equals(ctx.getBlockchain().getCurrency()) && - address.getEnvironment().equals("MAINNET")) { - resolvedAddress = address.getAddressDetails().getAddress(); - break; - } - } - if (validateAddress(resolvedAddress)) { - if (!resolvedAddress.equals(coinData.getWallet())) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); - } else { - observer.onError(new Exception("Resolved PayID address equals source address")); - } - } else { - observer.onError(new Exception("Unknown address format in PayID response")); - } - } catch (Exception e) { - observer.onError(new Exception("Unknown response format on PayID request")); - } - } - - @Override - public void onError(Throwable e) { - Log.i(TAG, "onFail: " + "payID" + " " + e.getMessage()); - observer.onError(new Exception("PayID error:" + e.getMessage())); - } - }; - - serverApiPayId.getAddress(targetAddress, ctx.getBlockchain(), payIdObserver); - } - - public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) { -// RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend); - try { - ServerApiBinance serverApiBinance = new ServerApiBinance(); - - ServerApiBinance.ResponseListener responseListener = new ServerApiBinance.ResponseListener() { - @Override - public void onSuccess() { - ctx.setError(null); - blockchainRequestsCallbacks.onComplete(true); - } - - @Override - public void onFail() { - ctx.setError("Broadcast error"); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBinance.setResponseListener(responseListener); - serverApiBinance.sendTransaction(txForSend, client); - - } catch (Exception e) { - Log.e(TAG, e.getMessage()); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - @Override - public int pendingTransactionTimeoutInSeconds() { - return 9; - } - - @Override - public boolean allowSelectFeeLevel() { - return false; - } - - @Override - public boolean allowSelectFeeInclusion() { - return coinData.getAssetBalance() == null; - } - - @Override - public boolean needMultipleLinesForBalance() { - return true; - } -} diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceData.java b/app/src/main/java/com/tangem/wallet/binance/BinanceData.java deleted file mode 100644 index bfe3b630cf..0000000000 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceData.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.tangem.wallet.binance; - -import android.os.Bundle; -import android.util.Log; - -import com.tangem.wallet.CoinData; -import com.tangem.wallet.CoinEngine; - -public class BinanceData extends CoinData { - private String balance, chainId; - private Long sequence; - private Integer accountNumber; - private boolean error404 = false; - - @Override - public void loadFromBundle(Bundle B) { - super.loadFromBundle(B); - - if (B.containsKey("Balance")) balance = B.getString("Balance"); - else balance = null; - if (B.containsKey("ChainId")) chainId = B.getString("ChainId"); - else chainId = null; - if (B.containsKey("Sequence")) sequence = B.getLong("Sequence"); - else sequence = null; - if (B.containsKey("AccountNumber")) accountNumber = B.getInt("AccountNumber"); - else accountNumber = null; - if (B.containsKey("Error404")) error404 = B.getBoolean("Error404"); - else error404 = false; - } - - @Override - public void saveToBundle(Bundle B) { - super.saveToBundle(B); - try { - if (balance != null) B.putString("Balance", balance); - if (chainId != null) B.putString("ChainId", chainId); - if (sequence != null) B.putLong("Sequence", sequence); - if (accountNumber != null) B.putInt("AccountNumber", accountNumber); - if (error404) B.putBoolean("Error404", true); - } catch (Exception e) { - Log.e("Can't save to bundle ", e.getMessage()); - } - } - - @Override - public void clearInfo() { - super.clearInfo(); - balance = null; - chainId = null; - sequence = null; - accountNumber = null; - error404 = false; - } - - public CoinEngine.Amount getBalance() { - return balance == null ? null : new CoinEngine.Amount(balance, "BNB"); - } - - public void setBalance(String balance) { - this.balance = balance; - } - - public boolean hasBalanceInfo() { - return balance != null; - } - - public Integer getAccountNumber() { - return accountNumber; - } - - public void setAccountNumber(Integer accountNumber) { - this.accountNumber = accountNumber; - } - - public Long getSequence() { - return sequence; - } - - public void setSequence(Long sequence) { - this.sequence = sequence; - } - - public String getChainId() { - return chainId; - } - - public void setChainId(String chain_id) { - this.chainId = chain_id; - } - - public boolean isError404() { - return error404; - } - - public void setError404(boolean error404) { - this.error404 = error404; - } -} diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java b/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java deleted file mode 100644 index 5fc513cb3a..0000000000 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java +++ /dev/null @@ -1,638 +0,0 @@ -package com.tangem.wallet.binance; - -import android.net.Uri; -import android.text.InputFilter; -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.tangem.App; -import com.tangem.data.Blockchain; -import com.tangem.data.network.BinanceApi; -import com.tangem.data.network.Server; -import com.tangem.data.network.ServerApiBinance; -import com.tangem.data.network.ServerApiPayId; -import com.tangem.data.network.model.BinanceFees; -import com.tangem.data.network.model.PayIdAddress; -import com.tangem.data.network.model.PayIdResponse; -import com.tangem.tangem_card.data.TangemCard; -import com.tangem.tangem_card.reader.CardProtocol; -import com.tangem.tangem_card.tasks.SignTask; -import com.tangem.tangem_card.util.Util; -import com.tangem.util.CryptoUtil; -import com.tangem.util.DecimalDigitsInputFilter; -import com.tangem.wallet.BalanceValidator; -import com.tangem.wallet.CoinData; -import com.tangem.wallet.CoinEngine; -import com.tangem.wallet.R; -import com.tangem.wallet.TangemContext; -import com.tangem.wallet.binance.client.BinanceDexApiClientFactory; -import com.tangem.wallet.binance.client.BinanceDexApiRestClient; -import com.tangem.wallet.binance.client.BinanceDexEnvironment; -import com.tangem.wallet.binance.client.domain.broadcast.TransactionOption; -import com.tangem.wallet.binance.client.domain.broadcast.Transfer; -import com.tangem.wallet.binance.client.encoding.Bech32; -import com.tangem.wallet.binance.client.encoding.Crypto; -import com.tangem.wallet.binance.client.encoding.message.MessageType; -import com.tangem.wallet.binance.client.encoding.message.TransactionRequestAssemblerExtSign; -import com.tangem.wallet.binance.client.encoding.message.TransferMessage; - -import org.bitcoinj.core.Utils; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.RoundingMode; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.List; - -import io.reactivex.CompletableObserver; -import io.reactivex.SingleObserver; -import io.reactivex.observers.DisposableCompletableObserver; -import io.reactivex.observers.DisposableSingleObserver; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - - -public class BinanceEngine extends CoinEngine { - private static final String TAG = BinanceEngine.class.getSimpleName(); - - public BinanceData coinData = null; - private BinanceDexApiRestClient client = null; - - public BinanceEngine(TangemContext context) throws Exception { - super(context); - if (context.getCoinData() == null) { - coinData = new BinanceData(); - context.setCoinData(coinData); - } else if (context.getCoinData() instanceof BinanceData) { - coinData = (BinanceData) context.getCoinData(); - } else { - throw new Exception("Invalid type of Blockchain data for " + TAG); - } - if (ctx.getBlockchain() == Blockchain.Binance) { - client = BinanceDexApiClientFactory.newInstance().newRestClient(BinanceDexEnvironment.PROD.getBaseUrl()); - coinData.setChainId("Binance-Chain-Tigris"); - } else if (ctx.getBlockchain() == Blockchain.BinanceTestNet) { - client = BinanceDexApiClientFactory.newInstance().newRestClient(BinanceDexEnvironment.TEST_NET.getBaseUrl()); - coinData.setChainId("Binance-Chain-Nile"); - } else { - throw new Exception("Invalid blockchain for BinanceEngine"); - } - } - - public BinanceEngine() { - super(); - } - - private static int getDecimals() { - return 8; - } - - private void checkBlockchainDataExists() throws Exception { - if (coinData == null) throw new Exception("No blockchain data"); - } - - @Override - public boolean awaitingConfirmation() { - return App.pendingTransactionsStorage.hasTransactions(ctx.getCard()); - } - - @Override - public String getBalanceHTML() { - Amount balance = getBalance(); - if (balance != null) { - return balance.toDescriptionString(getDecimals()); - } else { - return ""; - } - } - - @Override - public String getBalanceCurrency() { - return "BNB"; - } - - @Override - public boolean isBalanceNotZero() { - if (coinData == null) return false; - if (coinData.getBalance() == null) return false; - return coinData.getBalance().notZero(); - } - - @Override - public boolean hasBalanceInfo() { - if (coinData == null) return false; - return coinData.hasBalanceInfo() || coinData.isError404(); - } - - public boolean isExtractPossible() { - if (!hasBalanceInfo()) { - ctx.setMessage(R.string.loaded_wallet_error_obtaining_blockchain_data); - } else if (!isBalanceNotZero()) { - ctx.setMessage(R.string.general_wallet_empty); - } else if (awaitingConfirmation()) { - ctx.setMessage(R.string.loaded_wallet_message_wait); - } else { - return true; - } - return false; - } - - @Override - public String getFeeCurrency() { - return "BNB"; - } - - @Override - public boolean validateAddress(String address) { - if (address == null || address.isEmpty()) { - return false; - } - - if (address.contains("$")) { // PayID - return validatePayId(address); - } - - try { - Crypto.decodeAddress(address); - } catch (Exception e) { - return false; - } - - if (ctx.getBlockchain() == Blockchain.Binance && !address.startsWith("bnb1")) { - return false; - } - - if (ctx.getBlockchain() == Blockchain.BinanceTestNet && !address.startsWith("tbnb1")) { - return false; - } - - return true; - } - - @Override - public boolean isNeedCheckNode() { - return true; - } - - @Override - public Uri getWalletExplorerUri() { - if (ctx.getBlockchain() == Blockchain.Binance) { - return Uri.parse("https://explorer.binance.org/address/" + ctx.getCoinData().getWallet()); - } else if (ctx.getBlockchain() == Blockchain.BinanceTestNet) { - return Uri.parse("https://testnet-explorer.binance.org/address/" + ctx.getCoinData().getWallet()); - } else { - Log.e(TAG, "Invalid blockchain for BinanceEngine"); - return Uri.parse("https://explorer.binance.org/address/" + ctx.getCoinData().getWallet()); - } - } - - public Uri getShareWalletUri() { - return Uri.parse(ctx.getCoinData().getWallet()); - } - - @Override - public InputFilter[] getAmountInputFilters() { - return new InputFilter[]{new DecimalDigitsInputFilter(getDecimals())}; - } - - @Override - public boolean checkNewTransactionAmount(Amount amount) { - if (coinData == null) return false; - return amount.compareTo(coinData.getBalance()) <= 0; - } - - @Override - public boolean checkNewTransactionAmountAndFee(Amount amountValue, Amount feeValue, Boolean isIncludeFee) { - try { - checkBlockchainDataExists(); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - - if (feeValue == null || amountValue == null) - return false; - - if (feeValue.isZero() || amountValue.isZero()) - return false; - - if (isIncludeFee && (amountValue.compareTo(coinData.getBalance()) > 0 || amountValue.compareTo(feeValue) < 0)) - return false; - - if (!isIncludeFee && amountValue.add(feeValue).compareTo(coinData.getBalance()) > 0) - return false; - - return true; - } - - @Override - public boolean validateBalance(BalanceValidator balanceValidator) { - try { - if (((ctx.getCard().getOfflineBalance() == null) && !ctx.getCoinData().isBalanceReceived()) || (!ctx.getCoinData().isBalanceReceived() && (ctx.getCard().getRemainingSignatures() != ctx.getCard().getMaxSignatures()))) { - - if(coinData.isError404()) { - balanceValidator.setScore(0); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_no_account); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_create_account); - } else { - balanceValidator.setScore(0); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_unknown_balance); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_unverified_balance); - return false; - } - } - - if (coinData.isBalanceReceived()) { - balanceValidator.setScore(100); - balanceValidator.setFirstLine(R.string.balance_validator_first_line_verified_balance); - balanceValidator.setSecondLine(R.string.balance_validator_second_line_confirmed_in_blockchain); - if (coinData.getBalance().isZero()) { - balanceValidator.setFirstLine(R.string.balance_validator_first_line_empty_wallet); - balanceValidator.setSecondLine(R.string.empty_string); - } - } - -// if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) { -// balanceValidator.setScore(80); -// balanceValidator.setFirstLine(R.string.balance_validator_first_line_verified_offline); -// balanceValidator.setSecondLine(R.string.balance_validator_second_line_internet_to_get_balance); -// } - - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - @Override - public Amount getBalance() { - if (!hasBalanceInfo()) return null; - return coinData.getBalance(); - } - - @Override - public String evaluateFeeEquivalent(String fee) { - if (!coinData.getAmountEquivalentDescriptionAvailable()) return ""; - try { - Amount feeAmount = new Amount(fee, getFeeCurrency()); - return feeAmount.toEquivalentString(coinData.getRate()); - } catch (Exception e) { - return ""; - } - } - - @Override - public String getBalanceEquivalent() { - if (coinData == null || !coinData.getAmountEquivalentDescriptionAvailable()) return ""; - Amount balance = getBalance(); - if (balance == null) return ""; - return balance.toEquivalentString(coinData.getRate()); - } - - public String calculateAddress(byte[] pkCompressed) throws Exception { - byte[] pubKeyHash = Utils.sha256hash160(pkCompressed); - - if (ctx.getBlockchain() == Blockchain.Binance) { - return Bech32.encode("bnb", Crypto.convertBits(pubKeyHash, 0, pubKeyHash.length, 8, 5, false)); - } else if (ctx.getBlockchain() == Blockchain.BinanceTestNet) { - return Bech32.encode("tbnb", Crypto.convertBits(pubKeyHash, 0, pubKeyHash.length, 8, 5, false)); - } else { - throw new Exception("Invalid blockchain for BinanceEngine"); - } - } - - @Override - public Amount convertToAmount(InternalAmount internalAmount) { - return new Amount(internalAmount, getBalanceCurrency()); - } - - @Override - public Amount convertToAmount(String strAmount, String currency) { - return new Amount(strAmount, currency); - } - - @Override - public InternalAmount convertToInternalAmount(Amount amount) { - return new InternalAmount(amount, getBalanceCurrency()); - } - - @Override - public InternalAmount convertToInternalAmount(byte[] bytes) { - if (bytes == null) return null; - byte[] reversed = new byte[bytes.length]; - for (int i = 0; i < bytes.length; i++) reversed[i] = bytes[bytes.length - i - 1]; - return new InternalAmount(Util.byteArrayToLong(reversed), getBalanceCurrency()); - } - - @Override - public byte[] convertToByteArray(InternalAmount internalAmount) { - return Util.longToByteArray(internalAmount.longValueExact()); - } - - @Override - public CoinData createCoinData() { - return new BinanceData(); - } - - @Override - public String getUnspentInputsDescription() { - return ""; - } - - @Override - public void defineWallet() throws CardProtocol.TangemException { - try { - String wallet = calculateAddress(ctx.getCard().getWalletPublicKeyRar()); - ctx.getCoinData().setWallet(wallet); - } catch (Exception e) { - ctx.getCoinData().setWallet("ERROR"); - throw new CardProtocol.TangemException("Can't define wallet address"); - } - } - - @Override - public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception { - checkBlockchainDataExists(); - - String destination; - //PayID - if (coinData.getResolvedPayIdAddress() != null) { - destination = coinData.getResolvedPayIdAddress(); - } else { - destination = targetAddress; - } - - String amount; - - if (IncFee) { - amount = amountValue.subtract(feeValue).setScale(getDecimals(), RoundingMode.DOWN).toPlainString(); - } else { - amount = amountValue.setScale(getDecimals(), RoundingMode.DOWN).toPlainString(); - } - - byte[] pubKey = ctx.getCard().getWalletPublicKeyRar(); - byte[] pubKeyPrefix = MessageType.PubKey.getTypePrefixBytes(); - byte[] pubKeyForSign = new byte[pubKey.length + pubKeyPrefix.length + 1]; - System.arraycopy(pubKeyPrefix, 0, pubKeyForSign, 0, pubKeyPrefix.length); - pubKeyForSign[pubKeyPrefix.length] = (byte) 33; - System.arraycopy(pubKey, 0, pubKeyForSign, pubKeyPrefix.length + 1, pubKey.length); - - Transfer transfer = new Transfer(); - transfer.setCoin("BNB"); - transfer.setFromAddress(ctx.getCoinData().getWallet()); - transfer.setToAddress(destination); - transfer.setAmount(amount); - - TransactionOption options = TransactionOption.DEFAULT_INSTANCE; - - TransactionRequestAssemblerExtSign txAssembler = client.prepareTransfer(transfer, coinData, pubKeyForSign, options, true); - // TransactionRequestAssembler.buildTransfer as reference - TransferMessage msgBean = txAssembler.createTransferMessage(transfer); - byte[] msg = txAssembler.encodeTransferMessage(msgBean); - byte[] dataForSign = txAssembler.prepareForSign(msgBean); - - return new SignTask.TransactionToSign() { - - @Override - public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) { - return signingMethod == TangemCard.SigningMethod.Sign_Hash || signingMethod == TangemCard.SigningMethod.Sign_Raw; - } - - @Override - public byte[][] getHashesToSign() throws NoSuchAlgorithmException { - byte[][] hashForSign = new byte[1][]; - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - hashForSign[0] = digest.digest(dataForSign); - return hashForSign; - } - - @Override - public byte[] getRawDataToSign() { - return dataForSign; - } - - @Override - public String getHashAlgToSign() { - return "sha-256"; - } - - @Override - public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception { - throw new Exception("Transaction validation by issuer not supported in this version"); - } - - @Override - public byte[] onSignCompleted(byte[] signFromCard) throws Exception { - int size = signFromCard.length / 2; - BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, size)); - BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, size, size * 2)); - s = CryptoUtil.toCanonicalised(s); - - byte[] resultSig = new byte[64]; - System.arraycopy(Utils.bigIntegerToBytes(r, 32), 0, resultSig, 0, 32); - System.arraycopy(Utils.bigIntegerToBytes(s, 32), 0, resultSig, 32, 32); - - // TransactionRequestAssembler.buildTransfer as reference - byte[] signature = txAssembler.encodeSignature(resultSig); - byte[] txForSend = txAssembler.encodeStdTx(msg, signature); - - notifyOnNeedSendTransaction(txForSend); - return txForSend; - } - }; - } - - public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) { - try { - ServerApiBinance serverApiBinance = new ServerApiBinance(); - - ServerApiBinance.ResponseListener responseListener = new ServerApiBinance.ResponseListener() { - @Override - public void onSuccess() { - blockchainRequestsCallbacks.onComplete(true); - } - - @Override - public void onFail() { - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBinance.setResponseListener(responseListener); - serverApiBinance.getBalance(ctx, client); - - if (ctx.getBlockchain() == Blockchain.Binance) { - coinData.setValidationNodeDescription(Server.ApiBinance.URL_BINANCE); - } else if (ctx.getBlockchain() == Blockchain.BinanceTestNet) { - coinData.setValidationNodeDescription(Server.ApiBinanceTestnet.URL_BINANCE_TESTNET); - } else { - throw new Exception("Invalid blockchain for BinanceEngine"); - } - - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "FAIL Binance balance exception"); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) { - CompletableObserver payIdObserver = new DisposableCompletableObserver() { - @Override - public void onComplete() { - checkFee(blockchainRequestsCallbacks); - } - - @Override - public void onError(Throwable e) { - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - if (targetAddress.contains("$")) { // PayID - resolvePayID(targetAddress, payIdObserver); - } else { - checkFee(blockchainRequestsCallbacks); - } - } - - private void checkFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks) { - try { - String baseUrl; - - if (ctx.getBlockchain() == Blockchain.Binance) { - baseUrl = Server.ApiBinance.Method.API_V1; - } else if (ctx.getBlockchain() == Blockchain.BinanceTestNet) { - baseUrl = Server.ApiBinanceTestnet.Method.API_V1; - } else { - throw new Exception("Invalid blockchain for BinanceEngine"); - } - - Retrofit retrofitBinance = new Retrofit.Builder() - .baseUrl(baseUrl) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - - BinanceApi binanceApi = retrofitBinance.create(BinanceApi.class); - Call> call = binanceApi.binanceFees(); - call.enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.code() == 200) { - for (BinanceFees fee : response.body()) { - if (fee.getFixed_fee_params() != null) { - Long longFee = Long.valueOf(fee.getFixed_fee_params().getFee()); - Amount feeAmount = new Amount(BigDecimal.valueOf(longFee).divide(BigDecimal.valueOf(100000000)).setScale(8, RoundingMode.DOWN), getFeeCurrency()); - coinData.minFee = coinData.normalFee = coinData.maxFee = feeAmount; - Log.i(TAG, "requestFee onResponse " + response.code()); - blockchainRequestsCallbacks.onComplete(true); - } - } - } else { - ctx.setError(response.code()); - Log.e(TAG, "requestFee onResponse " + response.code()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - ctx.setError(t.getMessage()); - Log.e(TAG, "requestFee onFailure " + t.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - }); - } catch (Exception e) { - ctx.setError(e.getMessage()); - e.printStackTrace(); - Log.e(TAG, "FAIL Binance fee exception"); - blockchainRequestsCallbacks.onComplete(false); - } - } - - private void resolvePayID(String targetAddress, CompletableObserver observer) { - final ServerApiPayId serverApiPayId = new ServerApiPayId(); - - SingleObserver payIdObserver = new DisposableSingleObserver() { - @Override - public void onSuccess(PayIdResponse payIdResponse) { - try { - String resolvedAddress = null; - for (PayIdAddress address : payIdResponse.getAddresses()) { - if (address.getPaymentNetwork().equals(ctx.getBlockchain().getCurrency()) && - address.getEnvironment().equals("MAINNET")) { - resolvedAddress = address.getAddressDetails().getAddress(); - break; - } - } - if (validateAddress(resolvedAddress)) { - if (!resolvedAddress.equals(coinData.getWallet())) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); - } else { - observer.onError(new Exception("Resolved PayID address equals source address")); - } - } else { - observer.onError(new Exception("Unknown address format in PayID response")); - } - } catch (Exception e) { - observer.onError(new Exception("Unknown response format on PayID request")); - } - } - - @Override - public void onError(Throwable e) { - Log.i(TAG, "onFail: " + "payID" + " " + e.getMessage()); - observer.onError(new Exception("PayID error:" + e.getMessage())); - } - }; - - serverApiPayId.getAddress(targetAddress, ctx.getBlockchain(), payIdObserver); - } - - public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) { -// RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend); - try { - ServerApiBinance serverApiBinance = new ServerApiBinance(); - - ServerApiBinance.ResponseListener responseListener = new ServerApiBinance.ResponseListener() { - @Override - public void onSuccess() { - ctx.setError(null); - blockchainRequestsCallbacks.onComplete(true); - } - - @Override - public void onFail() { - ctx.setError("Broadcast error"); - blockchainRequestsCallbacks.onComplete(false); - } - }; - - serverApiBinance.setResponseListener(responseListener); - serverApiBinance.sendTransaction(txForSend, client); - - } catch (Exception e) { - Log.e(TAG, e.getMessage()); - ctx.setError(e.getMessage()); - blockchainRequestsCallbacks.onComplete(false); - } - } - - public int pendingTransactionTimeoutInSeconds() { - return 9; - } - - public boolean allowSelectFeeLevel() { - return false; - } -} diff --git a/app/src/main/java/com/tangem/wallet/binance/client/BinanceDexApi.java b/app/src/main/java/com/tangem/wallet/binance/client/BinanceDexApi.java deleted file mode 100644 index 95342b68bd..0000000000 --- a/app/src/main/java/com/tangem/wallet/binance/client/BinanceDexApi.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.tangem.wallet.binance.client; - -import com.tangem.wallet.binance.client.domain.*; -import okhttp3.RequestBody; -import retrofit2.Call; -import retrofit2.http.*; - -import java.util.List; - -public interface BinanceDexApi { - @GET("/api/v1/time") - Call