diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 255a33e953..ada7acbd0c 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -9,7 +9,9 @@
-
+
+
+
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000000..8b7f4afdab
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index b0c7b20c87..86bb94acb2 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,10 @@
+
+
+
+
+
diff --git a/app/build.gradle b/app/build.gradle
index 129a474e04..10b187ccff 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -15,7 +15,7 @@ android {
applicationId "com.tangem.wallet"
minSdkVersion 21
targetSdkVersion 28
- versionCode 100
+ versionCode 103
versionName "0.811.1." + generateVersionName()
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
@@ -44,13 +44,14 @@ android {
}
dependencies {
- implementation project(':tangemcard')
+ implementation project(':tangemcard-common')
+ implementation project(':tangemcard-android')
+ implementation project(':tangemserver-android')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
- implementation 'com.android.support:support-compat:28.0.0'
- implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ implementation 'com.google.dagger:dagger:2.16'
implementation 'com.google.zxing:core:3.3.3'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.madgag.spongycastle:core:1.56.0.0'
@@ -58,17 +59,18 @@ dependencies {
implementation 'com.scottyab:rootbeer-lib:0.0.7'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
- implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
+ implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
implementation 'com.skyfishjy.ripplebackground:library:1.0.1'
implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
- implementation 'com.google.dagger:dagger:2.16'
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'org.bitcoinj:bitcoinj-parent:0.14.7'
implementation 'org.bitcoinj:bitcoinj-core:0.14.7'
+ implementation 'org.greenrobot:eventbus:3.1.1'
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.1'
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
+
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b2cea5d8f7..033a88b840 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
+
-
+
@@ -20,11 +22,13 @@
+ android:theme="@style/AppTheme"
+ tools:ignore="GoogleAppIndexingWarning">
>() {
+ }.getType();
+
+
+ Issuer.fillIssuers(new Gson().fromJson(reader, listType));
+ }
+ }
+ } catch (Exception e) {
+ 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
index 5fb46a7a5f..57bb685c8c 100644
--- a/app/src/main/java/com/tangem/Constant.kt
+++ b/app/src/main/java/com/tangem/Constant.kt
@@ -1,13 +1,86 @@
package com.tangem
+import android.app.Activity
+
object Constant {
-
const val EXTRA_BLOCKCHAIN_DATA = "BLOCKCHAIN_DATA"
- const val MESSAGE = "Message"
- const val ERROR = "Error"
+ const val EXTRA_MESSAGE = "message"
const val EXTRA_MODIFICATION = "modification"
+ const val EXTRA_MODIFICATION_DELETE = "delete"
+ const val EXTRA_MODIFICATION_UPDATE = "update"
+
+ // LoadedWallet, VerifyCard
+ const val REQUEST_CODE_SEND_PAYMENT = 1
+ const val REQUEST_CODE_PURGE = 2
+ const val REQUEST_CODE_REQUEST_PIN2_FOR_PURGE = 3
+ const val REQUEST_CODE_VERIFY_CARD = 4
+ const val REQUEST_CODE_ENTER_NEW_PIN = 5
+ const val REQUEST_CODE_ENTER_NEW_PIN2 = 6
+ const val REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = 7
+ const val REQUEST_CODE_SWAP_PIN = 8
+ const val REQUEST_CODE_RECEIVE_PAYMENT = 9
+
+ // MainActivity
+ const val REQUEST_CODE_SHOW_CARD_ACTIVITY = 1
+ const val REQUEST_CODE_ENTER_PIN_ACTIVITY = 2
+ const val REQUEST_CODE_SEND_EMAIL = 3
+ const val REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS = 3
+
+ const val EXTRA_LAST_DISCOVERED_TAG = "extra_last_tag"
+ const val EXTRA_PIN2 = "PIN2"
+
+ // LogoActivity
+ const val EXTRA_AUTO_HIDE = "extra_auto_hide"
+ const val MILLIS_AUTO_HIDE = 1000
+
+ // PinRequestActivity
+ const val EXTRA_MODE = "mode"
+ const val KEY_ALIAS = "pinKey"
+ const val KEYSTORE = "AndroidKeyStore"
+
+ // QrScanActivity
+ const val EXTRA_QR_CODE = "QRCode"
+
+ // PinSwapActivity
+ 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"
+
+ // CreateNewWalletActivity
+ const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
+
+ // EmptyWalletActivity
+ const val REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY = 2
+ const val REQUEST_CODE_REQUEST_PIN2 = 3
+
+ // ConfirmPaymentActivity
+ const val REQUEST_CODE_SIGN_PAYMENT = 1
+ const val REQUEST_CODE_REQUEST_PIN2_ = 2
+
+ // SendTransactionActivity
+ const val EXTRA_TX: String = "TX"
+
+ // SignPaymentActivity
+ 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_PAYMENT_ = 1
+ const val RESULT_INVALID_PIN_ = Activity.RESULT_FIRST_USER
+
+ // PreparePaymentActivity
+ const val REQUEST_CODE_SCAN_QR = 1
+ const val REQUEST_CODE_SEND_PAYMENT__ = 2
+
+ // PrepareCryptonitOtherApiWithdrawalActivity
+ const val REQUEST_CODE_SCAN_QR_KEY = 1
+ const val REQUEST_CODE_SCAN_QR_SECRET = 2
+ const val REQUEST_CODE_SCAN_QR_USER_ID = 3
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/Blockchain.java b/app/src/main/java/com/tangem/data/Blockchain.java
similarity index 93%
rename from app/src/main/java/com/tangem/domain/wallet/Blockchain.java
rename to app/src/main/java/com/tangem/data/Blockchain.java
index f7bf3c304b..5ad40fedc9 100644
--- a/app/src/main/java/com/tangem/domain/wallet/Blockchain.java
+++ b/app/src/main/java/com/tangem/data/Blockchain.java
@@ -1,7 +1,6 @@
-package com.tangem.domain.wallet;
+package com.tangem.data;
-import com.google.common.base.Strings;
-import com.tangem.wallet.R;
+import com.tangem.tangemcard.R;
/**
* Created by dvol on 06.08.2017.
@@ -13,7 +12,8 @@ public enum Blockchain {
Ethereum("ETH", "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", "ERC20", 1.0, R.drawable.ic_logo_bat_token, "Ethereum"),
- BitcoinCash("BCH", "BCH", 100000000.0, R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash");
+ BitcoinCash("BCH", "BCH", 100000000.0, R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash"),
+ Litecoin("LTC", "LTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Litecoin");
Blockchain(String ID, String currency, double multiplier, int imageResource, String officialName) {
mID = ID;
@@ -71,7 +71,7 @@ public enum Blockchain {
}
public int getImageResource(android.content.Context context, String name) {
- if (Strings.isNullOrEmpty(name))
+ if (name==null || name.isEmpty())
return getImageResource();
name = name.toLowerCase();
diff --git a/app/src/main/java/com/tangem/data/LogFileProvider.java b/app/src/main/java/com/tangem/data/LogFileProvider.java
index be8a46d5a7..1c95cf0459 100644
--- a/app/src/main/java/com/tangem/data/LogFileProvider.java
+++ b/app/src/main/java/com/tangem/data/LogFileProvider.java
@@ -68,8 +68,7 @@ public class LogFileProvider extends ContentProvider {
// 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);
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY);
return pfd;
// Otherwise unrecognised Uri
diff --git a/app/src/main/java/com/tangem/data/Logger.java b/app/src/main/java/com/tangem/data/Logger.java
index e556515577..ad6f408d07 100644
--- a/app/src/main/java/com/tangem/data/Logger.java
+++ b/app/src/main/java/com/tangem/data/Logger.java
@@ -3,7 +3,7 @@ package com.tangem.data;
import android.content.Context;
import android.util.Log;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
diff --git a/app/src/main/java/com/tangem/data/fingerprint/StartFingerprintReaderTask.java b/app/src/main/java/com/tangem/data/fingerprint/StartFingerprintReaderTask.java
index 74de89e542..91b13b925c 100644
--- a/app/src/main/java/com/tangem/data/fingerprint/StartFingerprintReaderTask.java
+++ b/app/src/main/java/com/tangem/data/fingerprint/StartFingerprintReaderTask.java
@@ -8,8 +8,10 @@ import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
-import com.tangem.data.db.PINStorage;
+import com.tangem.Constant;
+import com.tangem.tangemcard.android.data.PINStorage;
import com.tangem.presentation.activity.PinRequestActivity;
+import com.tangem.util.LOG;
import java.io.IOException;
import java.lang.ref.WeakReference;
@@ -25,6 +27,8 @@ 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;
@@ -63,16 +67,14 @@ public class StartFingerprintReaderTask extends AsyncTask {
@Override
protected void onPostExecute(final Boolean success) {
- PinRequestActivity pinRequestActivity = reference.get();
onCancelled();
if (!success) {
- pinRequestActivity.doLog("Authentication failed!");
+ LOG.i(TAG, "Authentication failed!");
} else {
fingerprintHelper.startAuth(fingerprintManager, cryptoObject);
- pinRequestActivity.doLog("Authenticate using fingerprint!");
-
+ LOG.i(TAG, "Authenticate using fingerprint!");
}
}
@@ -84,11 +86,9 @@ public class StartFingerprintReaderTask extends AsyncTask {
}
private boolean getKeyStore() {
- PinRequestActivity pinRequestActivity = reference.get();
-
- pinRequestActivity.doLog("Getting keystore...");
+ LOG.i(TAG, "Getting keystore...");
try {
- keyStore = KeyStore.getInstance(PinRequestActivity.KEYSTORE);
+ keyStore = KeyStore.getInstance(Constant.KEYSTORE);
keyStore.load(null); // Create empty keystore
return true;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
@@ -100,17 +100,15 @@ public class StartFingerprintReaderTask extends AsyncTask {
@TargetApi(Build.VERSION_CODES.M)
public boolean createNewKey(boolean forceCreate) {
- PinRequestActivity pinRequestActivity = reference.get();
-
- pinRequestActivity.doLog("Creating new key...");
+ LOG.i(TAG, "Creating new key...");
try {
if (forceCreate)
- keyStore.deleteEntry(PinRequestActivity.KEY_ALIAS);
+ keyStore.deleteEntry(Constant.KEY_ALIAS);
- if (!keyStore.containsAlias(PinRequestActivity.KEY_ALIAS)) {
- KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, PinRequestActivity.KEYSTORE);
+ if (!keyStore.containsAlias(Constant.KEY_ALIAS)) {
+ KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, Constant.KEYSTORE);
- generator.init(new KeyGenParameterSpec.Builder(PinRequestActivity.KEY_ALIAS,
+ generator.init(new KeyGenParameterSpec.Builder(Constant.KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
@@ -119,9 +117,9 @@ public class StartFingerprintReaderTask extends AsyncTask {
);
generator.generateKey();
- pinRequestActivity.doLog("Key created.");
+ LOG.i(TAG, "Key created.");
} else
- pinRequestActivity.doLog("Key exists.");
+ LOG.i(TAG, "Key exists.");
return true;
} catch (Exception e) {
@@ -132,9 +130,7 @@ public class StartFingerprintReaderTask extends AsyncTask {
}
private boolean getCipher() {
- PinRequestActivity pinRequestActivity = reference.get();
-
- pinRequestActivity.doLog("Getting cipher...");
+ LOG.i(TAG, "Getting cipher...");
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
return true;
@@ -149,10 +145,10 @@ public class StartFingerprintReaderTask extends AsyncTask {
private boolean initCipher(int mode) {
PinRequestActivity pinRequestActivity = reference.get();
- pinRequestActivity.doLog("Initializing cipher...");
+ LOG.i(TAG, "Initializing cipher...");
try {
keyStore.load(null);
- SecretKey keyspec = (SecretKey) keyStore.getKey(PinRequestActivity.KEY_ALIAS, null);
+ SecretKey keyspec = (SecretKey) keyStore.getKey(Constant.KEY_ALIAS, null);
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(mode, keyspec);
@@ -180,9 +176,7 @@ public class StartFingerprintReaderTask extends AsyncTask {
@TargetApi(Build.VERSION_CODES.M)
private boolean initCryptObject() {
- PinRequestActivity pinRequestActivity = reference.get();
-
- pinRequestActivity.doLog("Initializing crypt object...");
+ LOG.i(TAG, "Initializing crypt object...");
try {
cryptoObject = new FingerprintManager.CryptoObject(cipher);
return true;
@@ -192,5 +186,4 @@ public class StartFingerprintReaderTask extends AsyncTask {
return false;
}
-
}
diff --git a/app/src/main/java/com/tangem/data/network/Cryptonit.java b/app/src/main/java/com/tangem/data/network/Cryptonit.java
index de709d7289..75f9586baa 100644
--- a/app/src/main/java/com/tangem/data/network/Cryptonit.java
+++ b/app/src/main/java/com/tangem/data/network/Cryptonit.java
@@ -4,30 +4,22 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import android.util.Log;
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.util.Util;
import com.tangem.wallet.R;
import java.io.IOException;
-import java.util.Arrays;
-
-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.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
-import okhttp3.RequestBody;
import okhttp3.Response;
//import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
@@ -36,9 +28,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.Headers;
-import retrofit2.http.Multipart;
import retrofit2.http.POST;
-import retrofit2.http.Part;
/**
* HTTP
diff --git a/app/src/main/java/com/tangem/data/network/CryptonitOtherApi.java b/app/src/main/java/com/tangem/data/network/CryptonitOtherApi.java
index 772da733a8..7e933b1951 100644
--- a/app/src/main/java/com/tangem/data/network/CryptonitOtherApi.java
+++ b/app/src/main/java/com/tangem/data/network/CryptonitOtherApi.java
@@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import android.util.Log;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
@@ -12,7 +11,7 @@ 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.util.Util;
+import com.tangem.tangemcard.util.Util;
import com.tangem.wallet.R;
import java.io.IOException;
diff --git a/app/src/main/java/com/tangem/data/network/ElectrumRequest.java b/app/src/main/java/com/tangem/data/network/ElectrumRequest.java
index e61b18008f..591b359973 100644
--- a/app/src/main/java/com/tangem/data/network/ElectrumRequest.java
+++ b/app/src/main/java/com/tangem/data/network/ElectrumRequest.java
@@ -17,14 +17,14 @@ public class ElectrumRequest {
public static final String METHOD_SendTransaction = "blockchain.transaction.broadcast";
public static final String METHOD_GetFee = "blockchain.estimatefee";
- public JSONObject jsRequestData;
- public String answerData;
- public String error;
- public String walletAddress;
+ private JSONObject jsRequestData;
+ String answerData;
+ private String error = null;
+ private String walletAddress;
public String txHash;
- public String TX;
- public String host;
- public int port;
+ private String TX;
+ String host;
+ int port;
private ElectrumRequest() {
}
@@ -84,10 +84,9 @@ public class ElectrumRequest {
}
- public static ElectrumRequest getFee(String wallet) {
+ public static ElectrumRequest getFee() {
ElectrumRequest request = new ElectrumRequest();
try {
- request.walletAddress = wallet; //METHOD_GetFee
request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetFee + "\", \"params\":[\"" + 6 + "\"] }");
} catch (JSONException e) {
e.printStackTrace();
@@ -143,8 +142,8 @@ public class ElectrumRequest {
return "";
}
- public boolean isMethod(String methodName) throws JSONException {
- return jsRequestData.getString("method").equals(methodName);
+ public boolean isMethod(String methodName) {
+ return getMethod().equals(methodName);
}
public JSONArray getParams() throws JSONException {
@@ -155,12 +154,36 @@ public class ElectrumRequest {
return getAnswer().getJSONObject("result");
}
- public JSONObject getError() throws JSONException {
- return getAnswer().getJSONObject("error");
+ 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 {
- return getAnswer().getString("result");
+ if (getAnswer().has("result")) {
+ return getAnswer().getString("result");
+ } else {
+ return null;
+ }
}
public JSONArray getResultArray() throws JSONException {
diff --git a/app/src/main/java/com/tangem/data/network/Kraken.java b/app/src/main/java/com/tangem/data/network/Kraken.java
index 318dd04900..3eefe0a9d9 100644
--- a/app/src/main/java/com/tangem/data/network/Kraken.java
+++ b/app/src/main/java/com/tangem/data/network/Kraken.java
@@ -4,10 +4,9 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import android.util.Log;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import com.tangem.wallet.R;
import org.spongycastle.util.encoders.Base64;
diff --git a/app/src/main/java/com/tangem/data/network/Server.java b/app/src/main/java/com/tangem/data/network/Server.java
index e7c666b4ec..7e8bc996aa 100644
--- a/app/src/main/java/com/tangem/data/network/Server.java
+++ b/app/src/main/java/com/tangem/data/network/Server.java
@@ -2,20 +2,6 @@ package com.tangem.data.network;
public class Server {
- /**
- * https://tangem-webapp.appspot.com/
- * https://tangem-services.appspot.com/
- */
- public static class ApiTangem {
- public static final String URL_TANGEM = ServerURL.API_TANGEM;
-
- public static class Method {
- static final String VERIFY = URL_TANGEM + "verify";
- static final String VERIFY_AND_GET_INFO = URL_TANGEM + "card/verify-and-get-info";
- static final String ARTWORK = URL_TANGEM + "card/artwork";
- }
- }
-
public static class ApiUpdateVersion {
public static final String URL_UPDATE_VERSION = ServerURL.API_UPDATE_VERSION;
@@ -42,7 +28,7 @@ public class Server {
public static final String URL_INFURA = ServerURL.API_INFURA;
public static class Method {
- static final String MAIN = URL_INFURA + "AfWg0tmYEX5Kukn2UkKV";
+ static final String MAIN = URL_INFURA + "613a0b14833145968b1f656240c7d245";
}
}
diff --git a/app/src/main/java/com/tangem/data/network/ServerApiCommon.java b/app/src/main/java/com/tangem/data/network/ServerApiCommon.java
index 50b790ad84..7ab8fe42e0 100644
--- a/app/src/main/java/com/tangem/data/network/ServerApiCommon.java
+++ b/app/src/main/java/com/tangem/data/network/ServerApiCommon.java
@@ -5,15 +5,7 @@ import android.support.annotation.NonNull;
import android.util.Log;
import com.tangem.App;
-import com.tangem.data.network.model.CardVerifyAndGetInfo;
import com.tangem.data.network.model.RateInfoResponse;
-import com.tangem.domain.wallet.TangemCard;
-import com.tangem.util.Util;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -36,7 +28,7 @@ public class ServerApiCommon {
public interface EstimateFeeListener {
void onSuccess(int blockCount, String estimateFeeResponse);
- void onFail(String message);
+ void onFail(int blockCount, String message);
}
public void setEstimateFee(EstimateFeeListener listener) {
@@ -71,106 +63,18 @@ public class ServerApiCommon {
estimateFeeListener.onSuccess(blockCount, response.body());
Log.i(TAG, "estimateFee onResponse " + response.code() + " " + response.body());
} else
- estimateFeeListener.onFail(response.body());
+ estimateFeeListener.onFail(blockCount, response.body());
Log.e(TAG, "estimateFee onResponse " + response.code());
}
@Override
public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- estimateFeeListener.onFail(t.getMessage());
+ estimateFeeListener.onFail(blockCount, t.getMessage());
Log.e(TAG, "estimateFee onFailure " + t.getMessage());
}
});
}
- /**
- * HTTP
- * Card verify
- */
- private CardVerifyAndGetInfoListener cardVerifyAndGetInfoListener;
-
- public interface CardVerifyAndGetInfoListener {
- void onSuccess(CardVerifyAndGetInfo.Response cardVerifyAndGetArtworkResponse);
- void onFail(String message);
- }
-
- public void setCardVerifyAndGetInfoListener(CardVerifyAndGetInfoListener listener) {
- cardVerifyAndGetInfoListener = listener;
- }
-
- public void cardVerifyAndGetInfo(TangemCard card) {
- TangemApi tangemApi = App.getNetworkComponent().getRetrofitTangem().create(TangemApi.class);
-
- List requests = new ArrayList<>();
- requests.add(new CardVerifyAndGetInfo.Request.Item(Util.bytesToHex(card.getCID()), Util.bytesToHex(card.getCardPublicKey())));
-
- CardVerifyAndGetInfo.Request requestBody = new CardVerifyAndGetInfo.Request(requests);
-
- Call call = tangemApi.getCardVerifyAndGetInfo(requestBody);
- call.enqueue(new Callback() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- if (response.code() == 200) {
- CardVerifyAndGetInfo.Response cardVerifyAndGetArtworkResponse = response.body();
- cardVerifyAndGetInfoListener.onSuccess(cardVerifyAndGetArtworkResponse);
- Log.i(TAG, "cardVerifyAndGeInfo onResponse " + response.code());
- } else {
- cardVerifyAndGetInfoListener.onFail(String.valueOf(response.code()));
- Log.e(TAG, "cardVerifyAndGetInfo onResponse " + response.code());
- }
- }
-
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- cardVerifyAndGetInfoListener.onFail(t.getMessage());
- Log.e(TAG, "cardVerifyAndGetInfo onFailure " + t.getMessage());
- }
- });
- }
-
- /**
- * HTTP
- * Last version request from GitHub
- */
- private ArtworkListener artworkListener;
-
- public interface ArtworkListener {
- void onSuccess(String artworkId, InputStream inputStream, Date updateDate);
- void onFail(String message);
- }
-
- public void setArtworkListener(ArtworkListener listener) {
- artworkListener = listener;
- }
-
- public void requestArtwork(String artworkId, Date updateDate, TangemCard card) {
- TangemApi tangemApi = App.getNetworkComponent().getRetrofitTangem().create(TangemApi.class);
-
- Call call = tangemApi.getArtwork(artworkId, Util.bytesToHex(card.getCID()), Util.bytesToHex(card.getCardPublicKey()));
- call.enqueue(new Callback() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- Log.i(TAG, "getArtwork onResponse " + response.code());
- if (response.code() == 200) {
- try {
- ResponseBody body = response.body();
- if (body != null) {
- artworkListener.onSuccess(artworkId, body.byteStream(), updateDate);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- artworkListener.onFail(t.getMessage());
- Log.e(TAG, "getArtwork onFailure " + t.getMessage());
- }
- });
- }
-
/**
* HTTP
* Used in Crypto-currency course
diff --git a/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java b/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java
index d212c06822..53b250d78b 100644
--- a/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java
+++ b/app/src/main/java/com/tangem/data/network/ServerApiElectrum.java
@@ -3,11 +3,14 @@ package com.tangem.data.network;
import android.util.Log;
import com.tangem.App;
-import com.tangem.domain.wallet.Blockchain;
-import com.tangem.domain.wallet.TangemCard;
+import com.tangem.domain.wallet.TangemContext;
+import com.tangem.data.Blockchain;
import com.tangem.domain.wallet.bch.BitcoinCashNode;
import com.tangem.domain.wallet.btc.BitcoinNode;
import com.tangem.domain.wallet.btc.BitcoinNodeTestNet;
+import com.tangem.domain.wallet.ltc.LitecoinNode;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.wallet.R;
import java.io.BufferedReader;
import java.io.IOException;
@@ -41,6 +44,17 @@ 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}.electrumRequestData(..)
+ * 2. Try send every request for max 4 times,
+ * 3. If all 4 times fail call DefaultObserver.onError (defined in .electrumRequestData(..)) and than
+ * {@link ElectrumRequestDataListener}.onFail(...) callback
+ * Error can be acquired with {@link ElectrumRequest}.getError() method
+ * 4. If request network communication finished successfully then call DefaultObserver.onComplete (defined in .electrumRequestData) and than
+ * {@link ElectrumRequestDataListener}.onSuccess(...) callback
+ */
public class ServerApiElectrum {
private static String TAG = ServerApiElectrum.class.getSimpleName();
@@ -52,19 +66,49 @@ public class ServerApiElectrum {
private String host;
private int port;
- public interface ElectrumRequestDataListener {
- void onSuccess(ElectrumRequest electrumRequest);
+ private int requestsCount=0;
- void onFail(String method);
+ 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 ElectrumRequestDataListener {
+
+ /**
+ * 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 setElectrumRequestData(ElectrumRequestDataListener listener) {
electrumRequestDataListener = listener;
}
- public void electrumRequestData(TangemCard card, ElectrumRequest electrumRequest) {
+
+ /**
+ * Start process request
+ * @param ctx
+ * @param electrumRequest
+ */
+ public void electrumRequestData(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(card, electrumRequest))
+ .doOnNext(electrumRequest1 -> doElectrumRequest(ctx, electrumRequest))
.flatMap(electrumRequest1 -> {
if (electrumRequest1.answerData == null) {
@@ -81,36 +125,56 @@ public class ServerApiElectrum {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
checkElectrumDataObserver.subscribe(new DefaultObserver() {
+ //TODO remove onNext
@Override
public void onNext(ElectrumRequest v) {
if (electrumRequest.answerData != null) {
- electrumRequestDataListener.onSuccess(electrumRequest);
-// Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onNext != null");
+ Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onNext != null");
} else {
- electrumRequestDataListener.onFail(electrumRequest.getMethod());
Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onNext == null");
}
}
@Override
public void onError(Throwable e) {
- electrumRequestDataListener.onFail(electrumRequest.getMethod());
+ requestsCount--;
Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onError " + e.getMessage());
+ Log.e(TAG, String.format("%d requests left in processing",requestsCount));
+ electrumRequest.setError(ctx.getString(R.string.cannot_obtain_data_from_blockchain));
+ //setErrorOccurred(e.getMessage());//;
+ electrumRequestDataListener.onFail(electrumRequest);
}
+ /**
+ * Called after completion request processing
+ */
@Override
public void onComplete() {
-// Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onComplete");
+ requestsCount--;
+ if (electrumRequest.answerData != null) {
+ Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onComplete, answerData!=null");
+ } else {
+ Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onComplete, answerData==null");
+ }
+ Log.e(TAG, String.format("%d requests left in processing",requestsCount));
+ if (electrumRequest.answerData != null && electrumRequest.getError()==null) {
+ electrumRequestDataListener.onSuccess(electrumRequest);
+ } else {
+// if( error==null || error.isEmpty() ) setErrorOccurred(ctx.getString(R.string.cannot_obtain_data_from_blockchain));
+ electrumRequestDataListener.onFail(electrumRequest);
+ }
}
});
}
- private List doElectrumRequest(TangemCard card, ElectrumRequest electrumRequest) {
+ private void doElectrumRequest(TangemContext ctx, ElectrumRequest electrumRequest) {
String host;
int port;
String proto;
- if (card.getBlockchain() == Blockchain.BitcoinTestNet) {
+ 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();
@@ -118,48 +182,59 @@ public class ServerApiElectrum {
this.host = host;
this.port = port;
- return doElectrumRequestTcp(electrumRequest, host, port);
-
- } else if (card.getBlockchain() == Blockchain.BitcoinCash) {
+ 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;
- return doElectrumRequestTcp(electrumRequest, host, port);
+ if (proto.equals("tcp")) {
+ doElectrumRequestTcp(electrumRequest, host, port);
+ } else {
+ doElectrumRequestSsl(electrumRequest, host, port);
+ }
- } else if (card.getBlockchain() == Blockchain.Bitcoin) {
+ } 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")) {
- this.host = host;
- this.port = port;
-
- return doElectrumRequestTcp(electrumRequest, host, port);
+ doElectrumRequestTcp(electrumRequest, host, port);
} else {
- this.host = host;
- this.port = port;
+ 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();
- return doElectrumRequestSsl(electrumRequest, host, port);
+ this.host = host;
+ this.port = port;
+
+ if (proto.equals("tcp")) {
+ doElectrumRequestTcp(electrumRequest, host, port);
+ } else {
+ doElectrumRequestSsl(electrumRequest, host, port);
}
}
- return null;
}
- private List doElectrumRequestTcp(ElectrumRequest electrumRequest, String host, int port) {
- List result = new ArrayList<>();
- Collections.addAll(result, electrumRequest);
-
+ private void doElectrumRequestTcp(ElectrumRequest electrumRequest, String host, int port) {
try {
Socket socket = App.getNetworkComponent().getSocket();
socket.setSoTimeout(3000);
+ Log.i(TAG, "Start process "+electrumRequest.getMethod()+" @ "+host + ":" + port);
socket.connect(new InetSocketAddress(InetAddress.getByName(host), port));
- Log.i(TAG, host + " " + port);
try {
OutputStream os = socket.getOutputStream();
OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8");
@@ -176,37 +251,46 @@ public class ServerApiElectrum {
if (electrumRequest.answerData != null) {
Log.i(TAG, ">> " + electrumRequest.answerData);
} else {
- electrumRequest.error = "No answer from server";
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_answer));
Log.i(TAG, ">> ");
}
} catch (ConnectException e) {
- e.printStackTrace();
- electrumRequestDataListener.onFail(e.getMessage());
- Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
+ //e.printStackTrace();
+ //electrumRequestDataListener.onFail(e.getMessage());
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_connection));
+ Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
} finally {
- Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " CLOSE");
- socket.close();
+ 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.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
+ }
}
} catch (IOException e) {
- e.printStackTrace();
- electrumRequestDataListener.onFail(e.getMessage());
- Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " IOException " + e.getMessage());
+ //e.printStackTrace();
+ //electrumRequestDataListener.onFail(e.getMessage());
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
+ Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " IOException " + e.getMessage());
}
- return result;
}
- private List doElectrumRequestSsl(ElectrumRequest electrumRequest, String host, int port) {
+ 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) throws CertificateException {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
- public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@@ -234,8 +318,8 @@ public class ServerApiElectrum {
Collections.addAll(result, electrumRequest);
try {
- sslSocket = (SSLSocket) sf.createSocket(host, port);
Log.i(TAG, host + " " + port);
+ sslSocket = (SSLSocket) sf.createSocket(host, port);
try {
OutputStream os = sslSocket.getOutputStream();
OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8");
@@ -250,34 +334,41 @@ public class ServerApiElectrum {
if (electrumRequest.answerData != null) {
Log.i(TAG, ">> " + electrumRequest.answerData);
} else {
- electrumRequest.error = "No answer from server";
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_answer));
Log.i(TAG, ">> ");
}
} catch (ConnectException e) {
e.printStackTrace();
- Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_connection));
+ Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
} finally {
- Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " CLOSE");
- sslSocket.close();
+ Log.i(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " socket.close");
+ try {
+ if( sslSocket.isConnected() ) sslSocket.close();
+ }
+ catch (Exception e)
+ {
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
+ e.printStackTrace();
+ Log.e(TAG, "Can't close ssl socket");
+ }
}
} catch (IOException e) {
e.printStackTrace();
- Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " IOException " + e.getMessage());
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
+ Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " IOException " + e.getMessage());
}
-
- return result;
-
} catch (NoSuchAlgorithmException | KeyManagementException e) {
+ electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain));
Log.e(TAG, e.getMessage());
}
-
- return null;
}
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/ServerApiInfura.java b/app/src/main/java/com/tangem/data/network/ServerApiInfura.java
index fb8e407099..34b2f33f3f 100644
--- a/app/src/main/java/com/tangem/data/network/ServerApiInfura.java
+++ b/app/src/main/java/com/tangem/data/network/ServerApiInfura.java
@@ -31,6 +31,13 @@ public class ServerApiInfura {
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;
+
+ public boolean isRequestsSequenceCompleted() {
+ Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
+ return requestsCount <= 0;
+ }
+
private InfuraBodyListener infuraBodyListener;
public interface InfuraBodyListener {
@@ -44,6 +51,7 @@ public class ServerApiInfura {
}
public void infura(String method, int id, String wallet, String contract, String tx) {
+ requestsCount++;
InfuraApi infuraApi = App.getNetworkComponent().getRetrofitInfura().create(InfuraApi.class);
InfuraBody infuraBody;
@@ -77,6 +85,7 @@ public class ServerApiInfura {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
if (response.code() == 200) {
+ requestsCount--;
infuraBodyListener.onSuccess(method, response.body());
Log.i(TAG, "infura " + method + " onResponse " + response.code());
} else {
diff --git a/app/src/main/java/com/tangem/data/network/ServerURL.java b/app/src/main/java/com/tangem/data/network/ServerURL.java
index 3911f7ed5d..297b3ee60c 100644
--- a/app/src/main/java/com/tangem/data/network/ServerURL.java
+++ b/app/src/main/java/com/tangem/data/network/ServerURL.java
@@ -3,7 +3,7 @@ package com.tangem.data.network;
class ServerURL {
static final String API_TANGEM = "https://verify.tangem.com/";
static final String API_COINMARKETCAP = "https://api.coinmarketcap.com/";
- static final String API_INFURA = "https://mainnet.infura.io/";
- static final String API_ESTIMATEFEE = " https://estimatefee.com/";
+ static final String API_INFURA = "https://mainnet.infura.io/v3/";
+ static final String API_ESTIMATEFEE = "https://estimatefee.com/";
static final String API_UPDATE_VERSION = "https://raw.githubusercontent.com/";
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/data/nfc/CreateNewWalletTask.java b/app/src/main/java/com/tangem/data/nfc/CreateNewWalletTask.java
deleted file mode 100644
index bdce5f6241..0000000000
--- a/app/src/main/java/com/tangem/data/nfc/CreateNewWalletTask.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.tangem.data.nfc;
-
-import android.content.Context;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.NfcManager;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.wallet.TangemCard;
-
-public class CreateNewWalletTask extends Thread {
- public static final String TAG = CreateNewWalletTask.class.getSimpleName();
-
- private Context mContext;
- private TangemCard mCard;
- private NfcManager mNfcManager;
- private IsoDep mIsoDep;
- private CardProtocol.Notifications mNotifications;
- private boolean isCancelled = false;
-
- public CreateNewWalletTask(Context context, TangemCard card, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications) {
- mCard = card;
- mContext = context;
- mNfcManager = nfcManager;
- mIsoDep = isoDep;
- mNotifications = notifications;
- }
-
- @Override
- public void run() {
- if (mIsoDep == null) {
- return;
- }
- CardProtocol protocol = new CardProtocol(mContext, mIsoDep, mCard, mNotifications);
- mNotifications.onReadStart(protocol);
- try {
- // for Samsung's bugs -
- // Workaround for the Samsung Galaxy S5 (since the
- // first connection always hangs on transceive).
- int timeout = mIsoDep.getTimeout();
- mIsoDep.connect();
- mIsoDep.close();
- mIsoDep.connect();
- mIsoDep.setTimeout(timeout);
- try {
- mNotifications.onReadProgress(protocol, 5);
-
- Log.i(TAG, "[-- Start create new wallet --]");
-
- if (isCancelled) return;
- protocol.run_VerifyCard();
-
- Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
-
- mNotifications.onReadProgress(protocol, 30);
- if (isCancelled) return;
-
-// if (mCard.getPauseBeforePIN2() > 0) {
-// mNotifications.onReadWait(mCard.getPauseBeforePIN2());
-// }
-// try {
- protocol.run_CreateWallet(PINStorage.getPIN2());
-// } finally {
-// mNotifications.onReadWait(0);
-// }
- mNotifications.onReadProgress(protocol, 60);
- if (isCancelled) return;
-
- protocol.run_Read();
-
- } finally {
- mNfcManager.ignoreTag(mIsoDep.getTag());
- }
- } catch (Exception e) {
- e.printStackTrace();
- protocol.setError(e);
-
- } finally {
- Log.i(TAG, "[-- Finish create new wallet --]");
- mNotifications.onReadFinish(protocol);
- }
- }
-
- public void cancel(Boolean AllowInterrupt) {
- try {
- if (isAlive()) {
- isCancelled = true;
- join(500);
- }
- if (isAlive() && AllowInterrupt) {
- interrupt();
- mNotifications.onReadCancel();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/data/nfc/PurgeTask.java b/app/src/main/java/com/tangem/data/nfc/PurgeTask.java
deleted file mode 100644
index a24c71e24e..0000000000
--- a/app/src/main/java/com/tangem/data/nfc/PurgeTask.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.tangem.data.nfc;
-
-import android.content.Context;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.NfcManager;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.wallet.TangemCard;
-
-public class PurgeTask extends Thread {
- public static final String TAG = PurgeTask.class.getSimpleName();
-
- private String txOutAddress;
- private Context mContext;
- private TangemCard mCard;
- private NfcManager mNfcManager;
- private IsoDep mIsoDep;
- private CardProtocol.Notifications mNotifications;
- private boolean isCancelled = false;
-
- public PurgeTask(Context context, TangemCard card, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications) {
- mCard = card;
- mContext = context;
- mNfcManager = nfcManager;
- mIsoDep = isoDep;
- mNotifications = notifications;
- }
-
- @Override
- public void run() {
- if (mIsoDep == null) {
- return;
- }
- CardProtocol protocol = new CardProtocol(mContext, mIsoDep, mCard, mNotifications);
-
- mNotifications.onReadStart(protocol);
- try {
-
- // for Samsung's bugs - Workaround for the Samsung Galaxy S5 (since the first connection always hangs on transceive).
- int timeout = mIsoDep.getTimeout();
- mIsoDep.connect();
- mIsoDep.close();
- mIsoDep.connect();
- mIsoDep.setTimeout(timeout);
- try {
- mNotifications.onReadProgress(protocol, 5);
-
- Log.i(TAG, "[-- Start purge --]");
-
- if (isCancelled) return;
-
- if (mCard.getPauseBeforePIN2() > 0) {
- mNotifications.onReadWait(mCard.getPauseBeforePIN2());
- }
-
-// try {
- protocol.run_PurgeWallet(PINStorage.getPIN2());
-// } finally {
-// mNotifications.onReadWait(0);
-// }
-
- mNotifications.onReadProgress(protocol, 50);
-
- protocol.run_Read();
-
- mNotifications.onReadProgress(protocol, 100);
-
- if (isCancelled)
- return;
-
- } finally {
- mNfcManager.ignoreTag(mIsoDep.getTag());
- mNotifications.onReadWait(0);
- }
- } catch (Exception e) {
- e.printStackTrace();
- protocol.setError(e);
-
- } finally {
- Log.i(TAG, "[-- Finish purge --]");
- mNotifications.onReadFinish(protocol);
- }
- }
-
- public void cancel(Boolean AllowInterrupt) {
- try {
- if (isAlive()) {
- isCancelled = true;
- join(500);
- }
- if (isAlive() && AllowInterrupt) {
- interrupt();
- mNotifications.onReadCancel();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/data/nfc/ReadCardInfoTask.java b/app/src/main/java/com/tangem/data/nfc/ReadCardInfoTask.java
deleted file mode 100644
index f0fa541df9..0000000000
--- a/app/src/main/java/com/tangem/data/nfc/ReadCardInfoTask.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package com.tangem.data.nfc;
-
-import android.content.Context;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.NfcManager;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.wallet.TangemCard;
-import com.tangem.util.Util;
-
-import java.util.ArrayList;
-
-public class ReadCardInfoTask extends Thread {
- public static final String TAG = ReadCardInfoTask.class.getSimpleName();
-
- private IsoDep mIsoDep;
- private CardProtocol.Notifications mNotifications;
- private boolean isCancelled = false;
- private Context mContext;
- private NfcManager mNfcManager;
-
- // this fields are static to optimize process when need enter pin and scan card again
- private static ArrayList lastRead_UnsuccessfullPINs = new ArrayList<>();
- private static TangemCard.EncryptionMode lastRead_Encryption = null;
- private static String lastRead_UID;
-
- public static void resetLastReadInfo() {
- lastRead_UID="";
- lastRead_Encryption=null;
- lastRead_UnsuccessfullPINs.clear();
- }
-
- public ReadCardInfoTask(Context context, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications) {
- mContext = context;
- mIsoDep = isoDep;
- mNotifications = notifications;
- mNfcManager = nfcManager;
-// ReadCardInfoTask.lastRead_UID = lastRead_UID;
- }
-
- @Override
- public void run() {
- if (mIsoDep == null) {
- return;
- }
- try {
- // for Samsung's bugs -
- // Workaround for the Samsung Galaxy S5 (since the
- // first connection always hangs on transceive).
- int timeout = mIsoDep.getTimeout();
- mIsoDep.connect();
- mIsoDep.close();
- mIsoDep.connect();
- mIsoDep.setTimeout(timeout);
- try {
- CardProtocol protocol = new CardProtocol(mContext, mIsoDep, mNotifications);
- mNotifications.onReadStart(protocol);
- try {
- mNotifications.onReadProgress(protocol, 5);
-
- byte[] UID = mIsoDep.getTag().getId();
- String sUID = Util.byteArrayToHexString(UID);
- if (!lastRead_UID.equals(sUID)) {
- resetLastReadInfo();
- }
-
- Log.i(TAG, "[-- Start read card info --]");
-
- if (isCancelled) return;
-
- protocol.setPIN(PINStorage.getDefaultPIN());
- protocol.clearReadResult();
-
- if (lastRead_Encryption == null) {
- Log.i(TAG, "Try get supported encryption mode");
- protocol.run_GetSupportedEncryption();
- } else {
- Log.i(TAG, "Use already defined encryption mode: " + lastRead_Encryption.name());
- protocol.getCard().encryptionMode = lastRead_Encryption;
- }
-
- if (protocol.haveReadResult()) {
- //already have read result (obtained while get supported encryption), only read issuer data and define offline balance
- protocol.parseReadResult();
- protocol.run_ReadWriteIssuerData();
- mNotifications.onReadProgress(protocol, 60);
- PINStorage.setLastUsedPIN(protocol.getCard().getPIN());
- } else {
- //don't have read result - may be don't get supported encryption on this try, need encryption or need another PIN
- if (lastRead_Encryption == null) {
- // we try get supported encryption on this time
- lastRead_Encryption = protocol.getCard().encryptionMode;
- if (protocol.getCard().encryptionMode == TangemCard.EncryptionMode.None) {
- // default pin not accepted
- lastRead_UnsuccessfullPINs.add(PINStorage.getDefaultPIN());
- }
- }
-
- boolean pinFound = false;
- for (String PIN : PINStorage.getPINs()) {
- Log.e(TAG, "PIN: " + PIN);
-
- boolean skipPin = false;
- for (int i = 0; i < lastRead_UnsuccessfullPINs.size(); i++) {
- if (lastRead_UnsuccessfullPINs.get(i).equals(PIN)) {
- skipPin = true;
- break;
- }
- }
-
- if (skipPin) {
- Log.e(TAG, "Skip PIN - already checked before");
- continue;
- }
-
- try {
- protocol.setPIN(PIN);
- if (protocol.getCard().encryptionMode != TangemCard.EncryptionMode.None) {
- protocol.CreateProtocolKey();
- }
- protocol.run_Read();
- mNotifications.onReadProgress(protocol, 60);
- PINStorage.setLastUsedPIN(PIN);
- pinFound = true;
- protocol.getCard().setPIN(PIN);
- break;
- } catch (CardProtocol.TangemException_InvalidPIN e) {
- Log.e(TAG, e.getMessage());
- lastRead_UnsuccessfullPINs.add(PIN);
- }
- }
- if (!pinFound) {
- throw new CardProtocol.TangemException_InvalidPIN("No valid PIN found!");
- }
- }
-
- protocol.run_CheckPIN2isDefault();
-
- } catch (Exception e) {
- e.printStackTrace();
- protocol.setError(e);
-
- } finally {
- Log.i(TAG, "[-- Finish read card info --]");
- mNotifications.onReadFinish(protocol);
- }
- } finally {
- mNfcManager.ignoreTag(mIsoDep.getTag());
- }
- } catch (Exception e) {
- e.printStackTrace();
- mNfcManager.notifyReadResult(false);
- }
- }
-
- public void cancel(Boolean AllowInterrupt) {
- try {
- if (isAlive()) {
- isCancelled = true;
- join(500);
- }
- if (isAlive() && AllowInterrupt) {
- interrupt();
- mNotifications.onReadCancel();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/data/nfc/SignPaymentTask.java b/app/src/main/java/com/tangem/data/nfc/SignPaymentTask.java
deleted file mode 100644
index 03499bc05f..0000000000
--- a/app/src/main/java/com/tangem/data/nfc/SignPaymentTask.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package com.tangem.data.nfc;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.NfcManager;
-import com.tangem.domain.wallet.Blockchain;
-import com.tangem.domain.wallet.CoinEngine;
-import com.tangem.domain.wallet.CoinEngineFactory;
-import com.tangem.domain.wallet.TangemContext;
-import com.tangem.presentation.activity.SendTransactionActivity;
-import com.tangem.presentation.activity.SignPaymentActivity;
-import com.tangem.domain.wallet.BTCUtils;
-
-import java.io.IOException;
-
-public class SignPaymentTask extends Thread {
- public static final String TAG = SignPaymentTask.class.getSimpleName();
-
- private CoinEngine.Amount txAmount;
- private CoinEngine.Amount txFee;
- private Boolean txIncFee = true;
-
- public void SetTransactionValue(CoinEngine.Amount amount, CoinEngine.Amount fee, Boolean incfee) {
- txAmount = amount;
- txFee = fee;
- txIncFee = incfee;
- }
-
- private String txOutAddress;
- private Activity mContext;
- private TangemContext mCtx;
- private NfcManager mNfcManager;
- private IsoDep mIsoDep;
- private CardProtocol.Notifications mNotifications;
- private boolean isCancelled = false;
-
- public SignPaymentTask(Activity context, TangemContext ctx, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications, CoinEngine.Amount amount, CoinEngine.Amount fee, Boolean IncFee, String outAddress) {
- mCtx=ctx;
- mContext = context;
- mNfcManager = nfcManager;
- mIsoDep = isoDep;
- mNotifications = notifications;
- txOutAddress = outAddress;
- SetTransactionValue(amount, fee, IncFee);
- }
-
- @Override
- public void run() {
- if (mIsoDep == null) {
- return;
- }
- CardProtocol protocol = new CardProtocol(mContext, mIsoDep, mCtx.getCard(), mNotifications);
-
- mNotifications.onReadStart(protocol);
- try {
-
- // for Samsung's bugs -
- // Workaround for the Samsung Galaxy S5 (since the
- // first connection always hangs on transceive).
- int timeout = mIsoDep.getTimeout();
- mIsoDep.connect();
- mIsoDep.close();
- mIsoDep.connect();
- mIsoDep.setTimeout(timeout);
- try {
- mNotifications.onReadProgress(protocol, 5);
-
- Log.i(TAG, "[-- Start sign payment --]");
-
- if (isCancelled) return;
- protocol.run_Read(false);
- protocol.run_VerifyCard();
-
- Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
-
- mNotifications.onReadProgress(protocol, 30);
- if (isCancelled) return;
-//
-// if (mCard.getBlockchain() == Blockchain.Ethereum) {
-// SignETH_TX(protocol);
-// } else {
-// SignBTC_TX(protocol);
-// }
-
- CoinEngine engine = CoinEngineFactory.INSTANCE.create(mCtx);
- if (engine != null) {
- if (mCtx.getCard().getPauseBeforePIN2() > 0) {
- mNotifications.onReadWait(mCtx.getCard().getPauseBeforePIN2());
- }
-
- byte[] tx = null;
- try {
- tx = engine.sign(txFee, txAmount, txIncFee, txOutAddress, protocol);
- }
- catch (IOException e) {
- e.printStackTrace();
- protocol.setError(e);
- } finally {
- mNotifications.onReadWait(0);
- }
-
- if (tx != null) {
- // TODO - move to engine!!!
- String txStr = BTCUtils.toHex(tx);
- if (mCtx.getBlockchain() == Blockchain.Ethereum || mCtx.getBlockchain() == Blockchain.EthereumTestNet || mCtx.getBlockchain() == Blockchain.Token) {
- txStr = String.format("0x%s", txStr);
- }
-
- Intent intent = new Intent(mContext, SendTransactionActivity.class);
- mCtx.saveToIntent(intent);
- intent.putExtra(SendTransactionActivity.EXTRA_TX, txStr);
- mContext.startActivityForResult(intent, SignPaymentActivity.REQUEST_CODE_SEND_PAYMENT);
- }
- }
- mNotifications.onReadProgress(protocol, 100);
-
-
- if (isCancelled) return;
-
- } finally {
- mNfcManager.ignoreTag(mIsoDep.getTag());
- mNotifications.onReadWait(0);
- }
- } catch (CardProtocol.TangemException_InvalidPIN e) {
- e.printStackTrace();
- protocol.setError(e);
- } catch (CardProtocol.TangemException_WrongAmount e) {
- e.printStackTrace();
- protocol.setError(e);
- } catch (Exception e) {
- e.printStackTrace();
- protocol.setError(e);
-
- } finally {
- Log.i(TAG, "[-- Finish sign payment --]");
- mNotifications.onReadFinish(protocol);
- }
- }
-
- public void cancel(Boolean AllowInterrupt) {
- try {
- if (isAlive()) {
- isCancelled = true;
- join(500);
- }
- if (isAlive() && AllowInterrupt) {
- interrupt();
- mNotifications.onReadCancel();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/data/nfc/SwapPINTask.java b/app/src/main/java/com/tangem/data/nfc/SwapPINTask.java
deleted file mode 100644
index 0e18d6e8bc..0000000000
--- a/app/src/main/java/com/tangem/data/nfc/SwapPINTask.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.tangem.data.nfc;
-
-import android.content.Context;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.NfcManager;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.wallet.TangemCard;
-
-public class SwapPINTask extends Thread {
- public static final String TAG = SwapPINTask.class.getSimpleName();
-
- private Context mContext;
- private TangemCard mCard;
- private NfcManager mNfcManager;
- private String newPIN, newPIN2;
- private IsoDep mIsoDep;
- private CardProtocol.Notifications mNotifications;
- private boolean isCancelled = false;
-
- public SwapPINTask(Context context, TangemCard card, NfcManager nfcManager, String newPIN, String newPIN2, IsoDep isoDep, CardProtocol.Notifications notifications) {
- this.newPIN = newPIN;
- this.newPIN2 = newPIN2;
- mCard = card;
- mContext = context;
- mNfcManager = nfcManager;
- mIsoDep = isoDep;
- mNotifications = notifications;
- }
-
- @Override
- public void run() {
- if (mIsoDep == null) {
- return;
- }
- CardProtocol protocol = new CardProtocol(mContext, mIsoDep, mCard, mNotifications);
-
- mNotifications.onReadStart(protocol);
- try {
-
- // for Samsung's bugs -
- // Workaround for the Samsung Galaxy S5 (since the
- // first connection always hangs on transceive).
- int timeout = mIsoDep.getTimeout();
- mIsoDep.connect();
- mIsoDep.close();
- mIsoDep.connect();
- mIsoDep.setTimeout(timeout);
- try {
-
- mNotifications.onReadProgress(protocol, 5);
-
- Log.i(TAG, "[-- Start swap pin --]");
-
- if (isCancelled) return;
-
- if (mCard.getPauseBeforePIN2() > 0) {
- mNotifications.onReadWait(mCard.getPauseBeforePIN2());
- }
-
-// try {
- protocol.run_SetPIN(PINStorage.getPIN2(), newPIN, newPIN2, false);
- protocol.setPIN(newPIN);
- mCard.setPIN(newPIN);
-// } finally {
-// mNotifications.onReadWait(0);
-// }
-
- mNotifications.onReadProgress(protocol, 50);
-
- protocol.run_Read();
-
- mNotifications.onReadProgress(protocol, 100);
-
- } finally {
- mNfcManager.ignoreTag(mIsoDep.getTag());
- mNotifications.onReadWait(0);
- }
- } catch (Exception e) {
- e.printStackTrace();
- protocol.setError(e);
-
- } finally {
- Log.i(TAG, "[-- Finish purge --]");
- mNotifications.onReadFinish(protocol);
- }
- }
-
- public void cancel(Boolean AllowInterrupt) {
- try {
- if (isAlive()) {
- isCancelled = true;
- join(500);
- }
- if (isAlive() && AllowInterrupt) {
- interrupt();
- mNotifications.onReadCancel();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/data/nfc/VerifyCardTask.java b/app/src/main/java/com/tangem/data/nfc/VerifyCardTask.java
deleted file mode 100644
index 9db5b0f682..0000000000
--- a/app/src/main/java/com/tangem/data/nfc/VerifyCardTask.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.tangem.data.nfc;
-
-import android.content.Context;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.Firmwares;
-import com.tangem.domain.cardReader.NfcManager;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.wallet.TangemCard;
-
-import java.util.Arrays;
-
-/**
- * Created by dvol on 04.02.2018.
- */
-
-public class VerifyCardTask extends Thread {
- public static final String TAG = VerifyCardTask.class.getSimpleName();
-
- private IsoDep mIsoDep;
- private CardProtocol.Notifications mNotifications;
- private boolean isCancelled = false;
- private Context mContext;
- private TangemCard mCard;
- private NfcManager mNfcManager;
-
- public VerifyCardTask(Context context, TangemCard card, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications) {
- mCard = card;
- mContext = context;
- mIsoDep = isoDep;
- mNotifications = notifications;
- mNfcManager = nfcManager;
- }
-
- @Override
- public void run() {
- if (mIsoDep == null) {
- return;
- }
- try {
- // for Samsung's bugs -
- // Workaround for the Samsung Galaxy S5 (since the
- // first connection always hangs on transceive).
- int timeout = mIsoDep.getTimeout();
- mIsoDep.connect();
- mIsoDep.close();
- mIsoDep.connect();
- mIsoDep.setTimeout(timeout);
- try {
- CardProtocol protocol = new CardProtocol(mContext, mIsoDep, mCard, mNotifications);
- mNotifications.onReadStart(protocol);
- try {
- mNotifications.onReadProgress(protocol, 5);
-
- Log.i(TAG, "[-- Start verify card --]");
-
- if (isCancelled) return;
-
- String PIN = mCard.getPIN();
- protocol.setPIN(PIN);
- protocol.run_Read(false);
- PINStorage.setLastUsedPIN(PIN);
- mNotifications.onReadProgress(protocol, 20);
- if (isCancelled) return;
- protocol.run_VerifyCard();
- mNotifications.onReadProgress(protocol, 50);
- Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
- if (isCancelled) return;
- if (protocol.getCard().getStatus() == TangemCard.Status.Loaded) {
- protocol.run_CheckWalletWithSignatureVerify();
- mNotifications.onReadProgress(protocol, 80);
- }
- if (isCancelled) return;
- Firmwares.VerifyCodeRecord record=Firmwares.selectRandomVerifyCodeBlock(mCard.getFirmwareVersion());
- if (isCancelled) return;
- if( record!=null ) {
- byte[] returnedDigest = protocol.run_VerifyCode(record.hashAlg, record.blockIndex, record.blockCount, record.challenge);
- mCard.setCodeConfirmed(Arrays.equals(returnedDigest, record.digest));
- }else{
- mCard.setCodeConfirmed(null);
- }
- mNotifications.onReadProgress(protocol, 90);
- } catch (Exception e) {
- e.printStackTrace();
- protocol.setError(e);
-
- } finally {
- Log.i(TAG, "[-- Finish verify card --]");
- mNotifications.onReadFinish(protocol);
- }
- } finally {
- mNfcManager.ignoreTag(mIsoDep.getTag());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void cancel(Boolean AllowInterrupt) {
- try {
- if (isAlive()) {
- isCancelled = true;
- join(500);
- }
- if (isAlive() && AllowInterrupt) {
- interrupt();
- mNotifications.onReadCancel();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/di/Navigator.kt b/app/src/main/java/com/tangem/di/Navigator.kt
index 15eb86bb96..3a620229c4 100644
--- a/app/src/main/java/com/tangem/di/Navigator.kt
+++ b/app/src/main/java/com/tangem/di/Navigator.kt
@@ -2,14 +2,9 @@ package com.tangem.di
import android.app.Activity
import android.nfc.Tag
-import android.os.Bundle
-import com.tangem.domain.wallet.CoinData
-import com.tangem.domain.wallet.TangemCard
-import com.tangem.presentation.activity.EmptyWalletActivity
-import com.tangem.presentation.activity.LoadedWalletActivity
-import com.tangem.presentation.activity.MainActivity
-import com.tangem.presentation.activity.VerifyCardActivity
-import com.tangem.presentation.fragment.LoadedWallet
+import com.tangem.Constant
+import com.tangem.domain.wallet.TangemContext
+import com.tangem.presentation.activity.*
class Navigator {
@@ -17,28 +12,68 @@ class Navigator {
context.startActivity(MainActivity.callingIntent(context))
}
- fun showLoadedWallet(context: Activity, lastTag: Tag, cardInfo: Bundle) {
- context.startActivityForResult(LoadedWalletActivity.callingIntent(context, lastTag, cardInfo), MainActivity.REQUEST_CODE_SHOW_CARD_ACTIVITY)
+ fun showLogo(context: Activity, autoHide: Boolean) {
+ context.startActivity(LogoActivity.callingIntent(context, autoHide))
}
- fun showEmptyWallet(context: Activity) {
- context.startActivity(EmptyWalletActivity.callingIntent(context))
+ fun showPinSave(context: Activity, hasPin2: Boolean) {
+ context.startActivity(PinSaveActivity.callingIntent(context, hasPin2))
}
- fun showVerifyCard(context: Activity, card: TangemCard, coinData: CoinData, message: String, error: String) {
- context.startActivityForResult(VerifyCardActivity.callingIntent(context, card, coinData, message, error), LoadedWallet.REQUEST_CODE_VERIFY_CARD)
+ fun showPinRequest(context: Activity, mode: String) {
+ context.startActivityForResult(PinRequestActivity.callingIntent(context, mode), Constant.REQUEST_CODE_ENTER_PIN_ACTIVITY)
}
- fun showPinSwap(context: Activity) {
-
+ fun showQrScanActivity(context: Activity, requestCode: Int) {
+ context.startActivityForResult(QrScanActivity.callingIntent(context), requestCode)
}
-// fun showPreparePayment(context: Activity) {
-//
-// }
-//
-// fun showCreateNewWallet(context: Activity) {
-//
-// }
+ fun showPinRequestRequestPin(context: Activity, mode: String, ctx: TangemContext, newPin: String) {
+ context.startActivityForResult(PinRequestActivity.callingIntentRequestPin(context, mode, ctx, newPin), Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ }
+
+ fun showPinRequestRequestPin2(context: Activity, mode: String, ctx: TangemContext, newPin2: String) {
+ context.startActivityForResult(PinRequestActivity.callingIntentRequestPin2(context, mode, ctx, newPin2), Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ }
+
+ fun showPinRequestRequestPin2(context: Activity, mode: String, ctx: TangemContext) {
+ context.startActivityForResult(PinRequestActivity.callingIntentRequestPin2(context, mode, ctx), Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ }
+
+ fun showPinRequestConfirmNewPin(context: Activity, mode: String, newPin: String) {
+ context.startActivityForResult(PinRequestActivity.callingIntentConfirmPin(context, mode, newPin), Constant.REQUEST_CODE_ENTER_NEW_PIN)
+ }
+
+ fun showPinRequestConfirmNewPin2(context: Activity, mode: String, newPin2: String) {
+ context.startActivityForResult(PinRequestActivity.callingIntentConfirmPin2(context, mode, newPin2), Constant.REQUEST_CODE_ENTER_NEW_PIN2)
+ }
+
+ fun showLoadedWallet(context: Activity, lastTag: Tag, ctx: TangemContext) {
+ context.startActivityForResult(LoadedWalletActivity.callingIntent(context, lastTag, ctx), Constant.REQUEST_CODE_SHOW_CARD_ACTIVITY)
+ }
+
+ fun showEmptyWallet(context: Activity, ctx: TangemContext) {
+ context.startActivity(EmptyWalletActivity.callingIntent(context, ctx))
+ }
+
+ fun showVerifyCard(context: Activity, ctx: TangemContext) {
+ context.startActivityForResult(VerifyCardActivity.callingIntent(context, ctx), Constant.REQUEST_CODE_VERIFY_CARD)
+ }
+
+ fun showPinSwap(context: Activity, newPIN: String, newPIN2: String) {
+ context.startActivityForResult(PinSwapActivity.callingIntent(context, newPIN, newPIN2), Constant.REQUEST_CODE_SWAP_PIN)
+ }
+
+ fun showPurge(context: Activity, ctx: TangemContext) {
+ context.startActivityForResult(PurgeActivity.callingIntent(context, ctx), Constant.REQUEST_CODE_PURGE)
+ }
+
+ fun showPreparePayment(context: Activity, ctx: TangemContext) {
+ context.startActivityForResult(PreparePaymentActivity.callingIntent(context, ctx), Constant.REQUEST_CODE_SEND_PAYMENT)
+ }
+
+ fun showCreateNewWallet(context: Activity, ctx: TangemContext) {
+ context.startActivityForResult(CreateNewWalletActivity.callingIntent(context, ctx), Constant.REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/di/NavigatorComponent.java b/app/src/main/java/com/tangem/di/NavigatorComponent.java
index dc6bf5a5fc..23bd390f21 100644
--- a/app/src/main/java/com/tangem/di/NavigatorComponent.java
+++ b/app/src/main/java/com/tangem/di/NavigatorComponent.java
@@ -4,6 +4,9 @@ import com.tangem.presentation.activity.EmptyWalletActivity;
import com.tangem.presentation.activity.LoadedWalletActivity;
import com.tangem.presentation.activity.LogoActivity;
import com.tangem.presentation.activity.MainActivity;
+import com.tangem.presentation.activity.PrepareCryptonitOtherApiWithdrawalActivity;
+import com.tangem.presentation.activity.PrepareKrakenWithdrawalActivity;
+import com.tangem.presentation.activity.PreparePaymentActivity;
import com.tangem.presentation.activity.VerifyCardActivity;
import javax.inject.Singleton;
@@ -20,6 +23,12 @@ public interface NavigatorComponent {
void inject(MainActivity activity);
+ void inject(PreparePaymentActivity activity);
+
+ void inject(PrepareCryptonitOtherApiWithdrawalActivity activity);
+
+ void inject(PrepareKrakenWithdrawalActivity activity);
+
void inject(LoadedWalletActivity activity);
void inject(VerifyCardActivity activity);
diff --git a/app/src/main/java/com/tangem/di/NetworkComponent.java b/app/src/main/java/com/tangem/di/NetworkComponent.java
index b8ac3affa5..4de9763426 100644
--- a/app/src/main/java/com/tangem/di/NetworkComponent.java
+++ b/app/src/main/java/com/tangem/di/NetworkComponent.java
@@ -20,9 +20,6 @@ public interface NetworkComponent {
@Named(Server.ApiEstimatefee.URL_ESTIMATEFEE)
Retrofit getRetrofitEstimatefee();
- @Named(Server.ApiTangem.URL_TANGEM)
- Retrofit getRetrofitTangem();
-
@Named(Server.ApiCoinmarket.URL_COINMARKET)
Retrofit getRetrofitCoinmarketcap();
diff --git a/app/src/main/java/com/tangem/di/NetworkModule.java b/app/src/main/java/com/tangem/di/NetworkModule.java
index 5fbadb3e82..86e669389e 100644
--- a/app/src/main/java/com/tangem/di/NetworkModule.java
+++ b/app/src/main/java/com/tangem/di/NetworkModule.java
@@ -41,17 +41,6 @@ class NetworkModule {
.build();
}
- @Singleton
- @Provides
- @Named(Server.ApiTangem.URL_TANGEM)
- Retrofit provideRetrofitTangem() {
- return new Retrofit.Builder()
- .baseUrl(Server.ApiTangem.URL_TANGEM)
- .addConverterFactory(GsonConverterFactory.create())
- .client(createOkHttpClient())
- .build();
- }
-
@Singleton
@Provides
@Named(Server.ApiUpdateVersion.URL_UPDATE_VERSION)
diff --git a/app/src/main/java/com/tangem/domain/LitecoinNode.kt b/app/src/main/java/com/tangem/domain/LitecoinNode.kt
deleted file mode 100644
index 5b4cad42dd..0000000000
--- a/app/src/main/java/com/tangem/domain/LitecoinNode.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.tangem.domain
-
-enum class LitecoinNode(val host: String, val port: Int) {
- n1("ltc.rentonisk.com", 50001),
- n2("backup.electrum-ltc.org", 50001),
- n3("node.ispol.sk", 50003),
- n4("electrum-ltc.wilv.in", 50001),
- n5("ltc01.knas.systems", 50003),
- n6("electrumx.nmdps.net", 9433),
- n7("e-3.claudioboxx.com", 50003),
- n8("electrum.ltc.xurious.com", 50001),
- n9("e-1.claudioboxx.com", 50003),
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/cardReader/SettingsMask.java b/app/src/main/java/com/tangem/domain/cardReader/SettingsMask.java
deleted file mode 100644
index 2472e06a33..0000000000
--- a/app/src/main/java/com/tangem/domain/cardReader/SettingsMask.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.tangem.domain.cardReader;
-
-/**
- * Created by dvol on 07.03.2018.
- */
-
-public class SettingsMask {
- public static final int IsReusable = 0x0001;
- public static final int UseActivation = 0x0002;
- public static final int UseBlock = 0x0008;
-
- public static final int AllowSwapPIN = 0x0010;
- public static final int AllowSwapPIN2 = 0x0020;
- public static final int UseCVC = 0x0040;
- public static final int ForbidDefaultPIN = 0x0080;
-
- public static final int UseOneCommandAtTime = 0x0100;
- public static final int UseNDEF = 0x0200;
- public static final int UseDynamicNDEF = 0x0400;
- public static final int SmartSecurityDelay = 0x0800;
-
- public static final int Protocol_AllowUnencrypted = 0x1000;
- public static final int Protocol_AllowStaticEncryption = 0x2000;
-
- public static final int ProtectIssuerDataAgainstReplay = 0x4000;
-
-}
diff --git a/app/src/main/java/com/tangem/domain/wallet/BCHUtils.java b/app/src/main/java/com/tangem/domain/wallet/BCHUtils.java
new file mode 100644
index 0000000000..91da8e43cf
--- /dev/null
+++ b/app/src/main/java/com/tangem/domain/wallet/BCHUtils.java
@@ -0,0 +1,345 @@
+package com.tangem.domain.wallet;
+
+/**
+ * Created by Ilia on 29.09.2017.
+ */
+
+import android.util.Log;
+
+import com.tangem.domain.wallet.btc.BitcoinException;
+import com.tangem.domain.wallet.btc.BitcoinOutputStream;
+import com.tangem.domain.wallet.btc.BtcData;
+import com.tangem.util.CryptoUtil;
+import com.tangem.util.FormatUtil;
+import com.tangem.tangemcard.util.Util;
+
+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.Raw);
+ if (rawTxByte == null || current.Raw.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/domain/wallet/BTCUtils.java b/app/src/main/java/com/tangem/domain/wallet/BTCUtils.java
index c32c5bcad9..973d4ed231 100644
--- a/app/src/main/java/com/tangem/domain/wallet/BTCUtils.java
+++ b/app/src/main/java/com/tangem/domain/wallet/BTCUtils.java
@@ -11,21 +11,14 @@ import com.tangem.domain.wallet.btc.BitcoinOutputStream;
import com.tangem.domain.wallet.btc.BtcData;
import com.tangem.util.CryptoUtil;
import com.tangem.util.FormatUtil;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.math.BigDecimal;
import java.math.BigInteger;
-import java.math.RoundingMode;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.List;
-import java.util.Stack;
@SuppressWarnings({"WeakerAccess", "TryWithIdenticalCatches", "unused"})
public final class BTCUtils {
diff --git a/app/src/main/java/com/tangem/domain/wallet/BalanceValidator.java b/app/src/main/java/com/tangem/domain/wallet/BalanceValidator.java
index edb0ea6ddc..e5ada4f494 100644
--- a/app/src/main/java/com/tangem/domain/wallet/BalanceValidator.java
+++ b/app/src/main/java/com/tangem/domain/wallet/BalanceValidator.java
@@ -1,5 +1,6 @@
package com.tangem.domain.wallet;
+import com.tangem.tangemcard.data.TangemCard;
import com.tangem.wallet.R;
public class BalanceValidator {
diff --git a/app/src/main/java/com/tangem/domain/wallet/CoinData.java b/app/src/main/java/com/tangem/domain/wallet/CoinData.java
index a96b5dbb74..9447ee6935 100644
--- a/app/src/main/java/com/tangem/domain/wallet/CoinData.java
+++ b/app/src/main/java/com/tangem/domain/wallet/CoinData.java
@@ -3,8 +3,8 @@ package com.tangem.domain.wallet;
import android.os.Bundle;
import android.util.Log;
-import java.math.BigDecimal;
-import java.math.BigInteger;
+import com.tangem.data.Blockchain;
+
import java.util.concurrent.atomic.AtomicInteger;
public abstract class CoinData {
@@ -12,6 +12,24 @@ 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;
}
@@ -23,12 +41,14 @@ public abstract class CoinData {
}
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("FailedBalance"))
+// failedBalanceRequestCounter = new AtomicInteger(B.getInt("FailedBalance"));
if (B.containsKey("isBalanceEqual")) setIsBalanceEqual(B.getBoolean("isBalanceEqual"));
@@ -40,10 +60,12 @@ public abstract class CoinData {
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());
+// if (failedBalanceRequestCounter != null)
+// B.putInt("FailedBalance", failedBalanceRequestCounter.get());
B.putFloat("rate", rate);
B.putFloat("rateAlter", rateAlter);
@@ -121,25 +143,32 @@ public abstract class CoinData {
public void clearInfo() {
setIsBalanceEqual(false);
+ setBalanceReceived(false); // TODO check
+ setValidationNodeDescription("");
+ minFee=null;
+ maxFee=null;
+ normalFee=null;
+ rate=0f;
+ rateAlter=0f;
}
- 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 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;
@@ -161,7 +190,7 @@ public abstract class CoinData {
this.validationNodeDescription = validationNodeDescription;
}
-
-
-
+ public CoinEngine.Amount minFee = null;
+ public CoinEngine.Amount normalFee = null;
+ public CoinEngine.Amount maxFee = null;
}
diff --git a/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java b/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java
index b13a5c280b..83b0f987bf 100644
--- a/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java
+++ b/app/src/main/java/com/tangem/domain/wallet/CoinEngine.java
@@ -3,7 +3,8 @@ package com.tangem.domain.wallet;
import android.net.Uri;
import android.text.InputFilter;
-import com.tangem.domain.cardReader.CardProtocol;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.tasks.SignTask;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -20,41 +21,41 @@ import java.util.Locale;
public abstract class CoinEngine {
+
public static class InternalAmount extends BigDecimal {
private String currency;
public InternalAmount() {
super(0);
- currency="";
+ currency = "";
}
public InternalAmount(String amountString, String currency) {
- super(amountString.replace(',','.'));
- this.currency=currency;
+ super(amountString.replace(',', '.'));
+ this.currency = currency;
}
public InternalAmount(long amount, String currency) {
super(amount);
- this.currency=currency;
+ this.currency = currency;
}
public InternalAmount(BigDecimal amount, String currency) {
super(amount.unscaledValue(), amount.scale());
- this.currency=currency;
+ this.currency = currency;
}
public InternalAmount(BigInteger amount, String currency) {
super(new BigDecimal(amount).unscaledValue(), new BigDecimal(amount).scale());
- this.currency=currency;
+ this.currency = currency;
}
- public boolean notZero()
- {
- return compareTo(BigDecimal.ZERO)>0;
+ public boolean notZero() {
+ return compareTo(BigDecimal.ZERO) > 0;
}
public boolean isZero() {
- return compareTo(BigDecimal.ZERO)==0;
+ return compareTo(BigDecimal.ZERO) == 0;
}
public String getCurrency() {
@@ -72,7 +73,7 @@ public abstract class CoinEngine {
df.setGroupingUsed(false);
- BigDecimal bd=new BigDecimal(unscaledValue(), scale());
+ BigDecimal bd = new BigDecimal(unscaledValue(), scale());
bd.setScale(decimals, ROUND_DOWN);
return df.format(bd);
}
@@ -93,11 +94,11 @@ public abstract class CoinEngine {
public Amount() {
super(0);
- currency="";
+ currency = "";
}
public Amount(String amountString, String currency) {
- super(amountString.replace(',','.'));
+ super(amountString.replace(',', '.'));
this.currency = currency;
}
@@ -120,13 +121,12 @@ public abstract class CoinEngine {
return super.toString() + " " + currency;
}
- public boolean notZero()
- {
- return compareTo(BigDecimal.ZERO)>0;
+ public boolean notZero() {
+ return compareTo(BigDecimal.ZERO) > 0;
}
public String toDescriptionString(int decimals) {
- return toValueString(decimals)+ " " + currency;
+ return toValueString(decimals) + " " + currency;
}
public String toValueString(int decimals) {
@@ -140,7 +140,7 @@ public abstract class CoinEngine {
df.setGroupingUsed(false);
- BigDecimal bd=new BigDecimal(unscaledValue(), scale());
+ BigDecimal bd = new BigDecimal(unscaledValue(), scale());
bd.setScale(decimals, ROUND_DOWN);
return df.format(bd);
}
@@ -161,7 +161,7 @@ public abstract class CoinEngine {
}
public boolean isZero() {
- return compareTo(BigDecimal.ZERO)==0;
+ return compareTo(BigDecimal.ZERO) == 0;
}
}
@@ -181,7 +181,7 @@ public abstract class CoinEngine {
public abstract boolean isBalanceNotZero();
- public abstract byte[] sign(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress, CardProtocol protocol) throws Exception;
+// public abstract byte[] sign(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress, CardProtocol protocol) throws Exception;
// TODO - change isExtractPossible to isExtractPossible and if not - return string message
public abstract boolean isExtractPossible();
@@ -220,9 +220,11 @@ public abstract class CoinEngine {
public abstract String calculateAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException;
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;
@@ -231,4 +233,112 @@ public abstract class CoinEngine {
public abstract String getUnspentInputsDescription();
+ 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.PaymentToSign} used for transaction signing and sending
+ *
+ * Transaction processing sequence:
+ * 1. User enter transaction attributes
+ * 2. Application create instance of {@link SignTask.PaymentToSign} by call {@see constructPayment}
+ * 3. Application set notification when transaction were prepared {@see setOnNeedSendPayment} and start {@link SignTask}
+ * 4. User tap card and card sign transaction
+ * 5. Application receive {@link CoinEngine.OnNeedSendPayment} notification with prepared raw transaction
+ * 6. Application show user information that transaction ready for sending and start 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.PaymentToSign}
+ * @throws Exception if something goes wrong
+ */
+ public abstract SignTask.PaymentToSign constructPayment(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 OnNeedSendPayment {
+ void onPaymentPrepared(byte[] txForSend);
+ }
+
+ protected OnNeedSendPayment onNeedSendPayment;
+
+
+ /**
+ * Set notification callback when new transaction is prepared to send
+ */
+ public void setOnNeedSendPayment(OnNeedSendPayment onNeedSendPayment) {
+ this.onNeedSendPayment = onNeedSendPayment;
+ }
+
+ protected void notifyOnNeedSendPayment(byte[] txForSend) throws Exception {
+ if (onNeedSendPayment == null)
+ throw new Exception("Payment signed but no callback defined to send!");
+ onNeedSendPayment.onPaymentPrepared(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;
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt b/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt
index 71e8d249a0..951b7eb457 100644
--- a/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt
+++ b/app/src/main/java/com/tangem/domain/wallet/CoinEngineFactory.kt
@@ -6,6 +6,8 @@ import com.tangem.domain.wallet.btc.BtcEngine
import com.tangem.domain.wallet.eth.EthEngine
import com.tangem.domain.wallet.token.TokenEngine
import com.tangem.domain.wallet.bch.BtcCashEngine
+import com.tangem.data.Blockchain
+import com.tangem.domain.wallet.ltc.LtcEngine
/**
* Factory for create specific engine
@@ -24,6 +26,7 @@ object CoinEngineFactory {
Blockchain.BitcoinCash -> BtcCashEngine()
Blockchain.Ethereum, Blockchain.EthereumTestNet -> EthEngine()
Blockchain.Token -> TokenEngine()
+ Blockchain.Litecoin -> LtcEngine()
else -> null
}
}
@@ -39,6 +42,8 @@ object CoinEngineFactory {
EthEngine(context)
else if (Blockchain.Token == context.blockchain)
TokenEngine(context)
+ else if (Blockchain.Litecoin == context.blockchain)
+ LtcEngine(context)
else
return null
} catch (e: Exception) {
diff --git a/app/src/main/java/com/tangem/domain/wallet/TangemContext.java b/app/src/main/java/com/tangem/domain/wallet/TangemContext.java
index cbbcf52164..5802887489 100644
--- a/app/src/main/java/com/tangem/domain/wallet/TangemContext.java
+++ b/app/src/main/java/com/tangem/domain/wallet/TangemContext.java
@@ -5,6 +5,9 @@ import android.content.Intent;
import android.os.Bundle;
import com.tangem.Constant;
+import com.tangem.data.Blockchain;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.data.TangemCardExtensionsKt;
public class TangemContext {
@@ -15,7 +18,6 @@ public class TangemContext {
private String error;
private String message;
-
public TangemContext() {
}
@@ -26,12 +28,29 @@ public class TangemContext {
public Blockchain getBlockchain() {
if (card == null) return Blockchain.Unknown;
- return card.getBlockchain();
+ Blockchain blockchain=Blockchain.fromId(card.getBlockchainID());
+ if( (blockchain==Blockchain.Ethereum || blockchain==Blockchain.EthereumTestNet)&& card.isToken() )
+ {
+ return Blockchain.Token;
+ }
+ return blockchain;
}
- public void setBlockchain(Blockchain blockchain) {
- if (card == null) return;
- card.setBlockchain(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.Ethereum || blockchain==Blockchain.EthereumTestNet)&& card.isToken() ) {
+ String token = card.getTokenSymbol();
+ return token + "
" + getBlockchain().getOfficialName() + " ERC20 token";
+ }else {
+ return blockchain.getOfficialName();
+ }
}
public Context getContext() {
@@ -66,6 +85,10 @@ public class TangemContext {
return error;
}
+ public boolean hasError() {
+ return error!=null && !error.isEmpty();
+ }
+
public void setMessage(String value) {
this.message = value;
}
@@ -83,9 +106,9 @@ public class TangemContext {
TangemContext tangemContext = new TangemContext();
tangemContext.setContext(context);
- if (bundle.containsKey(TangemCard.EXTRA_UID)) {
- tangemContext.card = new TangemCard(bundle.getString(TangemCard.EXTRA_UID));
- tangemContext.card.loadFromBundle(bundle.getBundle(TangemCard.EXTRA_CARD));
+ 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) {
@@ -104,8 +127,8 @@ public class TangemContext {
public void saveToIntent(Intent intent) {
if (card != null) {
- intent.putExtra(TangemCard.EXTRA_UID, card.getUID());
- intent.putExtra(TangemCard.EXTRA_CARD, card.getAsBundle());
+ intent.putExtra(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID, card.getUID());
+ intent.putExtra(TangemCardExtensionsKt.EXTRA_TANGEM_CARD, TangemCardExtensionsKt.getAsBundle(card));
}
if (coinData != null) {
@@ -121,4 +144,17 @@ public class TangemContext {
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/domain/wallet/Transaction.java b/app/src/main/java/com/tangem/domain/wallet/Transaction.java
index 99fa23ccdd..792a116802 100644
--- a/app/src/main/java/com/tangem/domain/wallet/Transaction.java
+++ b/app/src/main/java/com/tangem/domain/wallet/Transaction.java
@@ -566,11 +566,11 @@ public final class Transaction {
public static Script buildOutput(String address) throws BitcoinException {
//noinspection TryWithIdenticalCatches
byte[] addressWithCheckSumAndNetworkCode = Base58.decodeBase58(address);
- if (addressWithCheckSumAndNetworkCode[0] == 0 || addressWithCheckSumAndNetworkCode[0] == 111) {
+ if (addressWithCheckSumAndNetworkCode[0] == 0 || addressWithCheckSumAndNetworkCode[0] == 111 || addressWithCheckSumAndNetworkCode[0] == 48) { //0 for BTC/BCH 1 address | 48 for LTC L address
return buildOutputP2H(address);
}
- if(addressWithCheckSumAndNetworkCode[0] == 5 || addressWithCheckSumAndNetworkCode[0] == (byte)0xc4) {
+ 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);
}
@@ -579,7 +579,7 @@ public final class Transaction {
public static Script buildOutputP2SH(String address) throws BitcoinException {
try {
byte[] addressWithCheckSumAndNetworkCode = Base58.decodeBase58(address);
- if (addressWithCheckSumAndNetworkCode[0] != 5 && addressWithCheckSumAndNetworkCode[0] != (byte)0xc4) {
+ if (addressWithCheckSumAndNetworkCode[0] != 5 && addressWithCheckSumAndNetworkCode[0] != (byte)0xc4 && addressWithCheckSumAndNetworkCode[0] != 50) {
throw new BitcoinException(BitcoinException.ERR_UNSUPPORTED, "Unknown address type", address);
}
@@ -601,7 +601,7 @@ public final class Transaction {
//noinspection TryWithIdenticalCatches
try {
byte[] addressWithCheckSumAndNetworkCode = Base58.decodeBase58(address);
- if (addressWithCheckSumAndNetworkCode[0] != 0 && addressWithCheckSumAndNetworkCode[0] != 111) {
+ if (addressWithCheckSumAndNetworkCode[0] != 0 && addressWithCheckSumAndNetworkCode[0] != 111 && addressWithCheckSumAndNetworkCode[0] != 48) {
throw new BitcoinException(BitcoinException.ERR_UNSUPPORTED, "Unknown address type", address);
}
diff --git a/app/src/main/java/com/tangem/domain/wallet/UnspentOutputInfo.java b/app/src/main/java/com/tangem/domain/wallet/UnspentOutputInfo.java
index ddd4b2a113..88191c50b6 100644
--- a/app/src/main/java/com/tangem/domain/wallet/UnspentOutputInfo.java
+++ b/app/src/main/java/com/tangem/domain/wallet/UnspentOutputInfo.java
@@ -13,8 +13,6 @@ public class UnspentOutputInfo {
public final long confirmations;
public String txHashForBuild;
public byte[] scriptForBuild;
- public byte[] bodyDoubleHash;
- public byte[] bodyHash;
public UnspentOutputInfo(byte[] txHash, Transaction.Script script, long value, int outputIndex, long confirmations, String hashForBuild, byte[] sign) {
this.txHash = txHash;
diff --git a/app/src/main/java/com/tangem/domain/wallet/bch/BitcoinCashNode.kt b/app/src/main/java/com/tangem/domain/wallet/bch/BitcoinCashNode.kt
index 7cd8f18c8c..e08f74eacf 100644
--- a/app/src/main/java/com/tangem/domain/wallet/bch/BitcoinCashNode.kt
+++ b/app/src/main/java/com/tangem/domain/wallet/bch/BitcoinCashNode.kt
@@ -1,8 +1,24 @@
package com.tangem.domain.wallet.bch
-enum class BitcoinCashNode(val host: String, val port: Int) {
- n1("electrumx-bch.cryptonermal.net", 50001),
- n2("abc1.hsmiths.com", 60001),
- n3("electrum.imaginary.cash", 50001),
- n4("35.157.238.5", 51001),
+enum class BitcoinCashNode(val host: String, val port: Int, val proto: String) {
+ N_001("electrumx.hillsideinternet.com", 50002, "ssl"),
+ N_002("bch0.kister.net", 50002, "ssl"),
+ N_003("abc1.hsmiths.com", 60002, "ssl"),
+ N_004("bch.curalle.ovh", 50002, "ssl"),
+ N_005("207.180.215.112", 52002, "ssl"),
+ N_006("bch.imaginary.cash", 50002, "ssl"),
+ N_007("dedi.jochen-hoenicke.de", 51002, "ssl"),
+ N_008("crypto.mldlabs.com", 50002, "ssl"),
+ N_009("bch.electrumx.cash", 50002, "ssl"),
+ N_010("electroncash.cascharia.com", 50002, "ssl"),
+ N_011("bch.crypto.mldlabs.com", 50002, "ssl"),
+ N_012("electron-cash.dragon.zone", 50002, "ssl"),
+ N_013("electron.coinucopia.io", 50002, "ssl"),
+ N_014("blackie.c3-soft.com", 50002, "ssl"),
+ N_015("electroncash.ueo.ch", 51002, "ssl"),
+ N_016("electrum.imaginary.cash", 50002, "ssl"),
+ N_017("35.157.238.5", 51002, "ssl"),
+ N_018("bitcoincash.quangld.com", 50002, "ssl"),
+ N_019("bch.stitthappens.com", 50002, "ssl"),
+ N_020("electroncash.dk", 50002, "ssl"),
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/bch/BtcCashEngine.java b/app/src/main/java/com/tangem/domain/wallet/bch/BtcCashEngine.java
index a2cf960062..61c55ba38f 100644
--- a/app/src/main/java/com/tangem/domain/wallet/bch/BtcCashEngine.java
+++ b/app/src/main/java/com/tangem/domain/wallet/bch/BtcCashEngine.java
@@ -2,30 +2,39 @@ package com.tangem.domain.wallet.bch;
import android.net.Uri;
import android.text.InputFilter;
+import android.util.Log;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.TLV;
+import com.tangem.data.network.ElectrumRequest;
+import com.tangem.data.network.ServerApiCommon;
+import com.tangem.data.network.ServerApiElectrum;
+import com.tangem.domain.wallet.BCHUtils;
+import com.tangem.domain.wallet.BTCUtils;
+import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.domain.wallet.BalanceValidator;
-import com.tangem.domain.wallet.Blockchain;
-import com.tangem.domain.wallet.CoinEngineFactory;
+import com.tangem.data.Blockchain;
import com.tangem.domain.wallet.btc.BtcData;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;
-import com.tangem.domain.wallet.TangemCard;
+import com.tangem.tangemcard.data.TangemCard;
import com.tangem.domain.wallet.TangemContext;
import com.tangem.domain.wallet.Transaction;
import com.tangem.domain.wallet.UnspentOutputInfo;
-import com.tangem.domain.wallet.BTCUtils;
+import com.tangem.tangemcard.tasks.SignTask;
import com.tangem.util.CryptoUtil;
import com.tangem.util.DecimalDigitsInputFilter;
import com.tangem.util.DerEncodingUtil;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
+import com.tangem.util.FormatUtil;
import com.tangem.wallet.R;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
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;
@@ -35,6 +44,7 @@ import java.util.List;
public class BtcCashEngine extends CoinEngine {
+ private static final String TAG = BtcCashEngine.class.getSimpleName();
public BtcData coinData = null;
public BtcCashEngine(TangemContext context) throws Exception {
@@ -169,9 +179,7 @@ public class BtcCashEngine extends CoinEngine {
//
// return true;
- if(CashAddr.isValidCashAddress(address))
- return true;
- return false;
+ return CashAddr.isValidCashAddress(address);
}
@Override
@@ -181,12 +189,12 @@ public class BtcCashEngine extends CoinEngine {
@Override
public Uri getShareWalletUriExplorer() {
- return Uri.parse((ctx.getBlockchain() == Blockchain.BitcoinCash ? "https://bitcoincash.blockexplorer.com/address/" : "https://testnet.blockexplorer.com/address/") + ctx.getCard().getWallet());
+ return Uri.parse("https://bch.btc.com/" + ctx.getCoinData().getWallet());
}
@Override
public Uri getShareWalletUri() {
- return Uri.parse(ctx.getCard().getWallet());
+ return Uri.parse(ctx.getCoinData().getWallet());
}
@Override
@@ -223,7 +231,7 @@ public class BtcCashEngine extends CoinEngine {
if (fee.isZero() || amount.isZero())
return false;
- if (isIncludeFee && (amount.compareTo(coinData.getBalanceInInternalUnits()) > 0 || amount.compareTo(fee)<0))
+ if (isIncludeFee && (amount.compareTo(coinData.getBalanceInInternalUnits()) > 0 || amount.compareTo(fee) < 0))
return false;
if (!isIncludeFee && amount.add(fee).compareTo(coinData.getBalanceInInternalUnits()) > 0)
@@ -318,16 +326,16 @@ public class BtcCashEngine extends CoinEngine {
@Override
public String getBalanceEquivalent() {
if (coinData == null || !coinData.getAmountEquivalentDescriptionAvailable()) return "";
- Amount balance=getBalance();
- if( balance==null ) return "";
+ Amount balance = getBalance();
+ if (balance == null) return "";
return balance.toEquivalentString(coinData.getRate());
}
@Override
- public String calculateAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException {
+ public String calculateAddress(byte[] pubKey) throws NoSuchProviderException, NoSuchAlgorithmException {
// CashAddr format
- byte hash1[] = Util.calculateSHA256(pkUncompressed);
+ byte hash1[] = Util.calculateSHA256(pubKey);
byte hash2[] = Util.calculateRIPEMD160(hash1);
return CashAddr.toCashAddress(BitcoinCashAddressType.P2PKH, hash2);
@@ -428,20 +436,32 @@ public class BtcCashEngine extends CoinEngine {
return coinData.getUnspentInputsDescription();
}
+ @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 String getAmountDescription(TangemCard mCard, String amount) throws Exception {
// return mCard.getAmountDescription(Double.parseDouble(amount));
// }
- @Override
- public byte[] sign(Amount feeValue, Amount amountValue, boolean IncFee, String destAddress, CardProtocol protocol) throws Exception {
+ @Override
+ public SignTask.PaymentToSign constructPayment(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception {
checkBlockchainDataExists();
- CoinEngine engine = CoinEngineFactory.INSTANCE.create(ctx);
-
- String srcLegacyAddress = ((BtcCashEngine)engine).convertToLegacyAddress(ctx.getCard().getWallet());
- String destLegacyAddress = ((BtcCashEngine)engine).convertToLegacyAddress(destAddress);
+ String srcLegacyAddress = convertToLegacyAddress(ctx.getCoinData().getWallet());
+ String destLegacyAddress = convertToLegacyAddress(targetAddress);
byte[] pbKey = ctx.getCard().getWalletPublicKeyRar(); //ALWAYS USING COMPRESS KEY
// Build script for our address
@@ -449,7 +469,7 @@ public class BtcCashEngine extends CoinEngine {
byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(srcLegacyAddress).bytes;
// Collect unspent
- ArrayList unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
+ ArrayList unspentOutputs = BCHUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
long fullAmount = 0;
for (int i = 0; i < unspentOutputs.size(); ++i) {
@@ -470,48 +490,297 @@ public class BtcCashEngine extends CoinEngine {
throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < change (%d) + amount (%d)", fullAmount, change, amount));
}
- byte[][] dataForSign = new byte[unspentOutputs.size()][];
+ 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) {
- byte[] newTX = BTCUtils.buildTXForSign(srcLegacyAddress, destLegacyAddress, srcLegacyAddress, unspentOutputs, i, amount, change);
+ txForSign[i] = BCHUtils.buildTXForSign(srcLegacyAddress, destLegacyAddress, srcLegacyAddress, unspentOutputs, i, amount, change);
+ bodyHash[i] = Util.calculateSHA256(txForSign[i]);
+ bodyDoubleHash[i] = Util.calculateSHA256(bodyHash[i]);
+ }
- byte[] hashData = Util.calculateSHA256(newTX);
- byte[] doubleHashData = Util.calculateSHA256(hashData);
+ return new SignTask.PaymentToSign() {
- unspentOutputs.get(i).bodyDoubleHash = doubleHashData;
- unspentOutputs.get(i).bodyHash = hashData;
-
- if (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw || ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer) {
- dataForSign[i] = newTX;
- } else {
- dataForSign[i] = doubleHashData;
+ @Override
+ public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) {
+ return signingMethod == TangemCard.SigningMethod.Sign_Hash || signingMethod == TangemCard.SigningMethod.Sign_Raw;
}
- }
-
- byte[] signFromCard;
- if (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw || ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer) {
- ByteArrayOutputStream bs = new ByteArrayOutputStream();
- if (dataForSign.length > 10) throw new Exception("To much hashes in one transaction!");
- for (int i = 0; i < dataForSign.length; i++) {
- if (i != 0 && dataForSign[0].length != dataForSign[i].length)
- throw new Exception("Hashes length must be identical!");
- bs.write(dataForSign[i]);
+ @Override
+ public byte[][] getHashesToSign() throws Exception {
+ byte[][] dataForSign = new byte[unspentOutputs.size()][];
+ if (txForSign.length > 10) throw new Exception("To much hashes in one transaction!");
+ for (int i = 0; i < unspentOutputs.size(); ++i) {
+ dataForSign[i] = bodyDoubleHash[i];
+ }
+ return dataForSign;
}
- signFromCard = protocol.run_SignRaw(PINStorage.getPIN2(), bs.toByteArray()).getTLV(TLV.Tag.TAG_Signature).Value;
- } else {
- signFromCard = protocol.run_SignHashes(PINStorage.getPIN2(), dataForSign, ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer, null, ctx.getCard().getIssuer()).getTLV(TLV.Tag.TAG_Signature).Value;
- // TODO slice signFromCard to hashes.length parts
- }
- 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);
+ @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]);
+ }
- unspentOutputs.get(i).scriptForBuild = DerEncodingUtil.packSignDerBitcoinCash(r, s, pbKey);
- }
+ return bs.toByteArray();
+ }
- return BTCUtils.buildTXForSend(destLegacyAddress, srcLegacyAddress, unspentOutputs, amount, change);
+ @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);
+
+ notifyOnNeedSendPayment(txForSend);
+ return txForSend;
+ }
+ };
}
+
+ @Override
+ public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) throws Exception {
+ final ServerApiElectrum serverApiElectrum = new ServerApiElectrum();
+
+ ServerApiElectrum.ElectrumRequestDataListener electrumBodyListener = new ServerApiElectrum.ElectrumRequestDataListener() {
+ @Override
+ public void onSuccess(ElectrumRequest electrumRequest) {
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetBalance)) {
+ try {
+ Long confBalance = electrumRequest.getResult().getLong("confirmed");
+ Long unconfirmedBalance = electrumRequest.getResult().getLong("unconfirmed");
+ coinData.setBalanceReceived(true);
+ coinData.setBalanceConfirmed(confBalance);
+ coinData.setBalanceUnconfirmed(unconfirmedBalance);
+ coinData.setValidationNodeDescription(serverApiElectrum.getValidationNodeDescription());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ Log.e(TAG, "FAIL METHOD_GetBalance JSONException");
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "FAIL METHOD_GetBalance Exception");
+ }
+ }
+
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_ListUnspent)) {
+ try {
+ String walletAddress = electrumRequest.getParams().getString(0);
+ JSONArray jsUnspentArray = electrumRequest.getResultArray();
+ try {
+ coinData.getUnspentTransactions().clear();
+ for (int i = 0; i < jsUnspentArray.length(); i++) {
+ JSONObject jsUnspent = jsUnspentArray.getJSONObject(i);
+ BtcData.UnspentTransaction trUnspent = new BtcData.UnspentTransaction();
+ trUnspent.txID = jsUnspent.getString("tx_hash");
+ trUnspent.Amount = jsUnspent.getInt("value");
+ trUnspent.Height = jsUnspent.getInt("height");
+ coinData.getUnspentTransactions().add(trUnspent);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ Log.e(TAG, "FAIL METHOD_ListUnspent JSONException");
+ }
+
+ for (int i = 0; i < jsUnspentArray.length(); i++) {
+ JSONObject jsUnspent = jsUnspentArray.getJSONObject(i);
+ Integer height = jsUnspent.getInt("height");
+ String hash = jsUnspent.getString("tx_hash");
+ if (height != -1) {
+ if (blockchainRequestsCallbacks.allowAdvance()) {
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getTransaction(walletAddress, hash));
+ } else {
+ ctx.setError("Terminated by user");
+ }
+ }
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetTransaction)) {
+ try {
+ String txHash = electrumRequest.txHash;
+ String raw = electrumRequest.getResultString();
+ for (BtcData.UnspentTransaction tx : coinData.getUnspentTransactions()) {
+ if (tx.txID.equals(txHash))
+ tx.Raw = raw;
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (serverApiElectrum.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(!ctx.hasError());
+ }else{
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+
+ @Override
+ public void onFail(ElectrumRequest electrumRequest) {
+ Log.i(TAG, "onFail: "+electrumRequest.getMethod()+" "+electrumRequest.getError());
+ ctx.setError(electrumRequest.getError());
+ if (serverApiElectrum.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(false);//serverApiElectrum.isErrorOccurred(), serverApiElectrum.getError());
+ }else{
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+ };
+
+ serverApiElectrum.setElectrumRequestData(electrumBodyListener);
+
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.checkBalance(convertToLegacyAddress(coinData.getWallet())));
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.listUnspent(convertToLegacyAddress(coinData.getWallet())));
+ }
+
+ private Integer calculateEstimatedTransactionSize(String outputAddress, String outAmount) {
+ try {
+ SignTask.PaymentToSign ps=constructPayment(new Amount(outAmount, getBalanceCurrency()),new Amount("0.00",getFeeCurrency()), true, outputAddress );
+ OnNeedSendPayment onNeedSendPaymentBackup=onNeedSendPayment;
+ onNeedSendPayment=(tx)->{}; // empty function to bypass exception
+
+ byte[][] hashesToSign=ps.getHashesToSign();
+ byte[] signFromCard = new byte[64 * hashesToSign.length];
+ byte[] txForSend=ps.onSignCompleted(signFromCard);
+ onNeedSendPayment=onNeedSendPaymentBackup;
+ Log.e(TAG,"txForSend.length="+String.valueOf(txForSend.length));
+ return txForSend.length;
+ } 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 {
+ final int calcSize = calculateEstimatedTransactionSize(targetAddress, amount.toValueString());
+ Log.e(TAG, String.format("Estimated tx size %d", calcSize));
+ coinData.minFee=null;
+ coinData.maxFee=null;
+ coinData.normalFee=null;
+
+ final ServerApiElectrum serverApiElectrum = new ServerApiElectrum();
+
+ final ServerApiElectrum.ElectrumRequestDataListener electrumListener = new ServerApiElectrum.ElectrumRequestDataListener () {
+ @Override
+ public void onSuccess(ElectrumRequest electrumRequest) {
+ BigDecimal fee;
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetFee)) {
+ try {
+ fee = new BigDecimal(electrumRequest.getResultString()); //fee per KB
+
+ if (fee.equals(BigDecimal.ZERO)) {
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getFee());
+ }
+
+// if (calcSize != 0) {
+ fee = fee.multiply(new BigDecimal(calcSize)).divide(new BigDecimal(1024)); // (per KB -> per byte)*size
+// } else {
+// serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getFee());
+// }
+
+ //compare fee to usual relay fee
+ if (fee.compareTo(relayFee) < 0) {
+ fee = relayFee;
+ }
+ fee = fee.setScale(8, RoundingMode.DOWN);
+
+ CoinEngine.Amount feeAmount = new CoinEngine.Amount(fee, ctx.getBlockchain().getCurrency());
+ coinData.minFee = feeAmount;
+ coinData.normalFee = feeAmount;
+ coinData.maxFee = feeAmount;
+// if (coinData.minFee != null && coinData.normalFee != null && coinData.maxFee != null) {
+ blockchainRequestsCallbacks.onComplete(true);
+// } else {
+// blockchainRequestsCallbacks.onProgress();
+// }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void onFail(ElectrumRequest electrumRequest) {
+ ctx.setError(electrumRequest.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+ serverApiElectrum.setElectrumRequestData(electrumListener);
+
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getFee());
+ }
+
+ @Override
+ public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) throws Exception {
+ final ServerApiElectrum serverApiElectrum = new ServerApiElectrum();
+ final String txStr = BTCUtils.toHex(txForSend);
+
+ ServerApiElectrum.ElectrumRequestDataListener electrumBodyListener = new ServerApiElectrum.ElectrumRequestDataListener() {
+ @Override
+ public void onSuccess(ElectrumRequest electrumRequest) {
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_SendTransaction)) {
+ try {
+ String resultString = electrumRequest.getResultString();
+ if (resultString == null || resultString.isEmpty()) {
+ ctx.setError("Rejected by node: " + electrumRequest.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ }else {
+ ctx.setError(null);
+ blockchainRequestsCallbacks.onComplete(true);
+ }
+ } catch (Exception e) {
+ if (e.getMessage() != null) {
+ ctx.setError(e.getMessage());
+ blockchainRequestsCallbacks.onComplete(false);
+ } else {
+ ctx.setError(e.getClass().getName());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFail(ElectrumRequest electrumRequest) {
+ ctx.setError(electrumRequest.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+ serverApiElectrum.setElectrumRequestData(electrumBodyListener);
+
+
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.broadcast(ctx.getCoinData().getWallet(), txStr));
+
+ }
+
}
diff --git a/app/src/main/java/com/tangem/domain/wallet/bch/CashAddr.java b/app/src/main/java/com/tangem/domain/wallet/bch/CashAddr.java
index 203d2e7d25..d73f88f8d7 100644
--- a/app/src/main/java/com/tangem/domain/wallet/bch/CashAddr.java
+++ b/app/src/main/java/com/tangem/domain/wallet/bch/CashAddr.java
@@ -56,9 +56,11 @@ public class CashAddr {
String[] addressParts = bitcoinCashAddress.split(SEPARATOR);
if (addressParts.length == 2) {
decoded.setPrefix(addressParts[0]);
+ } else {
+ decoded.setPrefix(MAIN_NET_PREFIX);
}
- byte[] addressData = BitcoinCashBase32.decode(addressParts[1]);
+ 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];
@@ -84,19 +86,21 @@ public class CashAddr {
public static boolean isValidCashAddress(String bitcoinCashAddress ) {
try {
- String prefix;
- if (bitcoinCashAddress.contains(SEPARATOR)) {
- String[] split = bitcoinCashAddress.split(SEPARATOR);
- prefix = split[0];
- bitcoinCashAddress = split[1];
- } else {
- prefix =MAIN_NET_PREFIX;
- }
-
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 }),
diff --git a/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinNode.kt b/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinNode.kt
index e03b6df8d2..0d5d7cb997 100644
--- a/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinNode.kt
+++ b/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinNode.kt
@@ -2,18 +2,84 @@ package com.tangem.domain.wallet.btc
enum class BitcoinNode(val host: String, val port: Int, val proto: String) {
N_001("electrum.anduck.net", 50001, "tcp"),
- N_002("electrum-server.ninja", 50001, "tcp"),
- N_003("btc.cihar.com", 50001, "tcp"),
- N_004("vps.hsmiths.com", 50001, "tcp"),
- N_005("electrum.hsmiths.com", 50001, "tcp"),
- N_006("electrum.vom-stausee.de", 50001, "tcp"),
- N_007("node.ispol.sk", 50001, "tcp"),
- N_008("electrum2.eff.ro", 50001, "tcp"),
- N_009("electrumx.nmdps.net", 50001, "tcp"),
- N_010("kirsche.emzy.de", 50001, "tcp"),
- N_011("electrum.petrkr.net", 50001, "tcp"),
- N_012("electrum.dk", 50001, "tcp"),
- N_013("electrum.anduck.net", 50012, "ssl"),
- N_014("electrum.eff.ro", 50002, "ssl"),
- N_015("vps.hsmiths.com", 50002, "ssl"),
+ N_002("ip119.ip-54-37-91.eu", 50001, "tcp"),
+ N_003("electrum.qtornado.com", 50001, "tcp"),
+ N_004("ip239.ip-54-36-234.eu", 50001, "tcp"),
+ N_005("electrum-server.ninja", 50001, "tcp"),
+ N_006("174.138.11.174", 50001, "tcp"),
+ N_007("ndnd.selfhost.eu", 50001, "tcp"),
+ N_008("btc.cihar.com", 50001, "tcp"),
+ N_009("vps.hsmiths.com", 8080, "tcp"),
+ N_010("electrum.hsmiths.com", 8080, "tcp"),
+ N_011("ip120.ip-54-37-91.eu", 50001, "tcp"),
+ N_012("vps.hsmiths.com", 50001, "tcp"),
+ N_013("orannis.com", 50001, "tcp"),
+ N_014("ip101.ip-54-37-91.eu", 50001, "tcp"),
+ N_015("e-x.not.fyi", 50001, "tcp"),
+ N_016("electrum.hsmiths.com", 50001, "tcp"),
+ N_017("electrum.vom-stausee.de", 50001, "tcp"),
+ N_018("bitcoin.corgi.party", 50001, "tcp"),
+ N_019("electrum2.eff.ro", 50001, "tcp"),
+ N_020("electrum.coinucopia.io", 50001, "tcp"),
+ N_021("electrum.eff.ro", 50001, "tcp"),
+ N_022("btc.xskyx.net", 50001, "tcp"),
+ N_023("kirsche.emzy.de", 50001, "tcp"),
+ N_024("electrum.petrkr.net", 50001, "tcp"),
+ N_025("btc.knas.systems", 50001, "tcp"),
+ N_026("b.ooze.cc", 50002, "ssl"),
+ N_027("electrum.nute.net", 50002, "ssl"),
+ N_028("ndnd.selfhost.eu", 50002, "ssl"),
+ N_029("electrum.coinop.cc", 50002, "ssl"),
+ N_030("orannis.com", 50002, "ssl"),
+ N_031("electrum.vom-stausee.de", 50002, "ssl"),
+ N_032("ip119.ip-54-37-91.eu", 50002, "ssl"),
+ N_033("ip101.ip-54-37-91.eu", 50002, "ssl"),
+ N_034("electrum2.villocq.com", 50002, "ssl"),
+ N_035("dedi.jochen-hoenicke.de", 50002, "ssl"),
+ N_036("174.138.11.174", 50002, "ssl"),
+ N_037("tomscryptos.com", 50002, "ssl"),
+ N_038("elec.luggs.co", 443, "ssl"),
+ N_039("ip239.ip-54-36-234.eu", 50002, "ssl"),
+ N_040("bitcoins.sk", 50002, "ssl"),
+ N_041("btc.cihar.com", 50002, "ssl"),
+ N_042("e-x.not.fyi", 50002, "ssl"),
+ N_043("ip120.ip-54-37-91.eu", 50002, "ssl"),
+ N_044("electrum.villocq.com", 50002, "ssl"),
+ N_045("electrum.anduck.net", 50012, "ssl"),
+ N_046("technetium.network", 50002, "ssl"),
+ N_047("electrum.coinucopia.io", 50002, "ssl"),
+ N_048("currentlane.lovebitco.in", 50002, "ssl"),
+ N_049("dimon.trimon.de", 50002, "ssl"),
+ N_050("rbx.curalle.ovh", 50002, "ssl"),
+ N_051("btc.gravitech.net", 50002, "ssl"),
+ N_052("hetzner01.fischl-online.de", 50002, "ssl"),
+ N_053("fn.48.org", 50002, "ssl"),
+ N_054("185.64.116.15", 50002, "ssl"),
+ N_055("kirsche.emzy.de", 50002, "ssl"),
+ N_056("109.192.105.174", 50002, "ssl"),
+ N_057("fedaykin.goip.de", 50002, "ssl"),
+ N_058("vps.hsmiths.com", 50002, "ssl"),
+ N_059("104.250.141.242", 50002, "ssl"),
+ N_060("electrum.qtornado.com", 50002, "ssl"),
+ N_061("electrum-server.ninja", 50002, "ssl"),
+ N_062("electrum2.eff.ro", 50002, "ssl"),
+ N_063("electrum.hsmiths.com", 995, "ssl"),
+ N_064("electrum.hsmiths.com", 50002, "ssl"),
+ N_065("139.162.14.142", 50002, "ssl"),
+ N_066("electrum.eff.ro", 50002, "ssl"),
+ N_067("electrum.taborsky.cz", 50002, "ssl"),
+ N_068("electrum.festivaldelhumor.org", 50002, "ssl"),
+ N_069("electrum.petrkr.net", 50002, "ssl"),
+ N_070("us.electrum.be", 50002, "ssl"),
+ N_071("bitcoin-node.org", 50002, "ssl"),
+ N_072("vmd27610.contaboserver.net", 50002, "ssl"),
+ N_073("electrumx.soon.it", 50002, "ssl"),
+ N_074("vmd30612.contaboserver.net", 50002, "ssl"),
+ N_075("enode.duckdns.org", 50002, "ssl"),
+ N_076("81-7-13-84.blue.kundencontroller.de", 50002, "ssl"),
+ N_077("electrum.scumm.it", 50002, "ssl"),
+ N_078("helicarrier.bauerj.eu", 50002, "ssl"),
+ N_079("tardis.bauerj.eu", 50002, "ssl"),
+ N_080("such.ninja", 50002, "ssl"),
+ N_081("electrum.be", 50002, "ssl"),
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinOutputStream.java b/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinOutputStream.java
index 243eb7ca10..ced90a20d3 100644
--- a/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinOutputStream.java
+++ b/app/src/main/java/com/tangem/domain/wallet/btc/BitcoinOutputStream.java
@@ -4,6 +4,8 @@ package com.tangem.domain.wallet.btc;
* Created by Ilia on 29.09.2017.
*/
+import com.tangem.domain.wallet.Transaction;
+
import java.io.ByteArrayOutputStream;
@SuppressWarnings("WeakerAccess")
@@ -40,4 +42,7 @@ public final class BitcoinOutputStream extends ByteArrayOutputStream {
writeInt64(value);
}
}
+
+ public void write(Transaction.Script script) {
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/btc/BtcData.java b/app/src/main/java/com/tangem/domain/wallet/btc/BtcData.java
index 497ec30abe..f036a85aa0 100644
--- a/app/src/main/java/com/tangem/domain/wallet/btc/BtcData.java
+++ b/app/src/main/java/com/tangem/domain/wallet/btc/BtcData.java
@@ -18,11 +18,19 @@ public class BtcData extends CoinData {
private Long balanceConfirmed, balanceUnconfirmed;
public String getUnspentInputsDescription() {
- int gatheredUnspents = 0;
- for (int i=0; i 1) gatheredUnspents++;
+ try {
+ int gatheredUnspents = 0;
+ if( unspentTransactions==null ) return "";
+ for (int i = 0; i < unspentTransactions.size(); i++) {
+ if (unspentTransactions.get(i).Raw != null && unspentTransactions.get(i).Raw.length() > 1) gatheredUnspents++;
+ }
+ return String.valueOf(unspentTransactions.size()) + " unspents (" + String.valueOf(gatheredUnspents) + " received)";
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return "";
}
- return String.valueOf(unspentTransactions.size()) + " unspents (" + String.valueOf(gatheredUnspents) + " received)";
}
public static class UnspentTransaction {
diff --git a/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java b/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java
index 3f1bee11e5..80f0e11d56 100644
--- a/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java
+++ b/app/src/main/java/com/tangem/domain/wallet/btc/BtcEngine.java
@@ -2,29 +2,38 @@ package com.tangem.domain.wallet.btc;
import android.net.Uri;
import android.text.InputFilter;
+import android.util.Log;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.TLV;
+import com.tangem.data.network.ServerApiCommon;
+import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.domain.wallet.BalanceValidator;
import com.tangem.domain.wallet.Base58;
-import com.tangem.domain.wallet.Blockchain;
+import com.tangem.data.Blockchain;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;
-import com.tangem.domain.wallet.TangemCard;
+import com.tangem.tangemcard.data.TangemCard;
import com.tangem.domain.wallet.TangemContext;
import com.tangem.domain.wallet.Transaction;
import com.tangem.domain.wallet.UnspentOutputInfo;
import com.tangem.domain.wallet.BTCUtils;
+import com.tangem.tangemcard.tasks.SignTask;
import com.tangem.util.CryptoUtil;
import com.tangem.util.DecimalDigitsInputFilter;
import com.tangem.util.DerEncodingUtil;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import com.tangem.wallet.R;
+import com.tangem.data.network.ElectrumRequest;
+import com.tangem.data.network.ServerApiElectrum;
+
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
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;
@@ -34,6 +43,8 @@ import java.util.List;
public class BtcEngine extends CoinEngine {
+ private static final String TAG = BtcEngine.class.getSimpleName();
+
public BtcData coinData = null;
public BtcEngine(TangemContext context) throws Exception {
@@ -179,15 +190,15 @@ public class BtcEngine extends CoinEngine {
@Override
public Uri getShareWalletUriExplorer() {
- return Uri.parse((ctx.getBlockchain() == Blockchain.Bitcoin ? "https://blockchain.info/address/" : "https://testnet.blockchain.info/address/") + ctx.getCard().getWallet());
+ return Uri.parse((ctx.getBlockchain() == Blockchain.Bitcoin ? "https://blockchain.info/address/" : "https://testnet.blockchain.info/address/") + ctx.getCoinData().getWallet());
}
@Override
public Uri getShareWalletUri() {
if (ctx.getCard().getDenomination() != null) {
- return Uri.parse("bitcoin:" + ctx.getCard().getWallet() + "?amount=" + convertToAmount(convertToInternalAmount(ctx.getCard().getDenomination())).toValueString(8));
+ return Uri.parse("bitcoin:" + ctx.getCoinData().getWallet() + "?amount=" + convertToAmount(convertToInternalAmount(ctx.getCard().getDenomination())).toValueString(8));
} else {
- return Uri.parse("bitcoin:" + ctx.getCard().getWallet());
+ return Uri.parse("bitcoin:" + ctx.getCoinData().getWallet());
}
}
@@ -236,14 +247,15 @@ public class BtcEngine extends CoinEngine {
@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("Unknown balance");
- balanceValidator.setSecondLine("Balance cannot be verified. Swipe down to refresh.");
- return false;
- }
+ try {
+ if (((ctx.getCard().getOfflineBalance() == null) && !ctx.getCoinData().isBalanceReceived()) || (!ctx.getCoinData().isBalanceReceived() && (ctx.getCard().getRemainingSignatures() != ctx.getCard().getMaxSignatures()))) {
+ balanceValidator.setScore(0);
+ balanceValidator.setFirstLine("Unknown balance");
+ balanceValidator.setSecondLine("Balance cannot be verified. Swipe down to refresh.");
+ return false;
+ }
- // Workaround before new back-end
+ // Workaround before new back-end
// if (card.getRemainingSignatures() == card.getMaxSignatures()) {
// firstLine = "Verified balance";
// secondLine = "Balance confirmed in blockchain. ";
@@ -251,24 +263,24 @@ public class BtcEngine extends CoinEngine {
// return;
// }
- if (coinData.getBalanceUnconfirmed() != 0) {
- balanceValidator.setScore(0);
- balanceValidator.setFirstLine("Transaction in progress");
- balanceValidator.setSecondLine("Wait for confirmation in blockchain");
- return false;
- }
-
- if (coinData.isBalanceReceived() && coinData.isBalanceEqual()) {
- balanceValidator.setScore(100);
- balanceValidator.setFirstLine("Verified balance");
- balanceValidator.setSecondLine("Balance confirmed in blockchain");
- if (coinData.getBalanceInInternalUnits().isZero()) {
- balanceValidator.setFirstLine("Empty wallet");
- balanceValidator.setSecondLine("");
+ if (coinData.getBalanceUnconfirmed() != 0) {
+ balanceValidator.setScore(0);
+ balanceValidator.setFirstLine("Transaction in progress");
+ balanceValidator.setSecondLine("Wait for confirmation in blockchain");
+ return false;
}
- }
- // rule 4 TODO: need to check SignedHashed against number of outputs in blockchain
+ if (coinData.isBalanceReceived() && coinData.isBalanceEqual()) {
+ balanceValidator.setScore(100);
+ balanceValidator.setFirstLine("Verified balance");
+ balanceValidator.setSecondLine("Balance confirmed in blockchain");
+ if (coinData.getBalanceInInternalUnits().isZero()) {
+ balanceValidator.setFirstLine("Empty wallet");
+ balanceValidator.setSecondLine("");
+ }
+ }
+
+ // rule 4 TODO: need to check SignedHashed against number of outputs in blockchain
// if((card.getRemainingSignatures() != card.getMaxSignatures()) && card.getBalance() != 0)
// {
// score = 80;
@@ -277,11 +289,11 @@ public class BtcEngine extends CoinEngine {
// return;
// }
- if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && coinData.getBalanceInInternalUnits().notZero()) {
- balanceValidator.setScore(80);
- balanceValidator.setFirstLine("Verified offline balance");
- balanceValidator.setSecondLine("Can't obtain balance from blockchain. Restore internet connection to be more confident. ");
- }
+ if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && coinData.getBalanceInInternalUnits().notZero()) {
+ balanceValidator.setScore(80);
+ balanceValidator.setFirstLine("Verified offline balance");
+ balanceValidator.setSecondLine("Can't obtain balance from blockchain. Restore internet connection to be more confident. ");
+ }
// if(card.getFailedBalanceRequestCounter()!=0) {
// score -= 5 * card.getFailedBalanceRequestCounter();
@@ -290,7 +302,7 @@ public class BtcEngine extends CoinEngine {
// return;
// }
- //
+ //
// if(card.isBalanceReceived() && !card.isBalanceEqual()) {
// score = 0;
// firstLine = "Disputed balance";
@@ -298,7 +310,13 @@ public class BtcEngine extends CoinEngine {
// return;
// }
- return true;
+ return true;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return false;
+ }
}
@Override
@@ -372,7 +390,7 @@ public class BtcEngine extends CoinEngine {
}
@Override
- public InternalAmount convertToInternalAmount(Amount amount) throws Exception {
+ public InternalAmount convertToInternalAmount(Amount amount) {
BigDecimal d = amount.multiply(new BigDecimal("100000000"));
return new InternalAmount(d, "Satoshi");
}
@@ -386,7 +404,7 @@ public class BtcEngine extends CoinEngine {
}
@Override
- public byte[] convertToByteArray(InternalAmount internalAmount) throws Exception {
+ public byte[] convertToByteArray(InternalAmount internalAmount) {
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];
@@ -404,11 +422,11 @@ public class BtcEngine extends CoinEngine {
}
@Override
- public byte[] sign(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress, CardProtocol protocol) throws Exception {
-
+ public SignTask.PaymentToSign constructPayment(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception {
+ final ArrayList unspentOutputs;
checkBlockchainDataExists();
- String myAddress = ctx.getCard().getWallet();
+ String myAddress = ctx.getCoinData().getWallet();
byte[] pbKey = ctx.getCard().getWalletPublicKey();
// Build script for our address
@@ -416,14 +434,13 @@ public class BtcEngine extends CoinEngine {
byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes;
// Collect unspent
- ArrayList unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
+ unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
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;
@@ -433,52 +450,375 @@ public class BtcEngine extends CoinEngine {
change = change - fees;
}
+ final long amountFinal = amount;
+ final long changeFinal = change;
+
if (amount + fees > fullAmount) {
throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < change (%d) + amount (%d)", fullAmount, change, amount));
}
- byte[][] dataForSign = new byte[unspentOutputs.size()][];
+ final byte[][] txForSign = new byte[unspentOutputs.size()][];
+ final byte[][] bodyDoubleHash = new byte[unspentOutputs.size()][];
+ final byte[][] bodyHash = new byte[unspentOutputs.size()][];
for (int i = 0; i < unspentOutputs.size(); ++i) {
- byte[] newTX = BTCUtils.buildTXForSign(myAddress, targetAddress, myAddress, unspentOutputs, i, amount, change);
+ txForSign[i] = BTCUtils.buildTXForSign(myAddress, targetAddress, myAddress, unspentOutputs, i, amount, change);
+ bodyHash[i] = Util.calculateSHA256(txForSign[i]);
+ bodyDoubleHash[i] = Util.calculateSHA256(bodyHash[i]);
+ }
- byte[] hashData = Util.calculateSHA256(newTX);
- byte[] doubleHashData = Util.calculateSHA256(hashData);
+ return new SignTask.PaymentToSign() {
- unspentOutputs.get(i).bodyDoubleHash = doubleHashData;
- unspentOutputs.get(i).bodyHash = hashData;
-
- if (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw || ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer) {
- dataForSign[i] = newTX;
- } else {
- dataForSign[i] = doubleHashData;
+ @Override
+ public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) {
+ return signingMethod == TangemCard.SigningMethod.Sign_Hash || signingMethod == TangemCard.SigningMethod.Sign_Raw;
}
- }
- byte[] signFromCard;
- if (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw || ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer) {
- ByteArrayOutputStream bs = new ByteArrayOutputStream();
- if (dataForSign.length > 10) throw new Exception("To much hashes in one transaction!");
- for (int i = 0; i < dataForSign.length; i++) {
- if (i != 0 && dataForSign[0].length != dataForSign[i].length)
- throw new Exception("Hashes length must be identical!");
- bs.write(dataForSign[i]);
+ @Override
+ public byte[][] getHashesToSign() throws Exception {
+ byte[][] dataForSign = new byte[unspentOutputs.size()][];
+ if (txForSign.length > 10) throw new Exception("To much hashes in one transaction!");
+ for (int i = 0; i < unspentOutputs.size(); ++i) {
+ dataForSign[i] = bodyDoubleHash[i];
+ }
+ return dataForSign;
}
- signFromCard = protocol.run_SignRaw(PINStorage.getPIN2(), bs.toByteArray()).getTLV(TLV.Tag.TAG_Signature).Value;
- } else {
- signFromCard = protocol.run_SignHashes(PINStorage.getPIN2(), dataForSign, ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer, null, ctx.getCard().getIssuer()).getTLV(TLV.Tag.TAG_Signature).Value;
- // TODO slice signFromCard to hashes.length parts
+
+ @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("Issuer validation not supported!");
+ }
+
+ @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.packSignDer(r, s, pbKey);
+ }
+
+ byte[] txForSend = BTCUtils.buildTXForSend(targetAddress, myAddress, unspentOutputs, amountFinal, changeFinal);
+ notifyOnNeedSendPayment(txForSend);
+ return txForSend;
+ }
+ };
+ }
+
+ @Override
+ public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) {
+ final ServerApiElectrum serverApiElectrum = new ServerApiElectrum();
+
+ ServerApiElectrum.ElectrumRequestDataListener electrumListener = new ServerApiElectrum.ElectrumRequestDataListener() {
+ @Override
+ public void onSuccess(ElectrumRequest electrumRequest) {
+ Log.i(TAG, "onSuccess: "+electrumRequest.getMethod());
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetBalance)) {
+ try {
+ String walletAddress = electrumRequest.getParams().getString(0);
+ if (!walletAddress.equals(coinData.getWallet())) {
+ // todo - check
+ throw new Exception("Invalid wallet address in answer!");
+ }
+ Long confBalance = electrumRequest.getResult().getLong("confirmed");
+ Long unconfirmedBalance = electrumRequest.getResult().getLong("unconfirmed");
+ coinData.setBalanceReceived(true);
+ coinData.setBalanceConfirmed(confBalance);
+ coinData.setBalanceUnconfirmed(unconfirmedBalance);
+ coinData.setValidationNodeDescription(serverApiElectrum.getValidationNodeDescription());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ Log.e(TAG, "FAIL METHOD_GetBalance JSONException");
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "FAIL METHOD_GetBalance Exception");
+ }
+ } else if (electrumRequest.isMethod(ElectrumRequest.METHOD_ListUnspent)) {
+ try {
+ String walletAddress = electrumRequest.getParams().getString(0);
+ JSONArray jsUnspentArray = electrumRequest.getResultArray();
+ try {
+ coinData.getUnspentTransactions().clear();
+ for (int i = 0; i < jsUnspentArray.length(); i++) {
+ JSONObject jsUnspent = jsUnspentArray.getJSONObject(i);
+ BtcData.UnspentTransaction trUnspent = new BtcData.UnspentTransaction();
+ trUnspent.txID = jsUnspent.getString("tx_hash");
+ trUnspent.Amount = jsUnspent.getInt("value");
+ trUnspent.Height = jsUnspent.getInt("height");
+ coinData.getUnspentTransactions().add(trUnspent);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ Log.e(TAG, "FAIL METHOD_ListUnspent JSONException");
+ }
+
+ for (int i = 0; i < jsUnspentArray.length(); i++) {
+ JSONObject jsUnspent = jsUnspentArray.getJSONObject(i);
+ Integer height = jsUnspent.getInt("height");
+ String hash = jsUnspent.getString("tx_hash");
+ if (height != -1) {
+ if (blockchainRequestsCallbacks.allowAdvance()) {
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getTransaction(walletAddress, hash));
+ } else {
+ ctx.setError("Terminated by user");
+ }
+ }
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ } else if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetTransaction)) {
+ try {
+ String txHash = electrumRequest.txHash;
+ String raw = electrumRequest.getResultString();
+ for (BtcData.UnspentTransaction tx : coinData.getUnspentTransactions()) {
+ if (tx.txID.equals(txHash))
+ tx.Raw = raw;
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (serverApiElectrum.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(!ctx.hasError());
+ }else{
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+
+ @Override
+ public void onFail(ElectrumRequest electrumRequest) {
+ Log.i(TAG, "onFail: "+electrumRequest.getMethod()+" "+electrumRequest.getError());
+ ctx.setError(electrumRequest.getError());
+ if (serverApiElectrum.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(false);//serverApiElectrum.isErrorOccurred(), serverApiElectrum.getError());
+ }else{
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+ };
+
+ serverApiElectrum.setElectrumRequestData(electrumListener);
+
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.checkBalance(coinData.getWallet()));
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.listUnspent(coinData.getWallet()));
+ }
+
+ protected Integer calculateEstimatedTransactionSize(String outputAddress, String outAmount) {
+ //todo - правильней было бы использовать constructPayment
+ try {
+// String myAddress = coinData.getWallet();
+// byte[] pbKey = ctx.getCard().getWalletPublicKey();
+// byte[] pbComprKey = ctx.getCard().getWalletPublicKeyRar();
+//
+// // build script for our address
+// List rawTxList = coinData.getUnspentTransactions();
+// byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes;
+//
+// // collect unspent
+// ArrayList unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
+//
+// Long fullAmount = 0L;
+// for (int i = 0; i < unspentOutputs.size(); i++) {
+// fullAmount += unspentOutputs.get(i).value;
+// }
+//
+// // get first unspent
+//// val outPut = unspentOutputs[0]
+//// val outPutIndex = outPut.outputIndex
+//
+// // get prev TX id;
+//// val prevTXID = rawTxList[0].txID//"f67b838d6e2c0c587f476f583843e93ff20368eaf96a798bdc25e01f53f8f5d2";
+//
+// Long fees = FormatUtil.ConvertStringToLong("0.00");
+// Long amount = FormatUtil.ConvertStringToLong(outAmount);
+// amount -= fees;
+//
+// Long change = fullAmount - fees - amount;
+//
+// if (amount + fees > fullAmount) {
+// throw new Exception(String.format("Balance (%d) < amount (%d) + (%d)", fullAmount, change, amount));
+// }
+//
+// byte[][] hashesForSign = new byte[unspentOutputs.size()][];
+//
+// for (int i = 0; i < unspentOutputs.size(); i++) {
+// byte[] newTX = BTCUtils.buildTXForSign(myAddress, outputAddress, myAddress, unspentOutputs, i, amount, change);
+// byte[] hashData = Util.calculateSHA256(newTX);
+// byte[] doubleHashData = Util.calculateSHA256(hashData);
+//// Log.e("TX_BODY_1", BTCUtils.toHex(newTX))
+//// Log.e("TX_HASH_1", BTCUtils.toHex(hashData))
+//// Log.e("TX_HASH_2", BTCUtils.toHex(doubleHashData))
+//
+//// unspentOutputs[i].bodyDoubleHash = doubleHashData
+//// unspentOutputs[i].bodyHash = hashData
+// hashesForSign[i] = doubleHashData;
+// }
+//
+// byte[] signFromCard = new byte[64 * unspentOutputs.size()];
+//
+// 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));
+// byte[] encodingSign = DerEncodingUtil.packSignDer(r, s, pbKey);
+// unspentOutputs.get(i).scriptForBuild = encodingSign;
+// }
+//
+// byte[] realTX = BTCUtils.buildTXForSend(outputAddress, myAddress, unspentOutputs, amount, change);
+
+ SignTask.PaymentToSign ps=constructPayment(new Amount(outAmount, getBalanceCurrency()),new Amount("0.00",getFeeCurrency()), true, outputAddress );
+ OnNeedSendPayment onNeedSendPaymentBackup=onNeedSendPayment;
+ onNeedSendPayment=(tx)->{}; // empty function to bypass exception
+
+ byte[][] hashesToSign=ps.getHashesToSign();
+ byte[] signFromCard = new byte[64 * hashesToSign.length];
+ byte[] txForSend=ps.onSignCompleted(signFromCard);
+ onNeedSendPayment=onNeedSendPaymentBackup;
+ Log.e(TAG,"txForSend.length="+String.valueOf(txForSend.length));
+ return txForSend.length;
+
+// Log.e(TAG,"txForSend.length="+String.valueOf(txForSend.length)+" realTX.length="+String.valueOf(realTX.length));
+//
+// return realTX.length;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "Can't calculate transaction size -> use default!");
+ return 256;
}
+ }
- 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);
+ @Override
+ public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception {
+ final int calcSize = calculateEstimatedTransactionSize(targetAddress, amount.toValueString());
+ Log.e(TAG, String.format("Estimated tx size %d", calcSize));
+ coinData.minFee = null;
+ coinData.maxFee = null;
+ coinData.normalFee = null;
- unspentOutputs.get(i).scriptForBuild = DerEncodingUtil.packSignDer(r, s, pbKey);
- }
+ final ServerApiCommon serverApiCommon = new ServerApiCommon();
+
+ final ServerApiCommon.EstimateFeeListener estimateFeeListener = new ServerApiCommon.EstimateFeeListener() {
+ @Override
+ public void onSuccess(int blockCount, String estimateFeeResponse) {
+ BigDecimal fee = new BigDecimal(estimateFeeResponse); // BTC per 1 kb
+
+ if (fee.equals(BigDecimal.ZERO)) {
+ if (blockchainRequestsCallbacks.allowAdvance()) {
+ serverApiCommon.estimateFee(blockCount);
+ }
+ return;
+ }
+
+ if (calcSize != 0) {
+ fee = fee.multiply(new BigDecimal(calcSize)).divide(new BigDecimal(1024), BigDecimal.ROUND_DOWN); // per Kb -> per byte
+ } else {
+ if (blockchainRequestsCallbacks.allowAdvance()) {
+ serverApiCommon.estimateFee(blockCount);
+ }
+ return;
+ }
+
+ fee = fee.setScale(8, RoundingMode.DOWN);
+
+ switch (blockCount) {
+ case ServerApiCommon.ESTIMATE_FEE_MINIMAL:
+ coinData.minFee = new CoinEngine.Amount(fee, getFeeCurrency());
+ break;
+ case ServerApiCommon.ESTIMATE_FEE_NORMAL:
+ coinData.normalFee = new CoinEngine.Amount(fee, getFeeCurrency());
+ break;
+ case ServerApiCommon.ESTIMATE_FEE_PRIORITY:
+ coinData.maxFee = new CoinEngine.Amount(fee, getFeeCurrency());
+ break;
+ }
+
+ if(coinData.minFee!=null && coinData.normalFee!=null && coinData.maxFee!=null ) {
+ blockchainRequestsCallbacks.onComplete(true);
+ }else{
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+
+ @Override
+ public void onFail(int blockCount, String message) {
+ // TODO - add fail counter to terminate after NNN tries
+ if (blockchainRequestsCallbacks.allowAdvance()) {
+ serverApiCommon.estimateFee(blockCount);
+ return;
+ }
+ ctx.setError(ctx.getContext().getString(R.string.cannot_calculate_fee_wrong_data_received_from_node));
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+ serverApiCommon.setEstimateFee(estimateFeeListener);
+
+ serverApiCommon.estimateFee(ServerApiCommon.ESTIMATE_FEE_PRIORITY);
+ serverApiCommon.estimateFee(ServerApiCommon.ESTIMATE_FEE_NORMAL);
+ serverApiCommon.estimateFee(ServerApiCommon.ESTIMATE_FEE_MINIMAL);
+
+ }
+
+ @Override
+ public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) {
+ final ServerApiElectrum serverApiElectrum = new ServerApiElectrum();
+ final String txStr = BTCUtils.toHex(txForSend);
+
+ ServerApiElectrum.ElectrumRequestDataListener electrumListener = new ServerApiElectrum.ElectrumRequestDataListener() {
+ @Override
+ public void onSuccess(ElectrumRequest electrumRequest) {
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_SendTransaction)) {
+ try {
+ String resultString = electrumRequest.getResultString();
+ if (resultString == null || resultString.isEmpty()) {
+ ctx.setError("Rejected by node: " + electrumRequest.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ }else {
+ ctx.setError(null);
+ blockchainRequestsCallbacks.onComplete(true);
+ }
+ } catch (Exception e) {
+ if (e.getMessage() != null) {
+ ctx.setError(e.getMessage());
+ blockchainRequestsCallbacks.onComplete(false);
+ } else {
+ ctx.setError(e.getClass().getName());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFail(ElectrumRequest electrumRequest) {
+ ctx.setError(electrumRequest.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+ serverApiElectrum.setElectrumRequestData(electrumListener);
+
+
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.broadcast(ctx.getCoinData().getWallet(), txStr));
- return BTCUtils.buildTXForSend(targetAddress, myAddress, unspentOutputs, amount, change);
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/eth/EthData.java b/app/src/main/java/com/tangem/domain/wallet/eth/EthData.java
index df44ecef13..7921eaf1c6 100644
--- a/app/src/main/java/com/tangem/domain/wallet/eth/EthData.java
+++ b/app/src/main/java/com/tangem/domain/wallet/eth/EthData.java
@@ -62,8 +62,12 @@ public class EthData extends CoinData {
public void loadFromBundle(Bundle B) {
super.loadFromBundle(B);
- String currency = B.getString("BalanceCurrency");
- balance = new CoinEngine.InternalAmount(B.getString("BalanceDecimal"), currency);
+ if (B.containsKey("BalanceCurrency") && B.containsKey("BalanceDecimal")) {
+ String currency = B.getString("BalanceCurrency");
+ balance = new CoinEngine.InternalAmount(B.getString("BalanceDecimal"), currency);
+ } else {
+ balance = null;
+ }
if (B.containsKey("confirmTx"))
countConfirmedTX = new BigInteger(B.getString("confirmTx"), 16);
@@ -75,8 +79,10 @@ public class EthData extends CoinData {
public void saveToBundle(Bundle B) {
super.saveToBundle(B);
try {
- B.putString("BalanceCurrency", balance.getCurrency());
- B.putString("BalanceDecimal", balance.toString());
+ if (balance != null) {
+ B.putString("BalanceCurrency", balance.getCurrency());
+ B.putString("BalanceDecimal", balance.toString());
+ }
B.putString("confirmTx", getConfirmedTXCount().toString(16));
B.putString("unconfirmTx", getUnconfirmedTXCount().toString(16));
diff --git a/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java b/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java
index bcf844f3bb..876bc8bd17 100644
--- a/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java
+++ b/app/src/main/java/com/tangem/domain/wallet/eth/EthEngine.java
@@ -4,20 +4,19 @@ import android.net.Uri;
import android.text.InputFilter;
import android.util.Log;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.TLV;
+import com.tangem.data.Blockchain;
+import com.tangem.data.network.ServerApiInfura;
+import com.tangem.data.network.model.InfuraResponse;
+import com.tangem.domain.wallet.BTCUtils;
import com.tangem.domain.wallet.BalanceValidator;
-import com.tangem.domain.wallet.Blockchain;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;
import com.tangem.domain.wallet.ECDSASignatureETH;
import com.tangem.domain.wallet.EthTransaction;
-import com.tangem.domain.wallet.Issuer;
import com.tangem.domain.wallet.Keccak256;
-import com.tangem.domain.wallet.TangemCard;
import com.tangem.domain.wallet.TangemContext;
-import com.tangem.domain.wallet.BTCUtils;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.tasks.SignTask;
import com.tangem.util.CryptoUtil;
import com.tangem.util.DecimalDigitsInputFilter;
import com.tangem.wallet.R;
@@ -27,8 +26,6 @@ import org.bitcoinj.core.ECKey;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
import java.util.Arrays;
/**
@@ -37,6 +34,7 @@ import java.util.Arrays;
public class EthEngine extends CoinEngine {
+ private static final String TAG = EthEngine.class.getSimpleName();
public EthData coinData = null;
public EthEngine(TangemContext ctx) throws Exception {
@@ -60,7 +58,7 @@ public class EthEngine extends CoinEngine {
}
@Override
- public boolean awaitingConfirmation(){
+ public boolean awaitingConfirmation() {
return false;
}
@@ -74,17 +72,17 @@ public class EthEngine extends CoinEngine {
@Override
public String getBalanceHTML() {
- Amount balance=getBalance();
- if( balance!=null ) {
+ Amount balance = getBalance();
+ if (balance != null) {
return balance.toDescriptionString(getDecimals());
- }else{
+ } else {
return "";
}
}
@Override
public String getBalanceCurrency() {
- return "ETH";
+ return Blockchain.Ethereum.getCurrency();
}
@Override
@@ -96,14 +94,14 @@ public class EthEngine extends CoinEngine {
@Override
public boolean isBalanceNotZero() {
- if( coinData ==null ) return false;
+ if (coinData == null) return false;
if (coinData.getBalanceInInternalUnits() == null) return false;
return coinData.getBalanceInInternalUnits().notZero();
}
@Override
public String getFeeCurrency() {
- return "ETH";
+ return Blockchain.Ethereum.getCurrency();
}
public boolean isNeedCheckNode() {
@@ -186,8 +184,8 @@ public class EthEngine extends CoinEngine {
@Override
public String getBalanceEquivalent() {
- Amount balance=getBalance();
- if( balance==null ) return "";
+ Amount balance = getBalance();
+ if (balance == null) return "";
return balance.toEquivalentString(coinData.getRate());
}
@@ -203,8 +201,8 @@ public class EthEngine extends CoinEngine {
}
@Override
- public InternalAmount convertToInternalAmount(Amount amount){
- return new InternalAmount(amount.multiply(new BigDecimal("1000000000000000000")),"wei");
+ public InternalAmount convertToInternalAmount(Amount amount) {
+ return new InternalAmount(amount.multiply(new BigDecimal("1000000000000000000")), "wei");
}
@Override
@@ -221,24 +219,24 @@ public class EthEngine extends CoinEngine {
@Override
public boolean hasBalanceInfo() {
- return coinData.getBalanceInInternalUnits()!=null;
+ return coinData.getBalanceInInternalUnits() != null;
}
@Override
public Uri getShareWalletUri() {
if (ctx.getCard().getDenomination() != null) {
- return Uri.parse("ethereum:" + ctx.getCard().getWallet());// + "?value=" + mCard.getDenomination() +"e18");
+ return Uri.parse("ethereum:" + ctx.getCoinData().getWallet());// + "?value=" + mCard.getDenomination() +"e18");
} else {
- return Uri.parse("ethereum:" + ctx.getCard().getWallet());
+ return Uri.parse("ethereum:" + ctx.getCoinData().getWallet());
}
}
@Override
public Uri getShareWalletUriExplorer() {
- if (ctx.getCard().getBlockchain() == Blockchain.EthereumTestNet)
- return Uri.parse("https://rinkeby.etherscan.io/address/" + ctx.getCard().getWallet());
+ if (ctx.getBlockchain() == Blockchain.EthereumTestNet)
+ return Uri.parse("https://rinkeby.etherscan.io/address/" + ctx.getCoinData().getWallet());
else
- return Uri.parse("https://etherscan.io/address/" + ctx.getCard().getWallet());
+ return Uri.parse("https://etherscan.io/address/" + ctx.getCoinData().getWallet());
}
@Override
@@ -257,14 +255,14 @@ public class EthEngine extends CoinEngine {
@Override
public InputFilter[] getAmountInputFilters() {
- return new InputFilter[] { new DecimalDigitsInputFilter(getDecimals()) };
+ return new InputFilter[]{new DecimalDigitsInputFilter(getDecimals())};
}
@Override
- public boolean checkNewTransactionAmount(Amount amount){
- if( coinData ==null ) return false;
- Amount balance=getBalance();
- if (balance==null || amount.compareTo(balance) > 0) {
+ public boolean checkNewTransactionAmount(Amount amount) {
+ if (coinData == null) return false;
+ Amount balance = getBalance();
+ if (balance == null || amount.compareTo(balance) > 0) {
return false;
}
return true;
@@ -295,7 +293,7 @@ public class EthEngine extends CoinEngine {
try {
BigDecimal cardBalance = getBalance();
- if (isFeeIncluded && (amount.compareTo(cardBalance) > 0 || amount.compareTo(fee)<0))
+ if (isFeeIncluded && (amount.compareTo(cardBalance) > 0 || amount.compareTo(fee) < 0))
return false;
if (!isFeeIncluded && amount.add(fee).compareTo(cardBalance) > 0)
@@ -349,20 +347,18 @@ public class EthEngine extends CoinEngine {
try {
Amount feeValue = new Amount(fee, ctx.getBlockchain().getCurrency());
return feeValue.toEquivalentString(coinData.getRate());
- }
- catch (Exception e)
- {
+ } catch (Exception e) {
e.printStackTrace();
return "";
}
}
@Override
- public String calculateAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException {
+ public String calculateAddress(byte[] pkUncompressed) {
Keccak256 kec = new Keccak256();
int lenPk = pkUncompressed.length;
if (lenPk < 2) {
- throw new IllegalArgumentException("Uncompress public key length is invald");
+ throw new IllegalArgumentException("Uncompress public key length is invalid");
}
byte[] cleanKey = new byte[lenPk - 1];
for (int i = 0; i < cleanKey.length; ++i) {
@@ -379,21 +375,20 @@ public class EthEngine extends CoinEngine {
}
@Override
- public byte[] sign(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress, CardProtocol protocol) throws Exception {
+ public SignTask.PaymentToSign constructPayment(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) {
+
+ Log.e(TAG, "Construct payment " + amountValue.toString() + " with fee " + feeValue.toString() + (IncFee ? " including" : " excluding"));
BigInteger nonceValue = coinData.getConfirmedTXCount();
byte[] pbKey = ctx.getCard().getWalletPublicKey();
- boolean flag = (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer);
- Issuer issuer = ctx.getCard().getIssuer();
- BigInteger weiFee=convertToInternalAmount(feeValue).toBigIntegerExact();
- BigInteger weiAmount=convertToInternalAmount(amountValue).toBigIntegerExact();
+ BigInteger weiFee = convertToInternalAmount(feeValue).toBigIntegerExact();
+ BigInteger weiAmount = convertToInternalAmount(amountValue).toBigIntegerExact();
if (IncFee) {
weiAmount = weiAmount.subtract(weiFee);
}
- BigInteger nonce = nonceValue;
BigInteger gasPrice = weiFee.divide(BigInteger.valueOf(21000));
BigInteger gasLimit = BigInteger.valueOf(21000);
Integer chainId = ctx.getBlockchain() == Blockchain.Ethereum ? EthTransaction.ChainEnum.Mainnet.getValue() : EthTransaction.ChainEnum.Rinkeby.getValue();
@@ -404,41 +399,211 @@ public class EthEngine extends CoinEngine {
to = to.substring(2);
}
- EthTransaction tx = EthTransaction.create(to, weiAmount, nonce, gasPrice, gasLimit, chainId);
+ final EthTransaction tx = EthTransaction.create(to, weiAmount, nonceValue, gasPrice, gasLimit, chainId);
- byte[][] hashesForSign = new byte[1][];
- byte[] for_hash = tx.getRawHash();
- hashesForSign[0] = for_hash;
+ return new SignTask.PaymentToSign() {
+ @Override
+ public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) {
+ return signingMethod == TangemCard.SigningMethod.Sign_Hash;
+ }
- byte[] signFromCard = null;
- try {
- signFromCard = protocol.run_SignHashes(PINStorage.getPIN2(), hashesForSign, flag, null, issuer).getTLV(TLV.Tag.TAG_Signature).Value;
- // TODO slice signFromCard to hashes.length parts
- } catch (Exception ex) {
- Log.e("ETH", ex.getMessage());
- return null;
- }
+ @Override
+ public byte[][] getHashesToSign() {
+ byte[][] hashesForSign = new byte[1][];
+ hashesForSign[0] = tx.getRawHash();
+ return hashesForSign;
+ }
- BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, 32));
- BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32, 64));
- s = CryptoUtil.toCanonicalised(s);
+ @Override
+ public byte[] getRawDataToSign() throws Exception {
+ throw new Exception("Signing of raw transaction not supported for ETH");
+ }
- boolean f = ECKey.verify(for_hash, new ECKey.ECDSASignature(r, s), pbKey);
+ @Override
+ public String getHashAlgToSign() throws Exception {
+ throw new Exception("Signing of raw transaction not supported for ETH");
+ }
- if (!f) {
- Log.e("ETH-CHECK", "sign Failed.");
- }
+ @Override
+ public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception {
+ throw new Exception("Transaction validation by issuer not supported in this version");
+ }
- tx.signature = new ECDSASignatureETH(r, s);
- int v = tx.BruteRecoveryID2(tx.signature, for_hash, pbKey);
- if (v != 27 && v != 28) {
- Log.e("ETH", "invalid v");
- return null;
- }
- tx.signature.v = (byte) v;
- Log.e("ETH_v", String.valueOf(v));
+ @Override
+ public byte[] onSignCompleted(byte[] signFromCard) throws Exception {
+ byte[] for_hash = tx.getRawHash();
+ BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, 32));
+ BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32, 64));
+ s = CryptoUtil.toCanonicalised(s);
+
+ boolean f = ECKey.verify(for_hash, new ECKey.ECDSASignature(r, s), pbKey);
+
+ if (!f) {
+ Log.e("ETH-CHECK", "sign Failed.");
+ }
+
+ tx.signature = new ECDSASignatureETH(r, s);
+ int v = tx.BruteRecoveryID2(tx.signature, for_hash, pbKey);
+ if (v != 27 && v != 28) {
+ Log.e(TAG, "invalid v");
+ throw new Exception("Error in EthEngine - invalid v");
+ }
+ tx.signature.v = (byte) v;
+ Log.e(TAG, "ETH_v: " +String.valueOf(v));
+
+ byte[] txForSend = tx.getEncoded();
+ notifyOnNeedSendPayment(txForSend);
+ return txForSend;
+ }
+ };
+ }
+
+ @Override
+ public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) {
+ final ServerApiInfura serverApiInfura = new ServerApiInfura();
+ // request infura listener
+ ServerApiInfura.InfuraBodyListener infuraBodyListener = new ServerApiInfura.InfuraBodyListener() {
+ @Override
+ public void onSuccess(String method, InfuraResponse infuraResponse) {
+ switch (method) {
+ case ServerApiInfura.INFURA_ETH_GET_BALANCE: {
+ String balanceCap = infuraResponse.getResult();
+ balanceCap = balanceCap.substring(2);
+ BigInteger l = new BigInteger(balanceCap, 16);
+ coinData.setBalanceReceived(true);
+ coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, "wei"));
+
+// Log.i("$TAG eth_get_balance", balanceCap)
+ }
+ break;
+
+ case ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT: {
+ String nonce = infuraResponse.getResult();
+ nonce = nonce.substring(2);
+ BigInteger count = new BigInteger(nonce, 16);
+ coinData.setConfirmedTXCount(count);
+
+
+// Log.i("$TAG eth_getTransCount", nonce)
+ }
+ break;
+
+ case ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT: {
+ String pending = infuraResponse.getResult();
+ pending = pending.substring(2);
+ BigInteger count = new BigInteger(pending, 16);
+ coinData.setUnconfirmedTXCount(count);
+
+// Log.i("$TAG eth_getPendingTxCount", pending)
+ }
+ break;
+ }
+
+ if (serverApiInfura.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(!ctx.hasError());
+ } else {
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+
+ @Override
+ public void onFail(String method, String message) {
+ if (!serverApiInfura.isRequestsSequenceCompleted()) {
+ ctx.setError(message);
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ }
+ };
+ serverApiInfura.setInfuraResponse(infuraBodyListener);
+
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
+ }
+
+ @Override
+ public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) {
+ ServerApiInfura serverApiInfura = new ServerApiInfura();
+ // request infura eth gasPrice listener
+ ServerApiInfura.InfuraBodyListener infuraBodyListener = new ServerApiInfura.InfuraBodyListener() {
+ @Override
+ public void onSuccess(String method, InfuraResponse infuraResponse) {
+ String gasPrice = infuraResponse.getResult();
+ gasPrice = gasPrice.substring(2);
+ // rounding gas price to integer gwei
+ BigInteger l = new BigInteger(gasPrice, 16);//.divide(BigInteger.valueOf(1000000000L)).multiply(BigInteger.valueOf(1000000000L));
+
+ Log.i(TAG, "Infura gas price: " + gasPrice + " (" + l.toString() + ")");
+ BigInteger m = BigInteger.valueOf(21000);
+
+ Log.e(TAG, "fee multiplier: " + m.toString());
+
+ CoinEngine.InternalAmount weiMinFee = new CoinEngine.InternalAmount(l.multiply(m), "wei");
+ CoinEngine.InternalAmount weiNormalFee = new CoinEngine.InternalAmount(l.multiply(BigInteger.valueOf(12)).divide(BigInteger.valueOf(10)).multiply(m), "wei");
+ CoinEngine.InternalAmount weiMaxFee = new CoinEngine.InternalAmount(l.multiply(BigInteger.valueOf(15)).divide(BigInteger.valueOf(10)).multiply(m), "wei");
+
+ Log.i(TAG, "min fee : " + weiMinFee.toValueString() + " wei");
+ Log.i(TAG, "normal fee: " + weiNormalFee.toValueString() + " wei");
+ Log.i(TAG, "max fee : " + weiMaxFee.toValueString() + " wei");
+
+ coinData.minFee = convertToAmount(weiMinFee);
+ coinData.normalFee = convertToAmount(weiNormalFee);
+ coinData.maxFee = convertToAmount(weiMaxFee);
+
+ Log.i(TAG, "min fee : " + coinData.minFee.toString());
+ Log.i(TAG, "normal fee: " + coinData.normalFee.toString());
+ Log.i(TAG, "max fee : " + coinData.maxFee.toString());
+
+ blockchainRequestsCallbacks.onComplete(true);
+ }
+
+ @Override
+ public void onFail(String method, String message) {
+ ctx.setError(ctx.getContext().getString(R.string.cannot_calculate_fee_wrong_data_received_from_node));
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+ serverApiInfura.setInfuraResponse(infuraBodyListener);
+
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GAS_PRICE, 67, coinData.getWallet(), "", "");
+ }
+
+ @Override
+ public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) {
+
+ String txStr = String.format("0x%s", BTCUtils.toHex(txForSend));
+
+ ServerApiInfura serverApiInfura = new ServerApiInfura();
+ // request infura eth gasPrice listener
+ ServerApiInfura.InfuraBodyListener infuraBodyListener = new ServerApiInfura.InfuraBodyListener() {
+ @Override
+ public void onSuccess(String method, InfuraResponse infuraResponse) {
+ if (method.equals(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION)) {
+ if (infuraResponse.getResult().isEmpty()) {
+ ctx.setError("Rejected by node: " + infuraResponse.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ } else {
+ BigInteger nonce = coinData.getConfirmedTXCount();
+ nonce=nonce.add(BigInteger.valueOf(1));
+ coinData.setConfirmedTXCount(nonce);
+ ctx.setError(null);
+ blockchainRequestsCallbacks.onComplete(true);
+ }
+ }
+ }
+
+ @Override
+ public void onFail(String method, String message) {
+ if (method.equals(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION)) {
+ ctx.setError(message);
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ }
+ };
+
+ serverApiInfura.setInfuraResponse(infuraBodyListener);
+
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION, 67, coinData.getWallet(), "", txStr);
- byte[] realTX = tx.getEncoded();
- return realTX;
}
}
diff --git a/app/src/main/java/com/tangem/domain/wallet/ltc/LitecoinNode.kt b/app/src/main/java/com/tangem/domain/wallet/ltc/LitecoinNode.kt
new file mode 100644
index 0000000000..0d7ff8c172
--- /dev/null
+++ b/app/src/main/java/com/tangem/domain/wallet/ltc/LitecoinNode.kt
@@ -0,0 +1,17 @@
+package com.tangem.domain.wallet.ltc
+
+enum class LitecoinNode(val host: String, val port: Int, val proto: String) {
+ N_001("node.ispol.sk", 50004, "ssl"),
+ N_002("electrum-ltc.klippb.org", 50002, "ssl"),
+ N_003("backup.electrum-ltc.org", 443, "ssl"),
+ N_004("electrum-ltc.petrkr.net", 60002, "ssl"),
+ N_005("technetium.network", 50003, "ssl"),
+ N_006("167.99.146.166", 50002, "ssl"),
+ N_007("electrum-ltc.bysh.me", 50002, "ssl"),
+ N_008("e-3.claudioboxx.com", 50004, "ssl"),
+ N_009("electrum-ltc.wilv.in", 50002, "ssl"),
+ N_010("ltc.rentonisk.com", 50002, "ssl"),
+ N_011("e-1.claudioboxx.com", 50004, "ssl"),
+ N_012("electrum.ltc.xurious.com", 50002, "ssl"),
+ N_013("ltc01.knas.systems", 50004, "ssl"),
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/ltc/LtcEngine.java b/app/src/main/java/com/tangem/domain/wallet/ltc/LtcEngine.java
new file mode 100644
index 0000000000..4ab77928ef
--- /dev/null
+++ b/app/src/main/java/com/tangem/domain/wallet/ltc/LtcEngine.java
@@ -0,0 +1,560 @@
+package com.tangem.domain.wallet.ltc;
+
+import android.net.Uri;
+import android.text.InputFilter;
+import android.util.Log;
+
+import com.tangem.data.network.ElectrumRequest;
+import com.tangem.data.network.ServerApiElectrum;
+import com.tangem.domain.wallet.BTCUtils;
+import com.tangem.domain.wallet.BalanceValidator;
+import com.tangem.domain.wallet.Base58;
+import com.tangem.domain.wallet.CoinData;
+import com.tangem.domain.wallet.CoinEngine;
+import com.tangem.domain.wallet.TangemContext;
+import com.tangem.domain.wallet.Transaction;
+import com.tangem.domain.wallet.UnspentOutputInfo;
+import com.tangem.domain.wallet.btc.BtcData;
+import com.tangem.domain.wallet.btc.BtcEngine;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.tasks.SignTask;
+import com.tangem.tangemcard.util.Util;
+import com.tangem.util.CryptoUtil;
+import com.tangem.util.DecimalDigitsInputFilter;
+import com.tangem.util.DerEncodingUtil;
+import com.tangem.wallet.R;
+
+import org.json.JSONException;
+
+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 java.util.List;
+
+public class LtcEngine extends BtcEngine {
+ private static final String TAG = LtcEngine.class.getSimpleName();
+ public BtcData coinData = null;
+
+ public LtcEngine(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 LtcEngine");
+ }
+ }
+
+ public LtcEngine() {
+ 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() {
+ if (coinData == null) return false;
+ return coinData.getBalanceUnconfirmed() != 0;
+ }
+
+ @Override
+ public String getBalanceHTML() {
+ Amount balance = getBalance();
+ if (balance != null) {
+ return balance.toDescriptionString(getDecimals());
+ } else {
+ return "";
+ }
+ }
+
+ @Override
+ public String getBalanceCurrency() {
+ return "LTC";
+ }
+
+ @Override
+ public String getOfflineBalanceHTML() {
+ InternalAmount offlineInternalAmount = convertToInternalAmount(ctx.getCard().getOfflineBalance());
+ Amount offlineAmount = convertToAmount(offlineInternalAmount);
+ return offlineAmount.toDescriptionString(getDecimals());
+ }
+
+ @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.cannot_obtain_data_from_blockchain);
+ } else if (!isBalanceNotZero()) {
+ ctx.setMessage(R.string.wallet_empty);
+ } else if (awaitingConfirmation()) {
+ ctx.setMessage(R.string.please_wait_while_previous);
+ } else if (coinData.getUnspentTransactions().size() == 0) {
+ ctx.setMessage(R.string.please_wait_for_confirmation);
+ } else {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String getFeeCurrency() {
+ return "LTC";
+ }
+
+ @Override
+ public boolean validateAddress(String address) {
+ if (address == null || address.isEmpty()) {
+ return false;
+ }
+
+ if (address.length() < 25) {
+ return false;
+ }
+
+ if (address.length() > 35) {
+ return false;
+ }
+
+ if (!address.startsWith("L") && !address.startsWith("M")) {
+ return false;
+ }
+
+ byte[] decAddress = Base58.decodeBase58(address);
+
+ if (decAddress == null || decAddress.length == 0) {
+ return false;
+ }
+
+ byte[] rip = new byte[21];
+ for (int i = 0; i < 21; ++i) {
+ rip[i] = decAddress[i];
+ }
+
+ byte[] kcv = CryptoUtil.doubleSha256(rip);
+
+ for (int i = 0; i < 4; ++i) {
+ if (kcv[i] != decAddress[21 + i])
+ return false;
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public boolean isNeedCheckNode() {
+ return true;
+ }
+
+ @Override
+ public Uri getShareWalletUriExplorer() {
+ return Uri.parse("https://live.blockcypher.com/ltc/address/" + ctx.getCoinData().getWallet());
+ }
+
+ @Override
+ public Uri getShareWalletUri() {
+ if (ctx.getCard().getDenomination() != null) {
+ return Uri.parse("litecoin:" + ctx.getCoinData().getWallet() + "?amount=" + convertToAmount(convertToInternalAmount(ctx.getCard().getDenomination())).toValueString(8));
+ } else {
+ return Uri.parse("litecoin:" + 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("Unknown balance");
+ balanceValidator.setSecondLine("Balance cannot be verified. Swipe down to refresh.");
+ return false;
+ }
+
+ // Workaround before new back-end
+// if (card.getRemainingSignatures() == card.getMaxSignatures()) {
+// firstLine = "Verified balance";
+// secondLine = "Balance confirmed in blockchain. ";
+// secondLine += "Verified note identity. ";
+// return;
+// }
+
+ if (coinData.getBalanceUnconfirmed() != 0) {
+ balanceValidator.setScore(0);
+ balanceValidator.setFirstLine("Transaction in progress");
+ balanceValidator.setSecondLine("Wait for confirmation in blockchain");
+ return false;
+ }
+
+ if (coinData.isBalanceReceived() && coinData.isBalanceEqual()) {
+ balanceValidator.setScore(100);
+ balanceValidator.setFirstLine("Verified balance");
+ balanceValidator.setSecondLine("Balance confirmed in blockchain");
+ if (coinData.getBalanceInInternalUnits().isZero()) {
+ balanceValidator.setFirstLine("Empty wallet");
+ balanceValidator.setSecondLine("");
+ }
+ }
+
+ // rule 4 TODO: need to check SignedHashed against number of outputs in blockchain
+// if((card.getRemainingSignatures() != card.getMaxSignatures()) && card.getBalance() != 0)
+// {
+// score = 80;
+// firstLine = "Unguaranteed balance";
+// secondLine = "Potential unsent transaction. Redeem immediately if accept. ";
+// return;
+// }
+
+ if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && coinData.getBalanceInInternalUnits().notZero()) {
+ balanceValidator.setScore(80);
+ balanceValidator.setFirstLine("Verified offline balance");
+ balanceValidator.setSecondLine("Can't obtain balance from blockchain. Restore internet connection to be more confident. ");
+ }
+
+// if(card.getFailedBalanceRequestCounter()!=0) {
+// score -= 5 * card.getFailedBalanceRequestCounter();
+// secondLine += "Not all nodes have returned balance. Swipe down or tap again. ";
+// if(score <= 0)
+// return;
+// }
+
+ //
+// if(card.isBalanceReceived() && !card.isBalanceEqual()) {
+// score = 0;
+// firstLine = "Disputed balance";
+// secondLine += " Cannot obtain trusted balance at the moment. Try to tap and check this banknote later.";
+// return;
+// }
+
+ return true;
+ }
+
+ @Override
+ public Amount getBalance() {
+ if (!hasBalanceInfo()) return null;
+ 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[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException {
+ byte netSelectionByte = (byte) 0x30;
+
+ 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((byte) 0x6f);
+ 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) {
+ BigDecimal d = amount.multiply(new BigDecimal("100000000"));
+ return new InternalAmount(d, "Satoshi");
+ }
+
+ @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) {
+ 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() {
+ return coinData.getUnspentInputsDescription();
+ }
+
+ @Override
+ public SignTask.PaymentToSign constructPayment(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception {
+ final ArrayList unspentOutputs;
+ checkBlockchainDataExists();
+
+ String myAddress = ctx.getCoinData().getWallet();
+ byte[] pbKey = ctx.getCard().getWalletPublicKey();
+
+ // Build script for our address
+ List rawTxList = coinData.getUnspentTransactions();
+ byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes;
+
+ // Collect unspent
+ unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
+
+ 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;
+ }
+
+ final long amountFinal=amount;
+ final long changeFinal=change;
+
+ if (amount + fees > fullAmount) {
+ throw new CardProtocol.TangemException_WrongAmount(String.format("Balance (%d) < change (%d) + amount (%d)", fullAmount, change, amount));
+ }
+
+ final byte[][] txForSign = new byte[unspentOutputs.size()][];
+ final byte[][] bodyDoubleHash = new byte[unspentOutputs.size()][];
+ final byte[][] bodyHash= new byte[unspentOutputs.size()][];
+
+ for (int i = 0; i < unspentOutputs.size(); ++i) {
+ txForSign[i] = BTCUtils.buildTXForSign(myAddress, targetAddress, myAddress, unspentOutputs, i, amount, change);
+ bodyHash[i] = Util.calculateSHA256(txForSign[i]);
+ bodyDoubleHash[i] = Util.calculateSHA256(bodyHash[i]);
+ }
+
+ return new SignTask.PaymentToSign() {
+
+ @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()][];
+ if (txForSign.length > 10) throw new Exception("To much hashes in one transaction!");
+ 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("Issuer validation not supported!");
+ }
+
+ @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.packSignDer(r, s, pbKey);
+ }
+
+ byte[] txForSend=BTCUtils.buildTXForSend(targetAddress, myAddress, unspentOutputs, amountFinal, changeFinal);
+ notifyOnNeedSendPayment(txForSend);
+ return txForSend;
+ }
+ };
+ }
+
+ private final static BigDecimal relayFee = new BigDecimal(0.00001);
+
+ @Override
+ public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception {
+ final int calcSize = calculateEstimatedTransactionSize(targetAddress, amount.toValueString());
+ Log.e(TAG, String.format("Estimated tx size %d", calcSize));
+ coinData.minFee=null;
+ coinData.maxFee=null;
+ coinData.normalFee=null;
+
+ final ServerApiElectrum serverApiElectrum = new ServerApiElectrum();
+
+ final ServerApiElectrum.ElectrumRequestDataListener electrumListener = new ServerApiElectrum.ElectrumRequestDataListener () {
+ @Override
+ public void onSuccess(ElectrumRequest electrumRequest) {
+ BigDecimal fee;
+ if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetFee)) {
+ try {
+ fee = new BigDecimal(electrumRequest.getResultString()); //fee per KB
+
+ if (fee.equals(BigDecimal.ZERO)) {
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getFee());
+ }
+
+// if (calcSize != 0) {
+ fee = fee.multiply(new BigDecimal(calcSize)).divide(new BigDecimal(1024)); // (per KB -> per byte)*size
+// } else {
+// serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getFee());
+// }
+
+ //compare fee to usual relay fee
+ if (fee.compareTo(relayFee) < 0) {
+ fee = relayFee;
+ }
+ fee = fee.setScale(8, RoundingMode.DOWN);
+
+ CoinEngine.Amount feeAmount = new CoinEngine.Amount(fee, ctx.getBlockchain().getCurrency());
+ coinData.minFee = feeAmount;
+ coinData.normalFee = feeAmount;
+ coinData.maxFee = feeAmount;
+// if (coinData.minFee != null && coinData.normalFee != null && coinData.maxFee != null) {
+ blockchainRequestsCallbacks.onComplete(true);
+// } else {
+// blockchainRequestsCallbacks.onProgress();
+// }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void onFail(ElectrumRequest electrumRequest) {
+ ctx.setError(electrumRequest.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+ serverApiElectrum.setElectrumRequestData(electrumListener);
+
+ serverApiElectrum.electrumRequestData(ctx, ElectrumRequest.getFee());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/wallet/token/TokenData.java b/app/src/main/java/com/tangem/domain/wallet/token/TokenData.java
index b0bfd6cd50..832cc379de 100644
--- a/app/src/main/java/com/tangem/domain/wallet/token/TokenData.java
+++ b/app/src/main/java/com/tangem/domain/wallet/token/TokenData.java
@@ -28,7 +28,11 @@ public class TokenData extends EthData {
public void loadFromBundle(Bundle B) {
super.loadFromBundle(B);
- balanceAlter = new CoinEngine.InternalAmount(B.getString("BalanceDecimalAlter"),"wei");
+ if( B.containsKey("BalanceDecimalAlter" )) {
+ balanceAlter = new CoinEngine.InternalAmount(B.getString("BalanceDecimalAlter"), "wei");
+ }else{
+ balanceAlter=null;
+ }
}
@Override
@@ -36,7 +40,9 @@ public class TokenData extends EthData {
super.saveToBundle(B);
try {
- B.putString("BalanceDecimalAlter", balanceAlter.toString());
+ if( balanceAlter!=null ) {
+ B.putString("BalanceDecimalAlter", balanceAlter.toString());
+ }
} catch (Exception e) {
Log.e("Can't save to bundle ", e.getMessage());
}
diff --git a/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java b/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java
index a509810107..23bdd7d2e5 100644
--- a/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java
+++ b/app/src/main/java/com/tangem/domain/wallet/token/TokenEngine.java
@@ -1,23 +1,25 @@
package com.tangem.domain.wallet.token;
import android.net.Uri;
+import android.os.Bundle;
import android.text.InputFilter;
import android.util.Log;
import com.google.common.base.Strings;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.cardReader.CardProtocol;
-import com.tangem.domain.cardReader.TLV;
+import com.tangem.data.Blockchain;
+import com.tangem.data.network.ServerApiInfura;
+import com.tangem.data.network.model.InfuraResponse;
+import com.tangem.domain.wallet.BTCUtils;
import com.tangem.domain.wallet.BalanceValidator;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;
import com.tangem.domain.wallet.ECDSASignatureETH;
import com.tangem.domain.wallet.EthTransaction;
-import com.tangem.domain.wallet.Issuer;
import com.tangem.domain.wallet.Keccak256;
-import com.tangem.domain.wallet.TangemCard;
import com.tangem.domain.wallet.TangemContext;
-import com.tangem.domain.wallet.BTCUtils;
+import com.tangem.domain.wallet.eth.EthData;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.tasks.SignTask;
import com.tangem.util.CryptoUtil;
import com.tangem.util.DecimalDigitsInputFilter;
import com.tangem.wallet.R;
@@ -27,8 +29,6 @@ import org.bitcoinj.core.ECKey;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
import java.util.Arrays;
/**
@@ -37,6 +37,7 @@ import java.util.Arrays;
public class TokenEngine extends CoinEngine {
+ private static final String TAG = TokenEngine.class.getSimpleName();
public TokenData coinData = null;
public TokenEngine(TangemContext ctx) throws Exception {
@@ -46,6 +47,13 @@ public class TokenEngine extends CoinEngine {
ctx.setCoinData(coinData);
} else if (ctx.getCoinData() instanceof TokenData) {
coinData = (TokenData) ctx.getCoinData();
+ } else if (ctx.getCoinData() instanceof EthData) {
+ // special case with receive card data substitution from server at the moment
+ Bundle B=new Bundle();
+ ctx.getCoinData().saveToBundle(B);
+ coinData = new TokenData();
+ coinData.loadFromBundle(B);
+ ctx.setCoinData(coinData);
} else {
throw new Exception("Invalid type of Blockchain data for TokenEngine");
}
@@ -101,7 +109,7 @@ public class TokenEngine extends CoinEngine {
if (coinData.getBalanceInInternalUnits().notZero()) {
return currency;
} else {
- return "ETH";
+ return Blockchain.Ethereum.getCurrency();
}
} else {
return currency;
@@ -120,7 +128,7 @@ public class TokenEngine extends CoinEngine {
@Override
public String getFeeCurrency() {
- return "ETH";
+ return Blockchain.Ethereum.getCurrency();
}
@Override
@@ -128,15 +136,15 @@ public class TokenEngine extends CoinEngine {
return ctx.getString(R.string.not_implemented);
}
- public static int getEthDecimals() {
+ private static int getEthDecimals() {
return 18;
}
- public int getTokenDecimals() {
+ private int getTokenDecimals() {
return ctx.getCard().getTokensDecimal();
}
- public String getContractAddress(TangemCard card) {
+ private String getContractAddress(TangemCard card) {
return card.getContractAddress();
}
@@ -161,7 +169,7 @@ public class TokenEngine extends CoinEngine {
return true;
}
- public boolean isBalanceAlterNotZero() {
+ private boolean isBalanceAlterNotZero() {
if (coinData == null) return false;
if (coinData.getBalanceAlterInInternalUnits() == null) return false;
return coinData.getBalanceAlterInInternalUnits().notZero();
@@ -170,7 +178,7 @@ public class TokenEngine extends CoinEngine {
@Override
public boolean isBalanceNotZero() {
if (coinData == null) return false;
- if (coinData.getBalanceInInternalUnits() == null && coinData.getBalanceAlterInInternalUnits() == null ) return false;
+ if (coinData.getBalanceInInternalUnits() == null && coinData.getBalanceAlterInInternalUnits() == null) return false;
return coinData.getBalanceInInternalUnits().notZero() || coinData.getBalanceAlterInInternalUnits().notZero();
}
@@ -185,7 +193,7 @@ public class TokenEngine extends CoinEngine {
// TODO: check why Rate=EthRate
return "";//convertToAmount(coinData.getBalanceInInternalUnits()).toEquivalentString(coinData.getRate());
} else {
- if( coinData.getBalanceAlterInInternalUnits()==null ) return "";
+ if (coinData.getBalanceAlterInInternalUnits() == null) return "";
return convertToAmount(coinData.getBalanceAlterInInternalUnits()).toEquivalentString(coinData.getRateAlter());
}
} catch (Exception e) {
@@ -195,11 +203,11 @@ public class TokenEngine extends CoinEngine {
}
@Override
- public String calculateAddress(byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException {
+ public String calculateAddress(byte[] pkUncompressed) {
Keccak256 kec = new Keccak256();
int lenPk = pkUncompressed.length;
if (lenPk < 2) {
- throw new IllegalArgumentException("Uncompress public key length is invald");
+ throw new IllegalArgumentException("Uncompress public key length is invalid");
}
byte[] cleanKey = new byte[lenPk - 1];
for (int i = 0; i < cleanKey.length; ++i) {
@@ -219,7 +227,7 @@ public class TokenEngine extends CoinEngine {
public Amount convertToAmount(InternalAmount internalAmount) throws Exception {
if (internalAmount.getCurrency().equals("wei")) {
BigDecimal d = internalAmount.divide(new BigDecimal("1000000000000000000"), getEthDecimals(), RoundingMode.DOWN);
- return new Amount(d, "ETH");
+ return new Amount(d, Blockchain.Ethereum.getCurrency());
} else if (internalAmount.getCurrency().equals(ctx.getCard().getTokenSymbol())) {
BigDecimal p = new BigDecimal(10);
p = p.pow(getTokenDecimals());
@@ -236,7 +244,7 @@ public class TokenEngine extends CoinEngine {
@Override
public InternalAmount convertToInternalAmount(Amount amount) throws Exception {
- if (amount.getCurrency().equals("ETH")) {
+ if (amount.getCurrency().equals(Blockchain.Ethereum.getCurrency())) {
BigDecimal d = amount.multiply(new BigDecimal("1000000000000000000"));
return new InternalAmount(d, "wei");
} else if (amount.getCurrency().equals(ctx.getCard().getTokenSymbol())) {
@@ -282,15 +290,15 @@ public class TokenEngine extends CoinEngine {
@Override
public Uri getShareWalletUriExplorer() {
- return Uri.parse("https://etherscan.io/token/" + getContractAddress(ctx.getCard()) + "?a=" + ctx.getCard().getWallet());
+ return Uri.parse("https://etherscan.io/token/" + getContractAddress(ctx.getCard()) + "?a=" + ctx.getCoinData().getWallet());
}
@Override
public Uri getShareWalletUri() {
if (ctx.getCard().getDenomination() != null) {
- return Uri.parse("ethereum:" + ctx.getCard().getWallet());// + "?value=" + mCard.getDenomination() +"e18");
+ return Uri.parse("ethereum:" + ctx.getCoinData().getWallet());// + "?value=" + mCard.getDenomination() +"e18");
} else {
- return Uri.parse("ethereum:" + ctx.getCard().getWallet());
+ return Uri.parse("ethereum:" + ctx.getCoinData().getWallet());
}
}
@@ -317,7 +325,7 @@ public class TokenEngine extends CoinEngine {
try {
if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) {
balance = convertToAmount(coinData.getBalanceInInternalUnits());
- } else if (amount.getCurrency().equals("ETH") && coinData.getBalanceInInternalUnits().isZero()) {
+ } else if (amount.getCurrency().equals(Blockchain.Ethereum.getCurrency()) && coinData.getBalanceInInternalUnits().isZero()) {
balance = convertToAmount(coinData.getBalanceAlterInInternalUnits());
} else {
return false;
@@ -334,7 +342,7 @@ public class TokenEngine extends CoinEngine {
if (!hasBalanceInfo()) return false;
try {
- Amount balance = convertToAmount(coinData.getBalanceAlterInInternalUnits());
+ Amount balanceETH = convertToAmount(coinData.getBalanceAlterInInternalUnits());
if (fee == null || amount == null || fee.isZero() || amount.isZero())
return false;
@@ -342,22 +350,20 @@ public class TokenEngine extends CoinEngine {
if (amount.getCurrency().equals(ctx.getCard().tokenSymbol)) {
// token transaction
- if( fee.compareTo(balance)>0 )
+ if (fee.compareTo(balanceETH) > 0)
return false;
- } else if (amount.getCurrency().equals("ETH") && coinData.getBalanceInInternalUnits().isZero()) {
- // standart ETH transaction
- try {
- BigDecimal cardBalance = getBalance();
-
- if (isFeeIncluded && amount.compareTo(cardBalance) > 0)
+ } else if (amount.getCurrency().equals(Blockchain.Ethereum.getCurrency()) && coinData.getBalanceInInternalUnits().isZero()) {
+ // standard ETH transaction
+// try {
+ if (isFeeIncluded && (amount.compareTo(balanceETH) > 0 || fee.compareTo(balanceETH) > 0))
return false;
- if (!isFeeIncluded && amount.add(fee).compareTo(cardBalance) > 0)
+ if (!isFeeIncluded && amount.add(fee).compareTo(balanceETH) > 0)
return false;
- } catch (NumberFormatException e) {
- e.printStackTrace();
- }
+// } catch (NumberFormatException e) {
+// e.printStackTrace();
+// }
} else
{
@@ -425,19 +431,19 @@ public class TokenEngine extends CoinEngine {
}
@Override
- public byte[] sign(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress, CardProtocol protocol) throws Exception {
- if (amountValue.getCurrency().equals("ETH")) {
- return signETH(feeValue, amountValue, IncFee, targetAddress, protocol);
+ public SignTask.PaymentToSign constructPayment(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception {
+ if (amountValue.getCurrency().equals(Blockchain.Ethereum.getCurrency())) {
+ return constructPaymentETH(feeValue, amountValue, IncFee, targetAddress);
} else {
- return signToken(feeValue, amountValue, IncFee, targetAddress, protocol);
+ return constructPaymentToken(feeValue, amountValue, IncFee, targetAddress);
}
}
- public byte[] signETH(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress, CardProtocol protocol) throws Exception {
+ private SignTask.PaymentToSign constructPaymentETH(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress) throws Exception {
+ Log.e(TAG, "Construct ETH payment "+amountValue.toString()+" with fee "+feeValue.toString()+(IncFee?" including":" excluding"));
+
BigInteger nonceValue = coinData.getConfirmedTXCount();
byte[] pbKey = ctx.getCard().getWalletPublicKey();
- boolean flag = (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer);
- Issuer issuer = ctx.getCard().getIssuer();
BigInteger weiFee = convertToInternalAmount(feeValue).toBigIntegerExact();
BigInteger weiAmount = convertToInternalAmount(amountValue).toBigIntegerExact();
@@ -446,10 +452,8 @@ public class TokenEngine extends CoinEngine {
weiAmount = weiAmount.subtract(weiFee);
}
- BigInteger nonce = nonceValue;
BigInteger gasPrice = weiFee.divide(BigInteger.valueOf(21000));
BigInteger gasLimit = BigInteger.valueOf(21000);
-
// Integer chainId = ctx.getBlockchain() == Blockchain.Ethereum ? EthTransaction.ChainEnum.Mainnet.getValue() : EthTransaction.ChainEnum.Rinkeby.getValue();
Integer chainId = EthTransaction.ChainEnum.Mainnet.getValue(); // Token support on main net only!!!
@@ -459,62 +463,84 @@ public class TokenEngine extends CoinEngine {
to = to.substring(2);
}
- EthTransaction tx = EthTransaction.create(to, weiAmount, nonce, gasPrice, gasLimit, chainId);
+ final EthTransaction tx = EthTransaction.create(to, weiAmount, nonceValue, gasPrice, gasLimit, chainId);
- byte[][] hashesForSign = new byte[1][];
- byte[] for_hash = tx.getRawHash();
- hashesForSign[0] = for_hash;
+ return new SignTask.PaymentToSign() {
+ @Override
+ public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) {
+ return signingMethod == TangemCard.SigningMethod.Sign_Hash;
+ }
- byte[] signFromCard = null;
- try {
- signFromCard = protocol.run_SignHashes(PINStorage.getPIN2(), hashesForSign, flag, null, issuer).getTLV(TLV.Tag.TAG_Signature).Value;
- // TODO slice signFromCard to hashes.length parts
- } catch (Exception ex) {
- Log.e("ETH", ex.getMessage());
- return null;
- }
+ @Override
+ public byte[][] getHashesToSign() {
+ byte[][] hashesForSign = new byte[1][];
+ hashesForSign[0] = tx.getRawHash();
+ return hashesForSign;
+ }
- BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, 32));
- BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32, 64));
- s = CryptoUtil.toCanonicalised(s);
+ @Override
+ public byte[] getRawDataToSign() throws Exception {
+ throw new Exception("Signing of raw transaction not supported for ETH");
+ }
- boolean f = ECKey.verify(for_hash, new ECKey.ECDSASignature(r, s), pbKey);
+ @Override
+ public String getHashAlgToSign() throws Exception {
+ throw new Exception("Signing of raw transaction not supported for ETH");
+ }
- if (!f) {
- Log.e("ETH-CHECK", "sign Failed.");
- }
+ @Override
+ public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception {
+ throw new Exception("Transaction validation by issuer not supported in this version");
+ }
- tx.signature = new ECDSASignatureETH(r, s);
- int v = tx.BruteRecoveryID2(tx.signature, for_hash, pbKey);
- if (v != 27 && v != 28) {
- Log.e("ETH", "invalid v");
- return null;
- }
- tx.signature.v = (byte) v;
- Log.e("ETH_v", String.valueOf(v));
+ @Override
+ public byte[] onSignCompleted(byte[] signFromCard) throws Exception {
+ byte[] for_hash = tx.getRawHash();
+ BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, 32));
+ BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32, 64));
+ s = CryptoUtil.toCanonicalised(s);
- byte[] realTX = tx.getEncoded();
- return realTX;
+ boolean f = ECKey.verify(for_hash, new ECKey.ECDSASignature(r, s), pbKey);
+
+ if (!f) {
+ Log.e("ETH-CHECK", "sign Failed.");
+ }
+
+ tx.signature = new ECDSASignatureETH(r, s);
+ int v = tx.BruteRecoveryID2(tx.signature, for_hash, pbKey);
+ if (v != 27 && v != 28) {
+ Log.e(TAG, "invalid v");
+ throw new Exception("Error in EthEngine - invalid v");
+ }
+ tx.signature.v = (byte) v;
+ Log.e(TAG,"ETH_v "+ String.valueOf(v));
+
+ byte[] txForSend = tx.getEncoded();
+ notifyOnNeedSendPayment(txForSend);
+ return txForSend;
+ }
+ };
}
- public byte[] signToken(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress, CardProtocol protocol) throws Exception {
+ private SignTask.PaymentToSign constructPaymentToken(Amount feeValue, Amount amountValue, boolean IncFee, String targetAddress) throws Exception {
+ Log.e(TAG, "Construct TOKEN payment "+amountValue.toString()+" with fee "+feeValue.toString()+(IncFee?" including":" excluding"));
+
BigInteger nonceValue = coinData.getConfirmedTXCount();
byte[] pbKey = ctx.getCard().getWalletPublicKey();
- boolean flag = (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer);
- Issuer issuer = ctx.getCard().getIssuer();
+// boolean flag = (ctx.getCard().getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer);
+// Issuer issuer = ctx.getCard().getIssuer();
- BigInteger gigaK = BigInteger.valueOf(1000000000L);
+// BigInteger gigaK = BigInteger.valueOf(1000000000L);
BigInteger weiFee = convertToInternalAmount(feeValue).toBigIntegerExact();
- InternalAmount amountDec=convertToInternalAmount(amountValue);
+ InternalAmount amountDec = convertToInternalAmount(amountValue);
BigInteger amount = amountDec.toBigInteger(); //new BigInteger(amountValue, 10);
//amount = amount.subtract(fee);
- BigInteger nonce = nonceValue;
BigInteger gasPrice = weiFee.divide(BigInteger.valueOf(60000));
BigInteger gasLimit = BigInteger.valueOf(60000);
Integer chainId = EthTransaction.ChainEnum.Mainnet.getValue();
@@ -545,41 +571,239 @@ public class TokenEngine extends CoinEngine {
byte[] data = BTCUtils.fromHex(cmd);
- EthTransaction tx = EthTransaction.create(contractAddress, amountZero, nonce, gasPrice, gasLimit, chainId, data);
+ EthTransaction tx = EthTransaction.create(contractAddress, amountZero, nonceValue, gasPrice, gasLimit, chainId, data);
- byte[][] hashesForSign = new byte[1][];
- byte[] for_hash = tx.getRawHash();
- hashesForSign[0] = for_hash;
+ return new SignTask.PaymentToSign() {
+ @Override
+ public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) {
+ return signingMethod == TangemCard.SigningMethod.Sign_Hash;
+ }
- byte[] signFromCard = null;
- try {
- signFromCard = protocol.run_SignHashes(PINStorage.getPIN2(), hashesForSign, flag, null, issuer).getTLV(TLV.Tag.TAG_Signature).Value;
- // TODO slice signFromCard to hashes.length parts
- } catch (Exception ex) {
- Log.e("ETH", ex.getMessage());
- return null;
- }
+ @Override
+ public byte[][] getHashesToSign() {
+ byte[][] hashesForSign = new byte[1][];
+ hashesForSign[0] = tx.getRawHash();
+ return hashesForSign;
+ }
- BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, 32));
- BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32, 64));
- s = CryptoUtil.toCanonicalised(s);
+ @Override
+ public byte[] getRawDataToSign() throws Exception {
+ throw new Exception("Signing of raw transaction not supported for ETH");
+ }
- boolean f = ECKey.verify(for_hash, new ECKey.ECDSASignature(r, s), pbKey);
+ @Override
+ public String getHashAlgToSign() throws Exception {
+ throw new Exception("Signing of raw transaction not supported for ETH");
+ }
- if (!f) {
- Log.e("ETH-CHECK", "sign Failed.");
- }
+ @Override
+ public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception {
+ throw new Exception("Transaction validation by issuer not supported in this version");
+ }
- tx.signature = new ECDSASignatureETH(r, s);
- int v = tx.BruteRecoveryID2(tx.signature, for_hash, pbKey);
- if (v != 27 && v != 28) {
- Log.e("ETH", "invalid v");
- return null;
- }
- tx.signature.v = (byte) v;
- Log.e("ETH_v", String.valueOf(v));
+ @Override
+ public byte[] onSignCompleted(byte[] signFromCard) throws Exception {
+ byte[] for_hash = tx.getRawHash();
+ BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0, 32));
+ BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32, 64));
+ s = CryptoUtil.toCanonicalised(s);
+
+ boolean f = ECKey.verify(for_hash, new ECKey.ECDSASignature(r, s), pbKey);
+
+ if (!f) {
+ Log.e("ETH-CHECK", "sign Failed.");
+ }
+
+ tx.signature = new ECDSASignatureETH(r, s);
+ int v = tx.BruteRecoveryID2(tx.signature, for_hash, pbKey);
+ if (v != 27 && v != 28) {
+ Log.e(TAG, "invalid v");
+ throw new Exception("Error in EthEngine - invalid v");
+ }
+ tx.signature.v = (byte) v;
+ Log.e(TAG,"ETH_v: "+ String.valueOf(v));
+
+ byte[] txForSend = tx.getEncoded();
+ notifyOnNeedSendPayment(txForSend);
+ return txForSend;
+
+ }
+ };
- byte[] realTX = tx.getEncoded();
- return realTX;
}
+
+ @Override
+ public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) {
+ final ServerApiInfura serverApiInfura = new ServerApiInfura();
+ // request infura listener
+ ServerApiInfura.InfuraBodyListener infuraBodyListener = new ServerApiInfura.InfuraBodyListener() {
+ @Override
+ public void onSuccess(String method, InfuraResponse infuraResponse) {
+ switch (method) {
+ case ServerApiInfura.INFURA_ETH_GET_BALANCE: {
+ String balanceCap = infuraResponse.getResult();
+ balanceCap = balanceCap.substring(2);
+ BigInteger l = new BigInteger(balanceCap, 16);
+ coinData.setBalanceReceived(true);
+ coinData.setBalanceAlterInInternalUnits(new CoinEngine.InternalAmount(l, "wei"));
+
+// Log.i("$TAG eth_get_balance", balanceCap)
+ }
+ break;
+
+ case ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT: {
+ String nonce = infuraResponse.getResult();
+ nonce = nonce.substring(2);
+ BigInteger count = new BigInteger(nonce, 16);
+ coinData.setConfirmedTXCount(count);
+
+
+// Log.i("$TAG eth_getTransCount", nonce)
+ }
+ break;
+
+ case ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT: {
+ String pending = infuraResponse.getResult();
+ pending = pending.substring(2);
+ BigInteger count = new BigInteger(pending, 16);
+ coinData.setUnconfirmedTXCount(count);
+
+// Log.i("$TAG eth_getPendingTxCount", pending)
+ }
+ break;
+//
+ case ServerApiInfura.INFURA_ETH_CALL: {
+ try {
+ String balanceCap = infuraResponse.getResult();
+ balanceCap = balanceCap.substring(2);
+ BigInteger l = new BigInteger(balanceCap, 16);
+ coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol));
+
+// Log.i("$TAG eth_call", balanceCap)
+
+ if (blockchainRequestsCallbacks.allowAdvance()) {
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
+ } else {
+ ctx.setError("Terminated by user");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ break;
+
+ }
+ if (serverApiInfura.isRequestsSequenceCompleted()) {
+ blockchainRequestsCallbacks.onComplete(!ctx.hasError());
+ } else {
+ blockchainRequestsCallbacks.onProgress();
+ }
+ }
+
+ @Override
+ public void onFail(String method, String message) {
+ if (!serverApiInfura.isRequestsSequenceCompleted()) {
+ ctx.setError(message);
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ }
+ };
+ serverApiInfura.setInfuraResponse(infuraBodyListener);
+
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
+ }
+
+ @Override
+ public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) {
+ ServerApiInfura serverApiInfura = new ServerApiInfura();
+ // request infura eth gasPrice listener
+ ServerApiInfura.InfuraBodyListener infuraBodyListener = new ServerApiInfura.InfuraBodyListener() {
+ @Override
+ public void onSuccess(String method, InfuraResponse infuraResponse) {
+ String gasPrice = infuraResponse.getResult();
+ gasPrice = gasPrice.substring(2);
+
+ // rounding gas price to integer gwei
+ BigInteger l = new BigInteger(gasPrice, 16);
+
+ Log.i(TAG, "Infura gas price: "+gasPrice+" ("+l.toString()+")");
+ BigInteger m;
+ if (!amount.getCurrency().equals(Blockchain.Ethereum.getCurrency())) m = BigInteger.valueOf(60000);
+ else m = BigInteger.valueOf(21000);
+
+ Log.i(TAG, "fee multiplier: "+m.toString());
+
+ CoinEngine.InternalAmount weiMinFee = new CoinEngine.InternalAmount(l.multiply(m), "wei");
+ CoinEngine.InternalAmount weiNormalFee = new CoinEngine.InternalAmount(l.multiply(BigInteger.valueOf(12)).divide(BigInteger.valueOf(10)).multiply(m), "wei");
+ CoinEngine.InternalAmount weiMaxFee = new CoinEngine.InternalAmount(l.multiply(BigInteger.valueOf(15)).divide(BigInteger.valueOf(10)).multiply(m), "wei");
+ Log.i(TAG, "min fee : "+weiMinFee.toValueString()+" wei");
+ Log.i(TAG, "normal fee: "+weiNormalFee.toValueString()+" wei");
+ Log.i(TAG, "max fee : "+weiMaxFee.toValueString()+" wei");
+
+ try {
+ coinData.minFee = convertToAmount(weiMinFee);
+ coinData.normalFee = convertToAmount(weiNormalFee);
+ coinData.maxFee = convertToAmount(weiMaxFee);
+ Log.i(TAG, "min fee : "+coinData.minFee.toString());
+ Log.i(TAG, "normal fee: "+coinData.normalFee.toString());
+ Log.i(TAG, "max fee : "+coinData.maxFee.toString());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ blockchainRequestsCallbacks.onComplete(true);
+ }
+
+ @Override
+ public void onFail(String method, String message) {
+ ctx.setError(message);
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ };
+ serverApiInfura.setInfuraResponse(infuraBodyListener);
+
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_GAS_PRICE, 67, coinData.getWallet(), "", "");
+ }
+
+ @Override
+ public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) {
+
+ String txStr = String.format("0x%s", BTCUtils.toHex(txForSend));
+
+ ServerApiInfura serverApiInfura = new ServerApiInfura();
+ // request infura eth gasPrice listener
+ ServerApiInfura.InfuraBodyListener infuraBodyListener = new ServerApiInfura.InfuraBodyListener() {
+ @Override
+ public void onSuccess(String method, InfuraResponse infuraResponse) {
+ if (method.equals(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION)) {
+ if (infuraResponse.getResult().isEmpty()) {
+ ctx.setError("Rejected by node: " + infuraResponse.getError());
+ blockchainRequestsCallbacks.onComplete(false);
+ } else {
+ BigInteger nonce = coinData.getConfirmedTXCount();
+ nonce=nonce.add(BigInteger.valueOf(1));
+ coinData.setConfirmedTXCount(nonce);
+ ctx.setError(null);
+ blockchainRequestsCallbacks.onComplete(true);
+ }
+ }
+ }
+
+ @Override
+ public void onFail(String method, String message) {
+ if (method.equals(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION)) {
+ ctx.setError(message);
+ blockchainRequestsCallbacks.onComplete(false);
+ }
+ }
+ };
+
+ serverApiInfura.setInfuraResponse(infuraBodyListener);
+
+ serverApiInfura.infura(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION, 67, coinData.getWallet(), "", txStr);
+
+ }
+
}
diff --git a/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.kt b/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.kt
index 9b3741d068..d6329df62b 100644
--- a/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.kt
@@ -9,60 +9,40 @@ import android.support.v7.app.AppCompatActivity
import android.text.Editable
import android.text.Html
import android.text.TextWatcher
-import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.widget.Toast
-import com.tangem.data.network.ElectrumRequest
-import com.tangem.data.network.ServerApiCommon
-import com.tangem.data.network.ServerApiElectrum
-import com.tangem.data.network.ServerApiInfura
-import com.tangem.data.network.model.InfuraResponse
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.*
-import com.tangem.domain.wallet.btc.BtcData
-import com.tangem.util.*
+import com.tangem.Constant
+import com.tangem.data.Blockchain
+import com.tangem.domain.wallet.CoinEngine
+import com.tangem.domain.wallet.CoinEngineFactory
+import com.tangem.domain.wallet.TangemContext
+import com.tangem.presentation.event.TransactionFinishWithError
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.data.TangemCard
+import com.tangem.tangemcard.data.loadFromBundle
+import com.tangem.util.UtilHelper
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_confirm_payment.*
-import org.json.JSONException
+import org.greenrobot.eventbus.EventBus
import java.io.IOException
-import java.math.BigDecimal
-import java.math.BigInteger
-import java.math.RoundingMode
import java.util.*
class ConfirmPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
- companion object {
- private const val REQUEST_CODE_SIGN_PAYMENT = 1
- private const val REQUEST_CODE_REQUEST_PIN2 = 2
- }
-
- private var nfcManager: NfcManager? = null
-
- private var serverApiCommon: ServerApiCommon = ServerApiCommon()
- private var serverApiInfura: ServerApiInfura = ServerApiInfura()
- private var serverApiElectrum: ServerApiElectrum = ServerApiElectrum()
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
private lateinit var amount: CoinEngine.Amount
- private var feeRequestSuccess = false
-// private var balanceRequestSuccess = false
- private var minFee: CoinEngine.Amount? = null
- private var maxFee: CoinEngine.Amount? = null
- private var normalFee: CoinEngine.Amount? = null
private var isIncludeFee: Boolean = true
private var requestPIN2Count = 0
private var nodeCheck = true
private var dtVerified: Date? = null
- private var calcSize: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_confirm_payment)
- MainActivity.commonInit(applicationContext)
-
nfcManager = NfcManager(this, this)
ctx = TangemContext.loadFromBundle(this, intent.extras)
@@ -72,16 +52,16 @@ class ConfirmPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
val html = Html.fromHtml(engine!!.balanceHTML)
tvBalance.text = html
- isIncludeFee = intent.getBooleanExtra(SignPaymentActivity.EXTRA_FEE_INCLUDED, true)
+ isIncludeFee = intent.getBooleanExtra(Constant.EXTRA_FEE_INCLUDED, true)
if (isIncludeFee)
tvIncFee.setText(R.string.including_fee)
else
tvIncFee.setText(R.string.not_including_fee)
- amount = CoinEngine.Amount(intent.getStringExtra(SignPaymentActivity.EXTRA_AMOUNT), intent.getStringExtra(SignPaymentActivity.EXTRA_AMOUNT_CURRENCY))
+ amount = CoinEngine.Amount(intent.getStringExtra(Constant.EXTRA_AMOUNT), intent.getStringExtra(Constant.EXTRA_AMOUNT_CURRENCY))
- if (ctx.blockchain == Blockchain.Token && amount.currency!="ETH")
+ if (ctx.blockchain == Blockchain.Token && amount.currency != Blockchain.Ethereum.currency)
tvIncFee.visibility = View.INVISIBLE
else
tvIncFee.visibility = View.VISIBLE
@@ -90,36 +70,12 @@ class ConfirmPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
tvCurrency.text = engine.balanceCurrency
tvCurrency2.text = engine.feeCurrency
tvCardID.text = ctx.card!!.cidDescription
- etWallet.setText(intent.getStringExtra(SignPaymentActivity.EXTRA_TARGET_ADDRESS))
+ etWallet.setText(intent.getStringExtra(Constant.EXTRA_TARGET_ADDRESS))
etFee.setText("")
btnSend.visibility = View.INVISIBLE
- feeRequestSuccess = false
-// balanceRequestSuccess = false
- if (ctx.blockchain == Blockchain.Ethereum || ctx.blockchain == Blockchain.EthereumTestNet || ctx.blockchain == Blockchain.Token) {
- rgFee.isEnabled = false
-
- requestInfura(ServerApiInfura.INFURA_ETH_GAS_PRICE)
-
- } else {
- rgFee.isEnabled = true
-
-// requestElectrum(ctx.card, ElectrumRequest.checkBalance(ctx.card!!.wallet))
-
- calcSize = 256
- try {
- calcSize = buildSize(etWallet!!.text.toString(), "0.00", etAmount.text.toString())
- } catch (ex: Exception) {
- Log.e("Build Fee error", ex.message)
- }
-
- ctx.coinData!!.resetFailedBalanceRequestCounter()
-
- progressBar.visibility = View.VISIBLE
-
- requestEstimateFee()
- }
+ rgFee.isEnabled = !(ctx.blockchain == Blockchain.Ethereum || ctx.blockchain == Blockchain.EthereumTestNet || ctx.blockchain == Blockchain.Token || ctx.blockchain == Blockchain.BitcoinCash || ctx.blockchain == Blockchain.Litecoin)
// set listeners
rgFee.setOnCheckedChangeListener { _, checkedId -> doSetFee(checkedId) }
@@ -190,158 +146,58 @@ class ConfirmPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
requestPIN2Count = 0
val intent = Intent(baseContext, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
+ intent.putExtra(Constant.EXTRA_MODE, PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
- intent.putExtra(SignPaymentActivity.EXTRA_FEE_INCLUDED, isIncludeFee)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2)
+ intent.putExtra(Constant.EXTRA_FEE_INCLUDED, isIncludeFee)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_)
}
- // request electrum listener
-// val electrumBodyListener: ServerApiHelperElectrum.ElectrumRequestDataListener = object : ServerApiHelperElectrum.ElectrumRequestDataListener {
-// override fun onSuccess(electrumRequest: ElectrumRequest?) {
-// if (electrumRequest!!.isMethod(ElectrumRequest.METHOD_GetBalance)) {
-// try {
-// if (etFee.text.toString().isEmpty()) etFee.setText(getString(R.string.empty))
-// val engine = CoinEngineFactory.create(ctx)
-// val balance = engine.convertToAmount(CoinEngine.InternalAmount(electrumRequest.result.getLong("confirmed") + electrumRequest.result.getLong("unconfirmed"), "Satoshi"))
-// val amount = CoinEngine.Amount(etAmount.text.toString(), ctx.blockchain.currency)
-// if (balance < amount) {
-// etFee.error = getString(R.string.not_enough_funds)
-// } else {
-// etFee.error = null
-// balanceRequestSuccess = true
-// if (feeRequestSuccess && balanceRequestSuccess) {
-// btnSend.visibility = View.VISIBLE
-// }
-// dtVerified = Date()
-// nodeCheck = true
-// }
-// } catch (e: JSONException) {
-// e.printStackTrace()
-//// requestElectrum(ctx.card!!, ElectrumRequest.checkBalance(ctx.card!!.wallet))
-// }
-// }
-// }
-//
-// override fun onFail(message: String?) {
-// finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_check_balance_no_connection_with_blockchain_nodes))
-// }
-//
-// }
-// serverApiHelperElectrum.setElectrumRequestData(electrumBodyListener)
+ val coinEngine = CoinEngineFactory.create(ctx)
- // request infura eth gasPrice listener
- val infuraBodyListener: ServerApiInfura.InfuraBodyListener = object : ServerApiInfura.InfuraBodyListener {
- override fun onSuccess(method: String, infuraResponse: InfuraResponse) {
- when (method) {
- ServerApiInfura.INFURA_ETH_GAS_PRICE -> {
- var gasPrice = infuraResponse.result
- gasPrice = gasPrice.substring(2)
- //TODO - remove Gwei
- // rounding gas price to integer gwei
- val l = BigInteger(gasPrice, 16).divide(BigInteger.valueOf(1000000000L)).multiply(BigInteger.valueOf(1000000000L))
+ progressBar.visibility = View.VISIBLE
- //val m = if (ctx.blockchain==Blockchain.Token) BigInteger.valueOf(60000) else BigInteger.valueOf(21000)
- val m = if (amount.currency != "ETH") BigInteger.valueOf(60000) else BigInteger.valueOf(21000)
- val weiMinFee = CoinEngine.InternalAmount(l.multiply(m), "wei")
- val weiNormalFee = CoinEngine.InternalAmount(weiMinFee.multiply(BigDecimal.valueOf(12)).divide(BigDecimal.valueOf(10)), "wei")
- val weiMaxFee = CoinEngine.InternalAmount(weiMinFee.multiply(BigDecimal.valueOf(15)).divide(BigDecimal.valueOf(10)), "wei")
+ coinEngine!!.requestFee(
+ object : CoinEngine.BlockchainRequestsCallbacks {
+ override fun onComplete(success: Boolean) {
+ if (success) {
+ onProgress()
+ progressBar.visibility = View.INVISIBLE
+ dtVerified = Date()
+ } else {
+ finishWithError(Activity.RESULT_CANCELED, ctx.error)
+ }
+ }
- minFee = engine.convertToAmount(weiMinFee)
- normalFee = engine.convertToAmount(weiNormalFee)
- maxFee = engine.convertToAmount(weiMaxFee)
+ override fun onProgress() {
doSetFee(rgFee.checkedRadioButtonId)
- //etFee.setText(weiNormalFee.toValueString())
- etFee.error = null
- btnSend.visibility = View.VISIBLE
- feeRequestSuccess = true
-// balanceRequestSuccess = true
- dtVerified = Date()
- }
- }
- }
-
- override fun onFail(method: String, message: String) {
- when (method) {
- ServerApiInfura.INFURA_ETH_GAS_PRICE -> {
- finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_obtain_data_from_blockchain))
- }
- }
- }
- }
- serverApiInfura.setInfuraResponse(infuraBodyListener)
-
- // request estimate fee listener
- val estimateFeeListener: ServerApiCommon.EstimateFeeListener = object : ServerApiCommon.EstimateFeeListener {
- override fun onSuccess(blockCount: Int, estimateFeeResponse: String?) {
- var fee: BigDecimal?
- fee = BigDecimal(estimateFeeResponse) // BTC per 1 kb
-
- if (fee == BigDecimal.ZERO) {
- progressBar.visibility = View.INVISIBLE
- requestEstimateFee()
- }
-
- if (calcSize.toLong() != 0L) {
- fee = fee.multiply(BigDecimal(calcSize.toLong())).divide(BigDecimal(1024)) // per Kb -> per byte
- } else {
- requestEstimateFee()
- }
-
- progressBar.visibility = View.INVISIBLE
-
- fee = fee!!.setScale(8, RoundingMode.DOWN)
-
- when (blockCount) {
- ServerApiCommon.ESTIMATE_FEE_MINIMAL -> {
- minFee = CoinEngine.Amount(fee, engine.feeCurrency)
- if (rgFee.checkedRadioButtonId == R.id.rbMinimalFee) doSetFee(rgFee.checkedRadioButtonId)
}
- ServerApiCommon.ESTIMATE_FEE_NORMAL -> {
- normalFee = CoinEngine.Amount(fee, engine.feeCurrency)
- if (rgFee.checkedRadioButtonId == R.id.rbNormalFee) doSetFee(rgFee.checkedRadioButtonId)
+ override fun allowAdvance(): Boolean {
+ return UtilHelper.isOnline(this@ConfirmPaymentActivity)
}
-
- ServerApiCommon.ESTIMATE_FEE_PRIORITY -> {
- maxFee = CoinEngine.Amount(fee, engine.feeCurrency)
- if (rgFee.checkedRadioButtonId == R.id.rbMaximumFee) doSetFee(rgFee.checkedRadioButtonId)
- }
- }
-
- etFee.error = null
- feeRequestSuccess = true
- if (feeRequestSuccess)
-// if (feeRequestSuccess && balanceRequestSuccess)
- btnSend.visibility = View.VISIBLE
- dtVerified = Date()
- }
-
- override fun onFail(message: String?) {
- finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_calculate_fee_wrong_data_received_from_node))
- }
- }
- serverApiCommon.setEstimateFee(estimateFeeListener)
+ },
+ etWallet.text.toString(),
+ amount)
}
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
super.onPause()
- nfcManager!!.onPause()
+ nfcManager.onPause()
}
public override fun onStop() {
super.onStop()
- nfcManager!!.onStop()
+ nfcManager.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- if (requestCode == REQUEST_CODE_SIGN_PAYMENT) {
+ if (requestCode == Constant.REQUEST_CODE_SIGN_PAYMENT) {
if (data != null && data.extras != null) {
if (data.extras!!.containsKey("UID") && data.extras!!.containsKey("Card")) {
val updatedCard = TangemCard(data.getStringExtra("UID"))
@@ -349,28 +205,30 @@ class ConfirmPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
ctx.card = updatedCard
}
}
- if (resultCode == SignPaymentActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
+ if (resultCode == Constant.RESULT_INVALID_PIN_ && requestPIN2Count < 2) {
requestPIN2Count++
+
val intent = Intent(baseContext, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
+ intent.putExtra(Constant.EXTRA_MODE, PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
- intent.putExtra(SignPaymentActivity.EXTRA_FEE_INCLUDED, isIncludeFee)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2)
+ intent.putExtra(Constant.EXTRA_FEE_INCLUDED, isIncludeFee)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_)
+
return
}
setResult(resultCode, data)
finish()
- } else if (requestCode == REQUEST_CODE_REQUEST_PIN2) {
+ } else if (requestCode == Constant.REQUEST_CODE_REQUEST_PIN2_) {
if (resultCode == Activity.RESULT_OK) {
val intent = Intent(baseContext, SignPaymentActivity::class.java)
ctx.saveToIntent(intent)
- intent.putExtra(SignPaymentActivity.EXTRA_TARGET_ADDRESS, etWallet!!.text.toString())
- intent.putExtra(SignPaymentActivity.EXTRA_AMOUNT, etAmount.text.toString())
- intent.putExtra(SignPaymentActivity.EXTRA_AMOUNT_CURRENCY, tvCurrency.text.toString())
- intent.putExtra(SignPaymentActivity.EXTRA_FEE, etFee.text.toString())
- intent.putExtra(SignPaymentActivity.EXTRA_FEE_CURRENCY, tvCurrency2.text.toString())
- intent.putExtra(SignPaymentActivity.EXTRA_FEE_INCLUDED, isIncludeFee)
- startActivityForResult(intent, REQUEST_CODE_SIGN_PAYMENT)
+ intent.putExtra(Constant.EXTRA_TARGET_ADDRESS, etWallet!!.text.toString())
+ intent.putExtra(Constant.EXTRA_AMOUNT, etAmount.text.toString())
+ intent.putExtra(Constant.EXTRA_AMOUNT_CURRENCY, tvCurrency.text.toString())
+ intent.putExtra(Constant.EXTRA_FEE, etFee.text.toString())
+ intent.putExtra(Constant.EXTRA_FEE_CURRENCY, tvCurrency2.text.toString())
+ intent.putExtra(Constant.EXTRA_FEE_INCLUDED, isIncludeFee)
+ startActivityForResult(intent, Constant.REQUEST_CODE_SIGN_PAYMENT)
} else
Toast.makeText(baseContext, R.string.pin_2_is_required_to_sign_the_payment, Toast.LENGTH_LONG).show()
}
@@ -390,120 +248,44 @@ class ConfirmPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
override fun onTagDiscovered(tag: Tag) {
try {
- nfcManager!!.ignoreTag(tag)
+ nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
- // TODO - move to BtcEngine
- @Throws(Exception::class)
- internal fun buildSize(outputAddress: String, outFee: String, outAmount: String): Int {
- val myAddress = ctx.card!!.wallet
- val pbKey = ctx.card!!.walletPublicKey
- val pbComprKey = ctx.card!!.walletPublicKeyRar
-
- // build script for our address
- val rawTxList = (ctx.coinData!! as BtcData).unspentTransactions
- val outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes
-
- // collect unspent
- val unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend)
-
- var fullAmount: Long = 0
- for (i in unspentOutputs.indices) {
- fullAmount += unspentOutputs[i].value
- }
-
- // get first unspent
-// val outPut = unspentOutputs[0]
-// val outPutIndex = outPut.outputIndex
-
- // get prev TX id;
-// val prevTXID = rawTxList[0].txID//"f67b838d6e2c0c587f476f583843e93ff20368eaf96a798bdc25e01f53f8f5d2";
-
- val fees = FormatUtil.ConvertStringToLong(outFee)
- var amount = FormatUtil.ConvertStringToLong(outAmount)
- amount -= fees
-
- val change = fullAmount - fees - amount
-
- if (amount + fees > fullAmount) {
- throw Exception(String.format("Balance (%d) < amount (%d) + (%d)", fullAmount, change, amount))
- }
-
- val hashesForSign = arrayOfNulls(unspentOutputs.size)
-
- for (i in unspentOutputs.indices) {
- val newTX = BTCUtils.buildTXForSign(myAddress, outputAddress, myAddress, unspentOutputs, i, amount, change)
- val hashData = Util.calculateSHA256(newTX)
- val doubleHashData = Util.calculateSHA256(hashData)
-// Log.e("TX_BODY_1", BTCUtils.toHex(newTX))
-// Log.e("TX_HASH_1", BTCUtils.toHex(hashData))
-// Log.e("TX_HASH_2", BTCUtils.toHex(doubleHashData))
-
- unspentOutputs[i].bodyDoubleHash = doubleHashData
- unspentOutputs[i].bodyHash = hashData
- hashesForSign[i] = doubleHashData
- }
-
- val signFromCard = ByteArray(64 * unspentOutputs.size)
-
- for (i in unspentOutputs.indices) {
- val r = BigInteger(1, Arrays.copyOfRange(signFromCard, 0 + i * 64, 32 + i * 64))
- val s = BigInteger(1, Arrays.copyOfRange(signFromCard, 32 + i * 64, 64 + i * 64))
- val encodingSign = DerEncodingUtil.packSignDer(r, s, pbKey)
- unspentOutputs[i].scriptForBuild = encodingSign
- }
-
- val realTX = BTCUtils.buildTXForSend(outputAddress, myAddress, unspentOutputs, amount, change)
-
- return realTX.size
- }
-
- private fun requestElectrum(card: TangemCard, electrumRequest: ElectrumRequest) {
- if (UtilHelper.isOnline(this)) {
- serverApiElectrum.electrumRequestData(card, electrumRequest)
- } else
- finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_obtain_data_from_blockchain))
- }
-
- private fun requestInfura(method: String) {
- if (UtilHelper.isOnline(this)) {
- serverApiInfura.infura(method, 67, ctx.card!!.wallet, "", "")
- } else
- finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_obtain_data_from_blockchain))
- }
-
- private fun requestEstimateFee() {
- serverApiCommon.estimateFee(ServerApiCommon.ESTIMATE_FEE_PRIORITY)
- serverApiCommon.estimateFee(ServerApiCommon.ESTIMATE_FEE_NORMAL)
- serverApiCommon.estimateFee(ServerApiCommon.ESTIMATE_FEE_MINIMAL)
- }
-
private fun doSetFee(checkedRadioButtonId: Int) {
var txtFee = ""
when (checkedRadioButtonId) {
R.id.rbMinimalFee ->
- if (minFee != null)
- txtFee = minFee!!.toValueString()
- else
- finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_obtain_data_from_blockchain))
+ if (ctx.coinData.minFee != null) {
+ txtFee = ctx.coinData.minFee!!.toValueString()
+ btnSend.visibility = View.VISIBLE
+ } else
+ btnSend.visibility = View.INVISIBLE
+
R.id.rbNormalFee ->
- if (normalFee != null)
- txtFee = normalFee!!.toValueString()
- else
- finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_obtain_data_from_blockchain))
+ if (ctx.coinData.normalFee != null) {
+ txtFee = ctx.coinData.normalFee!!.toValueString()
+ btnSend.visibility = View.VISIBLE
+ } else
+ btnSend.visibility = View.INVISIBLE
+
R.id.rbMaximumFee ->
- if (maxFee != null)
- txtFee = maxFee!!.toValueString()
- else
- finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_obtain_data_from_blockchain))
+ if (ctx.coinData.maxFee != null) {
+ txtFee = ctx.coinData.maxFee!!.toValueString()
+ btnSend.visibility = View.VISIBLE
+ } else
+ btnSend.visibility = View.INVISIBLE
}
etFee.setText(txtFee.replace(',', '.'))
}
private fun finishWithError(errorCode: Int, message: String) {
+ val transactionFinishWithError = TransactionFinishWithError()
+ transactionFinishWithError.message = message
+ EventBus.getDefault().post(transactionFinishWithError)
+
val intent = Intent()
intent.putExtra("message", message)
setResult(errorCode, intent)
diff --git a/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.kt b/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.kt
index f1334508bd..cfdd251dad 100644
--- a/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.kt
@@ -1,6 +1,7 @@
package com.tangem.presentation.activity
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
@@ -12,27 +13,32 @@ import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
-import com.tangem.data.nfc.CreateNewWalletTask
-import com.tangem.domain.cardReader.CardProtocol
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.TangemCard
+import com.tangem.App
+import com.tangem.Constant
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
-import com.tangem.util.Util
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.android.reader.NfcReader
+import com.tangem.tangemcard.data.asBundle
+import com.tangem.tangemcard.reader.CardProtocol
+import com.tangem.tangemcard.tasks.CreateNewWalletTask
+import com.tangem.tangemcard.util.Util
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_create_new_wallet.*
class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications {
-
companion object {
- val TAG: String = CreateNewWalletActivity::class.java.simpleName
-
- const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
+ fun callingIntent(context: Context, ctx: TangemContext): Intent {
+ val intent = Intent(context, CreateNewWalletActivity::class.java)
+ intent.putExtra("UID", ctx.card!!.uid)
+ intent.putExtra("Card", ctx.card!!.asBundle)
+ return intent
+ }
}
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
- private var nfcManager: NfcManager? = null
private var createNewWalletTask: CreateNewWalletTask? = null
private var lastReadSuccess = true
@@ -43,8 +49,6 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_new_wallet)
- MainActivity.commonInit(applicationContext)
-
nfcManager = NfcManager(this, this)
ctx = TangemContext.loadFromBundle(this, intent.extras)
@@ -71,11 +75,11 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
} else {
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 65000
}
- createNewWalletTask = CreateNewWalletTask(this, ctx.card, nfcManager, isoDep, this)
+ createNewWalletTask = CreateNewWalletTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
createNewWalletTask!!.start()
} else {
// Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + mCard.getUID() + ")");
- nfcManager!!.ignoreTag(isoDep.tag)
+ nfcManager.ignoreTag(isoDep.tag)
}
} catch (e: Exception) {
@@ -85,11 +89,11 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
- nfcManager!!.onPause()
+ nfcManager.onPause()
if (createNewWalletTask != null)
createNewWalletTask!!.cancel(true)
super.onPause()
@@ -97,7 +101,7 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
public override fun onStop() {
// dismiss enable NFC dialog
- nfcManager!!.onStop()
+ nfcManager.onStop()
if (createNewWalletTask != null)
createNewWalletTask!!.cancel(true)
super.onStop()
@@ -138,8 +142,8 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
val intent = Intent()
intent.putExtra("message", "Cannot create wallet. Make sure you enter correct PIN2!")
intent.putExtra("UID", cardProtocol.card.uid)
- intent.putExtra("Card", cardProtocol.card.asBundle)
- setResult(RESULT_INVALID_PIN, intent)
+ intent.putExtra("Card", cardProtocol.card!!.asBundle)
+ setResult(Constant.RESULT_INVALID_PIN, intent)
finish()
} catch (e: Exception) {
e.printStackTrace()
@@ -177,7 +181,6 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
}
override fun onReadCancel() {
-
createNewWalletTask = null
progressBar!!.postDelayed({
@@ -192,7 +195,7 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
}
override fun onReadWait(msec: Int) {
- WaitSecurityDelayDialog.OnReadWait(this, msec)
+ WaitSecurityDelayDialog.onReadWait(this, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
diff --git a/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.kt b/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.kt
index e31879e9cc..cc7646b7db 100644
--- a/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.kt
@@ -13,31 +13,41 @@ import android.support.v7.app.AppCompatActivity
import android.text.Html
import android.view.View
import android.widget.Toast
-import com.tangem.data.nfc.VerifyCardTask
-import com.tangem.domain.cardReader.CardProtocol
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.TangemCard
+import com.tangem.App
+import com.tangem.Constant
+import com.tangem.di.Navigator
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
-import com.tangem.util.Util
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.android.reader.NfcReader
+import com.tangem.tangemcard.data.TangemCard
+import com.tangem.tangemcard.data.asBundle
+import com.tangem.tangemcard.data.loadFromBundle
+import com.tangem.tangemcard.reader.CardProtocol
+import com.tangem.tangemcard.tasks.VerifyCardTask
+import com.tangem.tangemcard.util.Util
+import com.tangem.util.LOG
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_empty_wallet.*
+import javax.inject.Inject
class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications {
-
companion object {
val TAG: String = EmptyWalletActivity::class.java.simpleName
-
- private const val REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY = 2
- private const val REQUEST_CODE_REQUEST_PIN2 = 3
- private const val REQUEST_CODE_VERIFY_CARD = 4
-
- fun callingIntent(context: Context) = Intent(context, EmptyWalletActivity::class.java)
+ fun callingIntent(context: Context, ctx: TangemContext): Intent {
+ val intent = Intent(context, EmptyWalletActivity::class.java)
+ ctx.saveToIntent(intent)
+ return intent
+ }
}
- private var nfcManager: NfcManager? = null
+ @Inject
+ internal lateinit var navigator: Navigator
+
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
+
private var lastReadSuccess = true
private var verifyCardTask: VerifyCardTask? = null
private var requestPIN2Count = 0
@@ -46,24 +56,24 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_empty_wallet)
- MainActivity.commonInit(applicationContext)
+ App.getNavigatorComponent().inject(this)
nfcManager = NfcManager(this, this)
ctx = TangemContext.loadFromBundle(this, intent.extras)
tvIssuer.text = ctx.card!!.issuerDescription
- //tvBlockchain.text = ctx.card!!.blockchainName
+
if (ctx.card!!.tokenSymbol.length > 1) {
- val html = Html.fromHtml(ctx.card!!.blockchainName)
+ val html = Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
} else
- tvBlockchain.text = ctx.card!!.blockchainName
+ tvBlockchain.text = ctx.blockchainName
tvCardID.text = ctx.card!!.cidDescription
- imgBlockchain.setImageResource(ctx.card!!.blockchain.getImageResource(this, ctx.card!!.tokenSymbol))
+ imgBlockchain.setImageResource(ctx.blockchain.getImageResource(this, ctx.card!!.tokenSymbol))
- if (ctx.card!!.useDefaultPIN1()!!) {
+ if (ctx.card!!.useDefaultPIN1()) {
imgPIN.setImageResource(R.drawable.unlock_pin1)
imgPIN.setOnClickListener { Toast.makeText(this@EmptyWalletActivity, R.string.this_banknote_protected_default_PIN1_code, Toast.LENGTH_LONG).show() }
} else {
@@ -97,27 +107,27 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
intent.putExtra("UID", ctx.card!!.uid)
intent.putExtra("Card", ctx.card!!.asBundle)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2)
}
}
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
super.onPause()
- nfcManager!!.onPause()
+ nfcManager.onPause()
}
public override fun onStop() {
super.onStop()
- nfcManager!!.onStop()
+ nfcManager.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- if (requestCode == REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY) {
+ if (requestCode == Constant.REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
@@ -132,21 +142,21 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
updatedCard.loadFromBundle(data.getBundleExtra("Card"))
ctx.card = updatedCard
}
- if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
+ if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++
val intent = Intent(baseContext, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
intent.putExtra("UID", ctx.card!!.uid)
intent.putExtra("Card", ctx.card!!.asBundle)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2)
return
}
}
setResult(resultCode, data)
finish()
- } else if (requestCode == REQUEST_CODE_REQUEST_PIN2) {
+ } else if (requestCode == Constant.REQUEST_CODE_REQUEST_PIN2) {
if (resultCode == Activity.RESULT_OK) {
- doCreateNewWallet()
+ navigator.showCreateNewWallet(this, ctx)
}
}
}
@@ -158,11 +168,11 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
if (ctx.card!!.uid != sUID) {
-// Log.d(TAG, "Invalid UID: " + sUID);
- nfcManager!!.ignoreTag(isoDep.tag)
+ LOG.d(TAG, "Invalid UID: $sUID")
+ nfcManager.ignoreTag(isoDep.tag)
return
} else {
-// Log.v(TAG, "UID: " + sUID);
+ LOG.d(TAG, "UID: $sUID")
}
if (lastReadSuccess) {
@@ -171,7 +181,7 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
isoDep.timeout = 65000
}
//lastTag = tag;
- verifyCardTask = VerifyCardTask(this, ctx.card, nfcManager, isoDep, this)
+ verifyCardTask = VerifyCardTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, App.firmwaresStorage, this)
verifyCardTask!!.start()
} catch (e: Exception) {
e.printStackTrace()
@@ -244,7 +254,7 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
}
override fun onReadWait(msec: Int) {
- WaitSecurityDelayDialog.OnReadWait(this, msec)
+ WaitSecurityDelayDialog.onReadWait(this, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
@@ -255,11 +265,4 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
WaitSecurityDelayDialog.onReadAfterRequest(this)
}
- private fun doCreateNewWallet() {
- val intent = Intent(this, CreateNewWalletActivity::class.java)
- intent.putExtra("UID", ctx.card!!.uid)
- intent.putExtra("Card", ctx.card!!.asBundle)
- startActivityForResult(intent, REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY)
- }
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.kt b/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.kt
index 04dab07418..f7a24d8c28 100644
--- a/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.kt
@@ -7,7 +7,9 @@ import android.nfc.Tag
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.tangem.App
+import com.tangem.Constant
import com.tangem.di.Navigator
+import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.fragment.LoadedWallet
import com.tangem.wallet.R
import javax.inject.Inject
@@ -18,10 +20,10 @@ class LoadedWalletActivity : AppCompatActivity() {
lateinit var navigator: Navigator
companion object {
- fun callingIntent(context: Context, lastTag: Tag, cardInfo: Bundle): Intent {
+ fun callingIntent(context: Context, lastTag: Tag, ctx: TangemContext): Intent {
val intent = Intent(context, LoadedWalletActivity::class.java)
- intent.putExtra(MainActivity.EXTRA_LAST_DISCOVERED_TAG, lastTag)
- intent.putExtras(cardInfo)
+ intent.putExtra(Constant.EXTRA_LAST_DISCOVERED_TAG, lastTag)
+ ctx.saveToIntent(intent)
return intent
}
}
@@ -32,8 +34,6 @@ class LoadedWalletActivity : AppCompatActivity() {
App.getNavigatorComponent().inject(this)
- MainActivity.commonInit(applicationContext)
-
if (intent.extras!!.containsKey(NfcAdapter.EXTRA_TAG)) {
val tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
if (tag != null) {
diff --git a/app/src/main/java/com/tangem/presentation/activity/LogoActivity.kt b/app/src/main/java/com/tangem/presentation/activity/LogoActivity.kt
index 6203e8962a..76e05876d3 100644
--- a/app/src/main/java/com/tangem/presentation/activity/LogoActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/LogoActivity.kt
@@ -1,9 +1,12 @@
package com.tangem.presentation.activity
import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.tangem.App
+import com.tangem.Constant
import com.tangem.di.Navigator
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
@@ -11,19 +14,19 @@ import kotlinx.android.synthetic.main.activity_logo.*
import javax.inject.Inject
class LogoActivity : AppCompatActivity() {
-
companion object {
- val TAG: String = LogoActivity::class.java.simpleName
-
- const val EXTRA_AUTO_HIDE = "extra_auto_hide"
- const val MILLIS_AUTO_HIDE = 1000
+ fun callingIntent(context: Context, autoHide: Boolean): Intent {
+ val intent = Intent(context, LogoActivity::class.java)
+ intent.putExtra(Constant.EXTRA_AUTO_HIDE, autoHide)
+ return intent
+ }
}
- private val hideRunnable = Runnable { this.hide() }
-
@Inject
internal lateinit var navigator: Navigator
+ private val hideRunnable = Runnable { this.hide() }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_logo)
@@ -42,8 +45,8 @@ class LogoActivity : AppCompatActivity() {
else
tvAppVersion.text = "BETA v." + BuildConfig.VERSION_NAME
- if (intent.getBooleanExtra(EXTRA_AUTO_HIDE, true))
- ivLogo.postDelayed(hideRunnable, MILLIS_AUTO_HIDE.toLong())
+ if (intent.getBooleanExtra(Constant.EXTRA_AUTO_HIDE, true))
+ ivLogo.postDelayed(hideRunnable, Constant.MILLIS_AUTO_HIDE.toLong())
}
private fun hide() {
diff --git a/app/src/main/java/com/tangem/presentation/activity/MainActivity.kt b/app/src/main/java/com/tangem/presentation/activity/MainActivity.kt
index f247ab61f4..79d8594bfd 100644
--- a/app/src/main/java/com/tangem/presentation/activity/MainActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/MainActivity.kt
@@ -25,20 +25,25 @@ import android.widget.RelativeLayout
import android.widget.Toast
import com.scottyab.rootbeer.RootBeer
import com.tangem.App
+import com.tangem.Constant
import com.tangem.data.Logger
-import com.tangem.data.db.PINStorage
import com.tangem.data.network.ServerApiCommon
-import com.tangem.data.nfc.DeviceNFCAntennaLocation
-import com.tangem.data.nfc.ReadCardInfoTask
import com.tangem.di.Navigator
-import com.tangem.domain.cardReader.CardProtocol
-import com.tangem.domain.cardReader.Firmwares
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.*
+import com.tangem.domain.wallet.CoinEngineFactory
+import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.RootFoundDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
+import com.tangem.tangemcard.android.nfc.DeviceNFCAntennaLocation
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.android.reader.NfcReader
+import com.tangem.tangemcard.data.TangemCard
+import com.tangem.tangemcard.data.loadFromBundle
+import com.tangem.tangemcard.data.saveToBundle
+import com.tangem.tangemcard.reader.CardProtocol
+import com.tangem.tangemcard.tasks.ReadCardInfoTask
import com.tangem.util.CommonUtil
+import com.tangem.util.LOG
import com.tangem.util.PhoneUtility
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
@@ -51,29 +56,14 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
companion object {
val TAG: String = MainActivity::class.java.simpleName
-
- private const val REQUEST_CODE_SEND_EMAIL = 3
- private const val REQUEST_CODE_ENTER_PIN_ACTIVITY = 2
- const val REQUEST_CODE_SHOW_CARD_ACTIVITY = 1
- private const val REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS = 3
-
- const val EXTRA_LAST_DISCOVERED_TAG = "extra_last_tag"
-
fun callingIntent(context: Context) = Intent(context, MainActivity::class.java)
-
- fun commonInit(context: Context) {
- if (PINStorage.needInit())
- PINStorage.init(context)
-
- if (Issuer.needInit())
- Issuer.init(context)
-
- if (Firmwares.needInit())
- Firmwares.init(context)
- }
}
- private var nfcManager: NfcManager? = null
+ @Inject
+ internal lateinit var navigator: Navigator
+
+ private lateinit var nfcManager: NfcManager
+
private var zipFile: File? = null
private var antenna: DeviceNFCAntennaLocation? = null
private var unsuccessReadCount = 0
@@ -81,9 +71,6 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
private var readCardInfoTask: ReadCardInfoTask? = null
private var onNfcReaderCallback: NfcAdapter.ReaderCallback? = null
- @Inject
- internal lateinit var navigator: Navigator
-
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action || NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action)) {
@@ -107,8 +94,6 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
- commonInit(applicationContext)
-
setNfcAdapterReaderCallback(this)
rippleBackgroundNfc.startRippleAnimation()
@@ -155,12 +140,11 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
// check if root device
val rootBeer = RootBeer(this)
if (rootBeer.isRootedWithoutBusyBoxCheck && !BuildConfig.DEBUG)
- RootFoundDialog().show(fragmentManager, RootFoundDialog.TAG)
+ RootFoundDialog().show(supportFragmentManager, RootFoundDialog.TAG)
// set listeners
fab.setOnClickListener { showMenu(it) }
-
val apiHelper = ServerApiCommon()
apiHelper.setLastVersionListener { response ->
try {
@@ -180,19 +164,19 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
NfcManager.verifyPermissions(this)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
Log.e("QRScanActivity", "User hasn't granted permission to use camera")
- ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS)
+ ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), Constant.REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
- REQUEST_CODE_SEND_EMAIL -> {
+ Constant.REQUEST_CODE_SEND_EMAIL -> {
if (zipFile != null) {
zipFile!!.delete()
zipFile = null
}
}
- REQUEST_CODE_ENTER_PIN_ACTIVITY -> {
+ Constant.REQUEST_CODE_ENTER_PIN_ACTIVITY -> {
if (resultCode == Activity.RESULT_OK && lastTag != null)
onTagDiscovered(lastTag!!)
else
@@ -216,17 +200,16 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
-
when (id) {
R.id.sendLogs -> {
var f: File? = null
try {
f = Logger.collectLogs(this)
if (f != null) {
-// Log.e(TAG, String.format("Collect %d log bytes", f.length()));
+ LOG.e(TAG, String.format("Collect %d log bytes", f.length()))
CommonUtil.sendEmail(this, zipFile, TAG, "Logs", PhoneUtility.getDeviceInfo(), arrayOf(f))
} else {
-// Log.e(TAG, "Can't create temporaly log file");
+ LOG.e(TAG, "Can't create temporarily log file")
}
} catch (e: Exception) {
e.printStackTrace()
@@ -237,17 +220,17 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
return true
}
R.id.managePIN -> {
- showSavePinActivity()
+ navigator.showPinSave(this, false)
return true
}
R.id.managePIN2 -> {
- showSavePin2Activity()
+ navigator.showPinSave(this, true)
return true
}
R.id.about -> {
- showLogoActivity()
+ navigator.showLogo(this, false)
return true
}
}
@@ -260,7 +243,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
val isoDep = IsoDep.get(tag)
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
-// Log.e(TAG, "setTimeout(" + String.valueOf(1000 + 3000 * unsuccessReadCount) + ")");
+ LOG.e(TAG, "setTimeout(" + (1000 + 3000 * unsuccessReadCount) + ")")
if (unsuccessReadCount < 2) {
isoDep.timeout = 2000 + 5000 * unsuccessReadCount
} else {
@@ -268,14 +251,14 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
}
lastTag = tag
- readCardInfoTask = ReadCardInfoTask(this, nfcManager, isoDep, this)
+ readCardInfoTask = ReadCardInfoTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
readCardInfoTask!!.start()
-// Log.i(TAG, "onTagDiscovered " + Arrays.toString(tag.getId()));
+ LOG.i(TAG, "onTagDiscovered " + Arrays.toString(tag.id))
} catch (e: Exception) {
e.printStackTrace()
- nfcManager!!.notifyReadResult(false)
+ nfcManager.notifyReadResult(false)
}
}
@@ -283,23 +266,19 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
super.onResume()
animate()
ReadCardInfoTask.resetLastReadInfo()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
- nfcManager!!.onPause()
- if (readCardInfoTask != null) {
- readCardInfoTask!!.cancel(true)
- }
+ nfcManager.onPause()
+ readCardInfoTask?.cancel(true)
super.onPause()
}
public override fun onStop() {
// dismiss enable NFC dialog
- nfcManager!!.onStop()
- if (readCardInfoTask != null) {
- readCardInfoTask!!.cancel(true)
- }
+ nfcManager.onStop()
+ readCardInfoTask?.cancel(true)
super.onStop()
}
@@ -315,7 +294,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
readCardInfoTask = null
if (cardProtocol != null) {
if (cardProtocol.error == null) {
- nfcManager!!.notifyReadResult(true)
+ nfcManager.notifyReadResult(true)
rlProgressBar.post {
rlProgressBar.visibility = View.GONE
@@ -330,12 +309,20 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
val card = TangemCard(uid)
card.loadFromBundle(cardInfo.getBundle("Card"))
+ val ctx = TangemContext(card)
when {
- card.status == TangemCard.Status.Loaded -> lastTag?.let { navigator.showLoadedWallet(this, it, cardInfo) }
- card.status == TangemCard.Status.Empty -> navigator.showEmptyWallet(this)
+ card.status == TangemCard.Status.Loaded -> lastTag?.let {
+ val engineCoin = CoinEngineFactory.create(ctx)
+ ?: throw CardProtocol.TangemException("Can't create CoinEngine!")
+ engineCoin.defineWallet()
+ //mCard.setWallet(Blockchain.calculateWalletAddress(mCard, pkUncompressed));
+
+ navigator.showLoadedWallet(this, it, ctx)
+ }
+ card.status == TangemCard.Status.Empty -> navigator.showEmptyWallet(this, ctx)
card.status == TangemCard.Status.Purged -> Toast.makeText(this, R.string.erased_wallet, Toast.LENGTH_SHORT).show()
card.status == TangemCard.Status.NotPersonalized -> Toast.makeText(this, R.string.not_personalized, Toast.LENGTH_SHORT).show()
- else -> lastTag?.let { navigator.showLoadedWallet(this, it, cardInfo) }
+ else -> lastTag?.let { navigator.showLoadedWallet(this, it, ctx) }
}
}
@@ -346,7 +333,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
unsuccessReadCount++
if (cardProtocol.error is CardProtocol.TangemException_InvalidPIN)
- doEnterPIN()
+ navigator.showPinRequest(this, PinRequestActivity.Mode.RequestPIN.toString())
else {
if (cardProtocol.error is CardProtocol.TangemException_ExtendedLengthNotSupported)
if (!NoExtendedLengthSupportDialog.allReadyShowed)
@@ -354,7 +341,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
lastTag = null
ReadCardInfoTask.resetLastReadInfo()
- nfcManager!!.notifyReadResult(false)
+ nfcManager.notifyReadResult(false)
}
}
}
@@ -382,7 +369,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
}
override fun onReadWait(msec: Int) {
- WaitSecurityDelayDialog.OnReadWait(Objects.requireNonNull(this), msec)
+ WaitSecurityDelayDialog.onReadWait(Objects.requireNonNull(this), msec)
}
override fun onReadBeforeRequest(timeout: Int) {
@@ -397,13 +384,6 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
onNfcReaderCallback = callback
}
- private fun showLogoActivity() {
- val intent = Intent(baseContext, LogoActivity::class.java)
- intent.putExtra(LogoActivity.TAG, true)
- intent.putExtra(LogoActivity.EXTRA_AUTO_HIDE, false)
- startActivity(intent)
- }
-
private fun animate() {
val lp = llHand.layoutParams as RelativeLayout.LayoutParams
val lp2 = llNfc.layoutParams as RelativeLayout.LayoutParams
@@ -424,18 +404,6 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
llHand.startAnimation(a)
}
- private fun showSavePinActivity() {
- val intent = Intent(baseContext, PinSaveActivity::class.java)
- intent.putExtra("PIN2", false)
- startActivity(intent)
- }
-
- private fun showSavePin2Activity() {
- val intent = Intent(baseContext, PinSaveActivity::class.java)
- intent.putExtra("PIN2", true)
- startActivity(intent)
- }
-
private fun showMenu(v: View) {
val popup = PopupMenu(this, v)
val inflater = popup.menuInflater
@@ -451,10 +419,4 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
popup.show()
}
- private fun doEnterPIN() {
- val intent = Intent(this, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN.toString())
- startActivityForResult(intent, REQUEST_CODE_ENTER_PIN_ACTIVITY)
- }
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/activity/PinRequestActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PinRequestActivity.kt
index 820dfb4dae..e8128a0825 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PinRequestActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PinRequestActivity.kt
@@ -19,29 +19,75 @@ import android.text.TextUtils
import android.util.Log
import android.view.View
import android.widget.Button
+import com.tangem.Constant
import com.tangem.data.fingerprint.StartFingerprintReaderTask
-import com.tangem.domain.cardReader.NfcManager
+import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.data.fingerprint.FingerprintHelper
-import com.tangem.data.db.PINStorage
-import com.tangem.domain.wallet.TangemCard
+import com.tangem.domain.wallet.TangemContext
+import com.tangem.tangemcard.android.data.PINStorage
+import com.tangem.tangemcard.data.TangemCard
+import com.tangem.tangemcard.data.loadFromBundle
+import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD
+import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD_UID
+import com.tangem.util.LOG
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_request.*
import kotlinx.android.synthetic.main.layout_pin_buttons.*
import java.io.IOException
class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, FingerprintHelper.FingerprintHelperListener {
-
companion object {
- const val KEY_ALIAS = "pinKey"
- const val KEYSTORE = "AndroidKeyStore"
+ val TAG: String = PinRequestActivity::class.java.simpleName
+
+ fun callingIntent(context: Activity, mode: String): Intent {
+ val intent = Intent(context, PinRequestActivity::class.java)
+ intent.putExtra(Constant.EXTRA_MODE, mode)
+ return intent
+ }
+
+ fun callingIntentRequestPin(context: Activity, mode: String, ctx: TangemContext, newPIN: String): Intent {
+ val intent = Intent(context, PinRequestActivity::class.java)
+ intent.putExtra(Constant.EXTRA_MODE, mode)
+ intent.putExtra(Constant.EXTRA_NEW_PIN, newPIN)
+ ctx.saveToIntent(intent)
+ return intent
+ }
+
+ fun callingIntentRequestPin2(context: Activity, mode: String, ctx: TangemContext, newPIN2: String): Intent {
+ val intent = Intent(context, PinRequestActivity::class.java)
+ intent.putExtra(Constant.EXTRA_MODE, mode)
+ intent.putExtra(Constant.EXTRA_NEW_PIN_2, newPIN2)
+ ctx.saveToIntent(intent)
+ return intent
+ }
+
+ fun callingIntentRequestPin2(context: Activity, mode: String, ctx: TangemContext): Intent {
+ val intent = Intent(context, PinRequestActivity::class.java)
+ intent.putExtra(Constant.EXTRA_MODE, mode)
+ ctx.saveToIntent(intent)
+ return intent
+ }
+
+ fun callingIntentConfirmPin(context: Activity, mode: String, newPIN: String): Intent {
+ val intent = Intent(context, PinRequestActivity::class.java)
+ intent.putExtra(Constant.EXTRA_MODE, mode)
+ intent.putExtra(Constant.EXTRA_NEW_PIN, newPIN)
+ return intent
+ }
+
+ fun callingIntentConfirmPin2(context: Activity, mode: String, newPIN2: String): Intent {
+ val intent = Intent(context, PinRequestActivity::class.java)
+ intent.putExtra(Constant.EXTRA_MODE, mode)
+ intent.putExtra(Constant.EXTRA_NEW_PIN_2, newPIN2)
+ return intent
+ }
}
+ private lateinit var nfcManager: NfcManager
+
lateinit var mode: Mode
private var allowFingerprint = false
- private var nfcManager: NfcManager? = null
-
var startFingerprintReaderTask: StartFingerprintReaderTask? = null
-
private var fingerprintManager: FingerprintManager? = null
private var fingerprintHelper: FingerprintHelper? = null
@@ -53,11 +99,9 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pin_request)
- MainActivity.commonInit(applicationContext)
-
nfcManager = NfcManager(this, this)
- mode = Mode.valueOf(intent.getStringExtra("mode"))
+ mode = Mode.valueOf(intent.getStringExtra(Constant.EXTRA_MODE))
if (mode == Mode.RequestNewPIN)
if (PINStorage.haveEncryptedPIN()) {
@@ -82,9 +126,9 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
else if (mode == Mode.ConfirmNewPIN2)
tvPinPrompt.setText(R.string.confirm_new_pin_2)
else if (mode == Mode.RequestPIN2) {
- val uid = intent.getStringExtra(TangemCard.EXTRA_UID)
+ val uid = intent.getStringExtra(EXTRA_TANGEM_CARD_UID)
val card = TangemCard(uid)
- card.loadFromBundle(intent.getBundleExtra(TangemCard.EXTRA_CARD))
+ card.loadFromBundle(intent.getBundleExtra(EXTRA_TANGEM_CARD))
if (card.PIN2 == TangemCard.PIN2_Mode.DefaultPIN2 || card.PIN2 == TangemCard.PIN2_Mode.Unchecked) {
// if we know PIN2 or not try default previously - use it
@@ -136,7 +180,7 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
startFingerprintReaderTask = null
}
- nfcManager!!.onPause()
+ nfcManager.onPause()
}
override fun onStop() {
@@ -149,12 +193,12 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
startFingerprintReaderTask = null
}
- nfcManager!!.onStop()
+ nfcManager.onStop()
}
override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
if (allowFingerprint)
startFingerprintReader()
}
@@ -162,20 +206,19 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
override fun onTagDiscovered(tag: Tag) {
try {
Log.w(javaClass.name, "Ignore discovered tag!")
- nfcManager!!.ignoreTag(tag)
+ nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
-
}
override fun authenticationFailed(error: String) {
- doLog(error)
+ LOG.w(TAG, error)
}
@TargetApi(Build.VERSION_CODES.M)
override fun authenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
- doLog("Authentication succeeded!")
+ LOG.i(TAG,"Authentication succeeded!")
val cipher = result.cryptoObject.cipher
if (mode == Mode.RequestNewPIN || mode == Mode.ConfirmNewPIN) {
@@ -203,10 +246,6 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
finish()
}
- fun doLog(text: String) {
- // Log.e("FP", text);
- }
-
@SuppressLint("SetTextI18n")
private fun buttonClick(button: Button) {
tvPin!!.text = tvPin!!.text.toString() + button.text as String
@@ -214,27 +253,27 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
@SuppressLint("NewApi")
private fun testFingerPrintSettings(): Boolean {
- doLog("Testing Fingerprint Settings")
+ LOG.i(TAG,"Testing Fingerprint Settings")
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
fingerprintManager = getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager
if (!keyguardManager.isKeyguardSecure) {
- doLog("User hasn't enabled Lock Screen")
+ LOG.i(TAG,"User hasn't enabled Lock Screen")
return false
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
- doLog("User hasn't granted permission to use Fingerprint")
+ LOG.i(TAG,"User hasn't granted permission to use Fingerprint")
return false
}
if (!fingerprintManager!!.hasEnrolledFingerprints()) {
- doLog("User hasn't registered any fingerprints")
+ LOG.i(TAG,"User hasn't registered any fingerprints")
return false
}
- doLog("Fingerprint authentication is set.\n")
+ LOG.i(TAG,"Fingerprint authentication is set.\n")
return true
}
diff --git a/app/src/main/java/com/tangem/presentation/activity/PinSaveActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PinSaveActivity.kt
index de85d4c251..b67ad84f01 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PinSaveActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PinSaveActivity.kt
@@ -6,6 +6,7 @@ import android.annotation.TargetApi
import android.app.Dialog
import android.app.KeyguardManager
import android.content.Context
+import android.content.Intent
import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
import android.os.Build
@@ -19,9 +20,10 @@ import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.Toast
+import com.tangem.Constant
import com.tangem.data.fingerprint.ConfirmWithFingerprintTask
import com.tangem.data.fingerprint.FingerprintHelper
-import com.tangem.data.db.PINStorage
+import com.tangem.tangemcard.android.data.PINStorage
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_save.*
import kotlinx.android.synthetic.main.layout_pin_buttons.*
@@ -37,6 +39,15 @@ import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
class PinSaveActivity : AppCompatActivity(), FingerprintHelper.FingerprintHelperListener {
+ companion object {
+ val TAG: String = PinSaveActivity::class.java.simpleName
+
+ fun callingIntent(context: Context, hasPin2: Boolean): Intent {
+ val intent = Intent(context, PinSaveActivity::class.java)
+ intent.putExtra(Constant.EXTRA_PIN2, hasPin2)
+ return intent
+ }
+ }
private var confirmWithFingerprintTask: ConfirmWithFingerprintTask? = null
private var keyStore: KeyStore? = null
@@ -56,9 +67,7 @@ class PinSaveActivity : AppCompatActivity(), FingerprintHelper.FingerprintHelper
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pin_save)
- MainActivity.commonInit(applicationContext)
-
- usePIN2 = intent.getBooleanExtra("PIN2", false)
+ usePIN2 = intent.getBooleanExtra(Constant.EXTRA_PIN2, false)
if (usePIN2)
tvPinPrompt.text = getString(R.string.enter_pin2_and_use_fingerprint_to_save_it)
@@ -155,7 +164,7 @@ class PinSaveActivity : AppCompatActivity(), FingerprintHelper.FingerprintHelper
fun getKeyStore(): Boolean {
try {
- keyStore = KeyStore.getInstance(PinRequestActivity.KEYSTORE)
+ keyStore = KeyStore.getInstance(Constant.KEYSTORE)
// create empty keystore
keyStore!!.load(null)
return true
@@ -176,12 +185,12 @@ class PinSaveActivity : AppCompatActivity(), FingerprintHelper.FingerprintHelper
fun createNewKey(forceCreate: Boolean): Boolean {
try {
if (forceCreate)
- keyStore!!.deleteEntry(PinRequestActivity.KEY_ALIAS)
+ keyStore!!.deleteEntry(Constant.KEY_ALIAS)
- if (!keyStore!!.containsAlias(PinRequestActivity.KEY_ALIAS)) {
- val generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, PinRequestActivity.KEYSTORE)
+ if (!keyStore!!.containsAlias(Constant.KEY_ALIAS)) {
+ val generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, Constant.KEYSTORE)
- generator.init(KeyGenParameterSpec.Builder(PinRequestActivity.KEY_ALIAS,
+ generator.init(KeyGenParameterSpec.Builder(Constant.KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
@@ -217,14 +226,14 @@ class PinSaveActivity : AppCompatActivity(), FingerprintHelper.FingerprintHelper
fun initCipher(mode: Int): Boolean {
try {
keyStore!!.load(null)
- val keyspec = keyStore!!.getKey(PinRequestActivity.KEY_ALIAS, null) as SecretKey
+ val keySpec = keyStore!!.getKey(Constant.KEY_ALIAS, null) as SecretKey
if (mode == Cipher.ENCRYPT_MODE) {
- cipher!!.init(mode, keyspec)
+ cipher!!.init(mode, keySpec)
} else {
val iv = PINStorage.loadEncryptedIV()
- val ivspec = IvParameterSpec(iv)
- cipher!!.init(mode, keyspec, ivspec)
+ val ivSpec = IvParameterSpec(iv)
+ cipher!!.init(mode, keySpec, ivSpec)
}
return true
@@ -302,7 +311,6 @@ class PinSaveActivity : AppCompatActivity(), FingerprintHelper.FingerprintHelper
}
// show a progress spinner, and kick off a background task to perform the user login attempt
- //showProgress(true);
confirmWithFingerprintTask = ConfirmWithFingerprintTask(this@PinSaveActivity)
confirmWithFingerprintTask!!.execute(null as Void?)
} else {
diff --git a/app/src/main/java/com/tangem/presentation/activity/PinSwapActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PinSwapActivity.kt
index 9b7c749348..38584e3d12 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PinSwapActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PinSwapActivity.kt
@@ -1,6 +1,7 @@
package com.tangem.presentation.activity
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
@@ -12,27 +13,37 @@ import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
-import com.tangem.data.nfc.SwapPINTask
-import com.tangem.domain.cardReader.CardProtocol
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.TangemCard
+import com.tangem.App
+import com.tangem.Constant
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
-import com.tangem.util.Util
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.android.reader.NfcReader
+import com.tangem.tangemcard.data.*
+import com.tangem.tangemcard.reader.CardProtocol
+import com.tangem.tangemcard.tasks.SwapPINTask
+import com.tangem.tangemcard.util.Util
+import com.tangem.util.LOG
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_swap.*
class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtocol.Notifications {
-
companion object {
val TAG: String = PinSwapActivity::class.java.simpleName
+ fun callingIntent(context: Context, newPIN: String, newPIN2: String): Intent {
+ val intent = Intent(context, PinSwapActivity::class.java)
+ intent.putExtra(Constant.EXTRA_NEW_PIN, newPIN)
+ intent.putExtra(Constant.EXTRA_NEW_PIN_2, newPIN2)
+ return intent
+ }
+
const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
}
- private var nfcManager: NfcManager? = null
- private var card: TangemCard? = null
+ private lateinit var nfcManager: NfcManager
+ private var card: TangemCard? = null
private var newPIN: String? = null
private var newPIN2: String? = null
@@ -44,15 +55,13 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pin_swap)
- MainActivity.commonInit(applicationContext)
-
nfcManager = NfcManager(this, this)
- card = TangemCard(intent.getStringExtra(TangemCard.EXTRA_UID))
- card!!.loadFromBundle(intent.extras!!.getBundle(TangemCard.EXTRA_CARD))
+ card = TangemCard(intent.getStringExtra(EXTRA_TANGEM_CARD_UID))
+ card!!.loadFromBundle(intent.extras!!.getBundle(EXTRA_TANGEM_CARD))
- newPIN = intent.getStringExtra("newPIN")
- newPIN2 = intent.getStringExtra("newPIN2")
+ newPIN = intent.getStringExtra(Constant.EXTRA_NEW_PIN)
+ newPIN2 = intent.getStringExtra(Constant.EXTRA_NEW_PIN_2)
tvCardID.text = card!!.cidDescription
@@ -68,17 +77,16 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
-// Log.v(TAG, "UID: $sUID")
+ LOG.d(TAG, "UID: $sUID")
if (sUID == card!!.uid) {
isoDep.timeout = card!!.pauseBeforePIN2 + 65000
- swapPinTask = SwapPINTask(this, card, nfcManager, newPIN, newPIN2, isoDep, this)
+ swapPinTask = SwapPINTask(card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this, newPIN, newPIN2)
swapPinTask!!.start()
} else {
-// Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + mCard!!.uid + ")")
- nfcManager!!.ignoreTag(isoDep.tag)
+ LOG.d(TAG, "Mismatch card UID (" + sUID + " instead of " + card!!.uid + ")")
+ nfcManager.ignoreTag(isoDep.tag)
}
-
} catch (e: Exception) {
e.printStackTrace()
}
@@ -86,11 +94,11 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
- nfcManager!!.onPause()
+ nfcManager.onPause()
if (swapPinTask != null)
swapPinTask!!.cancel(true)
super.onPause()
@@ -98,7 +106,7 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
public override fun onStop() {
// dismiss enable NFC dialog
- nfcManager!!.onStop()
+ nfcManager.onStop()
if (swapPinTask != null)
swapPinTask!!.cancel(true)
super.onStop()
@@ -190,7 +198,7 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
}
override fun onReadWait(msec: Int) {
- WaitSecurityDelayDialog.OnReadWait(this, msec)
+ WaitSecurityDelayDialog.onReadWait(this, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
diff --git a/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitOtherApiWithdrawalActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitOtherApiWithdrawalActivity.kt
index d7f21d2cac..88c5e358c0 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitOtherApiWithdrawalActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitOtherApiWithdrawalActivity.kt
@@ -9,36 +9,39 @@ import android.nfc.Tag
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
+import com.tangem.App
+import com.tangem.Constant
+import com.tangem.data.Blockchain
import com.tangem.data.network.CryptonitOtherApi
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.Blockchain
+import com.tangem.di.Navigator
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
+import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_cryptonit_other_api_withdrawal.*
import java.io.IOException
+import javax.inject.Inject
class PrepareCryptonitOtherApiWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareCryptonitOtherApiWithdrawalActivity::class.java.simpleName
-
- private const val REQUEST_CODE_SCAN_QR_KEY = 1
- private const val REQUEST_CODE_SCAN_QR_SECRET = 2
- private const val REQUEST_CODE_SCAN_QR_USER_ID = 3
}
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
- private var nfcManager: NfcManager? = null
+
private var cryptonit: CryptonitOtherApi? = null
+ @Inject
+ internal lateinit var navigator: Navigator
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_cryptonit_other_api_withdrawal)
- MainActivity.commonInit(applicationContext)
+ App.getNavigatorComponent().inject(this)
nfcManager = NfcManager(this, this)
@@ -51,27 +54,26 @@ class PrepareCryptonitOtherApiWithdrawalActivity : AppCompatActivity(), NfcAdapt
tvSecret.text = cryptonit!!.secretDescription
tvCardID.text = ctx.card!!.cidDescription
- tvWallet.text = ctx.card!!.wallet
+ 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.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)
- var dblAmount: Double = strAmount.toDouble()
+ 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.card!!.wallet)
+ cryptonit!!.requestCryptoWithdrawal(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
@@ -84,18 +86,11 @@ class PrepareCryptonitOtherApiWithdrawalActivity : AppCompatActivity(), NfcAdapt
// }
}
- ivCameraKey.setOnClickListener {
- val intent = Intent(baseContext, QrScanActivity::class.java)
- startActivityForResult(intent, REQUEST_CODE_SCAN_QR_KEY)
- }
- ivCameraSecret.setOnClickListener {
- val intent = Intent(baseContext, QrScanActivity::class.java)
- startActivityForResult(intent, REQUEST_CODE_SCAN_QR_SECRET)
- }
- ivCameraUserId.setOnClickListener {
- val intent = Intent(baseContext, QrScanActivity::class.java)
- startActivityForResult(intent, REQUEST_CODE_SCAN_QR_USER_ID)
- }
+ ivCameraKey.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR_KEY) }
+
+ ivCameraSecret.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR_SECRET) }
+
+ ivCameraUserId.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR_USER_ID) }
ivRefreshBalance.setOnClickListener { doRequestBalance() }
@@ -162,32 +157,32 @@ class PrepareCryptonitOtherApiWithdrawalActivity : AppCompatActivity(), NfcAdapt
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
super.onPause()
- nfcManager!!.onPause()
+ nfcManager.onPause()
}
public override fun onStop() {
super.onStop()
- nfcManager!!.onStop()
+ nfcManager.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- if( resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode") ) {
- when(requestCode) {
- REQUEST_CODE_SCAN_QR_KEY -> {
+ if (resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
+ when (requestCode) {
+ Constant.REQUEST_CODE_SCAN_QR_KEY -> {
cryptonit!!.key = data.getStringExtra("QRCode")
tvKey!!.text = cryptonit!!.key
}
- REQUEST_CODE_SCAN_QR_SECRET -> {
+ Constant.REQUEST_CODE_SCAN_QR_SECRET -> {
cryptonit!!.secret = data.getStringExtra("QRCode")
tvSecret!!.text = cryptonit!!.secretDescription
}
- REQUEST_CODE_SCAN_QR_USER_ID -> {
+ Constant.REQUEST_CODE_SCAN_QR_USER_ID -> {
cryptonit!!.userId = data.getStringExtra("QRCode")
tvUserID!!.text = cryptonit!!.userId
}
@@ -199,8 +194,7 @@ class PrepareCryptonitOtherApiWithdrawalActivity : AppCompatActivity(), NfcAdapt
override fun onTagDiscovered(tag: Tag) {
try {
-// Log.w(javaClass.name, "Ignore discovered tag!")
- nfcManager!!.ignoreTag(tag)
+ nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
diff --git a/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitWithdrawalActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitWithdrawalActivity.kt
index 167739a07a..a3ae2fc75d 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitWithdrawalActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PrepareCryptonitWithdrawalActivity.kt
@@ -13,8 +13,8 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import com.tangem.data.network.Cryptonit
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.Blockchain
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.data.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.util.DecimalDigitsInputFilter
@@ -22,25 +22,22 @@ import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_cryptonit_withdrawal.*
import java.io.IOException
-
class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareCryptonitWithdrawalActivity::class.java.simpleName
}
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
- private var nfcManager: NfcManager? = null
- private var cryptonit: Cryptonit? = null
+ private var cryptonit: Cryptonit? = null
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_cryptonit_withdrawal)
- MainActivity.commonInit(applicationContext)
-
nfcManager = NfcManager(this, this)
ctx = TangemContext.loadFromBundle(this, intent.extras)
@@ -52,7 +49,7 @@ class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.Reade
etFee.setText(cryptonit!!.fee)
tvCardID.text = ctx.card!!.cidDescription
- tvWallet.text = ctx.card!!.wallet
+ tvWallet.text = ctx.coinData!!.wallet
val engine = CoinEngineFactory.create(ctx)
tvCurrency.text = engine!!.balanceCurrency
@@ -89,18 +86,17 @@ class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.Reade
// set listeners
btnLoad.setOnClickListener {
-
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
val strFee: String = etFee.text.toString().replace(",", ".")
- var dblAmount: Double = strAmount.toDouble()
+ val dblAmount: Double = strAmount.toDouble()
var dblFee: Double = strFee.toDouble()
cryptonit!!.fee = strFee
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_withdrawal)
- cryptonit!!.requestWithdrawCoins(ctx.blockchain.currency, dblAmount, ctx.card!!.wallet)
+ cryptonit!!.requestWithdrawCoins(ctx.blockchain.currency, dblAmount, ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
@@ -145,7 +141,7 @@ class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.Reade
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_balance)
tvError.visibility = View.INVISIBLE
- cryptonit!!.requestBalance(ctx.card!!.blockchain.currency)
+ cryptonit!!.requestBalance(ctx.blockchain.currency)
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.cryptonit_not_enough_account_data)
@@ -154,22 +150,22 @@ class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.Reade
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
super.onPause()
- nfcManager!!.onPause()
+ nfcManager.onPause()
}
public override fun onStop() {
super.onStop()
- nfcManager!!.onStop()
+ nfcManager.onStop()
}
override fun onTagDiscovered(tag: Tag) {
try {
- nfcManager!!.ignoreTag(tag)
+ nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
diff --git a/app/src/main/java/com/tangem/presentation/activity/PrepareKrakenWithdrawalActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PrepareKrakenWithdrawalActivity.kt
index 1bafe7e5a3..542362a3db 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PrepareKrakenWithdrawalActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PrepareKrakenWithdrawalActivity.kt
@@ -15,9 +15,12 @@ import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
+import com.tangem.App
+import com.tangem.Constant
import com.tangem.data.network.Kraken
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.Blockchain
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.data.Blockchain
+import com.tangem.di.Navigator
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.wallet.R
@@ -26,13 +29,12 @@ import java.io.IOException
import java.math.BigDecimal
import java.net.URI
import java.util.*
+import javax.inject.Inject
class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareKrakenWithdrawalActivity::class.java.simpleName
-
- private const val REQUEST_CODE_SCAN_QR = 1
}
private lateinit var ctx: TangemContext
@@ -40,12 +42,15 @@ class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCa
private var kraken: Kraken? = null
private var fee: BigDecimal? = null
+ @Inject
+ internal lateinit var navigator: Navigator
+
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_kraken_withdrawal)
- MainActivity.commonInit(applicationContext)
+ App.getNavigatorComponent().inject(this)
nfcManager = NfcManager(this, this)
@@ -57,7 +62,7 @@ class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCa
tvSecret.text = kraken!!.secretDescription
tvCardID.text = ctx.card!!.cidDescription
- tvWallet.text = ctx.card!!.wallet
+ tvWallet.text = ctx.coinData!!.wallet
val engine = CoinEngineFactory.create(ctx)
tvCurrency.text = engine!!.balanceCurrency
@@ -85,16 +90,14 @@ class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCa
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.kraken_request_withdrawal)
- kraken!!.requestWithdrawInfo(ctx.blockchain.currency, dblAmount.toString(), ctx.card!!.wallet)
+ kraken!!.requestWithdrawInfo(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
}
- ivCamera.setOnClickListener {
- val intent = Intent(baseContext, QrScanActivity::class.java)
- startActivityForResult(intent, REQUEST_CODE_SCAN_QR)
- }
+
+ ivCamera.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR) }
ivRefreshBalance.setOnClickListener { doRequestBalance() }
@@ -184,7 +187,7 @@ class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCa
tvProgressDescription.text = getString(R.string.kraken_request_withdrawal)
//Toast.makeText(this, String.format("Withdraw %s!",dblAmount.toString()), Toast.LENGTH_LONG).show()
- kraken!!.requestWithdraw(ctx.blockchain.currency, dblAmount.toString(), ctx.card!!.wallet)
+ kraken!!.requestWithdraw(ctx.blockchain.currency, dblAmount.toString(), ctx.coinData!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
@@ -240,7 +243,7 @@ class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCa
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
when (requestCode) {
- REQUEST_CODE_SCAN_QR -> {
+ Constant.REQUEST_CODE_SCAN_QR -> {
val uri = URI(data.getStringExtra("QRCode"))
val query = uri.query
val params = query.split("&")
diff --git a/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.kt
index 987f307e47..fa94fbac01 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.kt
@@ -12,32 +12,40 @@ import android.text.Html
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.Blockchain
+import com.tangem.App
+import com.tangem.Constant
+import com.tangem.data.Blockchain
+import com.tangem.di.Navigator
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
+import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_payment.*
import java.io.IOException
+import javax.inject.Inject
class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
-
companion object {
val TAG: String = PreparePaymentActivity::class.java.simpleName
-
- private const val REQUEST_CODE_SCAN_QR = 1
- private const val REQUEST_CODE_SEND_PAYMENT = 2
+ fun callingIntent(context: Context, ctx: TangemContext): Intent {
+ val intent = Intent(context, PreparePaymentActivity::class.java)
+ ctx.saveToIntent(intent)
+ return intent
+ }
}
+ @Inject
+ internal lateinit var navigator: Navigator
+
private lateinit var ctx: TangemContext
- private var nfcManager: NfcManager? = null
+ private lateinit var nfcManager: NfcManager
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_payment)
- MainActivity.commonInit(applicationContext)
+ App.getNavigatorComponent().inject(this)
nfcManager = NfcManager(this, this)
@@ -50,7 +58,7 @@ class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
tvBalance.text = html
//TODO - to engine
- if (ctx.card!!.blockchain == Blockchain.Token && engine.balance.currency!="ETH") {
+ if (ctx.blockchain == Blockchain.Token && engine.balance.currency != Blockchain.Ethereum.currency) {
rgIncFee!!.visibility = View.INVISIBLE
} else {
rgIncFee!!.visibility = View.VISIBLE
@@ -77,7 +85,6 @@ class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
}
}
btnVerify.setOnClickListener {
-
val engine1 = CoinEngineFactory.create(ctx)
val strAmount: String = etAmount.text.toString().replace(",", ".")
@@ -92,67 +99,54 @@ class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
etAmount.error = getString(R.string.unknown_amount_format)
}
- var checkAddress = false
- if (engine1 != null)
- checkAddress = engine1.validateAddress(etWallet.text.toString())
-
// check wallet address
- if (!checkAddress) {
+ if (!engine1.validateAddress(etWallet.text.toString())) {
etWallet.error = getString(R.string.incorrect_destination_wallet_address)
return@setOnClickListener
- } else {
+ } else
etWallet.error = null
- }
- if (etWallet.text.toString() == ctx.card!!.wallet) {
+ if (etWallet.text.toString() == ctx.coinData!!.wallet) {
etWallet.error = getString(R.string.destination_wallet_address_equal_source_address)
return@setOnClickListener
}
- // check enough funds
- // TODO - double with engin.checkAmount
-// if (etAmount.text.toString().replace(",", ".").toDouble() > engine.getBalanceValue(card).replace(",", ".").toDouble()) {
-// etAmount.error = getString(R.string.not_enough_funds_on_your_card)
-// return@setOnClickListener
-// }
if (!etAmount.error.isNullOrEmpty() || !etWallet.error.isNullOrEmpty()) {
return@setOnClickListener
}
val intent = Intent(baseContext, ConfirmPaymentActivity::class.java)
ctx.saveToIntent(intent)
- intent.putExtra(SignPaymentActivity.EXTRA_TARGET_ADDRESS, etWallet!!.text.toString())
- intent.putExtra(SignPaymentActivity.EXTRA_FEE_INCLUDED, (rgIncFee!!.checkedRadioButtonId == R.id.rbFeeIn))
- intent.putExtra(SignPaymentActivity.EXTRA_AMOUNT, strAmount)
- intent.putExtra(SignPaymentActivity.EXTRA_AMOUNT_CURRENCY, tvCurrency.text.toString())
- startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT)
- }
- ivCamera.setOnClickListener {
- val intent = Intent(baseContext, QrScanActivity::class.java)
- startActivityForResult(intent, REQUEST_CODE_SCAN_QR)
+ intent.putExtra(Constant.EXTRA_TARGET_ADDRESS, etWallet!!.text.toString())
+ intent.putExtra(Constant.EXTRA_FEE_INCLUDED, (rgIncFee!!.checkedRadioButtonId == R.id.rbFeeIn))
+ intent.putExtra(Constant.EXTRA_AMOUNT, strAmount)
+ intent.putExtra(Constant.EXTRA_AMOUNT_CURRENCY, tvCurrency.text.toString())
+ startActivityForResult(intent, Constant.REQUEST_CODE_SEND_PAYMENT__)
}
+
+ ivCamera.setOnClickListener { navigator.showQrScanActivity(this, Constant.REQUEST_CODE_SCAN_QR) }
}
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
super.onPause()
- nfcManager!!.onPause()
+ nfcManager.onPause()
}
public override fun onStop() {
super.onStop()
- nfcManager!!.onStop()
+ nfcManager.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- if (requestCode == REQUEST_CODE_SCAN_QR && resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
+ if (requestCode == Constant.REQUEST_CODE_SCAN_QR && resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
var code = data.getStringExtra("QRCode")
- when (ctx.card!!.blockchain) {
+ when (ctx.blockchain) {
Blockchain.Bitcoin -> {
if (code.contains("bitcoin:")) {
val tmp = code.split("bitcoin:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
@@ -172,8 +166,7 @@ class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
}
}
etWallet!!.setText(code)
- } else if (requestCode == REQUEST_CODE_SEND_PAYMENT) {
-
+ } else if (requestCode == Constant.REQUEST_CODE_SEND_PAYMENT__) {
setResult(resultCode, data)
finish()
}
@@ -181,11 +174,10 @@ class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
override fun onTagDiscovered(tag: Tag) {
try {
- nfcManager!!.ignoreTag(tag)
+ nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
-
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.kt b/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.kt
index bc74b7da35..facf49ee7f 100644
--- a/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.kt
@@ -1,6 +1,7 @@
package com.tangem.presentation.activity
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.res.ColorStateList
@@ -12,14 +13,17 @@ import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.Toast
-import com.tangem.data.nfc.PurgeTask
-import com.tangem.domain.cardReader.CardProtocol
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.TangemCard
+import com.tangem.App
+import com.tangem.tangemcard.tasks.PurgeTask
+import com.tangem.tangemcard.reader.CardProtocol
+import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
-import com.tangem.util.Util
+import com.tangem.tangemcard.android.reader.NfcReader
+import com.tangem.tangemcard.data.asBundle
+import com.tangem.tangemcard.util.Util
+import com.tangem.util.LOG
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_purge.*
@@ -27,11 +31,19 @@ class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoc
companion object {
val TAG: String = PurgeActivity::class.java.simpleName
+
+ fun callingIntent(context: Context, ctx: TangemContext): Intent {
+ val intent = Intent(context, PurgeActivity::class.java)
+ ctx.saveToIntent(intent)
+ return intent
+ }
+
const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
}
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
- private var nfcManager: NfcManager? = null
+
private var purgeTask: PurgeTask? = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -42,8 +54,6 @@ class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoc
nfcManager = NfcManager(this, this)
- MainActivity.commonInit(applicationContext)
-
ctx = TangemContext.loadFromBundle(this, intent.extras)
tvCardID.text = ctx.card!!.cidDescription
@@ -53,18 +63,18 @@ class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoc
public override fun onResume() {
super.onResume()
- nfcManager?.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
- nfcManager?.onPause()
+ nfcManager.onPause()
purgeTask?.cancel(true)
super.onPause()
}
public override fun onStop() {
// dismiss enable NFC dialog
- nfcManager?.onStop()
+ nfcManager.onStop()
purgeTask?.cancel(true)
super.onStop()
}
@@ -72,19 +82,18 @@ class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoc
override fun onTagDiscovered(tag: Tag) {
try {
// get IsoDep handle and run cardReader thread
- val isoDep = IsoDep.get(tag)
- ?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
+ val isoDep = IsoDep.get(tag) ?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
-// Log.v(TAG, "UID: $sUID")
+ LOG.d(TAG, "UID: $sUID")
if (sUID == ctx.card!!.uid) {
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 65000
- purgeTask = PurgeTask(this, ctx.card, nfcManager, isoDep, this)
+ purgeTask = PurgeTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
purgeTask!!.start()
} else {
- // this Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + card.getUID() + ")");
- nfcManager?.ignoreTag(isoDep.tag)
+ LOG.d(TAG, "Mismatch card UID (" + sUID + " instead of " + ctx.card.uid + ")")
+ nfcManager.ignoreTag(isoDep.tag)
}
} catch (e: Exception) {
@@ -93,7 +102,7 @@ class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoc
}
override fun onReadWait(msec: Int) {
- WaitSecurityDelayDialog.OnReadWait(this, msec)
+ WaitSecurityDelayDialog.onReadWait(this, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
diff --git a/app/src/main/java/com/tangem/presentation/activity/QrScanActivity.kt b/app/src/main/java/com/tangem/presentation/activity/QrScanActivity.kt
index de92ba3256..1dcf4b0edb 100644
--- a/app/src/main/java/com/tangem/presentation/activity/QrScanActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/QrScanActivity.kt
@@ -2,17 +2,22 @@ package com.tangem.presentation.activity
import android.Manifest
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v7.app.AppCompatActivity
-
import com.google.zxing.Result
-
+import com.tangem.Constant
import me.dm7.barcodescanner.zxing.ZXingScannerView
class QrScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
+ companion object {
+ fun callingIntent(context: Context): Intent {
+ return Intent(context, QrScanActivity::class.java)
+ }
+ }
private var scannerView: ZXingScannerView? = null
@@ -26,14 +31,12 @@ class QrScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
override fun onPause() {
super.onPause()
- if (scannerView != null)
- scannerView!!.stopCamera()
+ scannerView?.stopCamera()
}
override fun onResume() {
super.onResume()
- if (scannerView != null)
- scannerView!!.startCamera()
+ scannerView?.startCamera()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
@@ -51,7 +54,7 @@ class QrScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
override fun handleResult(result: Result) {
val data = Intent()
- data.putExtra("QRCode", result.text)
+ data.putExtra(Constant.EXTRA_QR_CODE, result.text)
setResult(Activity.RESULT_OK, data)
finish()
}
@@ -60,9 +63,10 @@ class QrScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
// programmatically initialize the scanner view
scannerView = ZXingScannerView(this)
setContentView(scannerView)
+
// register ourselves as a handler for scan results.
- scannerView!!.setResultHandler(this)
- scannerView!!.startCamera()
+ scannerView?.setResultHandler(this)
+ scannerView?.startCamera()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.kt b/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.kt
index 279c561445..d3465e1d28 100644
--- a/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.kt
@@ -7,94 +7,54 @@ import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.KeyEvent
import android.widget.Toast
-import com.tangem.data.network.ElectrumRequest
-import com.tangem.data.network.ServerApiElectrum
-import com.tangem.data.network.ServerApiInfura
-import com.tangem.data.network.model.InfuraResponse
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.*
-import com.tangem.domain.wallet.eth.EthData
+import com.tangem.Constant
+import com.tangem.domain.wallet.CoinEngine
+import com.tangem.domain.wallet.CoinEngineFactory
+import com.tangem.domain.wallet.TangemContext
+import com.tangem.presentation.event.TransactionFinishWithError
+import com.tangem.presentation.event.TransactionFinishWithSuccess
+import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.util.UtilHelper
import com.tangem.wallet.R
+import org.greenrobot.eventbus.EventBus
import java.io.IOException
-import java.math.BigInteger
class SendTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
- companion object {
- const val EXTRA_TX: String = "TX"
- }
-
- private var serverApiInfura: ServerApiInfura = ServerApiInfura()
- private var serverApiElectrum: ServerApiElectrum = ServerApiElectrum()
-
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
- private var tx: String? = null
- private var nfcManager: NfcManager? = null
+
+ private var tx: ByteArray? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_send_transaction)
- MainActivity.commonInit(applicationContext)
-
nfcManager = NfcManager(this, this)
ctx = TangemContext.loadFromBundle(this, intent.extras)
- tx = intent.getStringExtra(EXTRA_TX)
+ tx = intent.getByteArrayExtra(Constant.EXTRA_TX)
val engine = CoinEngineFactory.create(ctx)
- if (ctx.blockchain == Blockchain.Ethereum || ctx.blockchain == Blockchain.EthereumTestNet || ctx.blockchain == Blockchain.Token)
- requestInfura(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION, "")
- else if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet)
- requestElectrum(ctx.card!!, ElectrumRequest.broadcast(ctx.card!!.wallet, tx))
- else if (ctx.blockchain == Blockchain.BitcoinCash)
- requestElectrum(ctx.card!!, ElectrumRequest.broadcast(ctx.card!!.wallet, tx))
-
- // request electrum listener
- val electrumBodyListener: ServerApiElectrum.ElectrumRequestDataListener = object : ServerApiElectrum.ElectrumRequestDataListener {
- override fun onSuccess(electrumRequest: ElectrumRequest?) {
- if (electrumRequest!!.isMethod(ElectrumRequest.METHOD_SendTransaction)) {
- if (electrumRequest.resultString.isEmpty())
- finishWithError("Rejected by node: " + electrumRequest.getError())
- else
- finishWithSuccess()
- }
- }
-
- override fun onFail(message: String?) {
- finishWithError(message!!)
- }
- }
- serverApiElectrum.setElectrumRequestData(electrumBodyListener)
-
- // request infura listener
- val infuraBodyListener: ServerApiInfura.InfuraBodyListener = object : ServerApiInfura.InfuraBodyListener {
- override fun onSuccess(method: String, infuraResponse: InfuraResponse) {
- when (method) {
- ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION -> {
- if (infuraResponse.result.isEmpty())
- finishWithError("Rejected by node: " + infuraResponse.error)
- else {
- val nonce = (ctx.coinData!! as EthData).confirmedTXCount
- nonce.add(BigInteger.valueOf(1))
- (ctx.coinData!! as EthData).confirmedTXCount = nonce
+ engine!!.requestSendTransaction(
+ object : CoinEngine.BlockchainRequestsCallbacks {
+ override fun onComplete(success: Boolean) {
+ if (success)
finishWithSuccess()
- }
+ else
+ finishWithError(this@SendTransactionActivity.getString(R.string.try_again_failed_to_send_transaction))
}
- }
- }
- override fun onFail(method: String, message: String) {
- when (method) {
- ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION -> {
- finishWithError(message)
+ override fun onProgress() {
}
- }
- }
- }
- serverApiInfura.setInfuraResponse(infuraBodyListener)
+
+ override fun allowAdvance(): Boolean {
+ return UtilHelper.isOnline(this@SendTransactionActivity)
+ }
+ },
+ tx
+ )
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
@@ -109,51 +69,45 @@ class SendTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
super.onPause()
- nfcManager!!.onPause()
+ nfcManager.onPause()
}
public override fun onStop() {
super.onStop()
- nfcManager!!.onStop()
+ nfcManager.onStop()
}
override fun onTagDiscovered(tag: Tag) {
try {
- nfcManager!!.ignoreTag(tag)
+ nfcManager.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
- private fun requestInfura(method: String, contract: String) {
- if (UtilHelper.isOnline(this)) {
- serverApiInfura.infura(method, 67, ctx.card!!.wallet, contract, tx)
- } else
- finishWithError(getString(R.string.no_connection))
- }
-
- private fun requestElectrum(card: TangemCard, electrumRequest: ElectrumRequest) {
- if (UtilHelper.isOnline(this)) {
- serverApiElectrum.electrumRequestData(card, electrumRequest)
- } else
- finishWithError(getString(R.string.no_connection))
- }
-
private fun finishWithSuccess() {
+ val transactionFinishWithSuccess = TransactionFinishWithSuccess()
+ transactionFinishWithSuccess.message = getString(R.string.transaction_has_been_successfully_signed)
+ EventBus.getDefault().post(transactionFinishWithSuccess)
+
val intent = Intent()
- intent.putExtra("message", getString(R.string.transaction_has_been_successfully_signed))
+ intent.putExtra(Constant.EXTRA_MESSAGE, getString(R.string.transaction_has_been_successfully_signed))
setResult(RESULT_OK, intent)
finish()
}
private fun finishWithError(message: String) {
+ val transactionFinishWithError = TransactionFinishWithError()
+ transactionFinishWithError.message = String.format(getString(R.string.try_again_failed_to_send_transaction), message)
+ EventBus.getDefault().post(transactionFinishWithError)
+
val intent = Intent()
- intent.putExtra("message", String.format(getString(R.string.try_again_failed_to_send_transaction), message))
+ intent.putExtra(Constant.EXTRA_MESSAGE, String.format(getString(R.string.try_again_failed_to_send_transaction), message))
setResult(RESULT_CANCELED, intent)
finish()
}
diff --git a/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.kt b/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.kt
index 52c13893f4..3258c8e3f4 100644
--- a/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.kt
@@ -13,14 +13,20 @@ import android.view.KeyEvent
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
-import com.tangem.data.nfc.SignPaymentTask
-import com.tangem.domain.cardReader.CardProtocol
-import com.tangem.domain.cardReader.NfcManager
+import com.tangem.App
+import com.tangem.Constant
import com.tangem.domain.wallet.CoinEngine
+import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
-import com.tangem.util.Util
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.android.reader.NfcReader
+import com.tangem.tangemcard.data.asBundle
+import com.tangem.tangemcard.reader.CardProtocol
+import com.tangem.tangemcard.tasks.SignTask
+import com.tangem.tangemcard.util.Util
+import com.tangem.util.LOG
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_sign_payment.*
@@ -28,24 +34,15 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
companion object {
val TAG: String = SignPaymentActivity::class.java.simpleName
-
- 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_PAYMENT = 1
- const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
}
- private var nfcManager: NfcManager? = null
+ private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
- private var signPaymentTask: SignPaymentTask? = null
+ private var signPaymentTask: SignTask? = null
- private var amount: CoinEngine.Amount? = null
- private var fee: CoinEngine.Amount? = 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
@@ -56,16 +53,14 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_payment)
- MainActivity.commonInit(applicationContext)
-
nfcManager = NfcManager(this, this)
- ctx=TangemContext.loadFromBundle(this, intent.extras)
+ ctx = TangemContext.loadFromBundle(this, intent.extras)
- amount = CoinEngine.Amount(intent.getStringExtra(EXTRA_AMOUNT), intent.getStringExtra(EXTRA_AMOUNT_CURRENCY))
- fee = CoinEngine.Amount(intent.getStringExtra(EXTRA_FEE), intent.getStringExtra(EXTRA_FEE_CURRENCY))
- isIncludeFee = intent.getBooleanExtra(EXTRA_FEE_INCLUDED, true)
- outAddressStr = intent.getStringExtra(EXTRA_TARGET_ADDRESS)
+ amount = CoinEngine.Amount(intent.getStringExtra(Constant.EXTRA_AMOUNT), intent.getStringExtra(Constant.EXTRA_AMOUNT_CURRENCY))
+ fee = CoinEngine.Amount(intent.getStringExtra(Constant.EXTRA_FEE), intent.getStringExtra(Constant.EXTRA_FEE_CURRENCY))
+ isIncludeFee = intent.getBooleanExtra(Constant.EXTRA_FEE_INCLUDED, true)
+ outAddressStr = intent.getStringExtra(Constant.EXTRA_TARGET_ADDRESS)
tvCardID.text = ctx.card!!.cidDescription
@@ -76,11 +71,11 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
public override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
public override fun onPause() {
- nfcManager!!.onPause()
+ nfcManager.onPause()
if (signPaymentTask != null)
signPaymentTask!!.cancel(true)
super.onPause()
@@ -88,14 +83,14 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
public override fun onStop() {
// dismiss enable NFC dialog
- nfcManager!!.onStop()
+ nfcManager.onStop()
if (signPaymentTask != null)
signPaymentTask!!.cancel(true)
super.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- if (requestCode == REQUEST_CODE_SEND_PAYMENT) {
+ if (requestCode == Constant.REQUEST_CODE_SEND_PAYMENT_) {
setResult(resultCode, data)
finish()
return
@@ -122,7 +117,6 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag.id
val sUID = Util.byteArrayToHexString(uid)
-// Log.v(TAG, "UID: $sUID")
if (sUID == ctx.card!!.uid) {
if (lastReadSuccess) {
@@ -130,13 +124,35 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
} else {
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 65000
}
- signPaymentTask = SignPaymentTask(this, ctx, nfcManager, isoDep, this, amount, fee, isIncludeFee, outAddressStr)
- signPaymentTask!!.start()
- } else {
-// Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + card!!.uid + ")")
- nfcManager!!.ignoreTag(isoDep.tag)
- }
+ val coinEngine = CoinEngineFactory.create(ctx)
+ ?: throw CardProtocol.TangemException("Can't create CoinEngine!")
+ coinEngine.setOnNeedSendPayment { tx ->
+ if (tx != null) {
+ val intent = Intent(this, SendTransactionActivity::class.java)
+ ctx.saveToIntent(intent)
+ intent.putExtra(Constant.EXTRA_TX, tx)
+ startActivityForResult(intent, Constant.REQUEST_CODE_SEND_PAYMENT_)
+ }
+ }
+ val paymentToSign = coinEngine.constructPayment(amount, fee, isIncludeFee, outAddressStr)
+
+ signPaymentTask = SignTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this, paymentToSign)
+ signPaymentTask!!.start()
+ } else
+ nfcManager.ignoreTag(isoDep.tag)
+
+ } catch (e: CardProtocol.TangemException_WrongAmount) {
+ try {
+ val intent = Intent()
+ intent.putExtra("message", getString(R.string.cannot_sign_transaction_wrong_amount))
+ intent.putExtra("UID", ctx.card.uid)
+ intent.putExtra("Card", ctx.card.asBundle)
+ setResult(Activity.RESULT_CANCELED, intent)
+ finish()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
} catch (e: Exception) {
e.printStackTrace()
}
@@ -174,10 +190,10 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
progressBar!!.progressTintList = ColorStateList.valueOf(Color.DKGRAY)
progressBar!!.visibility = View.INVISIBLE
val intent = Intent()
- intent.putExtra("message", getString(R.string.cannot_sign_transaction__make_sure_you_enter_correct_pin_2))
+ intent.putExtra("message", getString(R.string.cannot_sign_transaction_make_sure_you_enter_correct_pin_2))
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card.asBundle)
- setResult(RESULT_INVALID_PIN, intent)
+ setResult(Constant.RESULT_INVALID_PIN_, intent)
finish()
} catch (e: Exception) {
e.printStackTrace()
@@ -237,16 +253,41 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
}, 500)
}
- override fun onReadWait(msec: Int) {
- WaitSecurityDelayDialog.OnReadWait(this, msec)
- }
+// private val waitSecurityDelayDialogNew = WaitSecurityDelayDialogNew()
override fun onReadBeforeRequest(timeout: Int) {
+ LOG.i(TAG, "onReadBeforeRequest timeout $timeout")
WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout)
+
+// if (!waitSecurityDelayDialogNew.isAdded)
+// waitSecurityDelayDialogNew.show(supportFragmentManager, WaitSecurityDelayDialogNew.TAG)
+
+
+// val readBeforeRequest = ReadBeforeRequest()
+// readBeforeRequest.timeout = timeout
+// EventBus.getDefault().post(readBeforeRequest)
+
}
override fun onReadAfterRequest() {
+ LOG.i(TAG, "onReadAfterRequest")
WaitSecurityDelayDialog.onReadAfterRequest(this)
+
+// val readAfterRequest = ReadAfterRequest()
+// EventBus.getDefault().post(readAfterRequest)
+
}
+ override fun onReadWait(msec: Int) {
+ LOG.i(TAG, "onReadWait msec $msec")
+ WaitSecurityDelayDialog.onReadWait(this, msec)
+
+// val readWait = ReadWait()
+// readWait.msec = msec
+// EventBus.getDefault().post(readWait)
+
+
+ }
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.kt b/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.kt
index 402da7169c..408a7e36ca 100644
--- a/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.kt
+++ b/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.kt
@@ -7,8 +7,7 @@ import android.support.v7.app.AppCompatActivity
import com.tangem.App
import com.tangem.Constant
import com.tangem.di.Navigator
-import com.tangem.domain.wallet.CoinData
-import com.tangem.domain.wallet.TangemCard
+import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.fragment.VerifyCard
import com.tangem.wallet.R
import javax.inject.Inject
@@ -19,13 +18,9 @@ class VerifyCardActivity : AppCompatActivity() {
lateinit var navigator: Navigator
companion object {
- fun callingIntent(context: Context, card: TangemCard, coinData: CoinData, message: String, error: String): Intent {
+ fun callingIntent(context: Context, ctx: TangemContext): Intent {
val intent = Intent(context, VerifyCardActivity::class.java)
- intent.putExtra(TangemCard.EXTRA_UID, card.uid)
- intent.putExtra(TangemCard.EXTRA_CARD, card.asBundle)
- intent.putExtra(Constant.EXTRA_BLOCKCHAIN_DATA, coinData.asBundle())
- intent.putExtra(Constant.MESSAGE, message)
- intent.putExtra(Constant.ERROR, error)
+ ctx.saveToIntent(intent)
return intent
}
}
@@ -35,15 +30,13 @@ class VerifyCardActivity : AppCompatActivity() {
setContentView(R.layout.activity_verify_card)
App.getNavigatorComponent().inject(this)
-
- MainActivity.commonInit(applicationContext)
}
override fun onBackPressed() {
super.onBackPressed()
val verifyCard = supportFragmentManager.findFragmentById(R.id.verify_card_fragment) as VerifyCard
val data = verifyCard.prepareResultIntent()
- data.putExtra(Constant.EXTRA_MODIFICATION, "update")
+ data.putExtra(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_UPDATE)
finish()
}
diff --git a/app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.kt b/app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.kt
index b49551d716..f6aed9beb5 100644
--- a/app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.kt
+++ b/app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.kt
@@ -2,8 +2,8 @@ package com.tangem.presentation.dialog
import android.app.AlertDialog
import android.app.Dialog
-import android.app.DialogFragment
import android.os.Bundle
+import android.support.v4.app.DialogFragment
import com.tangem.wallet.R
diff --git a/app/src/main/java/com/tangem/presentation/dialog/ShowQRCodeDialog.java b/app/src/main/java/com/tangem/presentation/dialog/ShowQRCodeDialog.java
index 91090b4c39..eb92fe303e 100644
--- a/app/src/main/java/com/tangem/presentation/dialog/ShowQRCodeDialog.java
+++ b/app/src/main/java/com/tangem/presentation/dialog/ShowQRCodeDialog.java
@@ -11,15 +11,11 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
-import android.widget.ProgressBar;
import android.widget.TextView;
import com.tangem.util.UtilHelper;
import com.tangem.wallet.R;
-import java.util.Timer;
-import java.util.TimerTask;
-
/**
* Created by dvol on 06.03.2018.
*/
diff --git a/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialog.java b/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialog.java
index 00a53361a6..d23cf18cbc 100644
--- a/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialog.java
+++ b/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialog.java
@@ -3,12 +3,11 @@ package com.tangem.presentation.dialog;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.WindowManager;
import android.widget.ProgressBar;
import com.tangem.wallet.R;
@@ -20,24 +19,16 @@ import java.util.TimerTask;
* Created by dvol on 06.03.2018.
*/
public class WaitSecurityDelayDialog extends DialogFragment {
- private static final String TAG = WaitSecurityDelayDialog.class.getSimpleName();
-
- private ProgressBar progressBar;
- private int msTimeout = 60000, msProgress = 0;
- private Timer timer;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
+ ProgressBar progressBar;
+ int msTimeout = 60000, msProgress = 0;
+ Timer timer;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
- // Inflate and set t he layout for the dialog
+ // 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_wait_pin2, null);
@@ -49,17 +40,20 @@ public class WaitSecurityDelayDialog extends DialogFragment {
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);
+ progressBar.post(new Runnable() {
+ @Override
+ public void run() {
+ 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.security_delay)
+ .setTitle("Security delay")
.setView(v)
.setCancelable(false)
.create();
@@ -76,19 +70,22 @@ public class WaitSecurityDelayDialog extends DialogFragment {
}
public void setRemainingTimeout(final int msec) {
- 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.post(new Runnable() {
+ @Override
+ public void run() {
+ 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);
+ }
}
}
});
@@ -97,70 +94,75 @@ public class WaitSecurityDelayDialog extends DialogFragment {
static Timer timerToShowDelayDialog = null;
static WaitSecurityDelayDialog instance = null;
- public static WaitSecurityDelayDialog getInstance() {
- if (instance == null) {
- instance = new WaitSecurityDelayDialog();
- }
- return instance;
- }
+// public static WaitSecurityDelayDialog getInstance() {
+// if (instance == null) {
+// instance = new WaitSecurityDelayDialog();
+// }
+// return instance;
+// }
- private final static int MinRemainingDelayToShowDialog = 1000;
- private final static int DelayBeforeShowDialog = 5000;
+ private final static int MinRemainingDelayToShowDialog=1000;
+ private final static int DelayBeforeShowDialog=5000;
public static void onReadBeforeRequest(final Activity activity, final int 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);
- if (instance.getFragmentManager() != null)
- instance.show(instance.getFragmentManager(), TAG);
- }
- }, DelayBeforeShowDialog);
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ 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);
+ instance.show(activity.getFragmentManager(), "WaitSecurityDelayDialog");
+ }
+ }, DelayBeforeShowDialog);
+ }
});
}
public static void onReadAfterRequest(final Activity activity) {
- activity.runOnUiThread(() -> {
- if (timerToShowDelayDialog == null) return;
- timerToShowDelayDialog.cancel();
- timerToShowDelayDialog = null;
- });
- }
-
- public static void OnReadWait(final Activity activity, final int msec) {
- activity.runOnUiThread(() -> {
- if (timerToShowDelayDialog != null) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (timerToShowDelayDialog == null) return;
timerToShowDelayDialog.cancel();
timerToShowDelayDialog = null;
}
-
- if (msec == 0) {
- if (instance != null) {
- instance.dismiss();
- instance = null;
- }
- return;
- }
-
- if (instance == null) {
- if (msec > MinRemainingDelayToShowDialog) {
- instance = new WaitSecurityDelayDialog();
- // 1000ms - card delay notification interval
- instance.setup(msec + 1000, 1000);
- instance.setCancelable(false);
- if (instance.getFragmentManager() != null)
- instance.show(instance.getFragmentManager(), TAG);
- }
- } else
- instance.setRemainingTimeout(msec);
});
}
-}
\ No newline at end of file
+ public static void onReadWait(final Activity activity, final int msec) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (timerToShowDelayDialog != null) {
+ timerToShowDelayDialog.cancel();
+ timerToShowDelayDialog = null;
+ }
+
+ if (msec == 0) {
+ if (instance != null) {
+ instance.dismiss();
+ instance = null;
+ }
+ return;
+ }
+ if (instance == null) {
+ if( msec>MinRemainingDelayToShowDialog ) {
+ instance = new WaitSecurityDelayDialog();
+ // 1000ms - card delay notification interval
+ instance.setup(msec + 1000, 1000);
+ instance.setCancelable(false);
+ instance.show(activity.getFragmentManager(), "WaitSecurityDelayDialog");
+ }
+ } else {
+ instance.setRemainingTimeout(msec);
+ }
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialogNew.kt b/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialogNew.kt
new file mode 100644
index 0000000000..7a29f8f39b
--- /dev/null
+++ b/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialogNew.kt
@@ -0,0 +1,153 @@
+package com.tangem.presentation.dialog
+
+import android.annotation.SuppressLint
+import android.app.AlertDialog
+import android.app.Dialog
+import android.os.Bundle
+import android.support.v7.app.AppCompatDialogFragment
+import android.widget.ProgressBar
+import com.tangem.presentation.activity.SignPaymentActivity
+import com.tangem.presentation.event.ReadAfterRequest
+import com.tangem.presentation.event.ReadBeforeRequest
+import com.tangem.presentation.event.ReadWait
+import com.tangem.presentation.event.TransactionFinishWithSuccess
+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.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)
+ }
+ }, 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 (!isAdded)
+// show(activity?.supportFragmentManager, 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/presentation/event/ReadAfterRequest.kt b/app/src/main/java/com/tangem/presentation/event/ReadAfterRequest.kt
new file mode 100644
index 0000000000..a5b3398ec2
--- /dev/null
+++ b/app/src/main/java/com/tangem/presentation/event/ReadAfterRequest.kt
@@ -0,0 +1,4 @@
+package com.tangem.presentation.event
+
+class ReadAfterRequest {
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/event/ReadBeforeRequest.kt b/app/src/main/java/com/tangem/presentation/event/ReadBeforeRequest.kt
new file mode 100644
index 0000000000..e9d1690bd5
--- /dev/null
+++ b/app/src/main/java/com/tangem/presentation/event/ReadBeforeRequest.kt
@@ -0,0 +1,5 @@
+package com.tangem.presentation.event
+
+class ReadBeforeRequest {
+ var timeout: Int? = null
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/event/ReadWait.kt b/app/src/main/java/com/tangem/presentation/event/ReadWait.kt
new file mode 100644
index 0000000000..3b35bf479b
--- /dev/null
+++ b/app/src/main/java/com/tangem/presentation/event/ReadWait.kt
@@ -0,0 +1,5 @@
+package com.tangem.presentation.event
+
+class ReadWait {
+ var msec: Int? = null
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/event/TransactionFinishWithError.kt b/app/src/main/java/com/tangem/presentation/event/TransactionFinishWithError.kt
new file mode 100644
index 0000000000..bc5c5cb58c
--- /dev/null
+++ b/app/src/main/java/com/tangem/presentation/event/TransactionFinishWithError.kt
@@ -0,0 +1,5 @@
+package com.tangem.presentation.event
+
+class TransactionFinishWithError {
+ var message: String? = null
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/event/TransactionFinishWithSuccess.kt b/app/src/main/java/com/tangem/presentation/event/TransactionFinishWithSuccess.kt
new file mode 100644
index 0000000000..689c418d27
--- /dev/null
+++ b/app/src/main/java/com/tangem/presentation/event/TransactionFinishWithSuccess.kt
@@ -0,0 +1,5 @@
+package com.tangem.presentation.event
+
+class TransactionFinishWithSuccess {
+ var message: String? = null
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt b/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt
index 7346f13445..ca23b0aa1d 100644
--- a/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt
+++ b/app/src/main/java/com/tangem/presentation/fragment/LoadedWallet.kt
@@ -13,64 +13,61 @@ import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.text.Html
-import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
-import com.tangem.data.db.LocalStorage
-import com.tangem.data.db.PINStorage
-import com.tangem.data.network.ElectrumRequest
+import com.tangem.App
+import com.tangem.Constant
+import com.tangem.data.Blockchain
import com.tangem.data.network.ServerApiCommon
-import com.tangem.data.network.ServerApiElectrum
-import com.tangem.data.network.ServerApiInfura
-import com.tangem.data.network.model.CardVerifyAndGetInfo
-import com.tangem.data.network.model.InfuraResponse
-import com.tangem.data.nfc.VerifyCardTask
-import com.tangem.domain.cardReader.CardProtocol
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.*
-import com.tangem.domain.wallet.bch.BtcCashEngine
-import com.tangem.domain.wallet.btc.BtcData
-import com.tangem.domain.wallet.eth.EthData
-import com.tangem.domain.wallet.token.TokenData
-import com.tangem.domain.wallet.token.TokenEngine
-import com.tangem.presentation.activity.*
+import com.tangem.domain.wallet.BalanceValidator
+import com.tangem.domain.wallet.CoinEngine
+import com.tangem.domain.wallet.CoinEngineFactory
+import com.tangem.domain.wallet.TangemContext
+import com.tangem.presentation.activity.LoadedWalletActivity
+import com.tangem.presentation.activity.PinRequestActivity
+import com.tangem.presentation.activity.PrepareCryptonitWithdrawalActivity
+import com.tangem.presentation.activity.PrepareKrakenWithdrawalActivity
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.PINSwapWarningDialog
import com.tangem.presentation.dialog.ShowQRCodeDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
-import com.tangem.util.Util
+import com.tangem.presentation.event.TransactionFinishWithError
+import com.tangem.presentation.event.TransactionFinishWithSuccess
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.android.reader.NfcReader
+import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD
+import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD_UID
+import com.tangem.tangemcard.data.TangemCard
+import com.tangem.tangemcard.data.loadFromBundle
+import com.tangem.tangemcard.reader.CardProtocol
+import com.tangem.tangemcard.tasks.VerifyCardTask
+import com.tangem.tangemcard.util.Util
+import com.tangem.tangemserver.android.ServerApiTangem
+import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo
+import com.tangem.util.LOG
import com.tangem.util.UtilHelper
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fr_loaded_wallet.*
-import org.json.JSONException
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
import java.io.InputStream
-import java.math.BigInteger
import java.util.*
+import kotlin.concurrent.timerTask
class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notifications, SharedPreferences.OnSharedPreferenceChangeListener {
companion object {
val TAG: String = LoadedWallet::class.java.simpleName
- private const val REQUEST_CODE_SEND_PAYMENT = 1
- const val REQUEST_CODE_VERIFY_CARD = 4
- private const val REQUEST_CODE_PURGE = 2
- private const val REQUEST_CODE_REQUEST_PIN2_FOR_PURGE = 3
- private const val REQUEST_CODE_ENTER_NEW_PIN = 5
- private const val REQUEST_CODE_ENTER_NEW_PIN2 = 6
- private const val REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = 7
- private const val REQUEST_CODE_SWAP_PIN = 8
- private const val REQUEST_CODE_RECEIVE_PAYMENT = 9
}
- private var nfcManager: NfcManager? = null
+ private lateinit var nfcManager: NfcManager
private var serverApiCommon: ServerApiCommon = ServerApiCommon()
- private var serverApiInfura: ServerApiInfura = ServerApiInfura()
- private var serverApiElectrum: ServerApiElectrum = ServerApiElectrum()
+ private var serverApiTangem: ServerApiTangem = ServerApiTangem()
+
- private var singleToast: Toast? = null
private lateinit var ctx: TangemContext
private var lastTag: Tag? = null
@@ -83,19 +80,23 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
private var cardProtocol: CardProtocol? = null
private val inactiveColor: ColorStateList by lazy { resources.getColorStateList(R.color.btn_dark) }
private val activeColor: ColorStateList by lazy { resources.getColorStateList(R.color.colorAccent) }
- private var requestCounter = 0
- private var timerRepeatRefresh: Timer? = null
- private lateinit var localStorage: LocalStorage
-
+ 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
+ //updateViews()
+ } else if (srl != null && !srl.isRefreshing) srl.isRefreshing = true
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nfcManager = NfcManager(activity, this)
ctx = TangemContext.loadFromBundle(activity, activity?.intent?.extras)
- lastTag = activity?.intent?.getParcelableExtra(MainActivity.EXTRA_LAST_DISCOVERED_TAG)
-
- localStorage = activity?.let { LocalStorage(it) }!!
+ lastTag = activity?.intent?.getParcelableExtra(Constant.EXTRA_LAST_DISCOVERED_TAG)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -108,310 +109,99 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
if (ctx.blockchain == Blockchain.Token)
tvBalance.setSingleLine(false)
- ivTangemCard.setImageBitmap(localStorage.getCardArtworkBitmap(ctx.card))
+ ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card))
btnExtract.isEnabled = false
btnExtract.backgroundTintList = inactiveColor
- refresh()
-
- startVerify(lastTag)
-
- tvWallet.text = ctx.card.wallet
- tvWallet.text = ctx.card.wallet
+ tvWallet.text = ctx.coinData.wallet
// set listeners
srl.setOnRefreshListener { refresh() }
- btnLookup.setOnClickListener {
+
+ tvWallet.setOnClickListener { doShareWallet(false) }
+
+ btnExplore.setOnClickListener {
val engine = CoinEngineFactory.create(ctx)
- val browserIntent = Intent(Intent.ACTION_VIEW, engine?.shareWalletUriExplorer)
- startActivity(browserIntent)
+ startActivity(Intent(Intent.ACTION_VIEW, engine?.shareWalletUriExplorer))
}
btnCopy.setOnClickListener { doShareWallet(false) }
- tvWallet.setOnClickListener { doShareWallet(false) }
+
btnLoad.setOnClickListener {
- //if (BuildConfig.DEBUG) {
- if (true) {
- val items = arrayOf(getString(R.string.in_app), getString(R.string.load_via_share_address), getString(R.string.load_via_qr))//, getString(R.string.via_cryptonit), getString(R.string.via_kraken))
- val cw = android.view.ContextThemeWrapper(activity, R.style.AlertDialogTheme)
- val dialog = AlertDialog.Builder(cw).setItems(items
- ) { _, which ->
- when (items[which]) {
- getString(R.string.in_app) -> {
- try {
- val engine = CoinEngineFactory.create(ctx)
- val intent = Intent(Intent.ACTION_VIEW, engine!!.shareWalletUri)
- intent.addCategory(Intent.CATEGORY_DEFAULT)
- startActivity(intent)
- } catch (e: ActivityNotFoundException) {
- showSingleToast(R.string.no_compatible_wallet)
- }
- }
- getString(R.string.load_via_share_address) -> {
- doShareWallet(true)
- }
- getString(R.string.load_via_qr) -> {
+ val items = arrayOf(getString(R.string.in_app), getString(R.string.load_via_share_address), getString(R.string.load_via_qr))//, getString(R.string.via_cryptonit), getString(R.string.via_kraken))
+ val cw = android.view.ContextThemeWrapper(activity, R.style.AlertDialogTheme)
+ val dialog = AlertDialog.Builder(cw).setItems(items
+ ) { _, which ->
+ when (items[which]) {
+ getString(R.string.in_app) -> {
+ try {
val engine = CoinEngineFactory.create(ctx)
- ShowQRCodeDialog.show(activity, engine!!.shareWalletUri.toString())
- }
-// getString(R.string.via_cryptonit2) -> {
-// val intent = Intent(ctx, PrepareCryptonitOtherApiWithdrawalActivity::class.java)
-// intent.putExtra("UID", card!!.uid)
-// intent.putExtra("Card", card!!.asBundle)
-// startActivityForResult(intent, REQUEST_CODE_RECEIVE_PAYMENT)
-// }
- getString(R.string.via_cryptonit) -> {
- val intent = Intent(activity, PrepareCryptonitWithdrawalActivity::class.java)
- ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_RECEIVE_PAYMENT)
- }
- getString(R.string.via_kraken) -> {
- val intent = Intent(activity, PrepareKrakenWithdrawalActivity::class.java)
- ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_RECEIVE_PAYMENT)
- }
- else -> {
+ val intent = Intent(Intent.ACTION_VIEW, engine!!.shareWalletUri)
+ intent.addCategory(Intent.CATEGORY_DEFAULT)
+ startActivity(intent)
+ } catch (e: ActivityNotFoundException) {
+ UtilHelper.showSingleToast(context, getString(R.string.no_compatible_wallet))
}
}
- }
- val dlg = dialog.show()
- val wlp = dlg.window.attributes
- wlp.gravity = Gravity.BOTTOM
- dlg.window.attributes = wlp
- } else {
- try {
- val engine = CoinEngineFactory.create(ctx)
- val intent = Intent(Intent.ACTION_VIEW, engine!!.shareWalletUri)
- intent.addCategory(Intent.CATEGORY_DEFAULT)
- startActivity(intent)
- } catch (e: ActivityNotFoundException) {
- showSingleToast(R.string.no_compatible_wallet)
+
+ getString(R.string.load_via_share_address) -> {
+ doShareWallet(true)
+ }
+
+ getString(R.string.load_via_qr) -> {
+ val engine = CoinEngineFactory.create(ctx)
+ ShowQRCodeDialog.show(activity, engine!!.shareWalletUri.toString())
+ }
+
+ getString(R.string.via_cryptonit) -> {
+ val intent = Intent(activity, PrepareCryptonitWithdrawalActivity::class.java)
+ ctx.saveToIntent(intent)
+ startActivityForResult(intent, Constant.REQUEST_CODE_RECEIVE_PAYMENT)
+ }
+
+ getString(R.string.via_kraken) -> {
+ val intent = Intent(activity, PrepareKrakenWithdrawalActivity::class.java)
+ ctx.saveToIntent(intent)
+ startActivityForResult(intent, Constant.REQUEST_CODE_RECEIVE_PAYMENT)
+ }
+ else -> {
+ }
}
}
+ val dlg = dialog.show()
+ val wlp = dlg.window.attributes
+ wlp.gravity = Gravity.BOTTOM
+ dlg.window.attributes = wlp
}
- btnDetails.setOnClickListener {
- if (cardProtocol != null)
-// openVerifyCard(cardProtocol!!)
- (activity as LoadedWalletActivity).navigator.showVerifyCard(context as Activity, ctx.card, ctx.coinData, ctx.message, ctx.error)
- else
- showSingleToast(R.string.need_attach_card_again)
- }
- btnScanAgain.setOnClickListener { (activity as LoadedWalletActivity).navigator.showMain(context as Activity) }
btnExtract.setOnClickListener {
val engine = CoinEngineFactory.create(ctx)
- if (UtilHelper.isOnline(context as Activity)) {
+ if (UtilHelper.isOnline(context as Activity))
if (!engine!!.isExtractPossible)
- showSingleToast(ctx.message)
+ UtilHelper.showSingleToast(context, ctx.message)
else if (ctx.card!!.remainingSignatures == 0)
- showSingleToast(R.string.card_has_no_remaining_signature)
- else {
- val intent = Intent(activity, PreparePaymentActivity::class.java)
- ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT)
- }
- } else
+ UtilHelper.showSingleToast(context, getString(R.string.card_has_no_remaining_signature))
+ else
+ (activity as LoadedWalletActivity).navigator.showPreparePayment(context as Activity, ctx)
+ else
Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
}
- // request electrum listener
- val electrumBodyListener: ServerApiElectrum.ElectrumRequestDataListener = object : ServerApiElectrum.ElectrumRequestDataListener {
- override fun onSuccess(electrumRequest: ElectrumRequest?) {
- if (electrumRequest!!.isMethod(ElectrumRequest.METHOD_GetBalance)) {
- try {
- val walletAddress = electrumRequest.params.getString(0)
- val confBalance = electrumRequest.result.getLong("confirmed")
- val unconfirmedBalance = electrumRequest.result.getLong("unconfirmed")
- ctx.coinData!!.isBalanceReceived = true
- (ctx.coinData!! as BtcData).setBalanceConfirmed(confBalance)
- (ctx.coinData!! as BtcData).balanceUnconfirmed = unconfirmedBalance
- (ctx.coinData!! as BtcData).validationNodeDescription = serverApiElectrum.validationNodeDescription
- } catch (e: JSONException) {
- e.printStackTrace()
- Log.e(TAG, "FAIL METHOD_GetBalance JSONException")
- }
- }
-
- if (electrumRequest.isMethod(ElectrumRequest.METHOD_ListUnspent)) {
- try {
- val walletAddress = electrumRequest.params.getString(0)
- val jsUnspentArray = electrumRequest.resultArray
- try {
- (ctx.coinData!! as BtcData).unspentTransactions.clear()
- for (i in 0 until jsUnspentArray.length()) {
- val jsUnspent = jsUnspentArray.getJSONObject(i)
- val trUnspent = BtcData.UnspentTransaction()
- trUnspent.txID = jsUnspent.getString("tx_hash")
- trUnspent.Amount = jsUnspent.getInt("value")
- trUnspent.Height = jsUnspent.getInt("height")
- (ctx.coinData!! as BtcData).unspentTransactions.add(trUnspent)
- }
- } catch (e: JSONException) {
- e.printStackTrace()
- Log.e(TAG, "FAIL METHOD_ListUnspent JSONException")
- }
-
- for (i in 0 until jsUnspentArray.length()) {
- val jsUnspent = jsUnspentArray.getJSONObject(i)
- val height = jsUnspent.getInt("height")
- val hash = jsUnspent.getString("tx_hash")
- if (height != -1) {
- requestElectrum(ElectrumRequest.getTransaction(walletAddress, hash))
- }
- }
- } catch (e: JSONException) {
- e.printStackTrace()
- }
- }
-
- if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetTransaction)) {
- try {
- val txHash = electrumRequest.txHash
- val raw = electrumRequest.resultString
- val listTx = (ctx.coinData!! as BtcData).unspentTransactions
- for (tx in listTx) {
- if (tx.txID == txHash)
- tx.Raw = raw
- }
- } catch (e: JSONException) {
- e.printStackTrace()
- }
- }
-
- if (electrumRequest.isMethod(ElectrumRequest.METHOD_SendTransaction)) {
-
- }
-
- counterMinus()
- }
-
- override fun onFail(method: String?) {
-
- }
+ btnDetails.setOnClickListener {
+ if (cardProtocol != null)
+ (activity as LoadedWalletActivity).navigator.showVerifyCard(context as Activity, ctx)
+ else
+ UtilHelper.showSingleToast(context, getString(R.string.need_attach_card_again))
}
- serverApiElectrum.setElectrumRequestData(electrumBodyListener)
- // request infura listener
- val infuraBodyListener: ServerApiInfura.InfuraBodyListener = object : ServerApiInfura.InfuraBodyListener {
- override fun onSuccess(method: String, infuraResponse: InfuraResponse) {
- when (method) {
- ServerApiInfura.INFURA_ETH_GET_BALANCE -> {
- var balanceCap = infuraResponse.result
- balanceCap = balanceCap.substring(2)
- val l = BigInteger(balanceCap, 16)
-// val d = l.divide(BigInteger("1000000000000000000", 10))
-// val balance = d.toLong()
-
-// (ctx.coinData!! as EthData).setBalanceConfirmed(balance)
-// (ctx.coinData!! as EthData).balanceUnconfirmed = 0L
- if (ctx.blockchain != Blockchain.Token) {
- (ctx.coinData!! as EthData).isBalanceReceived = true
- (ctx.coinData!! as EthData).balanceInInternalUnits = CoinEngine.InternalAmount(l.toBigDecimal(), "wei")
- } else {
- (ctx.coinData!! as TokenData).isBalanceReceived = true
- //(ctx.coinData!! as TokenData).balanceInInternalUnits = CoinEngine.InternalAmount(l.toBigDecimal(),ctx.card.tokenSymbol)
- (ctx.coinData!! as TokenData).balanceAlterInInternalUnits = CoinEngine.InternalAmount(l.toBigDecimal(), "wei")
- }
-
-// Log.i("$TAG eth_get_balance", balanceCap)
- }
-
- ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT -> {
- var nonce = infuraResponse.result
- nonce = nonce.substring(2)
- val count = BigInteger(nonce, 16)
- (ctx.coinData!! as EthData).confirmedTXCount = count
-
-
-// Log.i("$TAG eth_getTransCount", nonce)
- }
-
- ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT -> {
- var pending = infuraResponse.result
- pending = pending.substring(2)
- val count = BigInteger(pending, 16)
- (ctx.coinData!! as EthData).unconfirmedTXCount = count
-
-// Log.i("$TAG eth_getPendingTxCount", pending)
- }
-
- ServerApiInfura.INFURA_ETH_CALL -> {
- try {
- var balanceCap = infuraResponse.result
- balanceCap = balanceCap.substring(2)
- val l = BigInteger(balanceCap, 16)
- val balance = l.toLong()
-// if (l.compareTo(BigInteger.ZERO) == 0) {
-// //ctx.card!!.blockchainID = Blockchain.Ethereum.id
-// ctx.card!!.addTokenToBlockchainName()
-//
-// //TODO check
-// //ctx.blockchain=lBlockchain.Ethereum
-//
-// requestCounter--
-// if (requestCounter == 0) srl!!.isRefreshing = false
-//
-// requestInfura(ServerApiCommon.INFURA_ETH_GET_BALANCE, "")
-// requestInfura(ServerApiCommon.INFURA_ETH_GET_TRANSACTION_COUNT, "")
-// requestInfura(ServerApiCommon.INFURA_ETH_GET_PENDING_COUNT, "")
-// return
-// }
- (ctx.coinData!! as EthData).balanceInInternalUnits = CoinEngine.InternalAmount(l.toBigDecimal(), ctx.card.tokenSymbol)
-
-// Log.i("$TAG eth_call", balanceCap)
-
- requestInfura(ServerApiInfura.INFURA_ETH_GET_BALANCE, "")
- requestInfura(ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT, "")
- requestInfura(ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT, "")
- } catch (e: JSONException) {
- e.printStackTrace()
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
-
- ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION -> {
- try {
- var hashTX: String
- try {
- val tmp = infuraResponse.result
- hashTX = tmp
- } catch (e: JSONException) {
- return
- }
-
- if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) {
- hashTX = hashTX.substring(2)
- }
-
- Log.e("$TAG TX_RESULT", hashTX)
-
- val nonce = (ctx.coinData!! as EthData).confirmedTXCount
- nonce.add(BigInteger.valueOf(1))
- (ctx.coinData!! as EthData).confirmedTXCount = nonce
-
- Log.e("$TAG TX_RESULT", hashTX)
-
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
- }
-
- counterMinus()
- }
-
- override fun onFail(method: String, message: String) {
-
- }
- }
- serverApiInfura.setInfuraResponse(infuraBodyListener)
+ btnNewScan.setOnClickListener { (activity as LoadedWalletActivity).navigator.showMain(context as Activity) }
// request card verify and get info listener
- val cardVerifyAndGetInfoListener: ServerApiCommon.CardVerifyAndGetInfoListener = object : ServerApiCommon.CardVerifyAndGetInfoListener {
+ 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
@@ -419,135 +209,146 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
ctx.card!!.isOnlineVerified = result.passed
- if (requestCounter == 0) updateViews()
+ requestCounter--
+ updateViews()
if (!result.passed) return
- if (localStorage.checkBatchInfoChanged(ctx.card!!, result)) {
- Log.w(TAG, "Batch ${result.batch} info changed to '$result'")
- ivTangemCard.setImageBitmap(localStorage.getCardArtworkBitmap(ctx.card!!))
- localStorage.applySubstitution(ctx.card!!)
- if (ctx.card!!.blockchain == Blockchain.Token || ctx.card!!.blockchain == Blockchain.Ethereum) {
- ctx.card!!.setBlockchainIDFromCard(Blockchain.Ethereum.id)
- //ctx.blockchain=Blockchain.Ethereum
- //engine=engine!!.swithToOtherEngine(Blockchain.Ethereum)
- }
+ 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 && localStorage.checkNeedUpdateArtwork(result.artwork)) {
- Log.w(TAG, "Artwork '${result.artwork!!.id}' updated, need download")
- serverApiCommon.requestArtwork(result.artwork!!.id, result.artwork!!.getUpdateDate(), ctx.card!!)
+ 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()
}
-// Log.i(TAG, "setCardVerify " + it.results!![0].passed)
}
override fun onFail(message: String?) {
-
+ LOG.i(TAG, "cardVerifyAndGetInfoListener onFail")
+ if (activity == null || !UtilHelper.isOnline(activity!!)) return
+ requestCounter--
+ updateViews()
}
}
- serverApiCommon.setCardVerifyAndGetInfoListener(cardVerifyAndGetInfoListener)
+ serverApiTangem.setCardVerifyAndGetInfoListener(cardVerifyAndGetInfoListener)
// request artwork listener
- val artworkListener: ServerApiCommon.ArtworkListener = object : ServerApiCommon.ArtworkListener {
+ val artworkListener: ServerApiTangem.ArtworkListener = object : ServerApiTangem.ArtworkListener {
override fun onSuccess(artworkId: String?, inputStream: InputStream?, updateDate: Date?) {
- localStorage.updateArtwork(artworkId!!, inputStream!!, updateDate!!)
- ivTangemCard.setImageBitmap(localStorage.getCardArtworkBitmap(ctx.card!!))
+ 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()
}
}
- serverApiCommon.setArtworkListener(artworkListener)
+ serverApiTangem.setArtworkListener(artworkListener)
// request rate info listener
serverApiCommon.setRateInfoData {
+ if (activity == null || !UtilHelper.isOnline(activity!!)) return@setRateInfoData
val rate = it.priceUsd.toFloat()
ctx.coinData!!.rate = rate
ctx.coinData!!.rateAlter = rate
}
- }
- private fun counterMinus() {
- requestCounter--
- if (requestCounter == 0) {
- if (srl != null) srl!!.isRefreshing = false
- updateViews()
- }
+ refresh()
+
+ startVerify(lastTag)
}
override fun onResume() {
super.onResume()
- nfcManager!!.onResume()
+ nfcManager.onResume()
}
override fun onPause() {
super.onPause()
- nfcManager!!.onPause()
- if (timerRepeatRefresh != null)
- timerRepeatRefresh!!.cancel()
+ nfcManager.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() {
super.onStop()
- nfcManager!!.onStop()
+ nfcManager.onStop()
+ }
+
+ override fun onDestroy() {
+ EventBus.getDefault().unregister(this)
+ super.onDestroy()
+ }
+
+ @Subscribe
+ fun onTransactionFinishWithSuccess(transactionFinishWithSuccess: TransactionFinishWithSuccess) {
+ ctx.message = transactionFinishWithSuccess.message
+ ctx.coinData.clearInfo()
+ updateViews()
+ srl?.isRefreshing=true
+ srl?.postDelayed({ refresh() }, 5000)
+ }
+
+ @Subscribe
+ fun onTransactionFinishWithError(transactionFinishWithError: TransactionFinishWithError) {
+ ctx.error = transactionFinishWithError.message
+ updateViews()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- var data = data
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
- REQUEST_CODE_VERIFY_CARD ->
- // action when erase wallet
- if (resultCode == Activity.RESULT_OK) {
- if (activity != null)
- activity?.finish()
- }
+ Constant.REQUEST_CODE_VERIFY_CARD ->
+ // action after erase wallet
+ if (resultCode == Activity.RESULT_OK)
+ activity?.finish()
- REQUEST_CODE_ENTER_NEW_PIN -> if (resultCode == Activity.RESULT_OK) {
- if (data != null) {
- if (data.extras != null && data.extras!!.containsKey("confirmPIN")) {
- val intent = Intent(activity, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
- ctx.saveToIntent(intent)
- newPIN = data.getStringExtra("newPIN")
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
- } else {
- val intent = Intent(activity, PinRequestActivity::class.java)
- intent.putExtra("newPIN", data.getStringExtra("newPIN"))
- intent.putExtra("mode", PinRequestActivity.Mode.ConfirmNewPIN.toString())
- startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN)
- }
- }
- }
- REQUEST_CODE_ENTER_NEW_PIN2 -> if (resultCode == Activity.RESULT_OK) {
- if (data != null) {
- if (data.extras != null && data.extras!!.containsKey("confirmPIN2")) {
- val intent = Intent(activity, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
- ctx.saveToIntent(intent)
- newPIN2 = data.getStringExtra("newPIN2")
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
- } else {
- val intent = Intent(activity, PinRequestActivity::class.java)
- intent.putExtra("newPIN2", data.getStringExtra("newPIN2"))
- intent.putExtra("mode", PinRequestActivity.Mode.ConfirmNewPIN2.toString())
- startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN2)
- }
- }
- }
- REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
+ Constant.REQUEST_CODE_ENTER_NEW_PIN -> if (resultCode == Activity.RESULT_OK)
+ if (data != null)
+ if (data.extras != null && data.extras!!.containsKey(Constant.EXTRA_CONFIRM_PIN))
+ (activity as LoadedWalletActivity).navigator.showPinRequestRequestPin(context as Activity, PinRequestActivity.Mode.RequestPIN.toString(), ctx, data.getStringExtra(Constant.EXTRA_NEW_PIN))
+ else
+ (activity as LoadedWalletActivity).navigator.showPinRequestConfirmNewPin(context as Activity, PinRequestActivity.Mode.ConfirmNewPIN.toString(), data.getStringExtra(Constant.EXTRA_NEW_PIN))
+
+
+ Constant.REQUEST_CODE_ENTER_NEW_PIN2 -> if (resultCode == Activity.RESULT_OK)
+ if (data != null)
+ if (data.extras != null && data.extras!!.containsKey(Constant.EXTRA_CONFIRM_PIN_2))
+ (activity as LoadedWalletActivity).navigator.showPinRequestRequestPin2(context as Activity, PinRequestActivity.Mode.RequestPIN2.toString(), ctx, data.getStringExtra(Constant.EXTRA_NEW_PIN_2))
+ else
+ (activity as LoadedWalletActivity).navigator.showPinRequestConfirmNewPin2(context as Activity, PinRequestActivity.Mode.ConfirmNewPIN2.toString(), data.getStringExtra(Constant.EXTRA_NEW_PIN_2))
+
+ Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
if (newPIN == "")
newPIN = ctx.card!!.pin
if (newPIN2 == "")
- newPIN2 = PINStorage.getPIN2()
+ newPIN2 = App.pinStorage.piN2
val pinSwapWarningDialog = PINSwapWarningDialog()
- pinSwapWarningDialog.setOnRefreshPage { startSwapPINActivity() }
+ pinSwapWarningDialog.setOnRefreshPage { (activity as LoadedWalletActivity).navigator.showPinSwap(context as Activity, newPIN, newPIN2) }
val bundle = Bundle()
- if (!PINStorage.isDefaultPIN(newPIN) || !PINStorage.isDefaultPIN2(newPIN2))
+ if (!CardProtocol.isDefaultPIN(newPIN) || !CardProtocol.isDefaultPIN2(newPIN2))
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_forget))
else
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_use_default))
@@ -555,29 +356,25 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
pinSwapWarningDialog.show(activity?.supportFragmentManager, PINSwapWarningDialog.TAG)
}
- REQUEST_CODE_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
+ Constant.REQUEST_CODE_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
if (data == null) {
- data = Intent()
ctx.saveToIntent(data)
- data.putExtra("modification", "delete")
+ data?.putExtra(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_DELETE)
} else
- data.putExtra("modification", "update")
+ data.putExtra(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_UPDATE)
activity?.setResult(Activity.RESULT_OK, data)
activity?.finish()
} else {
- if (data != null && data.extras != null && data.extras!!.containsKey(TangemCard.EXTRA_UID) && data.extras!!.containsKey(TangemCard.EXTRA_CARD)) {
- val updatedCard = TangemCard(data.getStringExtra(TangemCard.EXTRA_UID))
- updatedCard.loadFromBundle(data.getBundleExtra(TangemCard.EXTRA_CARD))
+ if (data != null && data.extras != null && data.extras!!.containsKey(EXTRA_TANGEM_CARD_UID) && data.extras!!.containsKey(EXTRA_TANGEM_CARD)) {
+ val updatedCard = TangemCard(data.getStringExtra(EXTRA_TANGEM_CARD_UID))
+ updatedCard.loadFromBundle(data.getBundleExtra(EXTRA_TANGEM_CARD))
ctx.card = updatedCard
}
- if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
+ if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++
- val intent = Intent(activity, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
- ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ (activity as LoadedWalletActivity).navigator.showPinRequestRequestPin2(context as Activity, PinRequestActivity.Mode.RequestPIN2.toString(), ctx)
return
} else {
if (data != null && data.extras!!.containsKey("message")) {
@@ -585,35 +382,31 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
}
}
- REQUEST_CODE_REQUEST_PIN2_FOR_PURGE -> if (resultCode == Activity.RESULT_OK) {
- val intent = Intent(activity, PurgeActivity::class.java)
- ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_PURGE)
- }
- REQUEST_CODE_PURGE -> if (resultCode == Activity.RESULT_OK) {
+
+ Constant.REQUEST_CODE_PURGE -> if (resultCode == Activity.RESULT_OK) {
if (data == null) {
- data = Intent()
ctx.saveToIntent(data)
- data.putExtra("modification", "delete")
- } else {
- data.putExtra("modification", "update")
- }
+ data?.putExtra(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_DELETE)
+ } else
+ data.putExtra(Constant.EXTRA_MODIFICATION, Constant.EXTRA_MODIFICATION_UPDATE)
activity?.setResult(Activity.RESULT_OK, data)
activity?.finish()
} else {
- if (data != null && data.extras != null && data.extras!!.containsKey(TangemCard.EXTRA_UID) && data.extras!!.containsKey(TangemCard.EXTRA_CARD)) {
- val updatedCard = TangemCard(data.getStringExtra(TangemCard.EXTRA_UID))
- updatedCard.loadFromBundle(data.getBundleExtra(TangemCard.EXTRA_CARD))
+ if (data != null && data.extras != null && data.extras!!.containsKey(EXTRA_TANGEM_CARD_UID) && data.extras!!.containsKey(EXTRA_TANGEM_CARD)) {
+ val updatedCard = TangemCard(data.getStringExtra(EXTRA_TANGEM_CARD_UID))
+ updatedCard.loadFromBundle(data.getBundleExtra(EXTRA_TANGEM_CARD))
ctx.card = updatedCard
}
- if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
+ if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++
+
val intent = Intent(activity, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
+ intent.putExtra(Constant.EXTRA_MODE, PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
+
return
} else {
if (data != null && data.extras!!.containsKey("message")) {
@@ -622,7 +415,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
updateViews()
}
- REQUEST_CODE_SEND_PAYMENT, REQUEST_CODE_RECEIVE_PAYMENT -> {
+
+ Constant.REQUEST_CODE_SEND_PAYMENT, Constant.REQUEST_CODE_RECEIVE_PAYMENT -> {
if (resultCode == Activity.RESULT_OK) {
ctx.coinData?.clearInfo()
srl?.postDelayed({ this.refresh() }, 5000)
@@ -631,19 +425,19 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
if (data != null && data.extras != null) {
- if (data.extras!!.containsKey(TangemCard.EXTRA_UID) && data.extras!!.containsKey(TangemCard.EXTRA_CARD)) {
- val updatedCard = TangemCard(data.getStringExtra(TangemCard.EXTRA_UID))
- updatedCard.loadFromBundle(data.getBundleExtra(TangemCard.EXTRA_CARD))
+ if (data.extras!!.containsKey(EXTRA_TANGEM_CARD_UID) && data.extras!!.containsKey(EXTRA_TANGEM_CARD)) {
+ val updatedCard = TangemCard(data.getStringExtra(EXTRA_TANGEM_CARD_UID))
+ updatedCard.loadFromBundle(data.getBundleExtra(EXTRA_TANGEM_CARD))
ctx.card = updatedCard
}
- if (data.extras!!.containsKey("message")) {
- if (resultCode == Activity.RESULT_OK) {
- ctx.message = data.getStringExtra("message")
- } else {
- ctx.error = data.getStringExtra("message")
- }
- }
- updateViews()
+// if (data.extras!!.containsKey("message")) {
+// if (resultCode == Activity.RESULT_OK) {
+// ctx.message = data.getStringExtra("message")
+// } else {
+// ctx.error = data.getStringExtra("message")
+// }
+// }
+// updateViews()
}
}
}
@@ -664,10 +458,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
override fun onReadFinish(cardProtocol: CardProtocol?) {
verifyCardTask = null
-
if (cardProtocol != null) {
if (cardProtocol.error == null) {
-
rlProgressBar?.post {
rlProgressBar?.visibility = View.GONE
this.cardProtocol = cardProtocol
@@ -708,7 +500,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
override fun onReadWait(msec: Int) {
- WaitSecurityDelayDialog.OnReadWait(activity, msec)
+ WaitSecurityDelayDialog.onReadWait(activity, msec)
}
override fun onReadBeforeRequest(timeout: Int) {
@@ -724,17 +516,19 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
fun updateViews() {
+ if (activity == null) return
+
if (timerHideErrorAndMessage != null) {
timerHideErrorAndMessage!!.cancel()
timerHideErrorAndMessage = null
}
- if (ctx.error == null || ctx.error.isEmpty()) {
- tvError.visibility = View.GONE
- tvError.text = ""
+ if (ctx.hasError()) {
+ tvError?.visibility = View.VISIBLE
+ tvError?.text = ctx.error
} else {
- tvError.visibility = View.VISIBLE
- tvError.text = ctx.error
+ tvError?.visibility = View.GONE
+ tvError?.text = ""
}
if (ctx.message == null || ctx.message.isEmpty()) {
@@ -745,6 +539,21 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
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.verifying_in_blockchain)
@@ -753,6 +562,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
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 = validator.firstLine
@@ -773,15 +583,15 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
else -> tvBalance.text = getString(R.string.no_data_string)
}
- tvWallet.text = ctx.card!!.wallet
+ tvWallet.text = ctx.coinData!!.wallet
if (ctx.card!!.tokenSymbol.length > 1) {
- val html = Html.fromHtml(ctx.card!!.blockchainName)
+ val html = Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
} else
- tvBlockchain.text = ctx.card!!.blockchainName
+ tvBlockchain.text = ctx.blockchainName
- if (engine.hasBalanceInfo()) {
+ if (requestCounter == 0 && engine.hasBalanceInfo()) {
btnExtract.isEnabled = true
btnExtract.backgroundTintList = activeColor
} else {
@@ -789,118 +599,135 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
btnExtract.backgroundTintList = inactiveColor
}
- ctx.error = null
- ctx.message = null
+ //TODO why ???
+// ctx.error = null
+// ctx.message = null
}
private fun refresh() {
if (ctx.card == null) return
// clear all card data and request again
- srl?.isRefreshing = true
ctx.coinData.clearInfo()
ctx.error = null
ctx.message = null
+
+ LOG.w(TAG, "============= START REFRESH")
requestCounter = 0
+ srl?.isRefreshing = true
updateViews()
+ // Bitcoin
+ // Litecoin
+ // BitcoinCash
+ if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet ||
+ ctx.blockchain == Blockchain.Litecoin || ctx.blockchain == Blockchain.BitcoinCash) {
+ ctx.coinData.setIsBalanceEqual(true)
+ }
+
requestVerifyAndGetInfo()
- // Bitcoin
- if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet) {
- ctx.coinData.setIsBalanceEqual(true)
+ requestBalanceAndUnspentTransactions()
- requestElectrum(ElectrumRequest.checkBalance(ctx.card!!.wallet))
- requestElectrum(ElectrumRequest.listUnspent(ctx.card!!.wallet))
- requestRateInfo("bitcoin")
- }
+ requestRateInfo()
- // BitcoinCash
- else if (ctx.blockchain == Blockchain.BitcoinCash) {
- ctx.coinData.setIsBalanceEqual(true)
- val engine = CoinEngineFactory.create(ctx)
-
- requestElectrum(ElectrumRequest.checkBalance((engine as BtcCashEngine).convertToLegacyAddress(ctx.card!!.wallet)))
- requestElectrum(ElectrumRequest.listUnspent(engine.convertToLegacyAddress(ctx.card!!.wallet)))
- requestRateInfo("bitcoin-cash")
- }
-
- // Ethereum
- else if (ctx.blockchain == Blockchain.Ethereum || ctx.blockchain == Blockchain.EthereumTestNet) {
- requestInfura(ServerApiInfura.INFURA_ETH_GET_BALANCE, "")
- requestInfura(ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT, "")
- requestInfura(ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT, "")
- requestRateInfo("ethereum")
- }
-
- // Token
- else if (ctx.blockchain == Blockchain.Token) {
- val engine = CoinEngineFactory.create(ctx)
- requestInfura(ServerApiInfura.INFURA_ETH_CALL, (engine as TokenEngine).getContractAddress(ctx.card))
- requestRateInfo("ethereum")
+ if( requestCounter==0 )
+ {
+ // if no connection and no requests posted
+ srl?.isRefreshing = false
+ updateViews()
}
}
- private fun requestElectrum(electrumRequest: ElectrumRequest) {
+ private fun requestBalanceAndUnspentTransactions() {
if (UtilHelper.isOnline(context as Activity)) {
+ val coinEngine = CoinEngineFactory.create(ctx)
requestCounter++
- serverApiElectrum.electrumRequestData(ctx.card, electrumRequest)
- } else {
- Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
- srl?.isRefreshing = false
- }
- }
+ coinEngine!!.requestBalanceAndUnspentTransactions(
+ object : CoinEngine.BlockchainRequestsCallbacks {
+ override fun onComplete(success: Boolean) {
+ LOG.i(TAG, "requestBalanceAndUnspentTransactions onComplete: " + success.toString() + ", request counter " + requestCounter.toString())
+ if (activity == null) return
+ requestCounter--
+ if (!success) {
+ LOG.e(TAG, "requestBalanceAndUnspentTransactions ctx.error: " + ctx.error)
+ }
+// if (!UtilHelper.isOnline(activity!!)) {
+// ctx.error = getString(R.string.no_connection)
+// }
+ updateViews()
+ }
- private fun requestInfura(method: String, contract: String) {
- if (UtilHelper.isOnline(context as Activity)) {
- requestCounter++
- serverApiInfura.infura(method, 67, ctx.card!!.wallet, contract, "")
+ override fun onProgress() {
+ if (activity == null) return
+ LOG.i(TAG, "requestBalanceAndUnspentTransactions onProgress")
+ updateViews()
+ }
+
+ override fun allowAdvance(): Boolean {
+ return UtilHelper.isOnline(context as Activity)
+ }
+ }
+ )
} else {
- Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
- srl?.isRefreshing = false
+ ctx.error = getString(R.string.no_connection)
+ updateViews()
}
}
private fun requestVerifyAndGetInfo() {
if (UtilHelper.isOnline(context as Activity)) {
if ((ctx.card!!.isOnlineVerified == null || !ctx.card!!.isOnlineVerified)) {
- serverApiCommon.cardVerifyAndGetInfo(ctx.card)
+ LOG.i(TAG, "requestVerifyAndGetInfo")
+ requestCounter++
+ serverApiTangem.cardVerifyAndGetInfo(ctx.card)
}
} else {
- Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
- srl?.isRefreshing = false
+ ctx.error = getString(R.string.no_connection)
+ updateViews()
+ //Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
+ //LOG.e(TAG, "+++++++++++ Hide refresh 1")
+ //srl?.isRefreshing = false
}
}
- private fun requestRateInfo(cryptoId: String) {
+ private fun requestRateInfo() {
if (UtilHelper.isOnline(context as Activity)) {
+ LOG.i(TAG, "requestRateInfo")
+
+ // TODO - move requestRateInfo to CoinEngine
+ val cryptoId: String = when (ctx.blockchain) {
+ Blockchain.Bitcoin -> "bitcoin"
+ Blockchain.BitcoinTestNet -> "bitcoin"
+ Blockchain.Ethereum -> "ethereum"
+ Blockchain.EthereumTestNet -> "ethereum"
+ Blockchain.Token -> "ethereum"
+ Blockchain.BitcoinCash -> "bitcoin-cash"
+ Blockchain.Litecoin -> "litecoin"
+ else -> {
+ throw Exception("Can''t get rate for blockchain " + ctx.blockchainName)
+ }
+ }
serverApiCommon.rateInfoData(cryptoId)
} else {
- Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
- srl?.isRefreshing = false
+ ctx.error = getString(R.string.no_connection)
+ updateViews()
+// Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
+// LOG.e(TAG, "+++++++++++ Hide refresh 2")
+// srl?.isRefreshing = false
}
}
-// private fun openVerifyCard(cardProtocol: CardProtocol) {
-// val intent = Intent(activity, VerifyCardActivity::class.java)
-// ctx.saveToIntent(intent)
-// startActivityForResult(intent, REQUEST_CODE_VERIFY_CARD)
-//
-// ctx.coinData
-// }
-
private fun startVerify(tag: Tag?) {
try {
- val isoDep = IsoDep.get(tag) ?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
+ val isoDep = IsoDep.get(tag)
+ ?: throw CardProtocol.TangemException(getString(R.string.wrong_tag_err))
val uid = tag!!.id
val sUID = Util.byteArrayToHexString(uid)
if (ctx.card.uid != sUID) {
-// Log.d(TAG, "Invalid UID: $sUID")
- nfcManager!!.ignoreTag(isoDep.tag)
+ nfcManager.ignoreTag(isoDep.tag)
return
- } else {
-// Log.v(TAG, "UID: $sUID")
}
if (lastReadSuccess)
@@ -908,9 +735,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
else
isoDep.timeout = 65000
- verifyCardTask = VerifyCardTask(activity, ctx.card, nfcManager, isoDep, this)
+ verifyCardTask = VerifyCardTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, App.firmwaresStorage, this)
verifyCardTask?.start()
-
} catch (e: Exception) {
e.printStackTrace()
}
@@ -943,41 +769,11 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
Toast.makeText(activity, R.string.copied_clipboard, Toast.LENGTH_LONG).show()
}
} else {
- val txtShare = ctx.card.wallet
+ val txtShare = ctx.coinData.wallet
val clipboard = activity?.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
clipboard.primaryClip = ClipData.newPlainText(txtShare, txtShare)
Toast.makeText(activity, R.string.copied_clipboard, Toast.LENGTH_LONG).show()
}
}
- private fun startSwapPINActivity() {
- val intent = Intent(activity, PinSwapActivity::class.java)
- ctx.saveToIntent(intent)
- intent.putExtra("newPIN", newPIN)
- intent.putExtra("newPIN2", newPIN2)
- startActivityForResult(intent, REQUEST_CODE_SWAP_PIN)
- }
-
- private var showTime: Date = Date()
-
- private fun showSingleToast(text: Int) {
- if (singleToast == null || !singleToast!!.view.isShown || showTime.time + 2000 < Date().time) {
- if (singleToast != null)
- singleToast!!.cancel()
- singleToast = Toast.makeText(activity, text, Toast.LENGTH_LONG)
- singleToast!!.show()
- showTime = Date()
- }
- }
-
- private fun showSingleToast(text: String) {
- if (singleToast == null || !singleToast!!.view.isShown || showTime.time + 2000 < Date().time) {
- if (singleToast != null)
- singleToast!!.cancel()
- singleToast = Toast.makeText(activity, text, Toast.LENGTH_LONG)
- singleToast!!.show()
- showTime = Date()
- }
- }
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt b/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt
index 618aaee44c..b9247d0270 100644
--- a/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt
+++ b/app/src/main/java/com/tangem/presentation/fragment/VerifyCard.kt
@@ -8,19 +8,24 @@ import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.text.Html
+import android.text.format.DateUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import android.widget.Toast
-import com.tangem.data.db.PINStorage
-import com.tangem.domain.cardReader.NfcManager
-import com.tangem.domain.wallet.*
-import com.tangem.presentation.activity.CreateNewWalletActivity
-import com.tangem.presentation.activity.PurgeActivity
-import com.tangem.presentation.activity.PinRequestActivity
-import com.tangem.presentation.activity.PinSwapActivity
+import com.tangem.App
+import com.tangem.Constant
+import com.tangem.data.Blockchain
+import com.tangem.domain.wallet.CoinEngineFactory
+import com.tangem.domain.wallet.TangemContext
+import com.tangem.presentation.activity.*
import com.tangem.presentation.dialog.PINSwapWarningDialog
+import com.tangem.tangemcard.android.data.PINStorage
+import com.tangem.tangemcard.android.reader.NfcManager
+import com.tangem.tangemcard.data.TangemCard
+import com.tangem.tangemcard.data.loadFromBundle
+import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fr_verify_card.*
@@ -31,15 +36,6 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = VerifyCard::class.java.simpleName
-
- private const val REQUEST_CODE_SEND_PAYMENT = 1
- private const val REQUEST_CODE_PURGE = 2
- private const val REQUEST_CODE_REQUEST_PIN2_FOR_PURGE = 3
- private const val REQUEST_CODE_VERIFY_CARD = 4
- private const val REQUEST_CODE_ENTER_NEW_PIN = 5
- private const val REQUEST_CODE_ENTER_NEW_PIN2 = 6
- private const val REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = 7
- private const val REQUEST_CODE_SWAP_PIN = 8
}
private var nfcManager: NfcManager? = null
@@ -70,9 +66,10 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
// set listeners
fabMenu.setOnClickListener { showMenu(fabMenu) }
+
btnOk.setOnClickListener {
val data = prepareResultIntent()
- data.putExtra("modification", "update")
+ data.putExtra(Constant.EXTRA_MODIFICATION, "update")
activity?.finish()
}
}
@@ -93,50 +90,50 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- var data = data
+// var data = data
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
- REQUEST_CODE_ENTER_NEW_PIN -> if (resultCode == Activity.RESULT_OK) {
+ Constant.REQUEST_CODE_ENTER_NEW_PIN -> if (resultCode == Activity.RESULT_OK) {
if (data != null) {
if (data.extras!!.containsKey("confirmPIN")) {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
newPIN = data.getStringExtra("newPIN")
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
} else {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("newPIN", data.getStringExtra("newPIN"))
intent.putExtra("mode", PinRequestActivity.Mode.ConfirmNewPIN.toString())
- startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN)
}
}
}
- REQUEST_CODE_ENTER_NEW_PIN2 -> if (resultCode == Activity.RESULT_OK) {
+ Constant.REQUEST_CODE_ENTER_NEW_PIN2 -> if (resultCode == Activity.RESULT_OK) {
if (data != null) {
if (data.extras!!.containsKey("confirmPIN2")) {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
newPIN2 = data.getStringExtra("newPIN2")
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
} else {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("newPIN2", data.getStringExtra("newPIN2"))
intent.putExtra("mode", PinRequestActivity.Mode.ConfirmNewPIN2.toString())
- startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN2)
+ startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN2)
}
}
}
- REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
+ Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
if (newPIN == "") newPIN = ctx.card!!.pin
- if (newPIN2 == "") newPIN2 = PINStorage.getPIN2()
+ if (newPIN2 == "") newPIN2 = App.pinStorage.getPIN2()
val pinSwapWarningDialog = PINSwapWarningDialog()
- pinSwapWarningDialog.setOnRefreshPage { startSwapPINActivity() }
+ pinSwapWarningDialog.setOnRefreshPage { (activity as VerifyCardActivity).navigator.showPinSwap(context as Activity, newPIN, newPIN2) }
val bundle = Bundle()
- if (!PINStorage.isDefaultPIN(newPIN) || !PINStorage.isDefaultPIN2(newPIN2))
+ if (!CardProtocol.isDefaultPIN(newPIN) || !CardProtocol.isDefaultPIN2(newPIN2))
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_forget))
else
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_use_default))
@@ -144,11 +141,11 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
pinSwapWarningDialog.show(activity?.supportFragmentManager, PINSwapWarningDialog.TAG)
}
- REQUEST_CODE_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
+ Constant.REQUEST_CODE_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
if (data == null) {
- data = Intent()
+// data = Intent()
ctx.saveToIntent(data)
- data.putExtra("modification", "delete")
+ data?.putExtra("modification", "delete")
} else
data.putExtra("modification", "update")
activity!!.setResult(Activity.RESULT_OK, data)
@@ -159,12 +156,12 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
updatedCard.loadFromBundle(data.getBundleExtra("Card"))
ctx.card = updatedCard
}
- if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
+ if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
return
} else {
if (data != null && data.extras!!.containsKey("message")) {
@@ -172,18 +169,16 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
}
}
}
- REQUEST_CODE_REQUEST_PIN2_FOR_PURGE -> if (resultCode == Activity.RESULT_OK) {
- val intent = Intent(context, PurgeActivity::class.java)
- ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_PURGE)
- }
- REQUEST_CODE_PURGE -> if (resultCode == Activity.RESULT_OK) {
+
+ Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE -> if (resultCode == Activity.RESULT_OK)
+ (activity as VerifyCardActivity).navigator.showPurge(context as Activity, ctx)
+
+ Constant.REQUEST_CODE_PURGE -> if (resultCode == Activity.RESULT_OK) {
if (data == null) {
- data = Intent()
ctx.saveToIntent(data)
- data.putExtra("modification", "delete")
+ data?.putExtra(Constant.EXTRA_MODIFICATION, "delete")
} else {
- data.putExtra("modification", "update")
+ data.putExtra(Constant.EXTRA_MODIFICATION, "update")
}
activity!!.setResult(Activity.RESULT_OK, data)
activity!!.finish()
@@ -193,12 +188,12 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
updatedCard.loadFromBundle(data.getBundleExtra("Card"))
ctx.card = updatedCard
}
- if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
+ if (resultCode == Constant.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++
val intent = Intent(context, PinRequestActivity::class.java)
- intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
+ intent.putExtra(Constant.EXTRA_MODE, PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
return
} else {
if (data != null && data.extras!!.containsKey("message")) {
@@ -207,35 +202,11 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
}
updateViews()
}
- REQUEST_CODE_SEND_PAYMENT -> {
- if (resultCode == Activity.RESULT_OK) {
- srlVerifyCard.isRefreshing = true
- ctx.coinData!!.clearInfo()
- ctx.card!!.switchToInitialBlockchain()
- updateViews()
- }
-
- if (data != null) {
- if (data.extras!!.containsKey("UID") && data.extras!!.containsKey("Card")) {
- val updatedCard = TangemCard(data.getStringExtra("UID"))
- updatedCard.loadFromBundle(data.getBundleExtra("Card"))
- ctx.card = updatedCard
- }
- if (data.extras!!.containsKey("message")) {
- if (resultCode == Activity.RESULT_OK)
- ctx.message = data.getStringExtra("message")
- else
- ctx.error = data.getStringExtra("message")
- }
- updateViews()
- }
- }
}
}
override fun onTagDiscovered(tag: Tag) {
try {
-// Log.w(getClass().getName(), "Ignore discovered tag!");
nfcManager!!.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
@@ -277,8 +248,9 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
}
tvIssuer.text = ctx.card!!.issuerDescription
- tvCardRegistredDate.text = ctx.card!!.personalizationDateTimeDescription
- val html = Html.fromHtml(ctx.card!!.blockchainName)
+
+ tvCardRegistredDate.text = DateUtils.formatDateTime(null, ctx.card!!.personalizationDateTime.time, DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NUMERIC_DATE or DateUtils.FORMAT_SHOW_YEAR)
+ val html = Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
tvValidationNode.text = ctx.coinData!!.validationNodeDescription
@@ -358,7 +330,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
tvFeatures.text = features
- if (ctx.card!!.useDefaultPIN1()!!) {
+ if (ctx.card!!.useDefaultPIN1()) {
imgPIN.setImageResource(R.drawable.unlock_pin1)
imgPIN.setOnClickListener { Toast.makeText(context, R.string.this_banknote_protected_default_PIN1_code, Toast.LENGTH_LONG).show() }
} else {
@@ -385,7 +357,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
imgDeveloperVersion.visibility = View.INVISIBLE
if (ctx.card!!.status == TangemCard.Status.Loaded) {
- tvWallet.text = ctx.card!!.shortWalletString
+ tvWallet.text = ctx.coinData!!.shortWalletString
if (ctx.card!!.isWalletPublicKeyValid) {
tvWalletIdentity.setText(R.string.possession_proved)
tvWalletIdentity.setTextColor(ContextCompat.getColor(context!!, R.color.confirmed))
@@ -422,7 +394,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
intent.putExtra("mode", PinRequestActivity.Mode.RequestNewPIN.toString())
newPIN = ""
newPIN2 = ""
- startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN)
}
private fun doResetPin() {
@@ -432,7 +404,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
ctx.saveToIntent(intent)
newPIN = PINStorage.getDefaultPIN()
newPIN2 = ""
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
}
private fun doResetPin2() {
@@ -442,7 +414,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
ctx.saveToIntent(intent)
newPIN = ""
newPIN2 = PINStorage.getDefaultPIN2()
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
}
private fun doResetPins() {
@@ -452,7 +424,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
ctx.saveToIntent(intent)
newPIN = PINStorage.getDefaultPIN()
newPIN2 = PINStorage.getDefaultPIN2()
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN)
}
private fun doSetPin2() {
@@ -461,7 +433,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
intent.putExtra("mode", PinRequestActivity.Mode.RequestNewPIN2.toString())
newPIN = ""
newPIN2 = ""
- startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN2)
+ startActivityForResult(intent, Constant.REQUEST_CODE_ENTER_NEW_PIN2)
}
private fun doPurge() {
@@ -477,15 +449,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
val intent = Intent(context, PinRequestActivity::class.java)
intent.putExtra("mode", PinRequestActivity.Mode.RequestPIN2.toString())
ctx.saveToIntent(intent)
- startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
- }
-
- private fun startSwapPINActivity() {
- val intent = Intent(context, PinSwapActivity::class.java)
- ctx.saveToIntent(intent)
- intent.putExtra("newPIN", newPIN)
- intent.putExtra("newPIN2", newPIN2)
- startActivityForResult(intent, REQUEST_CODE_SWAP_PIN)
+ startActivityForResult(intent, Constant.REQUEST_CODE_REQUEST_PIN2_FOR_PURGE)
}
fun prepareResultIntent(): Intent {
diff --git a/app/src/main/java/com/tangem/util/CryptoUtil.java b/app/src/main/java/com/tangem/util/CryptoUtil.java
index 40aa618577..495c29175e 100644
--- a/app/src/main/java/com/tangem/util/CryptoUtil.java
+++ b/app/src/main/java/com/tangem/util/CryptoUtil.java
@@ -3,6 +3,7 @@ package com.tangem.util;
import android.util.Log;
import com.tangem.domain.wallet.ECDSASignatureETH;
+import com.tangem.tangemcard.util.Util;
import org.spongycastle.asn1.ASN1EncodableVector;
import org.spongycastle.asn1.ASN1Integer;
diff --git a/app/src/main/java/com/tangem/util/LOG.java b/app/src/main/java/com/tangem/util/LOG.java
new file mode 100644
index 0000000000..387c3f90b1
--- /dev/null
+++ b/app/src/main/java/com/tangem/util/LOG.java
@@ -0,0 +1,58 @@
+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
index 2bb4c727e4..9b144c074e 100644
--- a/app/src/main/java/com/tangem/util/UtilHelper.kt
+++ b/app/src/main/java/com/tangem/util/UtilHelper.kt
@@ -6,6 +6,7 @@ import android.graphics.Bitmap
import android.graphics.Color
import android.net.ConnectivityManager
import android.net.NetworkInfo
+import android.widget.Toast
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
@@ -48,4 +49,19 @@ object UtilHelper {
}
}
+ 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/res/layout/fr_loaded_wallet.xml b/app/src/main/res/layout/fr_loaded_wallet.xml
index 8c510c672c..5ef4e5b85d 100644
--- a/app/src/main/res/layout/fr_loaded_wallet.xml
+++ b/app/src/main/res/layout/fr_loaded_wallet.xml
@@ -213,7 +213,7 @@
android:orientation="horizontal">
If you forget your new PIN you will lose your money forever!
If you use default PIN someone can steal your money!
Cannot obtain data from blockchain
+ Cannot obtain data from blockchain (connection refused)
+ Cannot obtain data from blockchain (empty answer received)
+ Cannot obtain data from blockchain (communication error)
Sending cached transaction…
NOT IMPLEMENTED
This banknote is protected by default PIN1 code
@@ -158,7 +161,7 @@
Please wait while the payment is sent…
Transaction has been successfully signed and sent to blockchain node. Wallet balance will be updated in a while
Try again. Failed to send transaction (%1$s)
- Cannot sign transaction. Make sure you enter correct PIN2!
+ Cannot sign transaction. Make sure you enter correct PIN2!
Amount and fee exceed total wallet balance!
diff --git a/build.gradle b/build.gradle
index a5d064f81b..3942b0608f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlin_version = '1.3.10'
+ ext.kotlin_version = '1.3.11'
repositories {
google()
jcenter()
diff --git a/settings.gradle b/settings.gradle
index 753d1d9277..38ca2a86f1 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':tangemcard'
+include ':app', ':tangemcard-android', ':tangemserver-android', ':tangemcard-common'
diff --git a/tangemcard/.gitignore b/tangemcard-android/.gitignore
similarity index 100%
rename from tangemcard/.gitignore
rename to tangemcard-android/.gitignore
diff --git a/tangemcard-android/build.gradle b/tangemcard-android/build.gradle
new file mode 100644
index 0000000000..6c4bbc429b
--- /dev/null
+++ b/tangemcard-android/build.gradle
@@ -0,0 +1,59 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ buildToolsVersion '28.0.3'
+
+}
+
+dependencies {
+ implementation project(':tangemcard-common')
+
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+// implementation 'com.android.support:design:28.0.0'
+ implementation 'com.google.code.gson:gson:2.8.5'
+ implementation 'com.scottyab:rootbeer-lib:0.0.7'
+
+// implementation 'com.android.support:support-compat:28.0.0'
+// implementation 'com.android.support:support-v4:28.0.0'
+// implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
+// implementation 'com.squareup.retrofit2:retrofit:2.5.0'
+// implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
+// implementation 'com.skyfishjy.ripplebackground:library:1.0.1'
+// implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
+// implementation 'com.google.dagger:dagger:2.16'
+// implementation 'org.bitcoinj:bitcoinj-parent:0.14.7'
+// implementation 'org.bitcoinj:bitcoinj-core:0.14.7'
+// annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
+// implementation 'info.hoang8f:android-segmented:1.0.6'
+// implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
+// implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
+// implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
+
+
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+
+}
+repositories {
+ mavenCentral()
+}
diff --git a/tangemcard/proguard-rules.pro b/tangemcard-android/proguard-rules.pro
similarity index 100%
rename from tangemcard/proguard-rules.pro
rename to tangemcard-android/proguard-rules.pro
diff --git a/tangemcard/src/androidTest/java/com/tangem/tangemcard/ExampleInstrumentedTest.java b/tangemcard-android/src/androidTest/java/com/tangem/tangemcard/android/ExampleInstrumentedTest.java
similarity index 94%
rename from tangemcard/src/androidTest/java/com/tangem/tangemcard/ExampleInstrumentedTest.java
rename to tangemcard-android/src/androidTest/java/com/tangem/tangemcard/android/ExampleInstrumentedTest.java
index 6349f4aa67..b278ba0d2e 100644
--- a/tangemcard/src/androidTest/java/com/tangem/tangemcard/ExampleInstrumentedTest.java
+++ b/tangemcard-android/src/androidTest/java/com/tangem/tangemcard/android/ExampleInstrumentedTest.java
@@ -1,4 +1,4 @@
-package com.tangem.tangemcard;
+package com.tangem.tangemcard.android;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
diff --git a/tangemcard-android/src/main/AndroidManifest.xml b/tangemcard-android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..9df3c4db3d
--- /dev/null
+++ b/tangemcard-android/src/main/AndroidManifest.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/app/src/main/java/com/tangem/domain/cardReader/Firmwares.java b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/data/Firmwares.java
similarity index 74%
rename from app/src/main/java/com/tangem/domain/cardReader/Firmwares.java
rename to tangemcard-android/src/main/java/com/tangem/tangemcard/android/data/Firmwares.java
index 251f62e41d..2282f61618 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/Firmwares.java
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/data/Firmwares.java
@@ -1,25 +1,22 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.android.data;
import android.content.Context;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.data.external.FirmwaresDigestsProvider;
+import com.tangem.tangemcard.util.Util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
-public class Firmwares {
+public class Firmwares implements FirmwaresDigestsProvider {
private static JsonArray jaFirmwares = null;
- public static boolean needInit() {
- return jaFirmwares == null;
- }
-
- public static void init(Context context) {
+ public Firmwares(Context context) {
try (InputStream is = context.getAssets().open("fw_hashes.json")) {
try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
JsonParser parser = new JsonParser();
@@ -30,21 +27,14 @@ public class Firmwares {
}
}
- public static class VerifyCodeRecord {
- public String hashAlg;
- public int blockIndex;
- public int blockCount;
- public byte[] challenge;
- public byte[] digest;
- }
-
- public static VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion) throws IOException {
+ @Override
+ public FirmwaresDigestsProvider.VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion) {
try {
for (int i = 0; i < jaFirmwares.size(); i++) {
JsonObject jsVersion = jaFirmwares.get(i).getAsJsonObject();
if (jsVersion.get("fw").getAsString().equals(firmwareVersion)) {
- VerifyCodeRecord result = new VerifyCodeRecord();
+ FirmwaresDigestsProvider.VerifyCodeRecord result = new FirmwaresDigestsProvider.VerifyCodeRecord();
result.hashAlg = "sha-256";
JsonArray jsHashes = jsVersion.get(result.hashAlg).getAsJsonArray();
result.challenge = Util.hexToBytes(jsVersion.get("challenge").getAsString());
diff --git a/app/src/main/java/com/tangem/data/db/PINStorage.java b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/data/PINStorage.java
similarity index 93%
rename from app/src/main/java/com/tangem/data/db/PINStorage.java
rename to tangemcard-android/src/main/java/com/tangem/tangemcard/android/data/PINStorage.java
index 91a9c3a47a..739fe3796c 100644
--- a/app/src/main/java/com/tangem/data/db/PINStorage.java
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/data/PINStorage.java
@@ -1,11 +1,12 @@
-package com.tangem.data.db;
+package com.tangem.tangemcard.android.data;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Base64;
-import com.tangem.domain.cardReader.CardProtocol;
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.reader.CardProtocol;
import java.util.ArrayList;
import java.util.List;
@@ -17,7 +18,7 @@ import javax.crypto.Cipher;
* Global PIN Storage
*/
-public class PINStorage {
+public class PINStorage implements PINsProvider {
private static String mSavedPIN, mUserPIN, mLastUsedPIN, mEncryptedPIN, mPIN2;
private static SharedPreferences sharedPreferences = null;
@@ -30,8 +31,8 @@ public class PINStorage {
mPIN2 = null;
}
-
- public static List getPINs() {
+ @Override
+ public List getPINs() {
ArrayList result = new ArrayList<>();
if (mLastUsedPIN != null) result.add(mLastUsedPIN);
if (mEncryptedPIN != null && !result.contains(mEncryptedPIN)) result.add(mEncryptedPIN);
@@ -41,7 +42,7 @@ public class PINStorage {
return result;
}
- public static void setLastUsedPIN(String PIN) {
+ public void setLastUsedPIN(String PIN) {
mLastUsedPIN = PIN;
}
@@ -177,18 +178,10 @@ public class PINStorage {
editor.apply();
}
- public static String getPIN2() {
+ public String getPIN2() {
return mPIN2;
}
- public static boolean isDefaultPIN(String pin) {
- return (CardProtocol.DefaultPIN.equals(pin));
- }
-
- public static boolean isDefaultPIN2(String pin2) {
- return (CardProtocol.DefaultPIN2.equals(pin2));
- }
-
public static String getDefaultPIN() {
return CardProtocol.DefaultPIN;
}
diff --git a/app/src/main/java/com/tangem/data/nfc/DeviceNFCAntennaLocation.kt b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/nfc/DeviceNFCAntennaLocation.kt
similarity index 93%
rename from app/src/main/java/com/tangem/data/nfc/DeviceNFCAntennaLocation.kt
rename to tangemcard-android/src/main/java/com/tangem/tangemcard/android/nfc/DeviceNFCAntennaLocation.kt
index 6caaa0a3d8..92cdaaa6c2 100644
--- a/app/src/main/java/com/tangem/data/nfc/DeviceNFCAntennaLocation.kt
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/nfc/DeviceNFCAntennaLocation.kt
@@ -1,7 +1,6 @@
-package com.tangem.data.nfc
+package com.tangem.tangemcard.android.nfc
import android.os.Build
-import com.tangem.tangemcard.nfc.NFCLocation
class DeviceNFCAntennaLocation {
companion object {
diff --git a/tangemcard/src/main/java/com/tangem/tangemcard/nfc/NFCLocation.kt b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/nfc/NFCLocation.kt
similarity index 99%
rename from tangemcard/src/main/java/com/tangem/tangemcard/nfc/NFCLocation.kt
rename to tangemcard-android/src/main/java/com/tangem/tangemcard/android/nfc/NFCLocation.kt
index ffce1f1988..cbb341b966 100644
--- a/tangemcard/src/main/java/com/tangem/tangemcard/nfc/NFCLocation.kt
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/nfc/NFCLocation.kt
@@ -1,4 +1,4 @@
-package com.tangem.tangemcard.nfc
+package com.tangem.tangemcard.android.nfc
enum class NFCLocation(val codename: String, val fullName: String, val orientation: Int, val x: Int, val y: Int, val z: Int) {
model1("sailfish", "Google Pixel", 0, 65, 25, 0),
diff --git a/app/src/main/java/com/tangem/presentation/dialog/NfcEnableDialog.kt b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/presentation/dialog/NfcEnableDialog.kt
similarity index 92%
rename from app/src/main/java/com/tangem/presentation/dialog/NfcEnableDialog.kt
rename to tangemcard-android/src/main/java/com/tangem/tangemcard/android/presentation/dialog/NfcEnableDialog.kt
index c8676fdc8f..24f0cabe39 100644
--- a/app/src/main/java/com/tangem/presentation/dialog/NfcEnableDialog.kt
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/presentation/dialog/NfcEnableDialog.kt
@@ -1,4 +1,4 @@
-package com.tangem.presentation.dialog
+package com.tangem.tangemcard.android.presentation.dialog
import android.app.Dialog
import android.content.Intent
@@ -8,7 +8,7 @@ import android.support.v4.app.DialogFragment
import android.support.v7.app.AlertDialog
-import com.tangem.wallet.R
+import com.tangem.tangemcard.R
class NfcEnableDialog : DialogFragment() {
diff --git a/app/src/main/java/com/tangem/domain/cardReader/NfcManager.java b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/reader/NfcManager.java
similarity index 97%
rename from app/src/main/java/com/tangem/domain/cardReader/NfcManager.java
rename to tangemcard-android/src/main/java/com/tangem/tangemcard/android/reader/NfcManager.java
index b60eaf3a5b..0581c7f107 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/NfcManager.java
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/reader/NfcManager.java
@@ -1,4 +1,4 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.android.reader;
import android.Manifest;
import android.annotation.TargetApi;
@@ -16,7 +16,7 @@ import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
-import com.tangem.presentation.dialog.NfcEnableDialog;
+import com.tangem.tangemcard.android.presentation.dialog.NfcEnableDialog;
import java.io.IOException;
diff --git a/tangemcard-android/src/main/java/com/tangem/tangemcard/android/reader/NfcReader.kt b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/reader/NfcReader.kt
new file mode 100644
index 0000000000..a23b8619a7
--- /dev/null
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/android/reader/NfcReader.kt
@@ -0,0 +1,41 @@
+package com.tangem.tangemcard.android.reader
+
+import android.nfc.tech.IsoDep
+
+data class NfcReader(
+ val nfcManager: NfcManager,
+ val isoDep: IsoDep
+) : com.tangem.tangemcard.reader.NfcReader {
+ override fun getId(): ByteArray {
+ return isoDep.tag.id
+ }
+
+ override fun setTimeout(timeout: Int) {
+ isoDep.timeout = timeout
+ }
+
+ override fun getTimeout(): Int {
+ return isoDep.timeout
+ }
+
+ override fun transceive(data: ByteArray?): ByteArray {
+ return isoDep.transceive(data)
+ }
+
+ override fun ignoreTag() {
+ nfcManager.ignoreTag(isoDep.tag)
+ }
+
+ override fun notifyReadResult(success: Boolean) {
+ nfcManager.notifyReadResult(success)
+ }
+
+ override fun connect() {
+ val timeout = isoDep.timeout
+ isoDep.connect()
+ isoDep.close()
+ isoDep.connect()
+ isoDep.timeout = timeout
+ }
+
+}
\ No newline at end of file
diff --git a/tangemcard-android/src/main/java/com/tangem/tangemcard/data/TangemCardExtensions.kt b/tangemcard-android/src/main/java/com/tangem/tangemcard/data/TangemCardExtensions.kt
new file mode 100644
index 0000000000..8bbcd3198f
--- /dev/null
+++ b/tangemcard-android/src/main/java/com/tangem/tangemcard/data/TangemCardExtensions.kt
@@ -0,0 +1,150 @@
+package com.tangem.tangemcard.data
+
+import android.os.Bundle
+import com.tangem.tangemcard.util.Log
+import java.util.*
+
+const val EXTRA_TANGEM_CARD = "Card"
+const val EXTRA_TANGEM_CARD_UID = "UID"
+
+fun TangemCard.loadFromBundle(B: Bundle) {
+ uid = B.getString("UID")
+ cid = B.getByteArray("CID")
+ pin = B.getString("PIN")
+ PIN2 = TangemCard.PIN2_Mode.valueOf(B.getString("PIN2")!!)
+ status = TangemCard.Status.valueOf(B.getString("Status")!!)
+ blockchainID = B.getString("Blockchain")
+ tokensDecimal = B.getInt("TokensDecimal", 18)
+ tokenSymbol = B.getString("TokenSymbol", "")
+ contractAddress = B.getString("ContractAddress", "")
+// if (B.containsKey("BlockchainName"))
+// blockchainName = B.getString("BlockchainName", "");
+ if (B.containsKey("dtPersonalization")) {
+ personalizationDateTime = Date(B.getLong("dtPersonalization"))
+ }
+ remainingSignatures = B.getInt("RemainingSignatures")
+ maxSignatures = B.getInt("MaxSignatures")
+ health = B.getInt("health")
+ if (B.containsKey("settingsMask")) settingsMask = B.getInt("settingsMask")
+ pauseBeforePIN2 = B.getInt("pauseBeforePIN2")
+ if (B.containsKey("signingMethod"))
+ setSigningMethod(TangemCard.SigningMethod.valueOf(B.getString("signingMethod")!!).ID)
+ if (B.containsKey("Manufacturer"))
+ setManufacturer(Manufacturer.valueOf(B.getString("Manufacturer")!!), B.getBoolean("ManufacturerConfirmed", false))
+ if (B.containsKey("EncryptionMode"))
+ encryptionMode = TangemCard.EncryptionMode.valueOf(B.getString("EncryptionMode")!!)
+ else
+ encryptionMode = null
+
+ if (B.containsKey("SignedHashes")) signedHashes = B.getInt("SignedHashes")
+
+ if (B.containsKey("Issuer")) setIssuer(B.getString("Issuer"), B.getByteArray("IssuerPublicDataKey"))
+
+ if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion")
+ if (B.containsKey("Batch")) batch = B.getString("Batch")
+
+ isCardPublicKeyValid = B.getBoolean("CardPublicKeyValid")
+ if (B.containsKey("CardPublicKey")) cardPublicKey = B.getByteArray("CardPublicKey")
+
+ if (B.containsKey("OfflineBalance")) offlineBalance = B.getByteArray("OfflineBalance")
+ else clearOfflineBalance()
+
+ if (B.containsKey("Denomination") && B.containsKey("DenominationText")) {
+ setDenomination(B.getByteArray("Denomination"), B.getString("DenominationText"))
+ } else if (B.containsKey("Denomination")) {
+ setDenomination(B.getByteArray("Denomination"), "N/A")
+ } else clearDenomination()
+
+ if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
+ setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"))
+ else setIssuerData(null, null)
+
+ if (B.containsKey("NeedWriteIssuerData"))
+ needWriteIssuerData = B.getBoolean("NeedWriteIssuerData")
+
+ isWalletPublicKeyValid = B.getBoolean("WalletPublicKeyValid")
+ if (B.containsKey("PublicKey")) {
+ walletPublicKey = B.getByteArray("PublicKey")
+ }
+ if (B.containsKey("PublicKeyRar")) {
+ walletPublicKeyRar = B.getByteArray("PublicKeyRar")
+ }
+
+ if (B.containsKey("codeConfirmed"))
+ isCodeConfirmed = B.getBoolean("codeConfirmed")
+
+ if (B.containsKey("onlineVerified"))
+ isOnlineVerified = B.getBoolean("onlineVerified")
+
+ if (B.containsKey("onlineValidated"))
+ isOnlineValidated = B.getBoolean("onlineValidated")
+
+}
+
+val TangemCard.asBundle: Bundle
+ get() {
+ val bundle = Bundle()
+ saveToBundle(bundle)
+ return bundle
+ }
+
+fun TangemCard.saveToBundle(B: Bundle) {
+ try {
+ B.putString("UID", uid)
+ B.putByteArray("CID", cid)
+ B.putString("PIN", pin)
+ B.putString("PIN2", PIN2.name)
+ B.putString("Status", status.name)
+ B.putString("Blockchain", blockchainID)
+ B.putInt("TokensDecimal", tokensDecimal)
+ B.putString("TokenSymbol", tokenSymbol)
+ B.putString("ContractAddress", contractAddress)
+ if (personalizationDateTime != null) B.putLong("dtPersonalization", personalizationDateTime.time)
+
+ B.putInt("RemainingSignatures", remainingSignatures)
+ B.putInt("MaxSignatures", maxSignatures)
+ B.putInt("Health", health)
+ if (settingsMask != null) B.putInt("settingsMask", settingsMask)
+ B.putInt("pauseBeforePIN2", pauseBeforePIN2)
+ if (signingMethod != null) B.putString("signingMethod", signingMethod.name)
+ if (manufacturer != null) B.putString("Manufacturer", manufacturer.name)
+ if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name)
+ if (issuer != null) B.putString("Issuer", issuer.getID())
+ if (issuerPublicDataKey != null) B.putByteArray("IssuerPublicDataKey", issuerPublicDataKey)
+ if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion)
+ if (batch != null) B.putString("Batch", batch)
+ B.putBoolean("ManufacturerConfirmed", isManufacturerConfirmed)
+ B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid)
+ B.putByteArray("CardPublicKey", cardPublicKey)
+
+ B.putInt("SignedHashes", signedHashes)
+ B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid)
+ if (walletPublicKey != null)
+ B.putByteArray("PublicKey", walletPublicKey)
+ if (walletPublicKeyRar != null)
+ B.putByteArray("PublicKeyRar", walletPublicKeyRar)
+
+ if (offlineBalance != null) B.putByteArray("OfflineBalance", offlineBalance)
+
+ if (denomination != null) B.putByteArray("Denomination", denomination)
+ if (denominationText != null) B.putString("DenominationText", denominationText)
+
+ if (issuerData != null && issuerDataSignature != null) {
+ B.putByteArray("IssuerData", issuerData)
+ B.putByteArray("IssuerDataSignature", issuerDataSignature)
+ B.putBoolean("NeedWriteIssuerData", needWriteIssuerData)
+ }
+
+ if (isCodeConfirmed != null)
+ B.putBoolean("codeConfirmed", isCodeConfirmed)
+
+ if (isOnlineVerified != null)
+ B.putBoolean("onlineVerified", isOnlineVerified)
+
+ if (isOnlineValidated != null)
+ B.putBoolean("onlineValidated", isOnlineValidated)
+ } catch (e: Exception) {
+ Log.e("Can't save to bundle ", e.message)
+ }
+
+}
diff --git a/app/src/main/res/drawable/card_default.png b/tangemcard-android/src/main/res/drawable/card_default.png
similarity index 100%
rename from app/src/main/res/drawable/card_default.png
rename to tangemcard-android/src/main/res/drawable/card_default.png
diff --git a/app/src/main/res/drawable/card_ru006.png b/tangemcard-android/src/main/res/drawable/card_ru006.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru006.png
rename to tangemcard-android/src/main/res/drawable/card_ru006.png
diff --git a/app/src/main/res/drawable/card_ru007.png b/tangemcard-android/src/main/res/drawable/card_ru007.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru007.png
rename to tangemcard-android/src/main/res/drawable/card_ru007.png
diff --git a/app/src/main/res/drawable/card_ru011.png b/tangemcard-android/src/main/res/drawable/card_ru011.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru011.png
rename to tangemcard-android/src/main/res/drawable/card_ru011.png
diff --git a/app/src/main/res/drawable/card_ru012.png b/tangemcard-android/src/main/res/drawable/card_ru012.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru012.png
rename to tangemcard-android/src/main/res/drawable/card_ru012.png
diff --git a/app/src/main/res/drawable/card_ru013.png b/tangemcard-android/src/main/res/drawable/card_ru013.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru013.png
rename to tangemcard-android/src/main/res/drawable/card_ru013.png
diff --git a/app/src/main/res/drawable/card_ru014.png b/tangemcard-android/src/main/res/drawable/card_ru014.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru014.png
rename to tangemcard-android/src/main/res/drawable/card_ru014.png
diff --git a/app/src/main/res/drawable/card_ru015.png b/tangemcard-android/src/main/res/drawable/card_ru015.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru015.png
rename to tangemcard-android/src/main/res/drawable/card_ru015.png
diff --git a/app/src/main/res/drawable/card_ru016.png b/tangemcard-android/src/main/res/drawable/card_ru016.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru016.png
rename to tangemcard-android/src/main/res/drawable/card_ru016.png
diff --git a/app/src/main/res/drawable/card_ru020.png b/tangemcard-android/src/main/res/drawable/card_ru020.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru020.png
rename to tangemcard-android/src/main/res/drawable/card_ru020.png
diff --git a/app/src/main/res/drawable/card_ru021.png b/tangemcard-android/src/main/res/drawable/card_ru021.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru021.png
rename to tangemcard-android/src/main/res/drawable/card_ru021.png
diff --git a/app/src/main/res/drawable/card_ru022.png b/tangemcard-android/src/main/res/drawable/card_ru022.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru022.png
rename to tangemcard-android/src/main/res/drawable/card_ru022.png
diff --git a/app/src/main/res/drawable/card_ru023.png b/tangemcard-android/src/main/res/drawable/card_ru023.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru023.png
rename to tangemcard-android/src/main/res/drawable/card_ru023.png
diff --git a/app/src/main/res/drawable/card_ru024.png b/tangemcard-android/src/main/res/drawable/card_ru024.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru024.png
rename to tangemcard-android/src/main/res/drawable/card_ru024.png
diff --git a/app/src/main/res/drawable/card_ru028.png b/tangemcard-android/src/main/res/drawable/card_ru028.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru028.png
rename to tangemcard-android/src/main/res/drawable/card_ru028.png
diff --git a/app/src/main/res/drawable/card_ru029.png b/tangemcard-android/src/main/res/drawable/card_ru029.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru029.png
rename to tangemcard-android/src/main/res/drawable/card_ru029.png
diff --git a/app/src/main/res/drawable/card_ru030.png b/tangemcard-android/src/main/res/drawable/card_ru030.png
similarity index 100%
rename from app/src/main/res/drawable/card_ru030.png
rename to tangemcard-android/src/main/res/drawable/card_ru030.png
diff --git a/app/src/main/res/drawable/hand_card_horizontal.png b/tangemcard-android/src/main/res/drawable/hand_card_horizontal.png
similarity index 100%
rename from app/src/main/res/drawable/hand_card_horizontal.png
rename to tangemcard-android/src/main/res/drawable/hand_card_horizontal.png
diff --git a/app/src/main/res/drawable/hand_card_vertical.png b/tangemcard-android/src/main/res/drawable/hand_card_vertical.png
similarity index 100%
rename from app/src/main/res/drawable/hand_card_vertical.png
rename to tangemcard-android/src/main/res/drawable/hand_card_vertical.png
diff --git a/app/src/main/res/drawable/ic_action_nfc_gray.png b/tangemcard-android/src/main/res/drawable/ic_action_nfc_gray.png
similarity index 100%
rename from app/src/main/res/drawable/ic_action_nfc_gray.png
rename to tangemcard-android/src/main/res/drawable/ic_action_nfc_gray.png
diff --git a/app/src/main/res/drawable/ic_logo_bat_token.png b/tangemcard-android/src/main/res/drawable/ic_logo_bat_token.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_bat_token.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_bat_token.png
diff --git a/app/src/main/res/drawable/ic_logo_bitcoin.png b/tangemcard-android/src/main/res/drawable/ic_logo_bitcoin.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_bitcoin.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_bitcoin.png
diff --git a/app/src/main/res/drawable/ic_logo_bitcoin_cash.png b/tangemcard-android/src/main/res/drawable/ic_logo_bitcoin_cash.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_bitcoin_cash.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_bitcoin_cash.png
diff --git a/app/src/main/res/drawable/ic_logo_bitcoin_testnet.png b/tangemcard-android/src/main/res/drawable/ic_logo_bitcoin_testnet.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_bitcoin_testnet.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_bitcoin_testnet.png
diff --git a/app/src/main/res/drawable/ic_logo_ethereum.png b/tangemcard-android/src/main/res/drawable/ic_logo_ethereum.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_ethereum.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_ethereum.png
diff --git a/app/src/main/res/drawable/ic_logo_ethereum_testnet.png b/tangemcard-android/src/main/res/drawable/ic_logo_ethereum_testnet.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_ethereum_testnet.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_ethereum_testnet.png
diff --git a/app/src/main/res/drawable/ic_logo_seed.png b/tangemcard-android/src/main/res/drawable/ic_logo_seed.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_seed.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_seed.png
diff --git a/app/src/main/res/drawable/ic_logo_unknown.png b/tangemcard-android/src/main/res/drawable/ic_logo_unknown.png
similarity index 100%
rename from app/src/main/res/drawable/ic_logo_unknown.png
rename to tangemcard-android/src/main/res/drawable/ic_logo_unknown.png
diff --git a/app/src/main/res/drawable/tangem2.png b/tangemcard-android/src/main/res/drawable/tangem2.png
similarity index 100%
rename from app/src/main/res/drawable/tangem2.png
rename to tangemcard-android/src/main/res/drawable/tangem2.png
diff --git a/tangemcard-android/src/main/res/values/strings.xml b/tangemcard-android/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..3be1a76c7b
--- /dev/null
+++ b/tangemcard-android/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+
+ tangemcard
+ OK
+ Quit
+ Enable NFC?
+ This app is useless when NFC is disabled. Reader mode depends on it. Hit OK to go to Settings, where you can enable NFC.
+
+
diff --git a/tangemcard-android/src/test/java/com/tangem/tangemcard/android/ExampleUnitTest.java b/tangemcard-android/src/test/java/com/tangem/tangemcard/android/ExampleUnitTest.java
new file mode 100644
index 0000000000..2727035d33
--- /dev/null
+++ b/tangemcard-android/src/test/java/com/tangem/tangemcard/android/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.tangem.tangemcard.android;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/tangemcard-common/.gitignore b/tangemcard-common/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/tangemcard-common/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/tangemcard-common/build.gradle b/tangemcard-common/build.gradle
new file mode 100644
index 0000000000..15d24ac6d8
--- /dev/null
+++ b/tangemcard-common/build.gradle
@@ -0,0 +1,12 @@
+apply plugin: 'java-library'
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'com.madgag.spongycastle:core:1.56.0.0'
+ implementation 'com.madgag.spongycastle:prov:1.56.0.0'
+
+}
+
+sourceCompatibility = "7"
+targetCompatibility = "7"
diff --git a/app/src/main/java/com/tangem/domain/wallet/Issuer.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/Issuer.java
similarity index 68%
rename from app/src/main/java/com/tangem/domain/wallet/Issuer.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/data/Issuer.java
index 778111463b..1a68d4799c 100644
--- a/app/src/main/java/com/tangem/domain/wallet/Issuer.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/Issuer.java
@@ -1,19 +1,8 @@
-package com.tangem.domain.wallet;
+package com.tangem.tangemcard.data;
-import android.content.Context;
+import com.tangem.tangemcard.reader.CardCrypto;
+import com.tangem.tangemcard.util.Util;
-import com.google.common.io.Files;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-import com.tangem.domain.cardReader.CardCrypto;
-import com.tangem.util.Util;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -30,7 +19,7 @@ public class Issuer {
byte[] getPrivateKey() throws Exception {
if (privateKey != null) {
- return CardCrypto.GeneratePublicKey(Util.hexToBytes(privateKey));
+ return Util.hexToBytes(privateKey);
} else {
throw new Exception("No private key!");
}
@@ -50,8 +39,8 @@ public class Issuer {
}
- private String id;
- private String officialName;
+ public String id;
+ public String officialName;
private KeyPair dataKey;
private KeyPair transactionKey;
@@ -61,27 +50,16 @@ public class Issuer {
private static List instances = new ArrayList<>();
- public static boolean needInit() {
- return instances.size() == 0;
+ static {
+ Issuer unknown = new Issuer();
+ unknown.id = "UNKNOWN";
+ unknown.officialName = "UNKNOWN";
+ instances.add(unknown);
}
- public static void init(Context context) {
- try {
- Issuer unknown = new Issuer();
- unknown.id = "UNKNOWN";
- unknown.officialName = "UNKNOWN";
-
- try (InputStream is = context.getAssets().open("issuers.json")) {
- try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
- Type listType = new TypeToken>() {
- }.getType();
- instances = new Gson().fromJson(reader, listType);
- }
- }
- instances.add(0, unknown);
- } catch (Exception e) {
- e.printStackTrace();
- }
+ public static void fillIssuers(List issuers)
+ {
+ instances.addAll(issuers);
}
public byte[] getPublicDataKey() throws Exception {
diff --git a/app/src/main/java/com/tangem/domain/wallet/Manufacturer.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/Manufacturer.java
similarity index 96%
rename from app/src/main/java/com/tangem/domain/wallet/Manufacturer.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/data/Manufacturer.java
index 8c298ce0c6..a3d1081032 100644
--- a/app/src/main/java/com/tangem/domain/wallet/Manufacturer.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/Manufacturer.java
@@ -1,4 +1,4 @@
-package com.tangem.domain.wallet;
+package com.tangem.tangemcard.data;
/**
* Created by dvol on 09.08.2017.
diff --git a/app/src/main/java/com/tangem/domain/wallet/TangemCard.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/TangemCard.java
similarity index 58%
rename from app/src/main/java/com/tangem/domain/wallet/TangemCard.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/data/TangemCard.java
index 54367b1a0d..67514def23 100644
--- a/app/src/main/java/com/tangem/domain/wallet/TangemCard.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/TangemCard.java
@@ -1,12 +1,8 @@
-package com.tangem.domain.wallet;
+package com.tangem.tangemcard.data;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.google.common.base.Strings;
-import com.tangem.data.db.PINStorage;
-import com.tangem.domain.cardReader.SettingsMask;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.reader.SettingsMask;
+import com.tangem.tangemcard.util.Util;
import java.util.Date;
@@ -16,12 +12,8 @@ import java.util.Date;
public class TangemCard {
- public static final String EXTRA_CARD = "Card";
- public static final String EXTRA_UID = "UID";
-
private byte[] CID;
private Status status;
- private String wallet;
private String UID;
private String blockchainID;
private Manufacturer manufacturer = Manufacturer.Unknown;
@@ -38,50 +30,10 @@ public class TangemCard {
return blockchainID;
}
- public Blockchain getBlockchain() {
- return Blockchain.fromId(blockchainID);
- }
-
- public void setBlockchain(Blockchain blockchain) {
- blockchainID=blockchain.getID();
- }
-
public void setBlockchainID(String blockchainID) {
this.blockchainID = blockchainID;
}
- public void addTokenToBlockchainName() {
- String token = getTokenSymbol();
- if (Strings.isNullOrEmpty(token))
- return;
- String oldName = getBlockchain().getOfficialName();
- //String newName = String.format("%s - %s ERC20 token", token, oldName);
- String newName = token + "
" + oldName + " ERC20 token";
- blockchainName=newName;
-
- }
-
- private String blockchainName = "";
-
- public String getBlockchainName() {
- if (Strings.isNullOrEmpty(blockchainName))
- return getBlockchain().getOfficialName();
- return blockchainName;
- }
-
- public void setBlockchainIDFromCard(String blockchainID) {
-
- if (Blockchain.fromId(blockchainID) != Blockchain.Ethereum && Blockchain.fromId(blockchainID) != Blockchain.EthereumTestNet)
- this.blockchainID = blockchainID;
-
- if (isToken()) {
- this.blockchainID = Blockchain.Token.getID();
- addTokenToBlockchainName();
- } else {
- this.blockchainID = blockchainID;
- }
- }
-
public void setWalletPublicKey(byte[] publicKey) {
pbWalletKey = publicKey;
}
@@ -190,10 +142,10 @@ public class TangemCard {
this.PIN = PIN;
}
- public void switchToInitialBlockchain() {
- if (tokenSymbol.length() > 1)
- blockchainID = Blockchain.Token.getID(); // Reset blockchain to Token from ETH for token cards with zero token balance on it
- }
+// public void switchToInitialBlockchain() {
+// if (tokenSymbol.length() > 1)
+// blockchainID = Blockchain.Token.getID(); // Reset blockchain to Token from ETH for token cards with zero token balance on it
+// }
public Date getPersonalizationDateTime() {
return dtPersonalization;
@@ -203,12 +155,12 @@ public class TangemCard {
this.dtPersonalization = dtPersonalization;
}
- public String getPersonalizationDateTimeDescription() {
- return Util.formatDate(dtPersonalization);
- }
-
private int health = 0;
+ public int getHealth() {
+ return health;
+ }
+
public void setHealth(int health) {
if (health > this.health) this.health = health;
}
@@ -217,15 +169,19 @@ public class TangemCard {
return health == 0;
}
- private Issuer issuer = Issuer.Unknown();
private byte[] issuerPublicDataKey = null;
+ private String issuerID = null;
-// public void setIssuer(Issuer issuer) {
-// this.issuer = issuer;
-// }
+
+ public byte[] getIssuerPublicDataKey() {
+ return issuerPublicDataKey;
+ }
+
+ private Issuer issuer = Issuer.Unknown();
public void setIssuer(String issuerID, byte[] issuerPublicDataKey) {
this.issuerPublicDataKey = issuerPublicDataKey;
+ this.issuerID = issuerID;
this.issuer = Issuer.FindIssuer(issuerID, issuerPublicDataKey);
}
@@ -233,14 +189,11 @@ public class TangemCard {
return issuer;
}
- public byte[] getIssuerPublicDataKey() {
- return issuerPublicDataKey;
- }
-
public String getIssuerDescription() {
return issuer.getOfficialName();
}
+
String contractAddress = "";
public void setContractAddress(String address) {
@@ -262,7 +215,7 @@ public class TangemCard {
}
public boolean isToken() {
- return !Strings.isNullOrEmpty(tokenSymbol);
+ return !(tokenSymbol == null || tokenSymbol.isEmpty());
}
int tokensDecimal = 18;
@@ -318,6 +271,10 @@ public class TangemCard {
private Integer settingsMask = null;
+ public Integer getSettingsMask() {
+ return settingsMask;
+ }
+
public void setSettingsMask(int settingsMask) {
this.settingsMask = settingsMask;
}
@@ -342,15 +299,15 @@ public class TangemCard {
return (settingsMask & SettingsMask.UseCVC) != 0;
}
- public Boolean useDefaultPIN1() {
- return PINStorage.isDefaultPIN(getPIN());
- }
-
public Boolean useSmartSecurityDelay() {
if (settingsMask == null) return null;
return (settingsMask & SettingsMask.SmartSecurityDelay) != 0;
}
+ public Boolean useDefaultPIN1() {
+ return CardProtocol.isDefaultPIN(getPIN());
+ }
+
public enum PIN2_Mode {Unchecked, DefaultPIN2, CustomPIN2}
public PIN2_Mode PIN2 = PIN2_Mode.Unchecked;
@@ -465,7 +422,9 @@ public class TangemCard {
Sign_Hash(0, "sign hash"),
Sign_Raw(1, "sign raw tx"),
Sign_Hash_Validated_By_Issuer(2, "sign hash validated by issuer"),
- Sign_Raw_Validated_By_Issuer(3, "sign raw tx validated by issuer");
+ Sign_Raw_Validated_By_Issuer(3, "sign raw tx validated by issuer"),
+ Sign_Hash_Validated_By_Issuer_And_WriteIssuerData(4, "sign hash validated by issuer and write issuer data"),
+ Sign_Raw_Validated_By_Issuer_And_WriteIssuerData(5, "sign raw tx validated by issuer and write issuer data");
int ID;
String mDescription;
@@ -549,22 +508,6 @@ public class TangemCard {
}
}
- 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 String getUID() {
return UID;
}
@@ -596,19 +539,6 @@ public class TangemCard {
this.DenominationText = denominationText;
}
- public void setDenomination(byte[] denomination) {
- this.Denomination = denomination;
- try {
- CoinEngine engine= CoinEngineFactory.INSTANCE.create(getBlockchain());
- CoinEngine.InternalAmount internalAmount=engine.convertToInternalAmount(denomination);
- CoinEngine.Amount amount=engine.convertToAmount(internalAmount);
- this.DenominationText = amount.toString();
- } catch (Exception e) {
- e.printStackTrace();
- this.DenominationText = "N/A";
- }
- }
-
public byte[] getDenomination() {
return Denomination;
}
@@ -637,161 +567,163 @@ public class TangemCard {
DenominationText = null;
}
- public Bundle getAsBundle() {
- Bundle B = new Bundle();
- saveToBundle(B);
- return B;
- }
-
- public void saveToBundle(Bundle B) {
- try {
- B.putString("UID", UID);
- B.putByteArray("CID", CID);
- B.putString("PIN", PIN);
- B.putString("PIN2", PIN2.name());
- B.putString("Status", status.name());
- B.putString("Blockchain", blockchainID);
- B.putString("BlockchainName", blockchainName);
- B.putInt("TokensDecimal", tokensDecimal);
- B.putString("TokenSymbol", tokenSymbol);
- B.putString("ContractAddress", contractAddress);
- if (dtPersonalization != null) B.putLong("dtPersonalization", dtPersonalization.getTime());
- B.putInt("RemainingSignatures", remainingSignatures);
- B.putInt("MaxSignatures", maxSignatures);
- B.putInt("Health", health);
- if (settingsMask != null) B.putInt("settingsMask", settingsMask);
- B.putInt("pauseBeforePIN2", pauseBeforePIN2);
- if (signingMethod != null) B.putString("signingMethod", signingMethod.name());
- if (manufacturer != null) B.putString("Manufacturer", manufacturer.name());
- if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
- if (issuer != null) B.putString("Issuer", issuer.getID());
- if (issuerPublicDataKey != null) B.putByteArray("IssuerPublicDataKey", issuerPublicDataKey);
- if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
- if (batch != null) B.putString("Batch", batch);
- B.putBoolean("ManufacturerConfirmed", manufacturerConfirmed);
- B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid());
- B.putByteArray("CardPublicKey", getCardPublicKey());
-
- B.putInt("SignedHashes", getSignedHashes());
- B.putString("Wallet", wallet);
- B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid());
- if (pbWalletKey != null)
- B.putByteArray("PublicKey", pbWalletKey);
- if (pbWalletKeyRar != null)
- B.putByteArray("PublicKeyRar", pbWalletKeyRar);
-
- if (getOfflineBalance() != null) B.putByteArray("OfflineBalance", getOfflineBalance());
-
- if (getDenomination() != null) B.putByteArray("Denomination", getDenomination());
-
- if (getIssuerData() != null && getIssuerDataSignature() != null) {
- B.putByteArray("IssuerData", getIssuerData());
- B.putByteArray("IssuerDataSignature", getIssuerDataSignature());
- B.putBoolean("NeedWriteIssuerData", getNeedWriteIssuerData());
- }
-
- if (codeConfirmed != null)
- B.putBoolean("codeConfirmed", codeConfirmed);
-
- if (codeConfirmed != null)
- B.putBoolean("codeConfirmed", codeConfirmed);
-
- if (onlineVerified != null)
- B.putBoolean("onlineVerified", onlineVerified);
-
- if (onlineValidated != null)
- B.putBoolean("onlineValidated", onlineValidated);
-
- if (codeConfirmed != null)
- B.putBoolean("codeConfirmed", codeConfirmed);
-
- if (codeConfirmed != null)
- B.putBoolean("codeConfirmed", codeConfirmed);
-
- if (onlineVerified != null)
- B.putBoolean("onlineVerified", onlineVerified);
-
- if (onlineValidated != null)
- B.putBoolean("onlineValidated", onlineValidated);
- } catch (Exception e) {
- Log.e("Can't save to bundle ", e.getMessage());
- }
-
- }
-
- public void loadFromBundle(Bundle B) {
- UID = B.getString("UID");
- CID = B.getByteArray("CID");
- PIN = B.getString("PIN");
- PIN2 = PIN2_Mode.valueOf(B.getString("PIN2"));
- status = Status.valueOf(B.getString("Status"));
- wallet = B.getString("Wallet");
- blockchainID = B.getString("Blockchain");
- tokensDecimal = B.getInt("TokensDecimal", 18);
- tokenSymbol = B.getString("TokenSymbol", "");
- contractAddress = B.getString("ContractAddress", "");
- if (B.containsKey("BlockchainName"))
- blockchainName = B.getString("BlockchainName", "");
- if (B.containsKey("dtPersonalization")) {
- dtPersonalization = new Date(B.getLong("dtPersonalization"));
- }
- remainingSignatures = B.getInt("RemainingSignatures");
- maxSignatures = B.getInt("MaxSignatures");
- health = B.getInt("health");
- if (B.containsKey("settingsMask")) settingsMask = B.getInt("settingsMask");
- pauseBeforePIN2 = B.getInt("pauseBeforePIN2");
- if (B.containsKey("signingMethod"))
- signingMethod = SigningMethod.valueOf(B.getString("signingMethod"));
- if (B.containsKey("Manufacturer"))
- manufacturer = Manufacturer.valueOf(B.getString("Manufacturer"));
- manufacturerConfirmed = B.getBoolean("ManufacturerConfirmed");
- if (B.containsKey("EncryptionMode"))
- encryptionMode = EncryptionMode.valueOf(B.getString("EncryptionMode"));
- else
- encryptionMode = null;
-
- if (B.containsKey("SignedHashes")) setSignedHashes(B.getInt("SignedHashes"));
-
- if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
- if (B.containsKey("IssuerPublicDataKey"))
- issuerPublicDataKey = B.getByteArray("IssuerPublicDataKey");
-
- if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
- if (B.containsKey("Batch")) batch = B.getString("Batch");
-
- cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
- if (B.containsKey("CardPublicKey")) setCardPublicKey(B.getByteArray("CardPublicKey"));
-
- if (B.containsKey("OfflineBalance")) setOfflineBalance(B.getByteArray("OfflineBalance"));
- else clearOfflineBalance();
-
- if (B.containsKey("Denomination")) setDenomination(B.getByteArray("Denomination"));
- else clearDenomination();
-
- if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
- setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"));
- else setIssuerData(null, null);
-
- if (B.containsKey("NeedWriteIssuerData"))
- setNeedWriteIssuerData(B.getBoolean("NeedWriteIssuerData"));
-
- walletPublicKeyValid = B.getBoolean("WalletPublicKeyValid");
- if (B.containsKey("PublicKey")) {
- pbWalletKey = B.getByteArray("PublicKey");
- }
- if (B.containsKey("PublicKeyRar")) {
- pbWalletKeyRar = B.getByteArray("PublicKeyRar");
- }
-
- if (B.containsKey("codeConfirmed"))
- codeConfirmed = B.getBoolean("codeConfirmed");
-
- if (B.containsKey("onlineVerified"))
- onlineVerified = B.getBoolean("onlineVerified");
-
- if (B.containsKey("onlineValidated"))
- onlineValidated = B.getBoolean("onlineValidated");
- }
+// public Bundle getAsBundle() {
+// Bundle B = new Bundle();
+// saveToBundle(B);
+// return B;
+// }
+//
+// public void saveToBundle(Bundle B) {
+// try {
+// B.putString("UID", UID);
+// B.putByteArray("CID", CID);
+// B.putString("PIN", PIN);
+// B.putString("PIN2", PIN2.name());
+// B.putString("Status", status.name());
+// B.putString("Blockchain", blockchainID);
+// B.putString("BlockchainName", blockchainName);
+// B.putInt("TokensDecimal", tokensDecimal);
+// B.putString("TokenSymbol", tokenSymbol);
+// B.putString("ContractAddress", contractAddress);
+// if (dtPersonalization != null) B.putLong("dtPersonalization", dtPersonalization.getTime());
+// B.putInt("RemainingSignatures", remainingSignatures);
+// B.putInt("MaxSignatures", maxSignatures);
+// B.putInt("Health", health);
+// if (settingsMask != null) B.putInt("settingsMask", settingsMask);
+// B.putInt("pauseBeforePIN2", pauseBeforePIN2);
+// if (signingMethod != null) B.putString("signingMethod", signingMethod.name());
+// if (manufacturer != null) B.putString("Manufacturer", manufacturer.name());
+// if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
+// if (issuer != null) B.putString("Issuer", issuer.getID());
+// if (issuerPublicDataKey != null) B.putByteArray("IssuerPublicDataKey", issuerPublicDataKey);
+// if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
+// if (batch != null) B.putString("Batch", batch);
+// B.putBoolean("ManufacturerConfirmed", manufacturerConfirmed);
+// B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid());
+// B.putByteArray("CardPublicKey", getCardPublicKey());
+//
+// B.putInt("SignedHashes", getSignedHashes());
+// B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid());
+// if (pbWalletKey != null)
+// B.putByteArray("PublicKey", pbWalletKey);
+// if (pbWalletKeyRar != null)
+// B.putByteArray("PublicKeyRar", pbWalletKeyRar);
+//
+// if (getOfflineBalance() != null) B.putByteArray("OfflineBalance", getOfflineBalance());
+//
+// if (getDenomination() != null) B.putByteArray("Denomination", getDenomination());
+// if (getDenominationText() != null) B.putString("DenominationText", getDenominationText());
+//
+// if (getIssuerData() != null && getIssuerDataSignature() != null) {
+// B.putByteArray("IssuerData", getIssuerData());
+// B.putByteArray("IssuerDataSignature", getIssuerDataSignature());
+// B.putBoolean("NeedWriteIssuerData", getNeedWriteIssuerData());
+// }
+//
+// if (codeConfirmed != null)
+// B.putBoolean("codeConfirmed", codeConfirmed);
+//
+// if (codeConfirmed != null)
+// B.putBoolean("codeConfirmed", codeConfirmed);
+//
+// if (onlineVerified != null)
+// B.putBoolean("onlineVerified", onlineVerified);
+//
+// if (onlineValidated != null)
+// B.putBoolean("onlineValidated", onlineValidated);
+//
+// if (codeConfirmed != null)
+// B.putBoolean("codeConfirmed", codeConfirmed);
+//
+// if (codeConfirmed != null)
+// B.putBoolean("codeConfirmed", codeConfirmed);
+//
+// if (onlineVerified != null)
+// B.putBoolean("onlineVerified", onlineVerified);
+//
+// if (onlineValidated != null)
+// B.putBoolean("onlineValidated", onlineValidated);
+// } catch (Exception e) {
+// Log.e("Can't save to bundle ", e.getMessage());
+// }
+//
+// }
+//
+// public void loadFromBundle(Bundle B) {
+// UID = B.getString("UID");
+// CID = B.getByteArray("CID");
+// PIN = B.getString("PIN");
+// PIN2 = PIN2_Mode.valueOf(B.getString("PIN2"));
+// status = Status.valueOf(B.getString("Status"));
+// blockchainID = B.getString("Blockchain");
+// tokensDecimal = B.getInt("TokensDecimal", 18);
+// tokenSymbol = B.getString("TokenSymbol", "");
+// contractAddress = B.getString("ContractAddress", "");
+// if (B.containsKey("BlockchainName"))
+// blockchainName = B.getString("BlockchainName", "");
+// if (B.containsKey("dtPersonalization")) {
+// dtPersonalization = new Date(B.getLong("dtPersonalization"));
+// }
+// remainingSignatures = B.getInt("RemainingSignatures");
+// maxSignatures = B.getInt("MaxSignatures");
+// health = B.getInt("health");
+// if (B.containsKey("settingsMask")) settingsMask = B.getInt("settingsMask");
+// pauseBeforePIN2 = B.getInt("pauseBeforePIN2");
+// if (B.containsKey("signingMethod"))
+// signingMethod = SigningMethod.valueOf(B.getString("signingMethod"));
+// if (B.containsKey("Manufacturer"))
+// manufacturer = Manufacturer.valueOf(B.getString("Manufacturer"));
+// manufacturerConfirmed = B.getBoolean("ManufacturerConfirmed");
+// if (B.containsKey("EncryptionMode"))
+// encryptionMode = EncryptionMode.valueOf(B.getString("EncryptionMode"));
+// else
+// encryptionMode = null;
+//
+// if (B.containsKey("SignedHashes")) setSignedHashes(B.getInt("SignedHashes"));
+//
+// if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
+// if (B.containsKey("IssuerPublicDataKey"))
+// issuerPublicDataKey = B.getByteArray("IssuerPublicDataKey");
+//
+// if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
+// if (B.containsKey("Batch")) batch = B.getString("Batch");
+//
+// cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
+// if (B.containsKey("CardPublicKey")) setCardPublicKey(B.getByteArray("CardPublicKey"));
+//
+// if (B.containsKey("OfflineBalance")) setOfflineBalance(B.getByteArray("OfflineBalance"));
+// else clearOfflineBalance();
+//
+// if (B.containsKey("Denomination") && B.containsKey("DenominationText")) {
+// setDenomination(B.getByteArray("Denomination"), B.getString("DenominationText"));
+// } else if (B.containsKey("Denomination")) {
+// setDenomination(B.getByteArray("Denomination"), "N/A");
+// } else clearDenomination();
+//
+// if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
+// setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"));
+// else setIssuerData(null, null);
+//
+// if (B.containsKey("NeedWriteIssuerData"))
+// setNeedWriteIssuerData(B.getBoolean("NeedWriteIssuerData"));
+//
+// walletPublicKeyValid = B.getBoolean("WalletPublicKeyValid");
+// if (B.containsKey("PublicKey")) {
+// pbWalletKey = B.getByteArray("PublicKey");
+// }
+// if (B.containsKey("PublicKeyRar")) {
+// pbWalletKeyRar = B.getByteArray("PublicKeyRar");
+// }
+//
+// if (B.containsKey("codeConfirmed"))
+// codeConfirmed = B.getBoolean("codeConfirmed");
+//
+// if (B.containsKey("onlineVerified"))
+// onlineVerified = B.getBoolean("onlineVerified");
+//
+// if (B.containsKey("onlineValidated"))
+// onlineValidated = B.getBoolean("onlineValidated");
+// }
public enum EncryptionMode {
None((byte) 0x0), Fast((byte) 0x1), Strong((byte) 0x2);
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/CardDataSubstitutionProvider.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/CardDataSubstitutionProvider.java
new file mode 100644
index 0000000000..ceaf756749
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/CardDataSubstitutionProvider.java
@@ -0,0 +1,12 @@
+package com.tangem.tangemcard.data.external;
+
+import com.tangem.tangemcard.data.TangemCard;
+
+
+/**
+ * This interface provide method to make substitution of read card data (token symbol, contract address)
+ * if they was unknown when the card was produced
+ */
+public interface CardDataSubstitutionProvider {
+ void applySubstitution(TangemCard card);
+}
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/FirmwaresDigestsProvider.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/FirmwaresDigestsProvider.java
new file mode 100644
index 0000000000..86e8ba4175
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/FirmwaresDigestsProvider.java
@@ -0,0 +1,18 @@
+package com.tangem.tangemcard.data.external;
+
+/**
+ * This interfaces provide function to randomly select parameters to run one VerifyCode command, check answer and
+ * state that card is genuine or not
+ */
+public interface FirmwaresDigestsProvider {
+ VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion);
+
+ class VerifyCodeRecord {
+ public String hashAlg;
+ public int blockIndex;
+ public int blockCount;
+ public byte[] challenge;
+ public byte[] digest;
+ }
+
+}
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/PINsProvider.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/PINsProvider.java
new file mode 100644
index 0000000000..05cabc54af
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/data/external/PINsProvider.java
@@ -0,0 +1,30 @@
+package com.tangem.tangemcard.data.external;
+
+import java.util.List;
+
+/**
+ * Interface of PINsProvider - object that know some list of PINs (used when start first time read), PIN2 (used for protected operation) and store last used PIN
+ * to use it in following operations
+ */
+public interface PINsProvider {
+
+ /**
+ * @return list of known PINs
+ * This PINs used when start reading of card
+ * When start reading a PINs from this list used sequential in search PIN algorithm until right PIN found
+ */
+ List getPINs();
+
+ /**
+ * @return PIN2 for protected operations
+ */
+ String getPIN2();
+
+
+ /**
+ * Call after successful first time reading of card to store founded PIN (normally this PIN must be returned in next time {@see getPINs} at first position)
+ * @param pin
+ */
+ void setLastUsedPIN(String pin);
+
+}
diff --git a/app/src/main/java/com/tangem/domain/cardReader/CardCrypto.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CardCrypto.java
similarity index 98%
rename from app/src/main/java/com/tangem/domain/cardReader/CardCrypto.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CardCrypto.java
index c9f8b83196..04bc55e590 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/CardCrypto.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CardCrypto.java
@@ -1,8 +1,8 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
-import android.util.Log;
-
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Log;
+import com.tangem.tangemcard.util.PBKDF2;
+import com.tangem.tangemcard.util.Util;
import org.spongycastle.asn1.ASN1EncodableVector;
import org.spongycastle.asn1.ASN1Integer;
@@ -23,7 +23,6 @@ import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
-import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
diff --git a/app/src/main/java/com/tangem/domain/cardReader/CardProtocol.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CardProtocol.java
similarity index 72%
rename from app/src/main/java/com/tangem/domain/cardReader/CardProtocol.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CardProtocol.java
index 3a2edcc10c..d1251f2451 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/CardProtocol.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CardProtocol.java
@@ -1,24 +1,13 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
-import android.content.Context;
-import android.nfc.Tag;
-import android.nfc.TagLostException;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.tangem.domain.wallet.CoinEngine;
-import com.tangem.domain.wallet.CoinEngineFactory;
-import com.tangem.domain.wallet.Issuer;
-import com.tangem.data.db.LocalStorage;
-import com.tangem.domain.wallet.TangemCard;
-import com.tangem.domain.wallet.Manufacturer;
-import com.tangem.domain.wallet.TangemContext;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.data.Manufacturer;
+import com.tangem.tangemcard.util.Log;
+import com.tangem.tangemcard.util.Util;
import org.spongycastle.jce.ECNamedCurveTable;
import org.spongycastle.jce.interfaces.ECPublicKey;
import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
-import org.spongycastle.math.ec.ECPoint;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -28,7 +17,6 @@ import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
-import java.util.Calendar;
import javax.crypto.KeyAgreement;
@@ -109,14 +97,8 @@ public class CardProtocol {
private static final int SW_PIN_ERROR = SW.INVALID_PARAMS;
- private IsoDep mIsoDep;
+ private NfcReader mIsoDep;
- /**
- * @return Android NFC tag object
- */
- public Tag getTag() {
- return mIsoDep.getTag();
- }
public static final String DefaultPIN = "000000";
public static final String DefaultPIN2 = "000";
@@ -130,9 +112,17 @@ public class CardProtocol {
}
}
+ public static boolean isDefaultPIN(String pin) {
+ return (DefaultPIN.equals(pin));
+ }
+
+ public static boolean isDefaultPIN2(String pin2) {
+ return (DefaultPIN2.equals(pin2));
+ }
+
+
private TangemCard mCard;
private Exception mError;
- private Context mContext;
/**
* Set occurred error
@@ -153,34 +143,22 @@ public class CardProtocol {
}
/**
- * Constructor for reading a card for the first time
- *
- * @param context - Android context
- * @param isoDep - Android NFC tag
+ * Constructor
+ * @param reader - NFC Reader interface
+ * @param card - TangemCard object, stored data from previous reading or null for reading a card for the first time
* @param notifications - UI notification callbacks
*/
- public CardProtocol(Context context, IsoDep isoDep, Notifications notifications) {
- mContext = context;
- mIsoDep = isoDep;
+ public CardProtocol(NfcReader reader, TangemCard card, Notifications notifications) {
+ mIsoDep = reader;
mNotifications = notifications;
- mPIN = null;
- mCard = new TangemCard(Util.byteArrayToHexString(mIsoDep.getTag().getId()));
- }
-
- /**
- * Constructor for subsequent reading of the card
- *
- * @param context - Android context
- * @param isoDep - Android NFC tag
- * @param card - TangemCard object, stored data from previous reading
- * @param notifications - UI notification callbacks
- */
- public CardProtocol(Context context, IsoDep isoDep, TangemCard card, Notifications notifications) {
- mContext = context;
- mIsoDep = isoDep;
- mNotifications = notifications;
- mPIN = card.getPIN();
- mCard = card;
+ if (card != null)
+ {
+ mPIN = card.getPIN();
+ mCard = card;
+ }else{
+ mPIN = null;
+ mCard = new TangemCard(Util.byteArrayToHexString(mIsoDep.getId()));
+ }
}
/**
@@ -192,6 +170,19 @@ public class CardProtocol {
}
}
+ /**
+ * Base exception class for exceptions on card reading
+ */
+ public static class TangemException_TagLost extends Exception {
+ public TangemException_TagLost() {
+ super("Tag lost");
+ }
+ public TangemException_TagLost(String message) {
+ super(message);
+ }
+ }
+
+
/**
* Thrown on failed attempt of reading with possible wrong PIN
*/
@@ -240,15 +231,15 @@ public class CardProtocol {
* @return UID byte array
*/
public byte[] GetUID() {
- if (mIsoDep == null || mIsoDep.getTag() == null) return null;
- return mIsoDep.getTag().getId();
+ if (mIsoDep == null ) return null;
+ return mIsoDep.getId();
}
/**
* Return ISO 14443-3 tag reading timeout
*/
public int getTimeout() {
- if (mIsoDep == null || mIsoDep.getTag() == null) return 60000;
+ if (mIsoDep == null ) return 60000;
return mIsoDep.getTimeout();
}
@@ -314,7 +305,7 @@ public class CardProtocol {
try {
if (mIsoDep == null) {
- throw new TagLostException();
+ throw new TangemException_TagLost();
}
byte[] cmdBytes = cmdApdu.toBytes();
String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc());
@@ -368,7 +359,7 @@ public class CardProtocol {
try {
if (mIsoDep == null) {
- throw new TagLostException();
+ throw new TangemException_TagLost();
}
//mIsoDep.setTimeout(msTimeout);
@@ -502,15 +493,15 @@ public class CardProtocol {
return Apdu;
}
- /**
- * Run READ command and parse answer
- * {@see run_Read(boolean parseResult) }
- *
- * @throws Exception if something went wrong
- */
- public void run_Read() throws Exception {
- run_Read(true);
- }
+// /**
+// * Run READ command and parse answer
+// * {@see run_Read(boolean parseResult) }
+// *
+// * @throws Exception if something went wrong
+// */
+// public void run_Read() throws Exception {
+// run_Read(true);
+// }
/**
* Run READ command and parse answer (if specified)
@@ -523,10 +514,9 @@ public class CardProtocol {
* This command requires only PIN1 parameter while other commands also need CID
* See [1] 8, 8.2
*
- * @param parseResult - parse answer into TangemCard object or not
* @throws Exception if something went wrong
*/
- public void run_Read(boolean parseResult) throws Exception {
+ public void run_Read() throws Exception {
CommandApdu rqApdu = StartPrepareCommand(INS.Read);
Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" ")));
@@ -536,15 +526,6 @@ public class CardProtocol {
Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" ")));
readResult = rspApdu.getTLVs();
- if (parseResult) {
- // After first successful read, data will be parsed into TangemCard object
- parseReadResult();
- //TODO: move issuer data out from here
- run_ReadWriteIssuerData();
- } else {
- //TODO: check that card is the same
- }
-
} else if (rspApdu.isStatus(SW_PIN_ERROR)) {
throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible PIN is invalid!\n", rspApdu.getSW1SW2()));
} else {
@@ -553,54 +534,6 @@ public class CardProtocol {
}
- /**
- * Executing GET_ISSUER_DATA or WRITE_ISSUER_DATA depending on state in TangemCard object {@see TangemCard.getNeedWriteIssuerData()}
- * See [1] 8.7
- *
- * @throws Exception if something went wrong
- */
- public void run_ReadWriteIssuerData() throws Exception {
- TLVList tlvIssuerData;
- if (mCard.getNeedWriteIssuerData()) {
- run_WriteIssuerData(mCard.getIssuerData(), mCard.getIssuerDataSignature());
- try {
- tlvIssuerData = TLVList.fromBytes(mCard.getIssuerData());
- } catch (TLVException e) {
- e.printStackTrace();
- tlvIssuerData = null;
- }
- } else {
- try {
- tlvIssuerData = run_GetIssuerData();
- } catch (Exception e) {
- e.printStackTrace();
- tlvIssuerData = null;
- }
- }
-
- // try read offline balance data
- if (mCard.getStatus() == TangemCard.Status.Loaded) {
- if (tlvIssuerData != null && tlvIssuerData.getTLV(TLV.Tag.TAG_ValidatedBalance) != null && mCard.getMaxSignatures() == mCard.getRemainingSignatures()) {
- mCard.setOfflineBalance(tlvIssuerData.getTLV(TLV.Tag.TAG_ValidatedBalance).Value);
- } else {
- mCard.clearOfflineBalance();
- }
- } else {
- mCard.clearOfflineBalance();
- }
-
- // try read denomination
- if (tlvIssuerData != null && tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination) != null) {
- if (tlvIssuerData.getTLV(TLV.Tag.TAG_DenominationText) != null) {
- mCard.setDenomination(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value, tlvIssuerData.getTLV(TLV.Tag.TAG_DenominationText).getAsString());
- } else {
- mCard.setDenomination(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value);
- }
- } else {
- mCard.clearDenomination();
- }
- }
-
/**
* A TLV list containing response of the last READ command
*/
@@ -615,181 +548,12 @@ public class CardProtocol {
return readResult != null;
}
- /**
- * Parse response of the last READ command into TangemCard object
- * See [1] 8.2, 5.3, 3.3
- *
- * @throws TangemException - if something went wrong
- */
- public void parseReadResult() throws TangemException {
- // These tags always present in the parsed response: TAG_Status, TAG_CID, TAG_Manufacture_ID, TAG_Health, TAG_Firmware
- TLV tlvStatus = readResult.getTLV(TLV.Tag.TAG_Status);
- mCard.setStatus(TangemCard.Status.fromCode(Util.byteArrayToInt(tlvStatus.Value)));
- TLV tlvCID = readResult.getTLV(TLV.Tag.TAG_CardID);
- mCard.setCID(tlvCID.Value);
- mCard.setManufacturer(Manufacturer.FindManufacturer(readResult.getTLV(TLV.Tag.TAG_Manufacture_ID).getAsString()), true);
-
- // Support of legacy Firmware
- if (readResult.getTLV(TLV.Tag.TAG_Firmware) != null) {
- mCard.setFirmwareVersion(readResult.getTLV(TLV.Tag.TAG_Firmware).getAsString());
- }
- mCard.setHealth(readResult.getTLV(TLV.Tag.TAG_Health).getAsInt());
-
- // If the card was previously personalized then parse personalized card data - card public key, blockchain data and other settings
- if (mCard.getStatus() != TangemCard.Status.NotPersonalized) {
- try {
- TLV tlvCardPubkicKey = readResult.getTLV(TLV.Tag.TAG_CardPublicKey);
- if (tlvCardPubkicKey == null)
- throw new TangemException("Invalid answer format");
-
- mCard.setCardPublicKey(tlvCardPubkicKey.Value);
-
- TLVList tlvCardData = TLVList.fromBytes(readResult.getTLV(TLV.Tag.TAG_CardData).Value);
-
- mCard.setBatch(tlvCardData.getTLV(TLV.Tag.TAG_Batch).getAsHexString());
-
- TLV tokenSymbol = tlvCardData.getTLV(TLV.Tag.TAG_Token_Symbol);
- TLV contractAddress = tlvCardData.getTLV(TLV.Tag.TAG_Token_Contract_Address);
- TLV tokens_decimal = tlvCardData.getTLV(TLV.Tag.TAG_Token_Decimal);
-
- if (tokenSymbol != null)
- mCard.setTokenSymbol(tokenSymbol.getAsString());
-
- if (contractAddress != null)
- mCard.setContractAddress(contractAddress.getAsString());
-
- if (tokens_decimal != null)
- mCard.setTokensDecimal(tokens_decimal.getAsInt());
-
- byte[] tlvPersonalizationDT = tlvCardData.getTLV(TLV.Tag.TAG_ManufactureDateTime).Value;
- int year = (tlvPersonalizationDT[0] & 0xFF) << 8 | (tlvPersonalizationDT[1] & 0xFF);
- int month = tlvPersonalizationDT[2] - 1;
- int day = tlvPersonalizationDT[3];
- Calendar cd = Calendar.getInstance();
- cd.set(year, month, day, 0, 0, 0);
- mCard.setPersonalizationDateTime(cd.getTime());
- try {
- // Support of legacy Firmware
- if (mCard.getFirmwareVersion() == null) {
- mCard.setFirmwareVersion(tlvCardData.getTLV(TLV.Tag.TAG_Firmware).getAsString());
- }
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(logTag, "Cannot get firmware version");
- mCard.setFirmwareVersion("0.00");
- }
-
- try {
- if (mCard.getFirmwareVersion().compareTo("1.05") < 0) {
- // In FW ver 1.05, the issuer has one key pair used as both DataKey and TransactionKey, see [1] 3.3.1 and [1] 3.3.2
- mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), readResult.getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value);
- } else {
- // In newer FW versions, the issuer has two different key pairs - DataKey and TransactionKey, see [1] 3.3.1 and [1] 3.3.2
- mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), readResult.getTLV(TLV.Tag.TAG_Issuer_Data_PublicKey).Value);
- }
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(logTag, "Cannot get issuer, try a version for older cards");
- try {
- // for very very old cards Issuer key can be stored in different TLV tag
- mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), readResult.getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value);
- } catch (Exception ee) {
- ee.printStackTrace();
- Log.e(logTag, "Cannot get issuer");
- mCard.setIssuer(Issuer.Unknown().getID(), null);
- }
- }
-
- // Overriding of missing card data, e.g. for cards with unknown ERC20 contract data
- // This method must be called after the issuer data is defined because newly written data is verified by issuer data key
- try {
- // Hardcoded for some known batches, or, for other batches, received from Tangem server and stored in local storage
- if (mCard.getBatch().equals("0017")) {
- mCard.setContractAddress("0x9Eef75bA8e81340da9D8d1fd06B2f313DB88839c");
- } else if (mCard.getBatch().equals("0019")) {
- mCard.setContractAddress("0x0c056b0cda0763cc14b8b2d6c02465c91e33ec72");
- } else {
- LocalStorage localStorage = new LocalStorage(mContext);
- localStorage.applySubstitution(mCard);
- }
- } catch (Exception e) {
- Log.e(logTag, "Can't apply card data substitution");
- e.printStackTrace();
- }
-
- mCard.setBlockchainIDFromCard(tlvCardData.getTLV(TLV.Tag.TAG_Blockchain_ID).getAsString());
-
- try {
- mCard.setSettingsMask(readResult.getTagAsInt(TLV.Tag.TAG_SettingsMask));
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(logTag, "Can't get settings mask");
- }
-
- if (readResult.getTLV(TLV.Tag.TAG_PauseBeforePIN2) != null) {
- mCard.setPauseBeforePIN2(10 * readResult.getTagAsInt(TLV.Tag.TAG_PauseBeforePIN2));
- }
-
- try {
- mCard.setSigningMethod(readResult.getTagAsInt(TLV.Tag.TAG_SigningMethod));
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(logTag, "Can't get signing method");
- mCard.setSigningMethod(0);
- }
-
- try {
- mCard.setMaxSignatures(readResult.getTagAsInt(TLV.Tag.TAG_MaxSignatures));
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(logTag, "Can't get max signatures");
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- throw new TangemException("Can't parse card data");
- }
- }
-
-
- // Parse additional parameters for Loaded cards: wallet public key, remaining signatures, etc
- if (mCard.getStatus() == TangemCard.Status.Loaded) {
-
- TLV tlvPublicKey = readResult.getTLV(TLV.Tag.TAG_Wallet_PublicKey);
-
- ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
- ECPoint p1 = spec.getCurve().decodePoint(tlvPublicKey.Value);
-
- byte pkUncompressed[] = p1.getEncoded(false);
-
- byte pkCompresses[] = p1.getEncoded(true);
- mCard.setWalletPublicKey(pkUncompressed);
- mCard.setWalletPublicKeyRar(pkCompresses);
-
- TangemContext ctx = new TangemContext(mCard);
- try {
- // TODO - store in mCard only public key, not wallet address, move wallet address to coinData
- CoinEngine engineCoin = CoinEngineFactory.INSTANCE.create(ctx);
- if (engineCoin == null) throw new Exception("Can't create CoinEngine!");
- String wallet = engineCoin.calculateAddress(pkUncompressed);
- mCard.setWallet(wallet);
- } catch (Exception e) {
- e.printStackTrace();
- throw new TangemException("Can't define wallet address");
- }
- //mCard.setWallet(Blockchain.calculateWalletAddress(mCard, pkUncompressed));
-
- mCard.setRemainingSignatures(readResult.getTagAsInt(TLV.Tag.TAG_RemainingSignatures));
-
- if (readResult != null && readResult.getTLV(TLV.Tag.TAG_SignedHashes) != null) {
- mCard.setSignedHashes(readResult.getTagAsInt(TLV.Tag.TAG_SignedHashes));
- }
-
- } else {
- mCard.setWallet("N/A");
- }
+ public TLVList getReadResult()
+ {
+ return readResult;
}
+
/**
* VERIFY_CARD command and verify card's signature
* By using standard challenge-response scheme, the card proves
@@ -801,7 +565,7 @@ public class CardProtocol {
*/
public TLVList run_VerifyCard() throws Exception {
if (mCard.getCardPublicKey() == null || readResult == null) {
- run_Read();
+ throw new TangemException("Before run_VerifyCard execute run_Read card first!");
}
if (mCard.getStatus() == TangemCard.Status.NotPersonalized) {
getCard().setManufacturer(Manufacturer.Unknown, false);
@@ -869,7 +633,7 @@ public class CardProtocol {
* @throws Exception - if something went wrong
*/
public void run_CreateWallet(String PIN2) throws Exception {
- if (readResult == null) run_Read();
+ if (readResult == null) throw new TangemException("Before run_VerifyCard execute run_Read card first!");
CommandApdu rqApdu = StartPrepareCommand(INS.CreateWallet);
rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2));
Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" ")));
@@ -930,7 +694,7 @@ public class CardProtocol {
*/
public void run_CheckWalletWithSignatureVerify() throws Exception {
if (mCard.getCardPublicKey() == null || readResult == null) {
- run_Read();
+ throw new TangemException("Before run_VerifyCard execute run_Read card first!");
}
if (mCard.getStatus() == TangemCard.Status.NotPersonalized) {
getCard().setManufacturer(Manufacturer.Unknown, false);
@@ -1043,65 +807,49 @@ public class CardProtocol {
}
}
- /**
- * Verify if default PIN2 is set on the card and enable UseDefaultPIN2 flag {@link TangemCard}
- * Works in firmware 1.12 and later, for older version UseDefaultPIN2 is always null
- * This function NEVER triggers security delay
- *
- * @throws Exception - if something went wrong
- */
- public void run_CheckPIN2isDefault() throws Exception {
- // can obtain SetPIN(to default) answer without security delay - try check if PIN2 is default with card request
- if (mCard.isFirmwareNewer("1.19") || (mCard.isFirmwareNewer("1.12") && (mCard.getPauseBeforePIN2() == 0 || mCard.useSmartSecurityDelay()))) {
- try {
- run_SetPIN(DefaultPIN2, mPIN, DefaultPIN2, true);
- mCard.setUseDefaultPIN2(true);
- } catch (TangemException_NeedPause e) {
- mCard.setUseDefaultPIN2(null);
- } catch (TangemException_InvalidPIN e) {
- mCard.setUseDefaultPIN2(false);
- }
- } else {
- mCard.setUseDefaultPIN2(null);
- }
- }
-
/**
* SIGN command to sign hashes - SigningMethod=0,2,4 (see {@link TangemCard.SigningMethod})
* See [1] 8.6
* @param PIN2 - PIN2 code to confirm operation
* @param hashes - array of digests to sign (max 10 digest at a time)
- * @param UseIssuerValidation - if card need issuer validation before sign (true for SigningMethod=2,4)
+ * @param issuerTransactionSignature - signature of hashes, if card need issuer validation before sign (for SigningMethod=2)
* @param issuerData - new issuerData to write on card (only for SigningMethod=4, null for other)
- * @param issuer - issuer (need only for SigningMethod=2,4)
+ * @param issuerDataSignature - signature of issuerData, if issuerData specified(for SigningMethod=4)
* @return TLVList with card answer contained wallet signatures of digests from hashes array (in case of success)
* @throws Exception - if something went wrong
*/
- // TODO - change function to run_SignHashes(String PIN2, byte[][] hashes, byte[] issuerData, byte[] issuerTransactionSignature) because normally issuer signature can be obtained only by external server
- public TLVList run_SignHashes(String PIN2, byte[][] hashes, boolean UseIssuerValidation, byte[] issuerData, Issuer issuer) throws Exception {
+ public TLVList run_SignHashes(String PIN2, byte[][] hashes, byte[] issuerTransactionSignature, byte[] issuerData, byte[] issuerDataSignature) throws Exception {
+ if ( mCard.getSigningMethod()!=TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer && mCard.getSigningMethod()!=TangemCard.SigningMethod.Sign_Hash ){
+ throw new TangemException("Card don't support signing hashes!");
+ }
+
ByteArrayOutputStream bs = new ByteArrayOutputStream();
- if (hashes.length > 10) throw new Exception("To much hashes in one transaction!");
+ if (hashes.length > 10) throw new TangemException("To much hashes in one transaction!");
for (int i = 0; i < hashes.length; i++) {
if (i != 0 && hashes[0].length != hashes[i].length)
- throw new Exception("Hashes length must be identical!");
+ throw new TangemException("Hashes length must be identical!");
bs.write(hashes[i]);
}
CommandApdu rqApdu = StartPrepareCommand(INS.Sign);
rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2));
rqApdu.addTLV_U8(TLV.Tag.TAG_TrOut_HashSize, hashes[0].length);
rqApdu.addTLV(TLV.Tag.TAG_TrOut_Hash, bs.toByteArray());
- if (UseIssuerValidation) {
- byte[] issuerSignature = CardCrypto.Signature(issuer.getPrivateTransactionKey(), bs.toByteArray());
- rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerSignature);
- }
if (issuerData != null) {
- if (issuer == null || issuer == Issuer.Unknown())
- throw new Exception("Need known Issuer to write issuer Data");
- rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data, issuerData);
- byte[] issuerSignature = CardCrypto.Signature(issuer.getPrivateTransactionKey(), issuerData);
- rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data_Signature, issuerSignature);
- }
+ if ( mCard.getSigningMethod()!=TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData )
+ throw new TangemException("Card don't support simultaneous sign with write issuer data!");
+ if (issuerDataSignature == null )
+ throw new TangemException("Card require issuer validation before write issuer data");
+ bs.write(issuerData);
+ rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data, issuerData);
+ rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data_Signature, issuerDataSignature);
+ }
+ if (issuerTransactionSignature!=null) {
+ //byte[] issuerSignature = CardCrypto.Signature(issuer.getPrivateTransactionKey(), bs.toByteArray());
+ rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerTransactionSignature);
+ }else if ( mCard.getSigningMethod()==TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer ){
+ throw new TangemException("Card require issuer validation before sign the transaction!");
+ }
Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" ")));
@@ -1128,19 +876,42 @@ public class CardProtocol {
* SIGN raw tx - SigningMethod=1 (see {@link TangemCard.SigningMethod})
* See [1] 8.6
* @param PIN2 - PIN2 code to confirm operation
+ * @param hashAlgID - name of hash alg, used for signature
* @param bTxOutData - part of raw transaction to sign
+ * @param issuerTransactionSignature - signature of hashes, if card need issuer validation before sign (for SigningMethod=2)
+ * @param issuerData - new issuerData to write on card (only for SigningMethod=4, null for other)
+ * @param issuerDataSignature - signature of issuerData, if issuerData specified(for SigningMethod=4)
* @return TLVList with card answer contained wallet signatures of bTxOutData(in case of success)
* @throws Exception - if something went wrong
*/
- // TODO - change function to run_SignRaw(String PIN2, String hashAlgID, byte[] bTxOutData, byte[] issuerData, byte[] issuerTransactionSignature) to support all signing methods
- public TLVList run_SignRaw(String PIN2, byte[] bTxOutData) throws Exception {
+ public TLVList run_SignRaw(String PIN2, String hashAlgID, byte[] bTxOutData, byte[] issuerTransactionSignature, byte[] issuerData, byte[] issuerDataSignature) throws Exception {
CommandApdu rqApdu = StartPrepareCommand(INS.Sign);
rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2));
rqApdu.addTLV(TLV.Tag.TAG_TrOut_Raw, bTxOutData);
- rqApdu.addTLV(TLV.Tag.TAG_HashAlgID, "sha-256x2".getBytes("US-ASCII"));
+ rqApdu.addTLV(TLV.Tag.TAG_HashAlgID, hashAlgID.getBytes("US-ASCII"));
Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" ")));
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ if (bTxOutData.length > 1024) throw new TangemException("Raw transaction size is to big!");
+ bs.write(bTxOutData);
+
+ if (issuerData != null) {
+ if ( mCard.getSigningMethod()!=TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData )
+ throw new TangemException("Card don't support simultaneous sign with write issuer data!");
+
+ if (issuerDataSignature == null )
+ throw new TangemException("Card require issuer validation before write issuer data");
+ bs.write(issuerData);
+ rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data, issuerData);
+ rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data_Signature, issuerDataSignature);
+ }
+ if (issuerTransactionSignature!=null) {
+ rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerTransactionSignature);
+ }else if ( mCard.getSigningMethod()==TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer ){
+ throw new TangemException("Card require issuer validation before sign the transaction!");
+ }
+
ResponseApdu rspApdu = SendAndReceive(rqApdu, false);
if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) {
@@ -1168,16 +939,16 @@ public class CardProtocol {
* by Tangem. It may contains ~150.000 precalculated hashes of COS binary code segments.
* VERIFY_CODE command internally reads a segment of COS binary code beginning at Code_Page_Address and having length of [64 x Code_Page_Count] bytes.
* Then it appends Challenge to the code segment, calculates resulting hash and returns it in the response.
- * The application needs to ensure that returned hash coincides with the one stored in the hash library (see {@link Firmwares}).
+ * The application needs to ensure that returned hash coincides with the one stored in the hash library (see {@see Firmwares}).
* @param hashAlgID - ‘sha-256’, ‘sha-1’, ‘sha-224’, ‘sha-384’, ‘sha-512’, ‘crc-16’
- * @param codePageAddress - Value from 0 to ~3000, take from {@link Firmwares}
- * @param codePageCount - Number of 32-byte pages to read: from 1 to 5, take from {@link Firmwares}
- * @param challenge - Additional challenge value from 1 to 10, take from {@link Firmwares}
- * @return digest bytes to compare with one stored in {@link Firmwares}
+ * @param codePageAddress - Value from 0 to ~3000, take from {@see Firmwares}
+ * @param codePageCount - Number of 32-byte pages to read: from 1 to 5, take from {@see Firmwares}
+ * @param challenge - Additional challenge value from 1 to 10, take from {@see Firmwares}
+ * @return digest bytes to compare with one stored in {@see Firmwares}
* @throws Exception - if something went wrong
*/
public byte[] run_VerifyCode(String hashAlgID, int codePageAddress, int codePageCount, byte[] challenge) throws Exception {
- if (readResult == null) run_Read();
+ if (readResult == null) throw new TangemException("Before run_VerifyCard execute run_Read card first!");
CommandApdu rqApdu = StartPrepareCommand(INS.VerifyCode);
rqApdu.addTLV(TLV.Tag.TAG_HashAlgID, hashAlgID.getBytes("US-ASCII"));
rqApdu.addTLV_U32(TLV.Tag.TAG_CodePageAddress, codePageAddress);
@@ -1212,7 +983,7 @@ public class CardProtocol {
* @throws Exception - if something went wrong
*/
private void run_ValidateCard(String PIN2) throws Exception {
- if (readResult == null) run_Read();
+ if (readResult == null) throw new TangemException("Before run_VerifyCard execute run_Read card first!");
CommandApdu rqApdu = StartPrepareCommand(INS.ValidateCard);
rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2));
@@ -1244,8 +1015,8 @@ public class CardProtocol {
* @param issuerSignature - signature of issuerData with IssuerDataKey
* @throws Exception - if something went wrong
*/
- private void run_WriteIssuerData(byte[] issuerData, byte[] issuerSignature) throws Exception {
- run_Read();
+ public void run_WriteIssuerData(byte[] issuerData, byte[] issuerSignature) throws Exception {
+ if( readResult==null ) throw new TangemException("Before run_VerifyCard execute run_Read card first!");
CommandApdu rqApdu = StartPrepareCommand(INS.WriteIssuerData);
rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data, issuerData);
@@ -1269,7 +1040,7 @@ public class CardProtocol {
* @return TLVList with issuerData (if success read and verify)
* @throws Exception - if something went wrong
*/
- private TLVList run_GetIssuerData() throws Exception {
+ public TLVList run_GetIssuerData() throws Exception {
CommandApdu rqApdu = StartPrepareCommand(INS.GetIssuerData);
Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" ")));
@@ -1294,7 +1065,7 @@ public class CardProtocol {
bsDataToVerify.write(issuerDataCounter.Value);
}
try {
- if (CardCrypto.VerifySignature(mCard.getIssuer().getPublicDataKey(), bsDataToVerify.toByteArray(), issuerDataSignature.Value)) {
+ if (CardCrypto.VerifySignature(mCard.getIssuerPublicDataKey(), bsDataToVerify.toByteArray(), issuerDataSignature.Value)) {
mCard.setIssuerData(issuerData.Value, issuerDataSignature.Value);
return TLVList.fromBytes(issuerData.Value);
} else {
@@ -1342,4 +1113,5 @@ public class CardProtocol {
} while (true);
}
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/cardReader/CommandApdu.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CommandApdu.java
similarity index 98%
rename from app/src/main/java/com/tangem/domain/cardReader/CommandApdu.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CommandApdu.java
index 0248d65f16..9706a68a35 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/CommandApdu.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/CommandApdu.java
@@ -1,6 +1,6 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
diff --git a/app/src/main/java/com/tangem/domain/cardReader/INS.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/INS.java
similarity index 94%
rename from app/src/main/java/com/tangem/domain/cardReader/INS.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/INS.java
index 0005be0b95..1fb6be61c1 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/INS.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/INS.java
@@ -1,4 +1,4 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
/**
* Created by dvol on 07.03.2018.
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/NfcReader.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/NfcReader.java
new file mode 100644
index 0000000000..8317bdeac7
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/NfcReader.java
@@ -0,0 +1,20 @@
+package com.tangem.tangemcard.reader;
+
+import java.io.IOException;
+
+public interface NfcReader {
+ byte[] getId();
+
+ void setTimeout(int timeout)throws IOException;
+
+ int getTimeout();
+
+ byte[] transceive(byte[] data) throws IOException;
+
+ void ignoreTag() throws IOException;
+
+ void notifyReadResult(boolean success);
+
+ void connect();
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/domain/cardReader/ResponseApdu.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/ResponseApdu.java
similarity index 98%
rename from app/src/main/java/com/tangem/domain/cardReader/ResponseApdu.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/ResponseApdu.java
index c4bddff265..fbc3b00be5 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/ResponseApdu.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/ResponseApdu.java
@@ -1,6 +1,6 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
diff --git a/app/src/main/java/com/tangem/domain/cardReader/SW.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/SW.java
similarity index 97%
rename from app/src/main/java/com/tangem/domain/cardReader/SW.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/SW.java
index cbc25c239a..cd3ef7ee05 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/SW.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/SW.java
@@ -1,4 +1,4 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
/**
* Created by dvol on 07.03.2018.
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/SettingsMask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/SettingsMask.java
new file mode 100644
index 0000000000..d6446b03ac
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/SettingsMask.java
@@ -0,0 +1,67 @@
+package com.tangem.tangemcard.reader;
+
+/**
+ * Created by dvol on 07.03.2018.
+ */
+
+public class SettingsMask {
+ public static final int IsReusable = 0x0001;
+ public static final int UseActivation = 0x0002;
+ public static final int ForbidPurgeWallet = 0x0004;
+ public static final int UseBlock = 0x0008;
+
+ public static final int AllowSwapPIN = 0x0010;
+ public static final int AllowSwapPIN2 = 0x0020;
+ public static final int UseCVC = 0x0040;
+ public static final int ForbidDefaultPIN = 0x0080;
+
+ public static final int UseOneCommandAtTime = 0x0100;
+ public static final int UseNDEF = 0x0200;
+ public static final int UseDynamicNDEF = 0x0400;
+ public static final int SmartSecurityDelay = 0x0800;
+
+ public static final int Protocol_AllowUnencrypted = 0x1000;
+ public static final int Protocol_AllowStaticEncryption = 0x2000;
+
+ public static final int ProtectIssuerDataAgainstReplay = 0x4000;
+
+ public static final int AllowSelectBlockchain = 0x8000;
+
+ public static final int DisablePrecomputedNDEF = 0x00010000;
+
+ public static String getDescription(int iValue) {
+ StringBuilder sb=new StringBuilder();
+ sb.append("[");
+ if ((iValue & SettingsMask.AllowSwapPIN) != 0) sb.append("AllowSwapPIN, ");
+ if ((iValue & SettingsMask.AllowSwapPIN2) != 0)
+ sb.append("AllowSwapPIN2, ");
+ if ((iValue & SettingsMask.ForbidDefaultPIN) != 0)
+ sb.append("ForbidDefaultPIN, ");
+ if ((iValue & SettingsMask.IsReusable) != 0) sb.append("IsReusable, ");
+ if ((iValue & SettingsMask.Protocol_AllowStaticEncryption) != 0)
+ sb.append("Protocol_AllowStaticEncryption, ");
+ if ((iValue & SettingsMask.Protocol_AllowUnencrypted) != 0)
+ sb.append("Protocol_AllowUnencrypted, ");
+ if ((iValue & SettingsMask.SmartSecurityDelay) != 0)
+ sb.append("SmartSecurityDelay, ");
+ if ((iValue & SettingsMask.UseActivation) != 0)
+ sb.append("UseActivation, ");
+ if ((iValue & SettingsMask.UseBlock) != 0) sb.append("UseBlock, ");
+ if ((iValue & SettingsMask.UseCVC) != 0) sb.append("UseCVC, ");
+ if ((iValue & SettingsMask.UseDynamicNDEF) != 0)
+ sb.append("UseDynamicNDEF, ");
+ if ((iValue & SettingsMask.UseNDEF) != 0) sb.append("UseNDEF, ");
+ if ((iValue & SettingsMask.UseOneCommandAtTime) != 0)
+ sb.append("UseOneCommandAtTime, ");
+ if ((iValue & SettingsMask.ProtectIssuerDataAgainstReplay) != 0)
+ sb.append("ProtectIssuerDataAgainstReplay, ");
+ if ((iValue & SettingsMask.ForbidPurgeWallet) != 0) sb.append("ForbidPurgeWallet, ");
+ if ((iValue & SettingsMask.AllowSelectBlockchain) != 0) sb.append("AllowSelectBlockchain, ");
+ if ((iValue & SettingsMask.DisablePrecomputedNDEF) != 0) sb.append("DisablePrecomputedNDEF, ");
+
+ if (sb.length() > 1) sb.delete(sb.length() - 2, sb.length());
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
diff --git a/app/src/main/java/com/tangem/domain/cardReader/TLV.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLV.java
similarity index 77%
rename from app/src/main/java/com/tangem/domain/cardReader/TLV.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLV.java
index a94a7856e7..58d32f4ddd 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/TLV.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLV.java
@@ -1,6 +1,6 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -215,34 +215,7 @@ public class TLV {
if( Value!=null ) {
try {
int iValue = Util.byteArrayToInt(Value);
- sb.append("[");
- if ((iValue & SettingsMask.AllowSwapPIN) != 0) sb.append("AllowSwapPIN, ");
- if ((iValue & SettingsMask.AllowSwapPIN2) != 0)
- sb.append("AllowSwapPIN2, ");
- if ((iValue & SettingsMask.ForbidDefaultPIN) != 0)
- sb.append("ForbidDefaultPIN, ");
- if ((iValue & SettingsMask.IsReusable) != 0) sb.append("IsReusable, ");
- if ((iValue & SettingsMask.Protocol_AllowStaticEncryption) != 0)
- sb.append("Protocol_AllowStaticEncryption, ");
- if ((iValue & SettingsMask.Protocol_AllowUnencrypted) != 0)
- sb.append("Protocol_AllowUnencrypted, ");
- if ((iValue & SettingsMask.SmartSecurityDelay) != 0)
- sb.append("SmartSecurityDelay, ");
- if ((iValue & SettingsMask.UseActivation) != 0)
- sb.append("UseActivation, ");
- if ((iValue & SettingsMask.UseBlock) != 0) sb.append("UseBlock, ");
- if ((iValue & SettingsMask.UseCVC) != 0) sb.append("UseCVC, ");
- if ((iValue & SettingsMask.UseDynamicNDEF) != 0)
- sb.append("UseDynamicNDEF, ");
- if ((iValue & SettingsMask.UseNDEF) != 0) sb.append("UseNDEF, ");
- if ((iValue & SettingsMask.UseOneCommandAtTime) != 0)
- sb.append("UseOneCommandAtTime, ");
- if ((iValue & SettingsMask.ProtectIssuerDataAgainstReplay) != 0)
- sb.append("ProtectIssuerDataAgainstReplay, ");
-
- if (sb.length() > 1) sb.delete(sb.length() - 2, sb.length());
- sb.append("]");
- return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), sb.toString());
+ return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), SettingsMask.getDescription(iValue));
}
catch (Exception e)
{
diff --git a/app/src/main/java/com/tangem/domain/cardReader/TLVException.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLVException.java
similarity index 90%
rename from app/src/main/java/com/tangem/domain/cardReader/TLVException.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLVException.java
index 6d69e73855..9b1a4eb3c8 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/TLVException.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLVException.java
@@ -1,4 +1,4 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
public class TLVException extends Exception {
diff --git a/app/src/main/java/com/tangem/domain/cardReader/TLVList.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLVList.java
similarity index 91%
rename from app/src/main/java/com/tangem/domain/cardReader/TLVList.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLVList.java
index fd320ac41a..f26e9066dd 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/TLVList.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/reader/TLVList.java
@@ -1,12 +1,10 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.reader;
/**
* Created by dvol on 23.06.2017.
*/
-import android.support.annotation.NonNull;
-
-import com.tangem.util.Util;
+import com.tangem.tangemcard.util.Util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -27,7 +25,7 @@ public class TLVList extends ArrayList {
super();
}
- public TLVList(@NonNull Collection extends TLV> c) {
+ public TLVList(Collection extends TLV> c) {
super(c);
}
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/CreateNewWalletTask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/CreateNewWalletTask.java
new file mode 100644
index 0000000000..d1b0f9fbfb
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/CreateNewWalletTask.java
@@ -0,0 +1,35 @@
+package com.tangem.tangemcard.tasks;
+
+
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.reader.NfcReader;
+import com.tangem.tangemcard.util.Log;
+
+public class CreateNewWalletTask extends CustomReadCardTask {
+ public static final String TAG = CreateNewWalletTask.class.getSimpleName();
+
+ public CreateNewWalletTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications) {
+ super(card, reader, cardDataSubstitutionProvider, pinsProvider, notifications);
+ }
+
+ @Override
+ public void run_Task() throws Exception {
+ mNotifications.onReadProgress(protocol, 20);
+ protocol.run_VerifyCard();
+
+ Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
+
+ mNotifications.onReadProgress(protocol, 30);
+ if (isCancelled) return;
+ protocol.run_CreateWallet(pinsProvider.getPIN2());
+ mNotifications.onReadProgress(protocol, 60);
+ if (isCancelled) return;
+
+ protocol.run_Read();
+ parseReadResult();
+ }
+
+}
\ No newline at end of file
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/CustomReadCardTask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/CustomReadCardTask.java
new file mode 100644
index 0000000000..e807ed2f74
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/CustomReadCardTask.java
@@ -0,0 +1,437 @@
+package com.tangem.tangemcard.tasks;
+
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
+import com.tangem.tangemcard.data.Manufacturer;
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.reader.NfcReader;
+import com.tangem.tangemcard.reader.TLV;
+import com.tangem.tangemcard.reader.TLVException;
+import com.tangem.tangemcard.reader.TLVList;
+import com.tangem.tangemcard.util.Log;
+import com.tangem.tangemcard.util.Util;
+
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.math.ec.ECPoint;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+
+/**
+ * Base class for card communication task
+ */
+public class CustomReadCardTask extends Thread {
+ public static final String TAG = CustomReadCardTask.class.getSimpleName();
+
+ protected NfcReader mIsoDep;
+ protected CardProtocol.Notifications mNotifications;
+ protected boolean isCancelled = false;
+ protected TangemCard mCard ;
+ CardDataSubstitutionProvider localStorage;
+ PINsProvider pinsProvider;
+ CardProtocol protocol;
+
+ // this fields are static to optimize process when need enter pin and scan card again
+ private static ArrayList lastRead_UnsuccessfullPINs = new ArrayList<>();
+ private static TangemCard.EncryptionMode lastRead_Encryption = null;
+ private static String lastRead_UID;
+
+ public static void resetLastReadInfo() {
+ lastRead_UID = "";
+ lastRead_Encryption = null;
+ lastRead_UnsuccessfullPINs.clear();
+ }
+
+ public CustomReadCardTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications) {
+ mIsoDep = reader;
+ mNotifications = notifications;
+ localStorage= cardDataSubstitutionProvider;
+ this.pinsProvider=pinsProvider;
+ mCard=card;
+ }
+
+ /**
+ * Executing GET_ISSUER_DATA or WRITE_ISSUER_DATA depending on state in TangemCard object {@see TangemCard.getNeedWriteIssuerData()}
+ * See [1] 8.7
+ * Usually this function must be called if run_Task() of descendants
+ *
+ * @throws Exception if something went wrong
+ */
+ protected void run_ReadOrWriteIssuerData() throws Exception {
+ TLVList tlvIssuerData;
+ if (mCard.getNeedWriteIssuerData()) {
+ protocol.run_WriteIssuerData(mCard.getIssuerData(), mCard.getIssuerDataSignature());
+ try {
+ tlvIssuerData = TLVList.fromBytes(mCard.getIssuerData());
+ } catch (TLVException e) {
+ e.printStackTrace();
+ tlvIssuerData = null;
+ }
+ } else {
+ try {
+ tlvIssuerData = protocol.run_GetIssuerData();
+ } catch (Exception e) {
+ e.printStackTrace();
+ tlvIssuerData = null;
+ }
+ }
+
+ // try read offline balance data
+ if (mCard.getStatus() == TangemCard.Status.Loaded) {
+ if (tlvIssuerData != null && tlvIssuerData.getTLV(TLV.Tag.TAG_ValidatedBalance) != null && mCard.getMaxSignatures() == mCard.getRemainingSignatures()) {
+ mCard.setOfflineBalance(tlvIssuerData.getTLV(TLV.Tag.TAG_ValidatedBalance).Value);
+ } else {
+ mCard.clearOfflineBalance();
+ }
+ } else {
+ mCard.clearOfflineBalance();
+ }
+
+ // try read denomination
+ if (tlvIssuerData != null && tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination) != null) {
+ if (tlvIssuerData.getTLV(TLV.Tag.TAG_DenominationText) != null) {
+ mCard.setDenomination(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value, tlvIssuerData.getTLV(TLV.Tag.TAG_DenominationText).getAsString());
+ } else {
+ mCard.setDenomination(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value, null);
+ }
+ } else {
+ mCard.clearDenomination();
+ }
+ }
+
+ /**
+ * Parse response of the last READ command into TangemCard object
+ * See [1] 8.2, 5.3, 3.3
+ *
+ * @throws CardProtocol.TangemException - if something went wrong
+ */
+ public void parseReadResult() throws CardProtocol.TangemException {
+ if( mCard==null ) mCard=protocol.getCard();
+ // These tags always present in the parsed response: TAG_Status, TAG_CID, TAG_Manufacture_ID, TAG_Health, TAG_Firmware
+ TLV tlvStatus = protocol.getReadResult().getTLV(TLV.Tag.TAG_Status);
+ mCard.setStatus(TangemCard.Status.fromCode(Util.byteArrayToInt(tlvStatus.Value)));
+ TLV tlvCID = protocol.getReadResult().getTLV(TLV.Tag.TAG_CardID);
+ mCard.setCID(tlvCID.Value);
+ mCard.setManufacturer(Manufacturer.FindManufacturer(protocol.getReadResult().getTLV(TLV.Tag.TAG_Manufacture_ID).getAsString()), true);
+
+ // Support of legacy Firmware
+ if (protocol.getReadResult().getTLV(TLV.Tag.TAG_Firmware) != null) {
+ mCard.setFirmwareVersion(protocol.getReadResult().getTLV(TLV.Tag.TAG_Firmware).getAsString());
+ }
+ mCard.setHealth(protocol.getReadResult().getTLV(TLV.Tag.TAG_Health).getAsInt());
+
+ // If the card was previously personalized then parse personalized card data - card public key, blockchain data and other settings
+ if (mCard.getStatus() != TangemCard.Status.NotPersonalized) {
+ try {
+ TLV tlvCardPubkicKey = protocol.getReadResult().getTLV(TLV.Tag.TAG_CardPublicKey);
+ if (tlvCardPubkicKey == null)
+ throw new CardProtocol.TangemException("Invalid answer format");
+
+ mCard.setCardPublicKey(tlvCardPubkicKey.Value);
+
+ TLVList tlvCardData = TLVList.fromBytes(protocol.getReadResult().getTLV(TLV.Tag.TAG_CardData).Value);
+
+ mCard.setBatch(tlvCardData.getTLV(TLV.Tag.TAG_Batch).getAsHexString());
+
+ TLV tokenSymbol = tlvCardData.getTLV(TLV.Tag.TAG_Token_Symbol);
+ TLV contractAddress = tlvCardData.getTLV(TLV.Tag.TAG_Token_Contract_Address);
+ TLV tokens_decimal = tlvCardData.getTLV(TLV.Tag.TAG_Token_Decimal);
+
+ if (tokenSymbol != null)
+ mCard.setTokenSymbol(tokenSymbol.getAsString());
+
+ if (contractAddress != null)
+ mCard.setContractAddress(contractAddress.getAsString());
+
+ if (tokens_decimal != null)
+ mCard.setTokensDecimal(tokens_decimal.getAsInt());
+
+ byte[] tlvPersonalizationDT = tlvCardData.getTLV(TLV.Tag.TAG_ManufactureDateTime).Value;
+ int year = (tlvPersonalizationDT[0] & 0xFF) << 8 | (tlvPersonalizationDT[1] & 0xFF);
+ int month = tlvPersonalizationDT[2] - 1;
+ int day = tlvPersonalizationDT[3];
+ Calendar cd = Calendar.getInstance();
+ cd.set(year, month, day, 0, 0, 0);
+ mCard.setPersonalizationDateTime(cd.getTime());
+ try {
+ // Support of legacy Firmware
+ if (mCard.getFirmwareVersion() == null) {
+ mCard.setFirmwareVersion(tlvCardData.getTLV(TLV.Tag.TAG_Firmware).getAsString());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "Cannot get firmware version");
+ mCard.setFirmwareVersion("0.00");
+ }
+
+ try {
+ if (mCard.getFirmwareVersion().compareTo("1.05") < 0) {
+ // In FW ver 1.05, the issuer has one key pair used as both DataKey and TransactionKey, see [1] 3.3.1 and [1] 3.3.2
+ //mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), protocol.getReadResult().getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value);
+ mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), protocol.getReadResult().getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value);
+ } else {
+ // In newer FW versions, the issuer has two different key pairs - DataKey and TransactionKey, see [1] 3.3.1 and [1] 3.3.2
+ mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), protocol.getReadResult().getTLV(TLV.Tag.TAG_Issuer_Data_PublicKey).Value);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "Cannot get issuer, try a version for older cards");
+ try {
+ // for very very old cards Issuer key can be stored in different TLV tag
+ mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), protocol.getReadResult().getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value);
+ } catch (Exception ee) {
+ ee.printStackTrace();
+ Log.e(TAG, "Cannot get issuer");
+ mCard.setIssuer("Unknown", null);
+ }
+ }
+
+ // Overriding of missing card data, e.g. for cards with unknown ERC20 contract data
+ // This method must be called after the issuer data is defined because newly written data is verified by issuer data key
+ try {
+ // Hardcoded for some known batches, or, for other batches, received from Tangem server and stored in local storage
+ if (mCard.getBatch().equals("0017")) {
+ mCard.setContractAddress("0x9Eef75bA8e81340da9D8d1fd06B2f313DB88839c");
+ } else if (mCard.getBatch().equals("0019")) {
+ mCard.setContractAddress("0x0c056b0cda0763cc14b8b2d6c02465c91e33ec72");
+ } else {
+ //CardDataSubstitutionProvider localStorage = new CardDataSubstitutionProvider(mContext);
+ if( localStorage!=null ) localStorage.applySubstitution(mCard);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Can't apply card data substitution");
+ e.printStackTrace();
+ }
+
+ mCard.setBlockchainID(tlvCardData.getTLV(TLV.Tag.TAG_Blockchain_ID).getAsString());
+
+ try {
+ mCard.setSettingsMask(protocol.getReadResult().getTagAsInt(TLV.Tag.TAG_SettingsMask));
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "Can't get settings mask");
+ }
+
+ if (protocol.getReadResult().getTLV(TLV.Tag.TAG_PauseBeforePIN2) != null) {
+ mCard.setPauseBeforePIN2(10 * protocol.getReadResult().getTagAsInt(TLV.Tag.TAG_PauseBeforePIN2));
+ }
+
+ try {
+ mCard.setSigningMethod(protocol.getReadResult().getTagAsInt(TLV.Tag.TAG_SigningMethod));
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "Can't get signing method");
+ mCard.setSigningMethod(0);
+ }
+
+ try {
+ mCard.setMaxSignatures(protocol.getReadResult().getTagAsInt(TLV.Tag.TAG_MaxSignatures));
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "Can't get max signatures");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new CardProtocol.TangemException("Can't parse card data");
+ }
+ }
+
+
+ // Parse additional parameters for Loaded cards: wallet public key, remaining signatures, etc
+ if (mCard.getStatus() == TangemCard.Status.Loaded) {
+
+ TLV tlvPublicKey = protocol.getReadResult().getTLV(TLV.Tag.TAG_Wallet_PublicKey);
+
+ ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
+ ECPoint p1 = spec.getCurve().decodePoint(tlvPublicKey.Value);
+
+ byte pkUncompressed[] = p1.getEncoded(false);
+
+ byte pkCompresses[] = p1.getEncoded(true);
+ mCard.setWalletPublicKey(pkUncompressed);
+ mCard.setWalletPublicKeyRar(pkCompresses);
+
+ mCard.setRemainingSignatures(protocol.getReadResult().getTagAsInt(TLV.Tag.TAG_RemainingSignatures));
+
+ if (protocol.getReadResult() != null && protocol.getReadResult().getTLV(TLV.Tag.TAG_SignedHashes) != null) {
+ mCard.setSignedHashes(protocol.getReadResult().getTagAsInt(TLV.Tag.TAG_SignedHashes));
+ }
+
+ } else {
+// mCard.setWallet("N/A");
+ }
+ }
+
+
+ /**
+ * On first time card reading run READ command, parse answer and Executing GET_ISSUER_DATA or WRITE_ISSUER_DATA depending on state in TangemCard object {@see TangemCard.getNeedWriteIssuerData()}
+ * See [1] 8.7
+ *
+ * @throws Exception if something went wrong
+ */
+ public void run_FirstTimeRead() throws Exception {
+
+
+ byte[] UID = mIsoDep.getId();
+ String sUID = Util.byteArrayToHexString(UID);
+ if (!lastRead_UID.equals(sUID)) {
+ resetLastReadInfo();
+ }
+
+ Log.i(TAG, "[-- Start read card info --]");
+
+ if (isCancelled) return;
+
+ protocol.setPIN(CardProtocol.DefaultPIN);
+ protocol.clearReadResult();
+
+ if (lastRead_Encryption == null) {
+ Log.i(TAG, "Try get supported encryption mode");
+ protocol.run_GetSupportedEncryption();
+ } else {
+ Log.i(TAG, "Use already defined encryption mode: " + lastRead_Encryption.name());
+ protocol.getCard().encryptionMode = lastRead_Encryption;
+ }
+
+ if (protocol.haveReadResult()) {
+ //already have read result (obtained while get supported encryption), only read issuer data and define offline balance
+ parseReadResult();
+ pinsProvider.setLastUsedPIN(protocol.getCard().getPIN());
+ } else {
+ //don't have read result - may be don't get supported encryption on this try, need encryption or need another PIN
+ if (lastRead_Encryption == null) {
+ // we try get supported encryption on this time
+ lastRead_Encryption = protocol.getCard().encryptionMode;
+ if (protocol.getCard().encryptionMode == TangemCard.EncryptionMode.None) {
+ // default pin not accepted
+ lastRead_UnsuccessfullPINs.add(CardProtocol.DefaultPIN);
+ }
+ }
+
+ boolean pinFound = false;
+ for (String PIN : pinsProvider.getPINs()) {
+ Log.e(TAG, "PIN: " + PIN);
+
+ boolean skipPin = false;
+ for (int i = 0; i < lastRead_UnsuccessfullPINs.size(); i++) {
+ if (lastRead_UnsuccessfullPINs.get(i).equals(PIN)) {
+ skipPin = true;
+ break;
+ }
+ }
+
+ if (skipPin) {
+ Log.e(TAG, "Skip PIN - already checked before");
+ continue;
+ }
+
+ try {
+ protocol.setPIN(PIN);
+ if (protocol.getCard().encryptionMode != TangemCard.EncryptionMode.None) {
+ protocol.CreateProtocolKey();
+ }
+ protocol.run_Read();
+ // After first successful read, data will be parsed into TangemCard object
+ parseReadResult();
+
+ pinsProvider.setLastUsedPIN(PIN);
+ pinFound = true;
+ protocol.getCard().setPIN(PIN);
+ break;
+ } catch (CardProtocol.TangemException_InvalidPIN e) {
+ Log.e(TAG, e.getMessage());
+ lastRead_UnsuccessfullPINs.add(PIN);
+ }
+ }
+ if (!pinFound) {
+ throw new CardProtocol.TangemException_InvalidPIN("No valid PIN found!");
+ }
+ }
+ }
+
+ /**
+ * Run read and check that the card is the same
+ *
+ * @throws Exception if something went wrong
+ */
+ public void run_SecondTimeRead() throws Exception {
+ String PIN = mCard.getPIN();
+ protocol.setPIN(PIN);
+ protocol.run_Read();
+ pinsProvider.setLastUsedPIN(PIN);
+ if (!Arrays.equals(mCard.getCID(),protocol.getReadResult().getTLV(TLV.Tag.TAG_CardID).Value)) {
+ throw new CardProtocol.TangemException("Card must be the same. Reading attempt on different card!");
+ }
+ }
+
+ /**
+ * This function must be override in descendants to arrive the task goal - sign, verify and etc
+ * @throws Exception if something went wrong
+ */
+ public void run_Task() throws Exception {
+
+ }
+
+ @Override
+ public void run() {
+ if (mIsoDep == null) {
+ return;
+ }
+ try {
+ // for Samsung's bugs -
+ // Workaround for the Samsung Galaxy S5 (since the
+ // first connection always hangs on transceive).
+
+ mIsoDep.connect();
+ try {
+ protocol = new CardProtocol(mIsoDep, mCard, mNotifications);
+ mNotifications.onReadStart(protocol);
+ try {
+ Log.i(TAG, String.format("[-- Start task -- %s --]", getClass().getSimpleName()));
+ mNotifications.onReadProgress(protocol, 5);
+ if (mCard == null) {
+ // first time reading
+ run_FirstTimeRead();
+ } else {
+ run_SecondTimeRead();
+ }
+ run_Task();
+ mNotifications.onReadProgress(protocol, 100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ protocol.setError(e);
+
+ } finally {
+ Log.i(TAG, String.format("[-- Finish task -- %s --]", getClass().getSimpleName()));
+ mNotifications.onReadFinish(protocol);
+ }
+ } finally {
+ mIsoDep.ignoreTag();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ mIsoDep.notifyReadResult(false);
+ }
+ }
+
+ public void cancel(Boolean AllowInterrupt) {
+ try {
+ if (isAlive()) {
+ isCancelled = true;
+ join(500);
+ }
+ if (isAlive() && AllowInterrupt) {
+ interrupt();
+ mNotifications.onReadCancel();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+}
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/PurgeTask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/PurgeTask.java
new file mode 100644
index 0000000000..b174bc3160
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/PurgeTask.java
@@ -0,0 +1,27 @@
+package com.tangem.tangemcard.tasks;
+
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.reader.NfcReader;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
+
+public class PurgeTask extends CustomReadCardTask {
+ public static final String TAG = PurgeTask.class.getSimpleName();
+
+ public PurgeTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications) {
+ super(card, reader, cardDataSubstitutionProvider, pinsProvider, notifications);
+ }
+
+ @Override
+ public void run_Task() throws Exception {
+ if (mCard.getPauseBeforePIN2() > 0) {
+ mNotifications.onReadWait(mCard.getPauseBeforePIN2());
+ }
+ protocol.run_PurgeWallet(pinsProvider.getPIN2());
+ mNotifications.onReadProgress(protocol, 50);
+ protocol.run_Read();
+ mNotifications.onReadProgress(protocol, 100);
+
+ }
+}
\ No newline at end of file
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/ReadCardInfoTask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/ReadCardInfoTask.java
new file mode 100644
index 0000000000..791b7b2a99
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/ReadCardInfoTask.java
@@ -0,0 +1,48 @@
+package com.tangem.tangemcard.tasks;
+
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.reader.NfcReader;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.data.TangemCard;
+
+public class ReadCardInfoTask extends CustomReadCardTask {
+ public static final String TAG = ReadCardInfoTask.class.getSimpleName();
+
+ public ReadCardInfoTask(NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications) {
+ super(null, reader, cardDataSubstitutionProvider, pinsProvider, notifications);
+ }
+
+ /**
+ * Verify if default PIN2 is set on the card and enable UseDefaultPIN2 flag {@link TangemCard}
+ * Works in firmware 1.12 and later, for older version UseDefaultPIN2 is always null
+ * This function NEVER triggers security delay
+ *
+ * @throws Exception - if something went wrong
+ */
+ private void run_CheckPIN2isDefault() throws Exception {
+ // can obtain SetPIN(to default) answer without security delay - try check if PIN2 is default with card request
+ if (mCard.isFirmwareNewer("1.19") || (mCard.isFirmwareNewer("1.12") && (mCard.getPauseBeforePIN2() == 0 || mCard.useSmartSecurityDelay()))) {
+ try {
+ protocol.run_SetPIN(CardProtocol.DefaultPIN2, mCard.getPIN(), CardProtocol.DefaultPIN2, true);
+ mCard.setUseDefaultPIN2(true);
+ } catch (CardProtocol.TangemException_NeedPause e) {
+ mCard.setUseDefaultPIN2(null);
+ } catch (CardProtocol.TangemException_InvalidPIN e) {
+ mCard.setUseDefaultPIN2(false);
+ }
+ } else {
+ mCard.setUseDefaultPIN2(null);
+ }
+ }
+
+ @Override
+ public void run_Task() throws Exception {
+ mNotifications.onReadProgress(protocol, 20);
+ run_ReadOrWriteIssuerData();
+ mNotifications.onReadProgress(protocol, 50);
+ run_CheckPIN2isDefault();
+ mNotifications.onReadProgress(protocol, 90);
+ }
+
+}
\ No newline at end of file
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/SignTask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/SignTask.java
new file mode 100644
index 0000000000..512aa917e3
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/SignTask.java
@@ -0,0 +1,91 @@
+package com.tangem.tangemcard.tasks;
+
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.reader.NfcReader;
+import com.tangem.tangemcard.reader.TLV;
+import com.tangem.tangemcard.reader.TLVList;
+import com.tangem.tangemcard.util.Log;
+
+import java.io.ByteArrayOutputStream;
+
+public class SignTask extends CustomReadCardTask {
+ public static final String TAG = SignTask.class.getSimpleName();
+
+ /**
+ * Payment Engine request/notifications during sign process
+ */
+ public interface PaymentToSign {
+ boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod);
+
+ byte[][] getHashesToSign() throws Exception;
+
+ byte[] getRawDataToSign() throws Exception;
+
+ String getHashAlgToSign() throws Exception;
+
+ byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception;
+
+ byte[] onSignCompleted(byte[] signature) throws Exception;
+ }
+
+ private PaymentToSign paymentToSign;
+
+ public SignTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications, PaymentToSign paymentToSign) {
+ super(card, reader, cardDataSubstitutionProvider, pinsProvider, notifications);
+ this.paymentToSign = paymentToSign;
+ }
+
+ @Override
+ public void run_Task() throws Exception {
+ protocol.run_VerifyCard();
+
+ Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
+
+ mNotifications.onReadProgress(protocol, 30);
+ if (isCancelled) return;
+
+ if (mCard.getPauseBeforePIN2() > 0) {
+ mNotifications.onReadWait(mCard.getPauseBeforePIN2());
+ }
+
+ if (!paymentToSign.isSigningMethodSupported(mCard.getSigningMethod())) {
+ throw new CardProtocol.TangemException("Signing method isn't supported!");
+ }
+
+ TLVList signResult;
+ switch (mCard.getSigningMethod()) {
+ case Sign_Hash:
+ signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), paymentToSign.getHashesToSign(), null, null, null);
+ break;
+ case Sign_Hash_Validated_By_Issuer:
+ case Sign_Hash_Validated_By_Issuer_And_WriteIssuerData:
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ byte[][] hashes = paymentToSign.getHashesToSign();
+ if (hashes.length > 10) throw new CardProtocol.TangemException("To much hashes in one transaction!");
+ for (int i = 0; i < hashes.length; i++) {
+ if (i != 0 && hashes[0].length != hashes[i].length)
+ throw new CardProtocol.TangemException("Hashes length must be identical!");
+ bs.write(hashes[i]);
+ }
+ signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), hashes, paymentToSign.getIssuerTransactionSignature(bs.toByteArray()), null, null);
+ break;
+ case Sign_Raw:
+ signResult = protocol.run_SignRaw(pinsProvider.getPIN2(), paymentToSign.getHashAlgToSign(), paymentToSign.getRawDataToSign(), null, null, null);
+ break;
+ case Sign_Raw_Validated_By_Issuer:
+ case Sign_Raw_Validated_By_Issuer_And_WriteIssuerData:
+ byte[] txOut = paymentToSign.getRawDataToSign();
+ signResult = protocol.run_SignRaw(pinsProvider.getPIN2(), paymentToSign.getHashAlgToSign(), txOut, paymentToSign.getIssuerTransactionSignature(txOut), null, null);
+ break;
+ default:
+ throw new CardProtocol.TangemException("Signing method isn't supported!");
+ }
+
+ paymentToSign.onSignCompleted(signResult.getTLV(TLV.Tag.TAG_Signature).Value);
+ mNotifications.onReadProgress(protocol, 100);
+
+ }
+}
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/SwapPINTask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/SwapPINTask.java
new file mode 100644
index 0000000000..342d67fb64
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/SwapPINTask.java
@@ -0,0 +1,40 @@
+package com.tangem.tangemcard.tasks;
+
+
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.reader.NfcReader;
+
+public class SwapPINTask extends CustomReadCardTask {
+ public static final String TAG = SwapPINTask.class.getSimpleName();
+
+ private String newPIN, newPIN2;
+
+ public SwapPINTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications, String newPIN, String newPIN2) {
+ super(card, reader, cardDataSubstitutionProvider, pinsProvider, notifications);
+ this.newPIN = newPIN;
+ this.newPIN2 = newPIN2;
+ }
+
+ @Override
+ public void run_Task() throws Exception {
+
+ if (mCard.getPauseBeforePIN2() > 0) {
+ mNotifications.onReadWait(mCard.getPauseBeforePIN2());
+ }
+
+ protocol.run_SetPIN(pinsProvider.getPIN2(), newPIN, newPIN2, false);
+ protocol.setPIN(newPIN);
+ mCard.setPIN(newPIN);
+
+ mNotifications.onReadProgress(protocol, 50);
+
+ protocol.run_Read();
+
+ mNotifications.onReadProgress(protocol, 100);
+
+ }
+
+}
\ No newline at end of file
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/VerifyCardTask.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/VerifyCardTask.java
new file mode 100644
index 0000000000..11ba76c657
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/tasks/VerifyCardTask.java
@@ -0,0 +1,51 @@
+package com.tangem.tangemcard.tasks;
+
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
+import com.tangem.tangemcard.data.external.FirmwaresDigestsProvider;
+import com.tangem.tangemcard.data.external.PINsProvider;
+import com.tangem.tangemcard.reader.CardProtocol;
+import com.tangem.tangemcard.reader.NfcReader;
+import com.tangem.tangemcard.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * Created by dvol on 04.02.2018.
+ */
+
+public class VerifyCardTask extends CustomReadCardTask {
+ public static final String TAG = VerifyCardTask.class.getSimpleName();
+
+ private FirmwaresDigestsProvider firmwaresDigestsProvider;
+ public VerifyCardTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, FirmwaresDigestsProvider firmwaresDigestsProvider, CardProtocol.Notifications notifications) {
+ super(card, reader, cardDataSubstitutionProvider, pinsProvider, notifications);
+ this.firmwaresDigestsProvider=firmwaresDigestsProvider;
+ }
+
+ @Override
+ public void run_Task() throws Exception {
+ mNotifications.onReadProgress(protocol, 20);
+ if (isCancelled) return;
+ protocol.run_VerifyCard();
+ mNotifications.onReadProgress(protocol, 50);
+ Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
+ if (isCancelled) return;
+ if (protocol.getCard().getStatus() == TangemCard.Status.Loaded) {
+ protocol.run_CheckWalletWithSignatureVerify();
+ mNotifications.onReadProgress(protocol, 80);
+ }
+ if (isCancelled) return;
+ FirmwaresDigestsProvider.VerifyCodeRecord record = firmwaresDigestsProvider.selectRandomVerifyCodeBlock(mCard.getFirmwareVersion());
+ if (isCancelled) return;
+ if (record != null) {
+ byte[] returnedDigest = protocol.run_VerifyCode(record.hashAlg, record.blockIndex, record.blockCount, record.challenge);
+ mCard.setCodeConfirmed(Arrays.equals(returnedDigest, record.digest));
+ } else {
+ mCard.setCodeConfirmed(null);
+ }
+ mNotifications.onReadProgress(protocol, 90);
+
+ }
+
+}
\ No newline at end of file
diff --git a/tangemcard-common/src/main/java/com/tangem/tangemcard/util/Log.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/util/Log.java
new file mode 100644
index 0000000000..c10ff8e768
--- /dev/null
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/util/Log.java
@@ -0,0 +1,13 @@
+package com.tangem.tangemcard.util;
+
+public class Log {
+ public static void i(String logTag, String message) {
+
+ }
+ public static void e(String logTag, String message) {
+
+ }
+ public static void v(String logTag, String message) {
+
+ }
+}
diff --git a/app/src/main/java/com/tangem/domain/cardReader/PBKDF2.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/util/PBKDF2.java
similarity index 98%
rename from app/src/main/java/com/tangem/domain/cardReader/PBKDF2.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/util/PBKDF2.java
index 700648c6dd..31d8d47a6e 100644
--- a/app/src/main/java/com/tangem/domain/cardReader/PBKDF2.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/util/PBKDF2.java
@@ -1,5 +1,5 @@
-package com.tangem.domain.cardReader;
+package com.tangem.tangemcard.util;
import org.spongycastle.crypto.CipherParameters;
import org.spongycastle.crypto.digests.SHA256Digest;
diff --git a/app/src/main/java/com/tangem/util/Util.java b/tangemcard-common/src/main/java/com/tangem/tangemcard/util/Util.java
similarity index 97%
rename from app/src/main/java/com/tangem/util/Util.java
rename to tangemcard-common/src/main/java/com/tangem/tangemcard/util/Util.java
index 3ebf4b4bfa..4ce101d85b 100644
--- a/app/src/main/java/com/tangem/util/Util.java
+++ b/tangemcard-common/src/main/java/com/tangem/tangemcard/util/Util.java
@@ -1,6 +1,4 @@
-package com.tangem.util;
-
-import android.text.format.DateUtils;
+package com.tangem.tangemcard.util;
import org.spongycastle.crypto.digests.RIPEMD160Digest;
@@ -219,23 +217,24 @@ public class Util {
}
- public static String formatDate(Date date)
- {
- return DateUtils.formatDateTime(null, date.getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_YEAR);
-// return DateFormat.getDateInstance(DateFormat.SHORT).format(date);
- }
-
- public static String formatDateTime(Date date)
- {
- return formatDate(date)+" "+formatTime(date);
- }
-
- public static String formatTime(Date date)
- {
- return new SimpleDateFormat("HH:mm:ss").format(date);
-// DateFormat.getTimeInstance(DateFormat.MEDIUM).format(date)
-// return DateUtils.formatDateTime(null, date.getTime(), DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR);//DateFormat.getTimeInstance(DateFormat.MEDIUM).format(date);
- }
+// public static String formatDate(Date date)
+// {
+// //return DateUtils.formatDateTime(null, date.getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_YEAR);
+//// return DateFormat.getDateInstance(DateFormat.SHORT).format(date);
+// return new SimpleDateFormat("yyyy_MM_dd__HH_mm_ss", Locale.US).format(date);
+// }
+//
+// public static String formatDateTime(Date date)
+// {
+// return formatDate(date)+" "+formatTime(date);
+// }
+//
+// public static String formatTime(Date date)
+// {
+// return new SimpleDateFormat("HH:mm:ss", Locale.US).format(date);
+//// DateFormat.getTimeInstance(DateFormat.MEDIUM).format(date)
+//// return DateUtils.formatDateTime(null, date.getTime(), DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR);//DateFormat.getTimeInstance(DateFormat.MEDIUM).format(date);
+// }
public static byte[] getCurrentDateAsNumericEncodedByteArray(){
SimpleDateFormat format = new SimpleDateFormat("yyMMdd", Locale.US);
diff --git a/tangemcard/src/main/AndroidManifest.xml b/tangemcard/src/main/AndroidManifest.xml
deleted file mode 100644
index d71fe3bba6..0000000000
--- a/tangemcard/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
diff --git a/tangemcard/src/main/java/com/tangem/tangemcard/Test.java b/tangemcard/src/main/java/com/tangem/tangemcard/Test.java
deleted file mode 100644
index 3d2329b2c4..0000000000
--- a/tangemcard/src/main/java/com/tangem/tangemcard/Test.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.tangem.tangemcard;
-
-public class Test {
-}
diff --git a/tangemcard/src/main/res/values/strings.xml b/tangemcard/src/main/res/values/strings.xml
deleted file mode 100644
index 2f96d49efc..0000000000
--- a/tangemcard/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- tangemcard
-
diff --git a/tangemserver-android/.gitignore b/tangemserver-android/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/tangemserver-android/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/tangemcard/build.gradle b/tangemserver-android/build.gradle
similarity index 50%
rename from tangemcard/build.gradle
rename to tangemserver-android/build.gradle
index e5d36fc391..a333b7819d 100644
--- a/tangemcard/build.gradle
+++ b/tangemserver-android/build.gradle
@@ -3,11 +3,8 @@ apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
-
-
-
defaultConfig {
- minSdkVersion 16
+ minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
@@ -15,20 +12,31 @@ android {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
-
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
-
+ productFlavors {
+ }
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
+ implementation project(':tangemcard-common')
+ implementation project(':tangemcard-android')
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
+ 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.squareup.retrofit2:converter-gson:2.5.0'
+ implementation 'com.squareup.retrofit2:retrofit:2.5.0'
+ implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
+ // implementation 'com.google.dagger:dagger:2.16'
+ // implementation 'org.bitcoinj:bitcoinj-parent:0.14.7'
+ // implementation 'org.bitcoinj:bitcoinj-core:0.14.7'
+ // annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
diff --git a/tangemserver-android/proguard-rules.pro b/tangemserver-android/proguard-rules.pro
new file mode 100644
index 0000000000..f1b424510d
--- /dev/null
+++ b/tangemserver-android/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/tangemserver-android/src/androidTest/java/com/tangem/tangemserver/ExampleInstrumentedTest.java b/tangemserver-android/src/androidTest/java/com/tangem/tangemserver/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000..a165ce8bf1
--- /dev/null
+++ b/tangemserver-android/src/androidTest/java/com/tangem/tangemserver/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.tangem.tangemserver;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.tangem.tangemserver.test", appContext.getPackageName());
+ }
+}
diff --git a/tangemserver-android/src/main/AndroidManifest.xml b/tangemserver-android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..25d98a0dca
--- /dev/null
+++ b/tangemserver-android/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/tangemserver-android/src/main/java/com/tangem/tangemserver/android/Server.java b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/Server.java
new file mode 100644
index 0000000000..a6b5a678a8
--- /dev/null
+++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/Server.java
@@ -0,0 +1,17 @@
+package com.tangem.tangemserver.android;
+
+public class Server {
+ /**
+ * https://tangem-webapp.appspot.com/
+ * https://tangem-services.appspot.com/
+ */
+ public static class ApiTangem {
+ public static final String URL_TANGEM = ServerURL.API_TANGEM;
+
+ public static class Method {
+ static final String VERIFY = URL_TANGEM + "verify";
+ static final String VERIFY_AND_GET_INFO = URL_TANGEM + "card/verify-and-get-info";
+ static final String ARTWORK = URL_TANGEM + "card/artwork";
+ }
+ }
+}
\ No newline at end of file
diff --git a/tangemserver-android/src/main/java/com/tangem/tangemserver/android/ServerApiTangem.java b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/ServerApiTangem.java
new file mode 100644
index 0000000000..549791aa9f
--- /dev/null
+++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/ServerApiTangem.java
@@ -0,0 +1,124 @@
+package com.tangem.tangemserver.android;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.tangem.tangemcard.data.TangemCard;
+import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo;
+import com.tangem.tangemcard.util.Util;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import okhttp3.ResponseBody;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+public class ServerApiTangem {
+ private static String TAG = ServerApiTangem.class.getSimpleName();
+
+ /**
+ * HTTP
+ * Card verify
+ */
+ private CardVerifyAndGetInfoListener cardVerifyAndGetInfoListener;
+
+ public interface CardVerifyAndGetInfoListener {
+ void onSuccess(CardVerifyAndGetInfo.Response cardVerifyAndGetArtworkResponse);
+ void onFail(String message);
+ }
+
+ public void setCardVerifyAndGetInfoListener(CardVerifyAndGetInfoListener listener) {
+ cardVerifyAndGetInfoListener = listener;
+ }
+
+ public void cardVerifyAndGetInfo(TangemCard card) {
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl("https://estimatefee.com/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+
+ TangemApi tangemApi = retrofit.create(TangemApi.class);
+
+ List requests = new ArrayList<>();
+ requests.add(new CardVerifyAndGetInfo.Request.Item(Util.bytesToHex(card.getCID()), Util.bytesToHex(card.getCardPublicKey())));
+
+ CardVerifyAndGetInfo.Request requestBody = new CardVerifyAndGetInfo.Request(requests);
+
+ Call call = tangemApi.getCardVerifyAndGetInfo(requestBody);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull Response response) {
+ if (response.code() == 200) {
+ CardVerifyAndGetInfo.Response cardVerifyAndGetArtworkResponse = response.body();
+ cardVerifyAndGetInfoListener.onSuccess(cardVerifyAndGetArtworkResponse);
+ Log.i(TAG, "cardVerifyAndGeInfo onResponse " + response.code());
+ } else {
+ cardVerifyAndGetInfoListener.onFail(String.valueOf(response.code()));
+ Log.e(TAG, "cardVerifyAndGetInfo onResponse " + response.code());
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call call, @NonNull Throwable t) {
+ cardVerifyAndGetInfoListener.onFail(t.getMessage());
+ Log.e(TAG, "cardVerifyAndGetInfo onFailure " + t.getMessage());
+ }
+ });
+ }
+
+ /**
+ * HTTP
+ * Last version request from GitHub
+ */
+ private ArtworkListener artworkListener;
+
+ public interface ArtworkListener {
+ void onSuccess(String artworkId, InputStream inputStream, Date updateDate);
+ void onFail(String message);
+ }
+
+ public void setArtworkListener(ArtworkListener listener) {
+ artworkListener = listener;
+ }
+
+ public void requestArtwork(final String artworkId, final Date updateDate, TangemCard card) {
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl("https://verify.tangem.com/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+
+ TangemApi tangemApi = retrofit.create(TangemApi.class);
+
+ Call call = tangemApi.getArtwork(artworkId, Util.bytesToHex(card.getCID()), Util.bytesToHex(card.getCardPublicKey()));
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull Response response) {
+ Log.i(TAG, "getArtwork onResponse " + response.code());
+ if (response.code() == 200) {
+ try {
+ ResponseBody body = response.body();
+ if (body != null) {
+ artworkListener.onSuccess(artworkId, body.byteStream(), updateDate);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call call, @NonNull Throwable t) {
+ artworkListener.onFail(t.getMessage());
+ Log.e(TAG, "getArtwork onFailure " + t.getMessage());
+ }
+ });
+ }
+
+
+}
\ No newline at end of file
diff --git a/tangemserver-android/src/main/java/com/tangem/tangemserver/android/ServerURL.java b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/ServerURL.java
new file mode 100644
index 0000000000..80be96c06e
--- /dev/null
+++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/ServerURL.java
@@ -0,0 +1,5 @@
+package com.tangem.tangemserver.android;
+
+class ServerURL {
+ static final String API_TANGEM = "https://verify.tangem.com/";
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/data/network/TangemApi.java b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/TangemApi.java
similarity index 85%
rename from app/src/main/java/com/tangem/data/network/TangemApi.java
rename to tangemserver-android/src/main/java/com/tangem/tangemserver/android/TangemApi.java
index 3a17e33874..96897eab67 100644
--- a/app/src/main/java/com/tangem/data/network/TangemApi.java
+++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/TangemApi.java
@@ -1,6 +1,6 @@
-package com.tangem.data.network;
+package com.tangem.tangemserver.android;
-import com.tangem.data.network.model.CardVerifyAndGetInfo;
+import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo;
import okhttp3.ResponseBody;
import retrofit2.Call;
diff --git a/app/src/main/java/com/tangem/data/db/LocalStorage.kt b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/data/LocalStorage.kt
similarity index 96%
rename from app/src/main/java/com/tangem/data/db/LocalStorage.kt
rename to tangemserver-android/src/main/java/com/tangem/tangemserver/android/data/LocalStorage.kt
index b0df8cadb9..426ac14e0e 100644
--- a/app/src/main/java/com/tangem/data/db/LocalStorage.kt
+++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/data/LocalStorage.kt
@@ -1,7 +1,9 @@
-package com.tangem.data.db
+package com.tangem.tangemserver.android.data
+
+import android.content.Context
+import com.tangem.tangemcard.data.TangemCard
import android.annotation.SuppressLint
-import android.content.Context
import android.graphics.Bitmap
import java.io.File
import kotlin.collections.HashMap
@@ -10,19 +12,20 @@ import android.util.Log
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import com.google.gson.reflect.TypeToken
-import com.tangem.data.network.model.CardVerifyAndGetInfo
-import com.tangem.domain.cardReader.CardCrypto
-import com.tangem.domain.wallet.TangemCard
-import com.tangem.util.Util
-import com.tangem.wallet.R
+import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo
+import com.tangem.tangemcard.R
+import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider
+import com.tangem.tangemcard.reader.CardCrypto
+import com.tangem.tangemcard.util.Util
import java.io.InputStream
import java.lang.Exception
import java.nio.charset.StandardCharsets
import java.util.*
-data class LocalStorage(
+class LocalStorage
+(
val context: Context
-) {
+) : CardDataSubstitutionProvider {
private lateinit var artworks: HashMap
private lateinit var batches: HashMap
private val artworksFile: File = File(context.filesDir, "artworks.json")
@@ -109,7 +112,7 @@ data class LocalStorage(
var sData: String? = result.substitution?.data
var sSignature: String? = result.substitution?.signature
if (card.batch != result.batch) {
- Log.e("LocalStorage", "Invalid batch received!")
+ Log.e("CardDataSubstitution", "Invalid batch received!")
return false
}
if (!BatchInfo.CardDataSubstitution.verifySignature(card, sData, sSignature)) {
@@ -236,7 +239,7 @@ data class LocalStorage(
return getArtworkBitmap(artworkId) ?: return getDefaultArtworkBitmap()
}
- fun applySubstitution(card: TangemCard) {
+ override fun applySubstitution(card: TangemCard) {
val batchInfo = batches[card.batch] ?: return
val substitution = batchInfo.getDataSubstitution(card) ?: return
substitution.applyToCard(card)
diff --git a/app/src/main/java/com/tangem/data/network/model/CardVerify.java b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/model/CardVerify.java
similarity index 81%
rename from app/src/main/java/com/tangem/data/network/model/CardVerify.java
rename to tangemserver-android/src/main/java/com/tangem/tangemserver/android/model/CardVerify.java
index c03c809cfb..9873dbd528 100644
--- a/app/src/main/java/com/tangem/data/network/model/CardVerify.java
+++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/model/CardVerify.java
@@ -1,4 +1,4 @@
-package com.tangem.data.network.model;
+package com.tangem.tangemserver.android.model;
public class CardVerify {
private String CID;
diff --git a/app/src/main/java/com/tangem/data/network/model/CardVerifyAndGetInfo.kt b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/model/CardVerifyAndGetInfo.kt
similarity index 96%
rename from app/src/main/java/com/tangem/data/network/model/CardVerifyAndGetInfo.kt
rename to tangemserver-android/src/main/java/com/tangem/tangemserver/android/model/CardVerifyAndGetInfo.kt
index 0888ca0b16..2da73766b4 100644
--- a/app/src/main/java/com/tangem/data/network/model/CardVerifyAndGetInfo.kt
+++ b/tangemserver-android/src/main/java/com/tangem/tangemserver/android/model/CardVerifyAndGetInfo.kt
@@ -1,4 +1,4 @@
-package com.tangem.data.network.model
+package com.tangem.tangemserver.android.model
import java.text.SimpleDateFormat
import java.util.*
diff --git a/tangemserver-android/src/main/res/values/strings.xml b/tangemserver-android/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..7c2c6570f5
--- /dev/null
+++ b/tangemserver-android/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ TangemServer
+
diff --git a/tangemcard/src/test/java/com/tangem/tangemcard/ExampleUnitTest.java b/tangemserver-android/src/test/java/com/tangem/tangemserver/ExampleUnitTest.java
similarity index 91%
rename from tangemcard/src/test/java/com/tangem/tangemcard/ExampleUnitTest.java
rename to tangemserver-android/src/test/java/com/tangem/tangemserver/ExampleUnitTest.java
index 053a2eef4f..6fd65d8f9b 100644
--- a/tangemcard/src/test/java/com/tangem/tangemcard/ExampleUnitTest.java
+++ b/tangemserver-android/src/test/java/com/tangem/tangemserver/ExampleUnitTest.java
@@ -1,4 +1,4 @@
-package com.tangem.tangemcard;
+package com.tangem.tangemserver;
import org.junit.Test;