From b19c30625073ef1b79032d0dd73394e2f1e6864d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 May 2018 16:11:22 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .gitignore | 1 + .idea/caches/build_file_checksums.ser | Bin 536 -> 536 bytes .../java/com/tangem/VerticalTextView.java | 52 + .../java/com/tangem/data/network/Server.java | 4 - .../network/request}/Electrum_Request.java | 366 +- .../network/request}/ExchangeRequest.java | 184 +- .../network/task}/Electrum_Task.java | 235 +- .../network/task}/ExchangeTask.java | 132 +- .../network/task}/Fee_Task.java | 127 +- .../network/task}/Infura_Task.java | 271 +- .../{ => domain}/cardReader/CardCrypto.java | 476 +-- .../{ => domain}/cardReader/CardProtocol.java | 1905 +++++----- .../{ => domain}/cardReader/CommandApdu.java | 2 +- .../cardReader/CustomCardReader.java | 2 +- .../tangem/{ => domain}/cardReader/INS.java | 86 +- .../{ => domain}/cardReader/NfcManager.java | 308 +- .../{ => domain}/cardReader/PBKDF2.java | 2 +- .../{ => domain}/cardReader/ResponseApdu.java | 2 +- .../tangem/{ => domain}/cardReader/SW.java | 86 +- .../{ => domain}/cardReader/SettingsMask.java | 50 +- .../tangem/{ => domain}/cardReader/TLV.java | 444 +-- .../{ => domain}/cardReader/TLVException.java | 34 +- .../{ => domain}/cardReader/TLVList.java | 144 +- .../tangem/{ => domain}/cardReader/Util.java | 3 +- .../java/com/tangem/presentation/Screen.java | 4 - .../activity/CardInfoActivity.java | 2 +- .../activity/ConfirmPaymentActivity.java | 12 +- .../activity/CreateNewWalletActivity.java | 10 +- .../activity/EmptyWalletActivity.java | 10 +- .../activity/LoadedWalletActivity.java | 2 +- .../presentation/activity/MainActivity.java | 2 +- .../activity/PreparePaymentActivity.java | 2 +- .../presentation/activity/PurgeActivity.java | 10 +- .../activity/RequestPINActivity.java | 2 +- .../activity/SendTransactionActivity.java | 6 +- .../activity/SignPaymentActivity.java | 2 +- .../activity/SwapPINActivity.java | 10 +- .../activity/VerifyCardActivity.java | 2 +- .../adapter}/CardListAdapter.java | 9 +- .../adapter}/CardUnspentListAdapter.java | 169 +- .../dialog}/NFCEnableDialog.java | 90 +- .../NoExtendedLengthSupportDialog.java | 70 +- .../dialog}/WaitSecurityDelayDialog.java | 334 +- .../LoadedWalletActivityFragment.java | 3229 +++++++++-------- .../fragment}/MainActivityFragment.java | 2100 +++++------ .../fragment}/VerifyCardActivityFragment.java | 722 ++-- .../fragment}/WalletInfoFragment.java | 302 +- .../main/java/com/tangem/wallet/BTCUtils.java | 33 +- .../java/com/tangem/wallet/Blockchain.java | 13 - .../java/com/tangem/wallet/BtcCashEngine.java | 6 +- .../java/com/tangem/wallet/BtcEngine.java | 6 +- .../java/com/tangem/wallet/CoinEngine.java | 2 +- .../com/tangem/wallet/CoinEngineFactory.java | 12 +- .../java/com/tangem/wallet/CryptoUtil.java | 2 +- .../java/com/tangem/wallet/EthEngine.java | 4 +- .../main/java/com/tangem/wallet/Issuer.java | 8 +- .../main/java/com/tangem/wallet/Logger.java | 2 +- .../java/com/tangem/wallet/PINStorage.java | 6 +- .../java/com/tangem/wallet/Tangem_Card.java | 9 +- .../java/com/tangem/wallet/TokenEngine.java | 145 +- .../com/tangem/wallet/VerifyCardTask.java | 4 +- .../com/tangem/wallet/VerticalTextView.java | 70 - app/src/main/res/layout/card_list_item.xml | 2 +- .../main/res/layout/content_loaded_wallet.xml | 2 +- app/src/main/res/layout/content_main.xml | 2 +- .../main/res/layout/content_verify_card.xml | 2 +- .../res/layout/fragment_loaded_wallet.xml | 2 +- app/src/main/res/layout/fragment_main.xml | 2 +- .../main/res/layout/fragment_verify_card.xml | 2 +- .../main/res/layout/fragment_wallet_info.xml | 2 +- 70 files changed, 6149 insertions(+), 6206 deletions(-) create mode 100644 app/src/main/java/com/tangem/VerticalTextView.java delete mode 100644 app/src/main/java/com/tangem/data/network/Server.java rename app/src/main/java/com/tangem/{wallet => data/network/request}/Electrum_Request.java (96%) rename app/src/main/java/com/tangem/{wallet => data/network/request}/ExchangeRequest.java (95%) rename app/src/main/java/com/tangem/{wallet => data/network/task}/Electrum_Task.java (95%) rename app/src/main/java/com/tangem/{wallet => data/network/task}/ExchangeTask.java (92%) rename app/src/main/java/com/tangem/{wallet => data/network/task}/Fee_Task.java (93%) rename app/src/main/java/com/tangem/{wallet => data/network/task}/Infura_Task.java (96%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/CardCrypto.java (97%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/CardProtocol.java (97%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/CommandApdu.java (99%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/CustomCardReader.java (98%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/INS.java (91%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/NfcManager.java (96%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/PBKDF2.java (98%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/ResponseApdu.java (98%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/SW.java (95%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/SettingsMask.java (93%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/TLV.java (96%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/TLVException.java (87%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/TLVList.java (94%) rename app/src/main/java/com/tangem/{ => domain}/cardReader/Util.java (99%) delete mode 100644 app/src/main/java/com/tangem/presentation/Screen.java rename app/src/main/java/com/tangem/{wallet => presentation/adapter}/CardListAdapter.java (99%) rename app/src/main/java/com/tangem/{wallet => presentation/adapter}/CardUnspentListAdapter.java (95%) rename app/src/main/java/com/tangem/{cardReader => presentation/dialog}/NFCEnableDialog.java (95%) rename app/src/main/java/com/tangem/{wallet => presentation/dialog}/NoExtendedLengthSupportDialog.java (94%) rename app/src/main/java/com/tangem/{wallet => presentation/dialog}/WaitSecurityDelayDialog.java (96%) rename app/src/main/java/com/tangem/{wallet => presentation/fragment}/LoadedWalletActivityFragment.java (97%) rename app/src/main/java/com/tangem/{wallet => presentation/fragment}/MainActivityFragment.java (97%) rename app/src/main/java/com/tangem/{wallet => presentation/fragment}/VerifyCardActivityFragment.java (97%) rename app/src/main/java/com/tangem/{wallet => presentation/fragment}/WalletInfoFragment.java (96%) delete mode 100644 app/src/main/java/com/tangem/wallet/VerticalTextView.java diff --git a/.gitignore b/.gitignore index 9a981e6c12..021d56e82b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ app/libs/ .idea/vcs.xml .idea/caches +.idea/dictionaries diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 9389fce7cb7f70f0695edf4207d9dbf9e9891a8e..14e5826a1f2f42cf22bfa29132e48bc3e16e898d 100644 GIT binary patch delta 14 WcmbQiGJ|EpOy;MXVm8jHVFUmy!v-P% delta 14 VcmbQiGJ|EpOlHSI?~QY67y%}11uOsn diff --git a/app/src/main/java/com/tangem/VerticalTextView.java b/app/src/main/java/com/tangem/VerticalTextView.java new file mode 100644 index 0000000000..62cf9151c6 --- /dev/null +++ b/app/src/main/java/com/tangem/VerticalTextView.java @@ -0,0 +1,52 @@ +package com.tangem; + +import android.content.Context; +import android.graphics.Canvas; +import android.support.v7.widget.AppCompatTextView; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.view.Gravity; + +public class VerticalTextView extends AppCompatTextView { + final boolean topDown; + + public VerticalTextView(Context context, AttributeSet attrs) { + super(context, attrs); + final int gravity = getGravity(); + if (Gravity.isVertical(gravity) && (gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) { + setGravity((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP); + topDown = false; + } else { + topDown = true; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(heightMeasureSpec, widthMeasureSpec); + setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); + } + + @Override + protected void onDraw(Canvas canvas) { + TextPaint textPaint = getPaint(); + textPaint.setColor(getCurrentTextColor()); + textPaint.drawableState = getDrawableState(); + + canvas.save(); + + if (topDown) { + canvas.translate(getWidth(), 0); + canvas.rotate(90); + } else { + canvas.translate(0, getHeight()); + canvas.rotate(-90); + } + + canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop()); + + getLayout().draw(canvas); + canvas.restore(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/data/network/Server.java b/app/src/main/java/com/tangem/data/network/Server.java deleted file mode 100644 index c844fda4ed..0000000000 --- a/app/src/main/java/com/tangem/data/network/Server.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.tangem.data.network; - -public class Server { -} diff --git a/app/src/main/java/com/tangem/wallet/Electrum_Request.java b/app/src/main/java/com/tangem/data/network/request/Electrum_Request.java similarity index 96% rename from app/src/main/java/com/tangem/wallet/Electrum_Request.java rename to app/src/main/java/com/tangem/data/network/request/Electrum_Request.java index 9654c7fb81..bb61241842 100644 --- a/app/src/main/java/com/tangem/wallet/Electrum_Request.java +++ b/app/src/main/java/com/tangem/data/network/request/Electrum_Request.java @@ -1,184 +1,182 @@ -package com.tangem.wallet; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Created by dvol on 16.07.2017. - */ - -public class Electrum_Request { - public static final String METHOD_GetBalance = "blockchain.address.get_balance"; - public static final String METHOD_ListUnspent = "blockchain.address.listunspent"; - public static final String METHOD_GetHistory = "blockchain.address.get_history"; - public static final String METHOD_GetTransaction = "blockchain.transaction.get"; - public static final String METHOD_GetHeader = "blockchain.block.get_header"; - public static final String METHOD_SendTransaction = "blockchain.transaction.broadcast"; - public static final String METHOD_GetFee = "blockchain.estimatefee"; - - - - public JSONObject jsRequestData; - public String answerData; - public String error; - public String WalletAddress; - public String TxHash; - public String Host; - public int Port; - - private Electrum_Request() { - } - - public Electrum_Request(JSONObject jsRequest) { - try { - jsRequestData = new JSONObject(jsRequest.toString()); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public JSONObject getAnswer() { - try { - return new JSONObject(answerData); - } catch (Exception e) { - try { - return new JSONObject(String.format("[\"Error\":\"%s\"]", e.getMessage())); - } catch (JSONException e1) { - e1.printStackTrace(); - return null; - } - } - } - - public String getAsString() { - return jsRequestData.toString(); - } - - public void setID(int value) { - try { - jsRequestData.put("id", String.format("%d", value)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public int getID() { - try { - return jsRequestData.getInt("id"); - } catch (JSONException e) { - e.printStackTrace(); - return 0; - } - } - - public static Electrum_Request CheckBalance(String wallet) { - Electrum_Request request = new Electrum_Request(); - try { - request.WalletAddress=wallet; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetBalance + "\", \"params\":[\"" + wallet + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - - public static Electrum_Request GetFee(String wallet) { - Electrum_Request request = new Electrum_Request(); - try{ - request.WalletAddress = wallet; //METHOD_GetFee - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetFee + "\", \"params\":[\"" + 6 + "\"] }"); - } - catch(JSONException e) - { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static Electrum_Request GetHeader(String wallet, String height) { - Electrum_Request request = new Electrum_Request(); - try { - request.WalletAddress=wallet; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetHeader + "\", \"params\":[\"" + height + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static Electrum_Request ListUnspent(String wallet) { - Electrum_Request request = new Electrum_Request(); - try { - request.WalletAddress=wallet; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_ListUnspent + "\", \"params\":[\"" + wallet + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static Electrum_Request Broadcast(String wallet, String tx) { - Electrum_Request request = new Electrum_Request(); - try { - request.WalletAddress=wallet; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_SendTransaction + "\", \"params\":[\"" + tx + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static Electrum_Request ListHistory(String wallet) { - Electrum_Request request = new Electrum_Request(); - try { - request.WalletAddress=wallet; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetHistory + "\", \"params\":[\"" + wallet + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public static Electrum_Request GetTransaction(String wallet, String tx_hash) { - Electrum_Request request = new Electrum_Request(); - try { - request.WalletAddress=wallet; - request.TxHash = tx_hash; - request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetTransaction + "\", \"params\":[\"" + tx_hash + "\"] }"); - } catch (JSONException e) { - e.printStackTrace(); - request.error = e.toString(); - } - return request; - } - - public boolean isMethod(String methodName) throws JSONException { - return jsRequestData.getString("method").equals(methodName); - } - - public JSONArray getParams() throws JSONException { - return jsRequestData.getJSONArray("params"); - } - - public JSONObject getResult() throws JSONException { - return getAnswer().getJSONObject("result"); - } - - public String getResultString() throws JSONException { - return getAnswer().getString("result"); - } - - public JSONArray getResultArray() throws JSONException { - return getAnswer().getJSONArray("result"); - } - - -} +package com.tangem.data.network.request; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by dvol on 16.07.2017. + */ + +public class Electrum_Request { + public static final String METHOD_GetBalance = "blockchain.address.get_balance"; + public static final String METHOD_ListUnspent = "blockchain.address.listunspent"; + public static final String METHOD_GetHistory = "blockchain.address.get_history"; + public static final String METHOD_GetTransaction = "blockchain.transaction.get"; + public static final String METHOD_GetHeader = "blockchain.block.get_header"; + public static final String METHOD_SendTransaction = "blockchain.transaction.broadcast"; + public static final String METHOD_GetFee = "blockchain.estimatefee"; + + public JSONObject jsRequestData; + public String answerData; + public String error; + public String WalletAddress; + public String TxHash; + public String Host; + public int Port; + + private Electrum_Request() { + } + + public Electrum_Request(JSONObject jsRequest) { + try { + jsRequestData = new JSONObject(jsRequest.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public JSONObject getAnswer() { + try { + return new JSONObject(answerData); + } catch (Exception e) { + try { + return new JSONObject(String.format("[\"Error\":\"%s\"]", e.getMessage())); + } catch (JSONException e1) { + e1.printStackTrace(); + return null; + } + } + } + + public String getAsString() { + return jsRequestData.toString(); + } + + public void setID(int value) { + try { + jsRequestData.put("id", String.format("%d", value)); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public int getID() { + try { + return jsRequestData.getInt("id"); + } catch (JSONException e) { + e.printStackTrace(); + return 0; + } + } + + public static Electrum_Request CheckBalance(String wallet) { + Electrum_Request request = new Electrum_Request(); + try { + request.WalletAddress=wallet; + request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetBalance + "\", \"params\":[\"" + wallet + "\"] }"); + } catch (JSONException e) { + e.printStackTrace(); + request.error = e.toString(); + } + return request; + } + + + public static Electrum_Request GetFee(String wallet) { + Electrum_Request request = new Electrum_Request(); + try{ + request.WalletAddress = wallet; //METHOD_GetFee + request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetFee + "\", \"params\":[\"" + 6 + "\"] }"); + } + catch(JSONException e) + { + e.printStackTrace(); + request.error = e.toString(); + } + return request; + } + + public static Electrum_Request GetHeader(String wallet, String height) { + Electrum_Request request = new Electrum_Request(); + try { + request.WalletAddress=wallet; + request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetHeader + "\", \"params\":[\"" + height + "\"] }"); + } catch (JSONException e) { + e.printStackTrace(); + request.error = e.toString(); + } + return request; + } + + public static Electrum_Request ListUnspent(String wallet) { + Electrum_Request request = new Electrum_Request(); + try { + request.WalletAddress=wallet; + request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_ListUnspent + "\", \"params\":[\"" + wallet + "\"] }"); + } catch (JSONException e) { + e.printStackTrace(); + request.error = e.toString(); + } + return request; + } + + public static Electrum_Request Broadcast(String wallet, String tx) { + Electrum_Request request = new Electrum_Request(); + try { + request.WalletAddress=wallet; + request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_SendTransaction + "\", \"params\":[\"" + tx + "\"] }"); + } catch (JSONException e) { + e.printStackTrace(); + request.error = e.toString(); + } + return request; + } + + public static Electrum_Request ListHistory(String wallet) { + Electrum_Request request = new Electrum_Request(); + try { + request.WalletAddress=wallet; + request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetHistory + "\", \"params\":[\"" + wallet + "\"] }"); + } catch (JSONException e) { + e.printStackTrace(); + request.error = e.toString(); + } + return request; + } + + public static Electrum_Request GetTransaction(String wallet, String tx_hash) { + Electrum_Request request = new Electrum_Request(); + try { + request.WalletAddress=wallet; + request.TxHash = tx_hash; + request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetTransaction + "\", \"params\":[\"" + tx_hash + "\"] }"); + } catch (JSONException e) { + e.printStackTrace(); + request.error = e.toString(); + } + return request; + } + + public boolean isMethod(String methodName) throws JSONException { + return jsRequestData.getString("method").equals(methodName); + } + + public JSONArray getParams() throws JSONException { + return jsRequestData.getJSONArray("params"); + } + + public JSONObject getResult() throws JSONException { + return getAnswer().getJSONObject("result"); + } + + public String getResultString() throws JSONException { + return getAnswer().getString("result"); + } + + public JSONArray getResultArray() throws JSONException { + return getAnswer().getJSONArray("result"); + } + + +} diff --git a/app/src/main/java/com/tangem/wallet/ExchangeRequest.java b/app/src/main/java/com/tangem/data/network/request/ExchangeRequest.java similarity index 95% rename from app/src/main/java/com/tangem/wallet/ExchangeRequest.java rename to app/src/main/java/com/tangem/data/network/request/ExchangeRequest.java index 8d48b16175..ecfd83965c 100644 --- a/app/src/main/java/com/tangem/wallet/ExchangeRequest.java +++ b/app/src/main/java/com/tangem/data/network/request/ExchangeRequest.java @@ -1,92 +1,92 @@ -package com.tangem.wallet; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Created by dvol on 16.07.2017. - */ - -public class ExchangeRequest { - public JSONObject jsRequestData; - public String answerData; - public String error; - public String WalletAddress; - public String currency; - public String currencyAlter; - - private ExchangeRequest() { - } - - public ExchangeRequest(JSONObject jsRequest) { - try { - jsRequestData = new JSONObject(jsRequest.toString()); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public JSONObject getAnswer() { - try { - return new JSONObject(answerData); - } catch (Exception e) { - try { - return new JSONObject(String.format("[\"Error\":\"%s\"]", e.getMessage())); - } catch (JSONException e1) { - e1.printStackTrace(); - return null; - } - } - } - - public JSONArray getAnswerList() throws JSONException { - return new JSONArray(answerData); - } - - public String getAsString() { - return jsRequestData.toString(); - } - - public void setID(int value) { - try { - jsRequestData.put("id", String.format("%d", value)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public int getID() { - try { - return jsRequestData.getInt("id"); - } catch (JSONException e) { - e.printStackTrace(); - return 0; - } - } - - public static ExchangeRequest GetRate(String wallet, String currency, String alterCurrency) { - ExchangeRequest request = new ExchangeRequest(); - request.WalletAddress=wallet; - request.currency = currency; - request.currencyAlter = alterCurrency; - return request; - } - - - public JSONArray getParams() throws JSONException { - return jsRequestData.getJSONArray("params"); - } - - public JSONObject getResult() throws JSONException { - return getAnswer().getJSONObject("result"); - } - - public String getResultString() throws JSONException { - return getAnswer().getString("result"); - } - - public JSONArray getResultArray() throws JSONException { - return getAnswer().getJSONArray("result"); - } -} +package com.tangem.data.network.request; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by dvol on 16.07.2017. + */ + +public class ExchangeRequest { + public JSONObject jsRequestData; + public String answerData; + public String error; + public String WalletAddress; + public String currency; + public String currencyAlter; + + private ExchangeRequest() { + } + + public ExchangeRequest(JSONObject jsRequest) { + try { + jsRequestData = new JSONObject(jsRequest.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public JSONObject getAnswer() { + try { + return new JSONObject(answerData); + } catch (Exception e) { + try { + return new JSONObject(String.format("[\"Error\":\"%s\"]", e.getMessage())); + } catch (JSONException e1) { + e1.printStackTrace(); + return null; + } + } + } + + public JSONArray getAnswerList() throws JSONException { + return new JSONArray(answerData); + } + + public String getAsString() { + return jsRequestData.toString(); + } + + public void setID(int value) { + try { + jsRequestData.put("id", String.format("%d", value)); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public int getID() { + try { + return jsRequestData.getInt("id"); + } catch (JSONException e) { + e.printStackTrace(); + return 0; + } + } + + public static ExchangeRequest GetRate(String wallet, String currency, String alterCurrency) { + ExchangeRequest request = new ExchangeRequest(); + request.WalletAddress=wallet; + request.currency = currency; + request.currencyAlter = alterCurrency; + return request; + } + + + public JSONArray getParams() throws JSONException { + return jsRequestData.getJSONArray("params"); + } + + public JSONObject getResult() throws JSONException { + return getAnswer().getJSONObject("result"); + } + + public String getResultString() throws JSONException { + return getAnswer().getString("result"); + } + + public JSONArray getResultArray() throws JSONException { + return getAnswer().getJSONArray("result"); + } +} diff --git a/app/src/main/java/com/tangem/wallet/Electrum_Task.java b/app/src/main/java/com/tangem/data/network/task/Electrum_Task.java similarity index 95% rename from app/src/main/java/com/tangem/wallet/Electrum_Task.java rename to app/src/main/java/com/tangem/data/network/task/Electrum_Task.java index 8aa9609371..d59e1cc05d 100644 --- a/app/src/main/java/com/tangem/wallet/Electrum_Task.java +++ b/app/src/main/java/com/tangem/data/network/task/Electrum_Task.java @@ -1,116 +1,119 @@ -package com.tangem.wallet; - -import android.os.AsyncTask; -import android.util.Log; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.InetAddress; -import java.net.Socket; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by dvol on 16.07.2017. - */ - -public class Electrum_Task extends AsyncTask> { - public static final String logTag = "Electrum"; - //public static final String Host = /*"hsmiths.changeip.net";*/ "testnetnode.arihanc.com"; - //public static final int Port = /*8080*/51001; - private int reqID = 1; - private String Host = ""; - private int Port = 0; - OutputStreamWriter out; - BufferedReader in; - - public SharedData sharedCounter = null; - - - public Electrum_Task(String host, int port) { - super(); - Host = host; - Port = port; - } - - public Electrum_Task(String host, int port, SharedData sharedCounter) { - super(); - Host = host; - Port = port; - this.sharedCounter = sharedCounter; - } - - @Override - protected List doInBackground(Electrum_Request... requests) { - List result = new ArrayList<>(); - for (int i = 0; i < requests.length; i++) { - result.add(requests[i]); - } - try { - - InetAddress serverAddress = InetAddress.getByName(Host); - Log.v(logTag, "Connecting..."+Host); - Socket socket = new Socket(serverAddress, Port); - socket.setSoTimeout(5000); - try { - OutputStream os = socket.getOutputStream(); - out = new OutputStreamWriter(os, "UTF-8"); - Log.v(logTag, "Connected"); - InputStream is = socket.getInputStream(); - in = new BufferedReader(new InputStreamReader(is)); - - publishProgress(5); - - for (int i = 0; i < requests.length; i++) { - requests[i].setID(reqID++); - doRequest(requests[i]); - publishProgress(5 + 90 * (i + 1) / requests.length); - } - - publishProgress(100); - - } catch (Exception e) { - Log.e(logTag, "Error: ", e); - } finally { - socket.close(); - } - } catch (Exception e) { - Log.e(logTag, "Error: ", e); - for (int i = 0; i < requests.length; i++) { - result.get(i).error = e.toString(); - } - } - return result; - } - - private void doRequest(Electrum_Request request) { - try { - - Log.v(logTag, "<< " + request.getAsString()); - - out.write(request.getAsString() + "\n"); - out.flush(); - - request.answerData = in.readLine(); - request.Host=Host; - request.Port=Port; - if (request.answerData != null) { - Log.v(logTag, ">> " + request.answerData); - } else { - request.error = "No answer from server"; - Log.v(logTag, ">> "); - } - } catch (Exception e) { - request.error = e.toString(); - } - } - - public String getValidationNodeDescription() { - return "Electrum, "+Host+":"+String.valueOf(Port); - } - - -} +package com.tangem.data.network.task; + +import android.os.AsyncTask; +import android.util.Log; + +import com.tangem.data.network.request.Electrum_Request; +import com.tangem.wallet.SharedData; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by dvol on 16.07.2017. + */ + +public class Electrum_Task extends AsyncTask> { + public static final String logTag = "Electrum"; + //public static final String Host = /*"hsmiths.changeip.net";*/ "testnetnode.arihanc.com"; + //public static final int Port = /*8080*/51001; + private int reqID = 1; + private String Host = ""; + private int Port = 0; + OutputStreamWriter out; + BufferedReader in; + + public SharedData sharedCounter = null; + + + public Electrum_Task(String host, int port) { + super(); + Host = host; + Port = port; + } + + public Electrum_Task(String host, int port, SharedData sharedCounter) { + super(); + Host = host; + Port = port; + this.sharedCounter = sharedCounter; + } + + @Override + protected List doInBackground(Electrum_Request... requests) { + List result = new ArrayList<>(); + for (int i = 0; i < requests.length; i++) { + result.add(requests[i]); + } + try { + + InetAddress serverAddress = InetAddress.getByName(Host); + Log.v(logTag, "Connecting..."+Host); + Socket socket = new Socket(serverAddress, Port); + socket.setSoTimeout(5000); + try { + OutputStream os = socket.getOutputStream(); + out = new OutputStreamWriter(os, "UTF-8"); + Log.v(logTag, "Connected"); + InputStream is = socket.getInputStream(); + in = new BufferedReader(new InputStreamReader(is)); + + publishProgress(5); + + for (int i = 0; i < requests.length; i++) { + requests[i].setID(reqID++); + doRequest(requests[i]); + publishProgress(5 + 90 * (i + 1) / requests.length); + } + + publishProgress(100); + + } catch (Exception e) { + Log.e(logTag, "Error: ", e); + } finally { + socket.close(); + } + } catch (Exception e) { + Log.e(logTag, "Error: ", e); + for (int i = 0; i < requests.length; i++) { + result.get(i).error = e.toString(); + } + } + return result; + } + + private void doRequest(Electrum_Request request) { + try { + + Log.v(logTag, "<< " + request.getAsString()); + + out.write(request.getAsString() + "\n"); + out.flush(); + + request.answerData = in.readLine(); + request.Host=Host; + request.Port=Port; + if (request.answerData != null) { + Log.v(logTag, ">> " + request.answerData); + } else { + request.error = "No answer from server"; + Log.v(logTag, ">> "); + } + } catch (Exception e) { + request.error = e.toString(); + } + } + + public String getValidationNodeDescription() { + return "Electrum, "+Host+":"+String.valueOf(Port); + } + + +} diff --git a/app/src/main/java/com/tangem/wallet/ExchangeTask.java b/app/src/main/java/com/tangem/data/network/task/ExchangeTask.java similarity index 92% rename from app/src/main/java/com/tangem/wallet/ExchangeTask.java rename to app/src/main/java/com/tangem/data/network/task/ExchangeTask.java index 7d1634071e..c72c710731 100644 --- a/app/src/main/java/com/tangem/wallet/ExchangeTask.java +++ b/app/src/main/java/com/tangem/data/network/task/ExchangeTask.java @@ -1,66 +1,66 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 16.01.2018. - */ - -import android.os.AsyncTask; - -import com.tangem.wallet.ExchangeRequest; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Ilia on 04.12.2017. - */ - -public class ExchangeTask extends AsyncTask> { - public ExchangeTask() - { - - } - protected List doInBackground(ExchangeRequest... requests) { - List result = new ArrayList<>(); - for (int i = 0; i < requests.length; i++) { - result.add(requests[i]); - } - - for (ExchangeRequest request: result) - { - HttpURLConnection httpcon = null; - - try { - - URL url = new URL("https://api.coinmarketcap.com/v1/ticker/?convert=USD&lmit=10"); - httpcon = (HttpURLConnection) url.openConnection(); - httpcon.setRequestMethod("GET"); - - httpcon.connect(); - - BufferedReader in = new BufferedReader( - new InputStreamReader(httpcon.getInputStream())); - String inputLine; - StringBuffer response = new StringBuffer(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - - request.answerData = response.toString(); - - } catch (Exception e) { - request.error = e.getMessage(); - } finally { - httpcon.disconnect(); - } - } - - return result; - } -} +package com.tangem.data.network.task; + +/** + * Created by Ilia on 16.01.2018. + */ + +import android.os.AsyncTask; + +import com.tangem.data.network.request.ExchangeRequest; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Ilia on 04.12.2017. + */ + +public class ExchangeTask extends AsyncTask> { + public ExchangeTask() + { + + } + protected List doInBackground(ExchangeRequest... requests) { + List result = new ArrayList<>(); + for (int i = 0; i < requests.length; i++) { + result.add(requests[i]); + } + + for (ExchangeRequest request: result) + { + HttpURLConnection httpcon = null; + + try { + + URL url = new URL("https://api.coinmarketcap.com/v1/ticker/?convert=USD&lmit=10"); + httpcon = (HttpURLConnection) url.openConnection(); + httpcon.setRequestMethod("GET"); + + httpcon.connect(); + + BufferedReader in = new BufferedReader( + new InputStreamReader(httpcon.getInputStream())); + String inputLine; + StringBuffer response = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + request.answerData = response.toString(); + + } catch (Exception e) { + request.error = e.getMessage(); + } finally { + httpcon.disconnect(); + } + } + + return result; + } +} diff --git a/app/src/main/java/com/tangem/wallet/Fee_Task.java b/app/src/main/java/com/tangem/data/network/task/Fee_Task.java similarity index 93% rename from app/src/main/java/com/tangem/wallet/Fee_Task.java rename to app/src/main/java/com/tangem/data/network/task/Fee_Task.java index 52d5c63806..52594e199d 100644 --- a/app/src/main/java/com/tangem/wallet/Fee_Task.java +++ b/app/src/main/java/com/tangem/data/network/task/Fee_Task.java @@ -1,63 +1,66 @@ -package com.tangem.wallet; - -import android.os.AsyncTask; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Ilia on 04.12.2017. - */ - -public class Fee_Task extends AsyncTask> { - - public SharedData sharedCounter = null; - - public Fee_Task(SharedData sharedData) - { - sharedCounter = sharedData; - } - protected List doInBackground(Fee_Request... requests) { - List result = new ArrayList<>(); - for (int i = 0; i < requests.length; i++) { - result.add(requests[i]); - } - - for (Fee_Request request: result) - { - HttpURLConnection httpcon = null; - - try { - - URL url = new URL("https://estimatefee.com/n/"+String.valueOf(request.getBlockCount())); - httpcon = (HttpURLConnection) url.openConnection(); - httpcon.setRequestMethod("GET"); - - httpcon.connect(); - - BufferedReader in = new BufferedReader( - new InputStreamReader(httpcon.getInputStream())); - String inputLine; - StringBuffer response = new StringBuffer(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - - request.answerData = response.toString(); - - } catch (Exception e) { - request.error = e.getMessage(); - } finally { - httpcon.disconnect(); - } - } - - return result; - } +package com.tangem.data.network.task; + +import android.os.AsyncTask; + +import com.tangem.wallet.Fee_Request; +import com.tangem.wallet.SharedData; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Ilia on 04.12.2017. + */ + +public class Fee_Task extends AsyncTask> { + + public SharedData sharedCounter = null; + + public Fee_Task(SharedData sharedData) + { + sharedCounter = sharedData; + } + protected List doInBackground(Fee_Request... requests) { + List result = new ArrayList<>(); + for (int i = 0; i < requests.length; i++) { + result.add(requests[i]); + } + + for (Fee_Request request: result) + { + HttpURLConnection httpcon = null; + + try { + + URL url = new URL("https://estimatefee.com/n/"+String.valueOf(request.getBlockCount())); + httpcon = (HttpURLConnection) url.openConnection(); + httpcon.setRequestMethod("GET"); + + httpcon.connect(); + + BufferedReader in = new BufferedReader( + new InputStreamReader(httpcon.getInputStream())); + String inputLine; + StringBuffer response = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + request.answerData = response.toString(); + + } catch (Exception e) { + request.error = e.getMessage(); + } finally { + httpcon.disconnect(); + } + } + + return result; + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/Infura_Task.java b/app/src/main/java/com/tangem/data/network/task/Infura_Task.java similarity index 96% rename from app/src/main/java/com/tangem/wallet/Infura_Task.java rename to app/src/main/java/com/tangem/data/network/task/Infura_Task.java index 18d9b2d4b6..da4afee677 100644 --- a/app/src/main/java/com/tangem/wallet/Infura_Task.java +++ b/app/src/main/java/com/tangem/data/network/task/Infura_Task.java @@ -1,134 +1,137 @@ -package com.tangem.wallet; - -/** - * Created by Ilia on 19.12.2017. - */ - -import android.os.AsyncTask; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -import javax.net.ssl.HttpsURLConnection; - -/** - * Created by Ilia on 04.12.2017. - */ - -public class Infura_Task extends AsyncTask> { - private Exception exception; - private Blockchain blockchain; - public Infura_Task(Blockchain blockchainNet) - { - blockchain = blockchainNet; - } - boolean useOurNode = false; - protected List doInBackground(Infura_Request... requests) { - List result = new ArrayList<>(); - for (int i = 0; i < requests.length; i++) { - result.add(requests[i]); - } - - for (Infura_Request request: result) - { - HttpURLConnection httpcon = null; - - try { - URL url = new URL("https://rinkeby.infura.io/AfWg0tmYEX5Kukn2UkKV"); - - if(blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token){ - if(useOurNode) { - URL tmp = new URL("http://52.230.23.88"); - url = new URL(tmp.getProtocol(), tmp.getHost(), 27172, tmp.getFile()); - }else - url = new URL("https://mainnet.infura.io/AfWg0tmYEX5Kukn2UkKV"); - - } - - if(useOurNode) - { - httpcon = (HttpURLConnection)url.openConnection(); - } - else - { - httpcon = (HttpsURLConnection)url.openConnection(); - } - - if(httpcon == null) - { - request.error = String.format("Cann't connect to %s", url.getHost()); - return result; - } - - httpcon.setRequestMethod("POST"); - httpcon.setRequestProperty("Content-Type", "application/json"); - String params = request.getAsString(); - - OutputStream os = httpcon.getOutputStream(); - if(os == null) - { - request.error = String.format("Cann't recieve data from %s", url.getHost()); - return result; - } - BufferedWriter writer = new BufferedWriter( - new OutputStreamWriter(os, "UTF-8")); - if(writer == null) - { - request.error = String.format("Cann't send data to %s", url.getHost()); - - } - writer.write(params); - writer.flush(); - writer.close(); - os.close(); - - - httpcon.connect(); - request.getParams(); - System.out.println("code:"+httpcon.getResponseCode()); - int code = httpcon.getResponseCode(); - - BufferedReader in = new BufferedReader( - new InputStreamReader(httpcon.getInputStream())); - String inputLine; - StringBuffer response = new StringBuffer(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - - request.answerData = response.toString(); - - } catch (Exception e) { - this.exception = e; - request.error = e.getMessage(); - } finally { - httpcon.disconnect(); - } - } - - return result; - } - - public String getValidationNodeDescription() { - if(blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token) - { - if(useOurNode) - return "52.230.23.88:27172"; - else - return "Infura, infura.io"; - } - - - return "Infura, rinkeby.infura.io"; - } - -} +package com.tangem.data.network.task; + +/** + * Created by Ilia on 19.12.2017. + */ + +import android.os.AsyncTask; + +import com.tangem.wallet.Blockchain; +import com.tangem.wallet.Infura_Request; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.HttpsURLConnection; + +/** + * Created by Ilia on 04.12.2017. + */ + +public class Infura_Task extends AsyncTask> { + private Exception exception; + private Blockchain blockchain; + public Infura_Task(Blockchain blockchainNet) + { + blockchain = blockchainNet; + } + boolean useOurNode = false; + protected List doInBackground(Infura_Request... requests) { + List result = new ArrayList<>(); + for (int i = 0; i < requests.length; i++) { + result.add(requests[i]); + } + + for (Infura_Request request: result) + { + HttpURLConnection httpcon = null; + + try { + URL url = new URL("https://rinkeby.infura.io/AfWg0tmYEX5Kukn2UkKV"); + + if(blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token){ + if(useOurNode) { + URL tmp = new URL("http://52.230.23.88"); + url = new URL(tmp.getProtocol(), tmp.getHost(), 27172, tmp.getFile()); + }else + url = new URL("https://mainnet.infura.io/AfWg0tmYEX5Kukn2UkKV"); + + } + + if(useOurNode) + { + httpcon = (HttpURLConnection)url.openConnection(); + } + else + { + httpcon = (HttpsURLConnection)url.openConnection(); + } + + if(httpcon == null) + { + request.error = String.format("Cann't connect to %s", url.getHost()); + return result; + } + + httpcon.setRequestMethod("POST"); + httpcon.setRequestProperty("Content-Type", "application/json"); + String params = request.getAsString(); + + OutputStream os = httpcon.getOutputStream(); + if(os == null) + { + request.error = String.format("Cann't recieve data from %s", url.getHost()); + return result; + } + BufferedWriter writer = new BufferedWriter( + new OutputStreamWriter(os, "UTF-8")); + if(writer == null) + { + request.error = String.format("Cann't send data to %s", url.getHost()); + + } + writer.write(params); + writer.flush(); + writer.close(); + os.close(); + + + httpcon.connect(); + request.getParams(); + System.out.println("code:"+httpcon.getResponseCode()); + int code = httpcon.getResponseCode(); + + BufferedReader in = new BufferedReader( + new InputStreamReader(httpcon.getInputStream())); + String inputLine; + StringBuffer response = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + request.answerData = response.toString(); + + } catch (Exception e) { + this.exception = e; + request.error = e.getMessage(); + } finally { + httpcon.disconnect(); + } + } + + return result; + } + + public String getValidationNodeDescription() { + if(blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token) + { + if(useOurNode) + return "52.230.23.88:27172"; + else + return "Infura, infura.io"; + } + + + return "Infura, rinkeby.infura.io"; + } + +} diff --git a/app/src/main/java/com/tangem/cardReader/CardCrypto.java b/app/src/main/java/com/tangem/domain/cardReader/CardCrypto.java similarity index 97% rename from app/src/main/java/com/tangem/cardReader/CardCrypto.java rename to app/src/main/java/com/tangem/domain/cardReader/CardCrypto.java index 72681ac5ba..b21b9072b4 100644 --- a/app/src/main/java/com/tangem/cardReader/CardCrypto.java +++ b/app/src/main/java/com/tangem/domain/cardReader/CardCrypto.java @@ -1,238 +1,238 @@ -package com.tangem.cardReader; - -import android.util.Log; - -import org.spongycastle.asn1.ASN1EncodableVector; -import org.spongycastle.asn1.ASN1Integer; -import org.spongycastle.asn1.DERSequence; -import org.spongycastle.jce.ECNamedCurveTable; -import org.spongycastle.jce.spec.ECNamedCurveParameterSpec; -import org.spongycastle.jce.spec.ECPrivateKeySpec; -import org.spongycastle.jce.spec.ECPublicKeySpec; -import org.spongycastle.math.ec.ECPoint; - -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Signature; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * Created by dvol on 14.11.2017. - */ - -public class CardCrypto { - public static PublicKey LoadPublicKey(byte[] publicKeyArray) throws Exception { - ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); - KeyFactory factory = KeyFactory.getInstance("EC", "SC"); - - ECPoint p1 = spec.getCurve().decodePoint(publicKeyArray); - ECPublicKeySpec keySpec = new ECPublicKeySpec(p1, spec); - - return factory.generatePublic(keySpec); - } - - public static boolean VerifySignature(byte[] publicKeyArray, byte[] data, byte[] signature) throws Exception { - Signature signatureInstance = Signature.getInstance("SHA256withECDSA"); - PublicKey publicKey = LoadPublicKey(publicKeyArray); - signatureInstance.initVerify(publicKey); - signatureInstance.update(data); - - ASN1EncodableVector v = new ASN1EncodableVector(); - int size = signature.length / 2; - v.add(/*r*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(signature, 0, size)))); - v.add(/*s*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(signature, size, size * 2)))); - byte[] sigDer = new DERSequence(v).getEncoded(); - - return signatureInstance.verify(sigDer); - } - - -// public static boolean isCanonical(BigInteger s) { -// -// ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); -// -// BigInteger HALF_CURVE_ORDER = spec.getN().shiftRight(1); -// return s.compareTo(HALF_CURVE_ORDER) <= 0; -// } -// -// public static BigInteger toCanonicalised(BigInteger s) { -// -// // The order of the curve is the number of valid points that exist on that curve. If S is in the upper -// // half of the number of valid points, then bring it back to the lower half. Otherwise, imagine that -// // N = 10 -// // s = 8, so (-8 % 10 == 2) thus both (r, 8) and (r, 2) are valid solutions. -// // 10 - 8 == 2, giving us always the latter solution, which is canonical. -// ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); -// if(!isCanonical(s)) { -// BigInteger canon = spec.getN().subtract(s); -// //Log.e("TX_SIGN", "non Canonical S"); -// return canon; -// } -// -// return s; -// -// } -// -// public static BigInteger[] calcSign2(byte[] priv, byte[] hash) -// { -// ECDSASigner signer = new ECDSASigner(); -// BigInteger d = new BigInteger(priv); -// -// ECNamedCurveParameterSpec CURVE_PARAMS = ECNamedCurveTable.getParameterSpec("secp256k1"); -// ECDomainParameters CURVE = new ECDomainParameters(CURVE_PARAMS.getCurve(), CURVE_PARAMS.getG(), CURVE_PARAMS.getN(), -// CURVE_PARAMS.getH()); -// ECPrivateKeyParameters params = new ECPrivateKeyParameters(d, CURVE); -// //ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE); -// signer.init(true, params); -// BigInteger[] rs = signer.generateSignature(hash); -// return rs; -// -// } -// -// public static byte[] Signature3(byte[] privateKeyArray, byte[] data) throws Exception -// { -// byte[] hash=Util.calculateSHA256(data); -// BigInteger[] signBI=calcSign2(privateKeyArray, hash); -// //signBI[0]=toCanonicalised(signBI[0]); -// signBI[1]=toCanonicalised(signBI[1]); -// byte[] r = signBI[0].toByteArray(); -// byte[] s = signBI[1].toByteArray(); -// -// byte[] res = new byte[64]; -// if( r.length==32 ) { -// System.arraycopy(r, 0, res, 0, r.length); -// }else if( r.length==33 && r[0]==0 ){ -// System.arraycopy(r, 1, res, 0, r.length-1); -// }else { -// throw new Exception("unsupported r-length"); -// } -// if( s.length==32 ) { -// System.arraycopy(s, 0, res, 32, 32); -// }else{ -// throw new Exception("unsupported s-length"); -// } -// return res; -// } - - public static byte[] Signature(byte[] privateKeyArray, byte[] data) throws Exception { - ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); - KeyFactory factory = KeyFactory.getInstance("EC", "SC"); - - ECPrivateKeySpec keySpecP = new ECPrivateKeySpec(new BigInteger(1,privateKeyArray), spec); - - Signature signature = Signature.getInstance("SHA256withECDSA"); - - PrivateKey privateKey = factory.generatePrivate(keySpecP); - signature.initSign(privateKey); - signature.update(data); - byte[] enc = signature.sign(); - - if (enc[0] != 0x30) throw new Exception("bad encoding 1"); - if ((enc[1] & 0x80) != 0) throw new Exception("unsupported length encoding 1"); - if (enc[2] != 0x02) throw new Exception("bad encoding 2"); - if ((enc[3] & 0x80) != 0) throw new Exception("unsupported length encoding 2"); - int rLength = enc[3]; - - if (enc[4 + rLength] != 0x02) throw new Exception("bad encoding 3"); - if ((enc[5 + rLength] & 0x80) != 0) throw new Exception("unsupported length encoding 3"); - int sLength = enc[5 + rLength]; - - - int sPos = 6 + rLength; - byte[] res = new byte[64]; - if (rLength <= 32) { - System.arraycopy(enc, 4, res, 32-rLength, rLength); - rLength=32; - } else if (rLength == 33 && enc[4] == 0) { - rLength--; - System.arraycopy(enc, 5, res, 0, rLength); - } else { - Log.e("cardCrypto","r-length:" + String.valueOf(rLength)); - Log.e("cardCrypto","s-length:" + String.valueOf(sLength)); - Log.e("cardCrypto","enc:" +Util.bytesToHex(enc)); - throw new Exception("unsupported r-length - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc)); - } - if (sLength <= 32) { - System.arraycopy(enc, sPos, res, rLength+32-sLength, sLength); - sLength=32; - } else if (sLength == 33 && enc[sPos] == 0) { - System.arraycopy(enc, sPos + 1, res, rLength, sLength - 1); - } else { - Log.e("cardCrypto","s-length:" + String.valueOf(sLength)); - Log.e("cardCrypto","r-length:" + String.valueOf(rLength)); - Log.e("cardCrypto","enc:" +Util.bytesToHex(enc)); - throw new Exception("unsupported s-length - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc)); - } - - if(!VerifySignature(GeneratePublicKey(privateKeyArray), data, res)) - { - throw new Exception("Signature self verify failed - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc)+",res:"+Util.bytesToHex(res)); - } - - return res; - } - - public static byte[] GeneratePublicKey(byte[] privateKeyArray) throws NoSuchProviderException, NoSuchAlgorithmException { - ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); - - - byte[] publicKeyArray = spec.getG().multiply(new BigInteger(1,privateKeyArray)).getEncoded(false); - - return publicKeyArray; - } - - /** - * Computes the PBKDF2 hash of a password. - * - * @param password the password to hash. - * @param salt the salt - * @param iterations the iteration count (slowness factor) - * @return the PBDKF2 hash of the password - */ - public static byte[] pbkdf2(byte[] password, byte[] salt, int iterations) - throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException { - return PBKDF2.deriveKey(password, salt, iterations); - } - - public static byte[] Encrypt(byte[] key, byte[] data) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException - { - SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/PKCS7PADDING"); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC"); - cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16])); - byte[] mEncryptedData = cipher.doFinal(data); - return mEncryptedData; - } - - public static byte[] Decrypt(byte[] key, byte[] data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { - try { - SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/PKCS7PADDING"); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING"); - cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16])); - byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length )); - return decryptedData; - } - catch (Exception e) - { - SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/NOPADDING"); - Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING"); - cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16])); - byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length )); - Log.e("decrypt",Util.bytesToHex(decryptedData)); - throw e; - } - } -} +package com.tangem.domain.cardReader; + +import android.util.Log; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.jce.ECNamedCurveTable; +import org.spongycastle.jce.spec.ECNamedCurveParameterSpec; +import org.spongycastle.jce.spec.ECPrivateKeySpec; +import org.spongycastle.jce.spec.ECPublicKeySpec; +import org.spongycastle.math.ec.ECPoint; + +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * Created by dvol on 14.11.2017. + */ + +public class CardCrypto { + public static PublicKey LoadPublicKey(byte[] publicKeyArray) throws Exception { + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); + KeyFactory factory = KeyFactory.getInstance("EC", "SC"); + + ECPoint p1 = spec.getCurve().decodePoint(publicKeyArray); + ECPublicKeySpec keySpec = new ECPublicKeySpec(p1, spec); + + return factory.generatePublic(keySpec); + } + + public static boolean VerifySignature(byte[] publicKeyArray, byte[] data, byte[] signature) throws Exception { + Signature signatureInstance = Signature.getInstance("SHA256withECDSA"); + PublicKey publicKey = LoadPublicKey(publicKeyArray); + signatureInstance.initVerify(publicKey); + signatureInstance.update(data); + + ASN1EncodableVector v = new ASN1EncodableVector(); + int size = signature.length / 2; + v.add(/*r*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(signature, 0, size)))); + v.add(/*s*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(signature, size, size * 2)))); + byte[] sigDer = new DERSequence(v).getEncoded(); + + return signatureInstance.verify(sigDer); + } + + +// public static boolean isCanonical(BigInteger s) { +// +// ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); +// +// BigInteger HALF_CURVE_ORDER = spec.getN().shiftRight(1); +// return s.compareTo(HALF_CURVE_ORDER) <= 0; +// } +// +// public static BigInteger toCanonicalised(BigInteger s) { +// +// // The order of the curve is the number of valid points that exist on that curve. If S is in the upper +// // half of the number of valid points, then bring it back to the lower half. Otherwise, imagine that +// // N = 10 +// // s = 8, so (-8 % 10 == 2) thus both (r, 8) and (r, 2) are valid solutions. +// // 10 - 8 == 2, giving us always the latter solution, which is canonical. +// ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); +// if(!isCanonical(s)) { +// BigInteger canon = spec.getN().subtract(s); +// //Log.e("TX_SIGN", "non Canonical S"); +// return canon; +// } +// +// return s; +// +// } +// +// public static BigInteger[] calcSign2(byte[] priv, byte[] hash) +// { +// ECDSASigner signer = new ECDSASigner(); +// BigInteger d = new BigInteger(priv); +// +// ECNamedCurveParameterSpec CURVE_PARAMS = ECNamedCurveTable.getParameterSpec("secp256k1"); +// ECDomainParameters CURVE = new ECDomainParameters(CURVE_PARAMS.getCurve(), CURVE_PARAMS.getG(), CURVE_PARAMS.getN(), +// CURVE_PARAMS.getH()); +// ECPrivateKeyParameters params = new ECPrivateKeyParameters(d, CURVE); +// //ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE); +// signer.init(true, params); +// BigInteger[] rs = signer.generateSignature(hash); +// return rs; +// +// } +// +// public static byte[] Signature3(byte[] privateKeyArray, byte[] data) throws Exception +// { +// byte[] hash=Util.calculateSHA256(data); +// BigInteger[] signBI=calcSign2(privateKeyArray, hash); +// //signBI[0]=toCanonicalised(signBI[0]); +// signBI[1]=toCanonicalised(signBI[1]); +// byte[] r = signBI[0].toByteArray(); +// byte[] s = signBI[1].toByteArray(); +// +// byte[] res = new byte[64]; +// if( r.length==32 ) { +// System.arraycopy(r, 0, res, 0, r.length); +// }else if( r.length==33 && r[0]==0 ){ +// System.arraycopy(r, 1, res, 0, r.length-1); +// }else { +// throw new Exception("unsupported r-length"); +// } +// if( s.length==32 ) { +// System.arraycopy(s, 0, res, 32, 32); +// }else{ +// throw new Exception("unsupported s-length"); +// } +// return res; +// } + + public static byte[] Signature(byte[] privateKeyArray, byte[] data) throws Exception { + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); + KeyFactory factory = KeyFactory.getInstance("EC", "SC"); + + ECPrivateKeySpec keySpecP = new ECPrivateKeySpec(new BigInteger(1,privateKeyArray), spec); + + Signature signature = Signature.getInstance("SHA256withECDSA"); + + PrivateKey privateKey = factory.generatePrivate(keySpecP); + signature.initSign(privateKey); + signature.update(data); + byte[] enc = signature.sign(); + + if (enc[0] != 0x30) throw new Exception("bad encoding 1"); + if ((enc[1] & 0x80) != 0) throw new Exception("unsupported length encoding 1"); + if (enc[2] != 0x02) throw new Exception("bad encoding 2"); + if ((enc[3] & 0x80) != 0) throw new Exception("unsupported length encoding 2"); + int rLength = enc[3]; + + if (enc[4 + rLength] != 0x02) throw new Exception("bad encoding 3"); + if ((enc[5 + rLength] & 0x80) != 0) throw new Exception("unsupported length encoding 3"); + int sLength = enc[5 + rLength]; + + + int sPos = 6 + rLength; + byte[] res = new byte[64]; + if (rLength <= 32) { + System.arraycopy(enc, 4, res, 32-rLength, rLength); + rLength=32; + } else if (rLength == 33 && enc[4] == 0) { + rLength--; + System.arraycopy(enc, 5, res, 0, rLength); + } else { + Log.e("cardCrypto","r-length:" + String.valueOf(rLength)); + Log.e("cardCrypto","s-length:" + String.valueOf(sLength)); + Log.e("cardCrypto","enc:" +Util.bytesToHex(enc)); + throw new Exception("unsupported r-length - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc)); + } + if (sLength <= 32) { + System.arraycopy(enc, sPos, res, rLength+32-sLength, sLength); + sLength=32; + } else if (sLength == 33 && enc[sPos] == 0) { + System.arraycopy(enc, sPos + 1, res, rLength, sLength - 1); + } else { + Log.e("cardCrypto","s-length:" + String.valueOf(sLength)); + Log.e("cardCrypto","r-length:" + String.valueOf(rLength)); + Log.e("cardCrypto","enc:" +Util.bytesToHex(enc)); + throw new Exception("unsupported s-length - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc)); + } + + if(!VerifySignature(GeneratePublicKey(privateKeyArray), data, res)) + { + throw new Exception("Signature self verify failed - r-length:" + String.valueOf(rLength)+",s-length:" + String.valueOf(sLength)+",enc:" +Util.bytesToHex(enc)+",res:"+Util.bytesToHex(res)); + } + + return res; + } + + public static byte[] GeneratePublicKey(byte[] privateKeyArray) throws NoSuchProviderException, NoSuchAlgorithmException { + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); + + + byte[] publicKeyArray = spec.getG().multiply(new BigInteger(1,privateKeyArray)).getEncoded(false); + + return publicKeyArray; + } + + /** + * Computes the PBKDF2 hash of a password. + * + * @param password the password to hash. + * @param salt the salt + * @param iterations the iteration count (slowness factor) + * @return the PBDKF2 hash of the password + */ + public static byte[] pbkdf2(byte[] password, byte[] salt, int iterations) + throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException { + return PBKDF2.deriveKey(password, salt, iterations); + } + + public static byte[] Encrypt(byte[] key, byte[] data) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException + { + SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/PKCS7PADDING"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16])); + byte[] mEncryptedData = cipher.doFinal(data); + return mEncryptedData; + } + + public static byte[] Decrypt(byte[] key, byte[] data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + try { + SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/PKCS7PADDING"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING"); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16])); + byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length )); + return decryptedData; + } + catch (Exception e) + { + SecretKeySpec skeySpec = new SecretKeySpec(key, "AES/CBC/NOPADDING"); + Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING"); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16])); + byte[] decryptedData = cipher.doFinal(Arrays.copyOfRange(data, 0, data.length )); + Log.e("decrypt",Util.bytesToHex(decryptedData)); + throw e; + } + } +} diff --git a/app/src/main/java/com/tangem/cardReader/CardProtocol.java b/app/src/main/java/com/tangem/domain/cardReader/CardProtocol.java similarity index 97% rename from app/src/main/java/com/tangem/cardReader/CardProtocol.java rename to app/src/main/java/com/tangem/domain/cardReader/CardProtocol.java index 9943bbe653..7f05266bab 100644 --- a/app/src/main/java/com/tangem/cardReader/CardProtocol.java +++ b/app/src/main/java/com/tangem/domain/cardReader/CardProtocol.java @@ -1,954 +1,951 @@ -package com.tangem.cardReader; - -import android.content.Context; -import android.nfc.Tag; -import android.nfc.TagLostException; -import android.nfc.tech.IsoDep; -import android.util.Log; - -import com.tangem.wallet.CoinEngine; -import com.tangem.wallet.CoinEngineFactory; -import com.tangem.wallet.Issuer; -import com.tangem.wallet.Tangem_Card; -import com.tangem.wallet.Manufacturer; - -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; -import java.security.InvalidKeyException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SecureRandom; -import java.security.Security; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.InvalidKeySpecException; -import java.util.Calendar; - -import javax.crypto.KeyAgreement; - - -/** - * Created by dvol on 14.07.2017. - */ - -public class CardProtocol { - - - public interface Notifications { - void OnReadStart(CardProtocol cardProtocol); - - void OnReadProgress(CardProtocol cardProtocol, int progress); - - void OnReadFinish(CardProtocol cardProtocol); - - void OnReadCancel(); - - void OnReadWait(int msec); - - void OnReadBeforeRequest(int timeout); - - void OnReadAfterRequest(); - } - - - public void setError(Exception error) { - mError = error; - } - - public Tangem_Card getCard() { - return mCard; - } - - public Exception getError() { - return mError; - } - - private static final String logTag = "CardProtocol"; - public static final int SW_PIN_ERROR = SW.INVALID_PARAMS; - - public static final String DefaultPIN = "000000"; - public static final String DefaultPIN2 = "000"; - - protected IsoDep mIsoDep; - - public Tag getTag() { - return mIsoDep.getTag(); - } - - protected String mPIN; - protected Notifications mNotifications; - - public void setPIN(String PIN) { - mPIN = PIN; - if (mCard != null) { - mCard.setPIN(PIN); - } - } - - protected Tangem_Card mCard; - protected Exception mError; - protected Context mContext; - - static { - Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1); - } - - public CardProtocol(Context context, IsoDep isoDep, Notifications notifications) { - mContext = context; - mIsoDep = isoDep; - mNotifications = notifications; - mPIN = null; - mCard = new Tangem_Card(Util.byteArrayToHexString(mIsoDep.getTag().getId())); - } - - public CardProtocol(Context context, IsoDep isoDep, Tangem_Card card, Notifications notifications) { - mContext = context; - mIsoDep = isoDep; - mNotifications = notifications; - mPIN = card.getPIN(); - mCard = card; - } - - public static class TangemException extends Exception { - public TangemException(String message) { - super(message); - } - } - - public static class TangemException_InvalidPIN extends TangemException { - public TangemException_InvalidPIN(String message) { - super(message); - } - } - - public static class TangemException_NeedPause extends TangemException { - public TangemException_NeedPause(String message) { - super(message); - } - } - - public static class TangemException_ExtendedLengthNotSupported extends TangemException { - public TangemException_ExtendedLengthNotSupported(String message) { - super(message); - } - } - - - public byte[] GetUID() { - if (mIsoDep == null || mIsoDep.getTag() == null) return null; - return mIsoDep.getTag().getId(); - } - - public int getTimeout() { - if (mIsoDep == null || mIsoDep.getTag() == null) return 60000; - return mIsoDep.getTimeout(); - } - - - protected byte[] protocolKey; - - public void resetProtocolKey() { - protocolKey = null; - } - - public void CreateProtocolKey() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException { - protocolKey = CardCrypto.pbkdf2(Util.calculateSHA256(mPIN), mIsoDep.getTag().getId(), 50); - //Log.e("Reader", String.format("PIN: %s, Protocol key: %s", mPIN, Util.bytesToHex(protocolKey))); - if (sessionKey != null) { - sessionKey = null; - } - } - - byte[] sessionKey = null; - - public void run_OpenSession(Tangem_Card.EncryptionMode encryptionMode) throws Exception { - sessionKey = null; - try { - CommandApdu cmdApdu = new CommandApdu(CommandApdu.ISO_CLA, INS.OpenSession.Code, 0, encryptionMode.getP()); - - switch (encryptionMode) { - case Fast: { - byte[] baMyChallenge = Util.generateRandomBytes(16); - - cmdApdu.addTLV(TLV.Tag.TAG_Session_Key_A, baMyChallenge); - Log.i(logTag, cmdApdu.getCommandName()); - ResponseApdu rspApdu = null; - - try { - if (mIsoDep == null) { - throw new TagLostException(); - } - byte[] cmdBytes = cmdApdu.toBytes(); - String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc()); - Log.v("NFC", String.format("<< [%s]: %s", cmdApdu.getCommandName(), cmdStr)); - - byte[] rsp = mIsoDep.transceive(cmdBytes); - rspApdu = new ResponseApdu(rsp); - - Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); - - if (rspApdu.isParsedWithError()) { - throw new Exception("Can't parse answer"); - } - } catch (Exception E) { - sessionKey = null; - throw E; - } - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - byte[] baTheirsChallenge = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Session_Key_B).Value; - if (protocolKey == null) CreateProtocolKey(); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write(baMyChallenge); - outputStream.write(baTheirsChallenge); - outputStream.write(protocolKey); - sessionKey = Util.calculateSHA256(outputStream.toByteArray()); - //Log.i(logTag, String.format("Session key: %s", Util.bytesToHex(sessionKey))); - } else { - Log.e(logTag, String.format("Failed: %04X - %s", rspApdu.getSW1SW2(), rspApdu.getSW1SW2Description())); - throw new Exception(String.format("Can't open session: SW - %04X", rspApdu.getSW1SW2())); - } - } - break; - case Strong: { - KeyPairGenerator kpgen = KeyPairGenerator.getInstance("ECDH", "SC"); - kpgen.initialize(new ECGenParameterSpec("secp256k1"), new SecureRandom()); - KeyPair KP = kpgen.generateKeyPair(); - KeyAgreement ka = KeyAgreement.getInstance("ECDH", "SC"); - ka.init(KP.getPrivate()); - - ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); - //return spec.getG().multiply(new BigInteger((ECPrivateKey) )).getEncoded(false); - ECPublicKey eckey = (ECPublicKey) KP.getPublic(); - byte[] baMyPublicKey = eckey.getQ().getEncoded(false); - - cmdApdu.addTLV(TLV.Tag.TAG_Session_Key_A, baMyPublicKey); - Log.i(logTag, cmdApdu.getCommandName()); - ResponseApdu rspApdu = null; - - try { - if (mIsoDep == null) { - throw new TagLostException(); - } - //mIsoDep.setTimeout(msTimeout); - - byte[] cmdBytes = cmdApdu.toBytes(); - String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc()); - Log.v("NFC", String.format("<< [%s]: %s", cmdApdu.getCommandName(), cmdStr)); - byte[] rsp = mIsoDep.transceive(cmdBytes); - rspApdu = new ResponseApdu(rsp); - Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); - - if (rspApdu.isParsedWithError()) { - throw new Exception("Can't parse answer"); - } - } catch (Exception E) { - sessionKey = null; - throw E; - } - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - byte[] baTheirsPublicKey = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Session_Key_B).Value; - ka.doPhase(CardCrypto.LoadPublicKey(baTheirsPublicKey), true); - if (protocolKey == null) CreateProtocolKey(); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - outputStream.write(ka.generateSecret()); - outputStream.write(protocolKey); - sessionKey = Util.calculateSHA256(outputStream.toByteArray()); -// Log.i(logTag, String.format("Session key: %s", Util.bytesToHex(sessionKey))); - } else { - Log.i(logTag, String.format("Failed: %04X - %s", rspApdu.getSW1SW2(), rspApdu.getSW1SW2Description())); - throw new Exception(String.format("Can't open session: SW - %04X", rspApdu.getSW1SW2())); - } - } - break; - default: - throw new Exception("Unknown encryption mode"); - } - } catch (Exception e) { - e.printStackTrace(); - Log.e(logTag, String.format("Exception: %s", e.getMessage())); - throw new Exception("Can't open session: " + e.getMessage()); - } - } - - - // send command APDU, get response APDU, and display HEX data to user - private ResponseApdu SendAndReceive(CommandApdu cmdApdu, boolean breakOnNeedPause) throws Exception { - if (mCard.encryptionMode != Tangem_Card.EncryptionMode.None) { - if (sessionKey == null) { - run_OpenSession(mCard.encryptionMode); - } - cmdApdu.Crypt(sessionKey); - } - cmdApdu.setP1(mCard.encryptionMode.getP()); - byte[] cmdBytes = cmdApdu.toBytes(); - String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc()); - Log.v("NFC", String.format("<< [%s]: %s", cmdApdu.getCommandName(), cmdStr)); - byte[] rsp; - ResponseApdu rspApdu; - try { - do { - try { - mNotifications.OnReadBeforeRequest(mIsoDep.getTimeout()); - try { - rsp = mIsoDep.transceive(cmdBytes); - } finally { - mNotifications.OnReadAfterRequest(); - } - } catch (IOException e) { - if (e.getMessage().contains("length exceeds supported maximum") && mIsoDep.isExtendedLengthApduSupported()) { - throw new TangemException_ExtendedLengthNotSupported(e.getMessage()); - } - throw e; - } - if (mCard.encryptionMode != Tangem_Card.EncryptionMode.None) { - rspApdu = ResponseApdu.Decrypt(rsp, sessionKey); - } else { - rspApdu = new ResponseApdu(rsp); - } - - if (rspApdu.isParsedWithError()) { - Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); - throw new TangemException(rspApdu.getParseErroMessage()); - } else if (rspApdu.getSW1SW2() == SW.NEED_PAUSE && mNotifications != null) { - int remainingPause = rspApdu.getTLVs().getTagAsInt(TLV.Tag.TAG_Pause) * 10; - Log.v("NFC", String.format(">> Security delay, remaining %f s", remainingPause / 1000.0)); - if (breakOnNeedPause) { - break; - } else { - mNotifications.OnReadWait(remainingPause); - } - } else { - Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); - } - } while (rspApdu.getSW1SW2() == SW.NEED_PAUSE); - } finally { - mNotifications.OnReadWait(0); - } - - return rspApdu; - } - - private CommandApdu StartPrepareCommand(INS ins) throws NoSuchAlgorithmException { - CommandApdu Apdu = new CommandApdu(ins); - byte[] baPIN = Util.calculateSHA256(mPIN); - Apdu.addTLV(TLV.Tag.TAG_PIN, baPIN); - if (ins != INS.Read) { - Apdu.addTLV(TLV.Tag.TAG_CardID, mCard.getCID()); - } - return Apdu; - } - - public void run_Read() throws Exception { - CommandApdu rqApdu = StartPrepareCommand(INS.Read); - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - - - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - - - readResult = rspApdu.getTLVs(); - - parseReadResult(); - - run_ReadOrWriteIssuerDataAndDefineOfflineBalance(); - - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible PIN is invalid!\n", rspApdu.getSW1SW2())); - } else { - throw new TangemException(String.format("FAILED: [%04X]\n", rspApdu.getSW1SW2())); - } - } - - public void run_ReadOrWriteIssuerDataAndDefineOfflineBalance() 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_ReadIssuerData(); - } catch (Exception e) { - e.printStackTrace(); - tlvIssuerData = null; - } - } - if (mCard.getStatus() == Tangem_Card.Status.Loaded) { - // try read offline balance data - if (tlvIssuerData != null && tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination) != null && mCard.getMaxSignatures() == mCard.getRemainingSignatures()) { - mCard.setOfflineBalance(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value); - } else { - mCard.clearOfflineBalance(); - } - } else { - mCard.clearOfflineBalance(); - } - } - - private TLVList readResult = null; - - public void clearReadResult() { - sessionKey = null; - readResult = null; - } - - public boolean haveReadResult() { - return readResult != null; - } - - public void parseReadResult() throws TangemException, NoSuchProviderException, NoSuchAlgorithmException { - TLV tlvStatus = readResult.getTLV(TLV.Tag.TAG_Status); - mCard.setStatus(Tangem_Card.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); - mCard.setHealth(readResult.getTLV(TLV.Tag.TAG_Health).getAsInt()); - - if (mCard.getStatus() != Tangem_Card.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); - - 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()); - - // this method has reflection TokenSymbol - // you mast call setBlockchainIDFromCard after calling setTokensDecimal - mCard.setBlockchainIDFromCard(tlvCardData.getTLV(TLV.Tag.TAG_Blockchain_ID).getAsString()); - 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 { - if (readResult.getTLV(TLV.Tag.TAG_Firmware) != null) { - mCard.setFirmwareVersion(readResult.getTLV(TLV.Tag.TAG_Firmware).getAsString()); - } else { - 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) { - mCard.setIssuer(Issuer.FindIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), readResult.getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value)); - } else { - mCard.setIssuer(Issuer.FindIssuer(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 { - mCard.setIssuer(Issuer.FindIssuer(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); - } - } - - 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"); - } - } - - - if (mCard.getStatus() == Tangem_Card.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); - - CoinEngine engineCoin = CoinEngineFactory.Create(mCard.getBlockchain()); - String wallet = engineCoin.calculateAddress(mCard, pkUncompressed); - mCard.setWallet(wallet); - //mCard.setWallet(Blockchain.calculateWalletAddress(mCard, pkUncompressed)); - - mCard.setRemainingSignatures(readResult.getTagAsInt(TLV.Tag.TAG_RemainingSignatures)); - - } else { - mCard.setWallet("N/A"); - } - } - - - public TLVList run_VerifyCard() throws Exception { - if (mCard.getCardPublicKey() == null || readResult == null) { - run_Read(); - } - if (mCard.getStatus() == Tangem_Card.Status.NotPersonalized) { - getCard().setManufacturer(Manufacturer.Unknown, false); - return null; - } - - if (mCard.getCardPublicKey() == null) { - throw new TangemException("Not all data read, can't verify card!"); - } - - CommandApdu rqApdu = StartPrepareCommand(INS.VerifyCard); - byte[] bChallenge = Util.generateRandomBytes(16); - rqApdu.addTLV(TLV.Tag.TAG_Challenge, bChallenge); - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - TLVList verifyResult = rspApdu.getTLVs(); - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - verifyResult.add(new TLV(TLV.Tag.TAG_Challenge, bChallenge)); - - TLV tlvSalt = verifyResult.getTLV(TLV.Tag.TAG_Salt); - TLV tlvCardSignature = verifyResult.getTLV(TLV.Tag.TAG_CardSignature); -// TLV tlvManufacturerSignature = verifyResult.getTLV(TLV.Tag.TAG_Manufacturer_Signature); - - if (tlvSalt == null || tlvCardSignature == null) { - throw new TangemException("Not all data read, can't verify card!"); - } - - try { - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - bs.write(bChallenge); - bs.write(tlvSalt.Value); - byte[] dataArray = bs.toByteArray(); - if (CardCrypto.VerifySignature(mCard.getCardPublicKey(), dataArray, tlvCardSignature.Value)) { - getCard().setCardPublicKeyValid(true); - Log.i(logTag, "Card signature verification OK"); - } else { - Log.e(logTag, "Card signature verification FAILED"); - getCard().setCardPublicKeyValid(false); - } - - //getCard().setManufacturer(Manufacturer.FindManufacturer(readResult.getTLV(TLV.Tag.TAG_Manufacture_ID).getAsString(), bChallenge, tlvSalt.Value, tlvManufacturerSignature.Value), true); - getCard().setManufacturer(Manufacturer.FindManufacturer(readResult.getTLV(TLV.Tag.TAG_Manufacture_ID).getAsString()), true); - } catch (Exception e) { - e.printStackTrace(); - getCard().setManufacturer(Manufacturer.Unknown, false); - } - return verifyResult; - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); - } else { - getCard().setManufacturer(Manufacturer.Unknown, false); - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - - } - - public void run_CreateWallet(String PIN2) throws Exception { - if (readResult == null) run_Read(); - 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(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(true); - } - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(false); - } - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - public TLVList run_CheckWallet() throws Exception { - CommandApdu rqApdu = StartPrepareCommand(INS.CheckWallet); - byte[] bChallenge = Util.generateRandomBytes(16); - rqApdu.addTLV(TLV.Tag.TAG_Challenge, bChallenge); - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - TLVList Result = rspApdu.getTLVs(); - Result.add(new TLV(TLV.Tag.TAG_Challenge, bChallenge)); - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - return Result; - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - public void run_CheckWalletWithSignatureVerify() throws Exception { - if (mCard.getCardPublicKey() == null || readResult == null) { - run_Read(); - } - if (mCard.getStatus() == Tangem_Card.Status.NotPersonalized) { - getCard().setManufacturer(Manufacturer.Unknown, false); - return; - } - - if (readResult.getTagAsInt(TLV.Tag.TAG_Status) != Tangem_Card.Status.Loaded.getCode()) { - throw new TangemException("Card must be loaded"); - } - TLVList checkResult = run_CheckWallet(); - if (checkResult == null) return; - - TLV tlvPublicKey = readResult.getTLV(TLV.Tag.TAG_Wallet_PublicKey); - TLV tlvChallenge = checkResult.getTLV(TLV.Tag.TAG_Challenge); - TLV tlvSalt = checkResult.getTLV(TLV.Tag.TAG_Salt); - TLV tlvSignature = checkResult.getTLV(TLV.Tag.TAG_Signature); - - if (tlvPublicKey == null || tlvChallenge == null || tlvSalt == null || tlvSignature == null) { - throw new TangemException("Not all data read, can't check signature!"); - } - - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - bs.write(tlvChallenge.Value); - bs.write(tlvSalt.Value); - byte[] dataArray = bs.toByteArray(); - - if (CardCrypto.VerifySignature(tlvPublicKey.Value, dataArray, tlvSignature.Value)) { - Log.i(logTag, "Signature verification OK"); - mCard.setWalletPublicKeyValid(true); - } else { - mCard.setWalletPublicKeyValid(false); - } - } - - public void run_PurgeWallet(String PIN2) throws Exception { - CommandApdu rqApdu = StartPrepareCommand(INS.PurgeWallet); - rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2)); - - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(true); - } - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(false); - } - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); - } else { - - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - public void run_SwapPIN(String PIN2, String newPin, String newPin2, boolean breakOnNeedPause) throws Exception { - CommandApdu rqApdu = StartPrepareCommand(INS.SwapPIN); - rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2)); - rqApdu.addTLV(TLV.Tag.TAG_NewPIN, Util.calculateSHA256(newPin)); - rqApdu.addTLV(TLV.Tag.TAG_NewPIN2, Util.calculateSHA256(newPin2)); - - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, breakOnNeedPause); - - if (rspApdu.isStatus(SW.PIN1_CHANGED) || rspApdu.isStatus(SW.PIN2_CHANGED) || rspApdu.isStatus(SW.PINS_CHANGED) || rspApdu.isStatus(SW.PINS_NOT_CHANGED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - if (newPin2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(true); - } else { - mCard.setUseDefaultPIN2(false); - } - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(false); - } - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); - } else if (breakOnNeedPause && rspApdu.isStatus(SW.NEED_PAUSE)) { - throw new TangemException_NeedPause(String.format("FAILED: [%04X] - Need pause\n", rspApdu.getSW1SW2())); - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - public void run_CheckPIN2isDefault() throws Exception { - if (mCard.isFirmwareNewer("1.19") || (mCard.isFirmwareNewer("1.12") && (mCard.getPauseBeforePIN2() == 0 || mCard.useSmartSecurityDelay()))) { - // can obtain SwapPIN(to default) answer without security delay - try check if PIN2 is default with card request - try { - run_SwapPIN(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); - } - } - - public TLVList run_SignHashes(String PIN2, byte[][] hashes, boolean UseIssuerValidation, byte[] issuerData, Issuer issuer) throws Exception { - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - if (hashes.length > 10) throw new Exception("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!"); - 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); - } - - - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - TLVList Result = rspApdu.getTLVs(); - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(true); - } - return Result; - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(false); - } - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible the PIN or PIN2 is invalid!\n", rspApdu.getSW1SW2())); - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - public TLVList run_SignRaw(String PIN2, byte[] bTxOutData) 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")); - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - TLVList Result = rspApdu.getTLVs(); - Result.add(new TLV(TLV.Tag.TAG_TrOut_Raw, bTxOutData)); - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(true); - } - return Result; - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(false); - } - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible the PIN or PIN2 is invalid!\n", rspApdu.getSW1SW2())); - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - private byte[] run_VerifyCode(String hashAlgID, int codePageAddress, int codePageCount, byte[] challenge) throws Exception { - if (readResult == null) run_Read(); - CommandApdu rqApdu = StartPrepareCommand(INS.VerifyCode); - rqApdu.addTLV(TLV.Tag.TAG_HashAlgID, hashAlgID.getBytes("US-ASCII")); - rqApdu.addTLV_U32(TLV.Tag.TAG_CodePageAddress, codePageAddress); - rqApdu.addTLV_U16(TLV.Tag.TAG_CodePageCount, codePageCount); - rqApdu.addTLV(TLV.Tag.TAG_Challenge, challenge); - - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - return rspApdu.getTLVs().getTLV(TLV.Tag.TAG_CodeHash).Value; - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - private void run_ValidateCard(String PIN2) throws Exception { - if (readResult == null) run_Read(); - CommandApdu rqApdu = StartPrepareCommand(INS.ValidateCard); - rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2)); - - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(true); - } - } else if (rspApdu.isStatus(SW_PIN_ERROR)) { - if (PIN2.equals(DefaultPIN2)) { - mCard.setUseDefaultPIN2(false); - } - throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible the PIN or PIN2 is invalid!\n", rspApdu.getSW1SW2())); - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - private void run_WriteIssuerData(byte[] issuerData, byte[] issuerSignature) throws Exception { - run_Read(); - - CommandApdu rqApdu = StartPrepareCommand(INS.WriteIssuerData); - rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data, issuerData); - rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data_Signature, issuerSignature); - - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - private TLVList run_ReadIssuerData() throws Exception { - CommandApdu rqApdu = StartPrepareCommand(INS.GetIssuerData); - - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - TLV issuerData = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Issuer_Data); - TLV issuerDataSignature = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Issuer_Data_Signature); - - if (issuerData == null || issuerDataSignature == null) - throw new TangemException("Invalid answer format (GetIssuerData)"); - - ByteArrayOutputStream bsDataToVerify = new ByteArrayOutputStream(); - bsDataToVerify.write(mCard.getCID()); - bsDataToVerify.write(issuerData.Value); - try { - if (CardCrypto.VerifySignature(mCard.getIssuer().getPublicDataKey(), bsDataToVerify.toByteArray(), issuerDataSignature.Value)) { - mCard.setIssuerData(issuerData.Value, issuerDataSignature.Value); - return TLVList.fromBytes(issuerData.Value); - } else { - throw new TangemException("Invalid issuer data read (signature verification failed)"); - } - } catch (Exception e) { - e.printStackTrace(); - throw new TangemException("Invalid issuer data read"); - } - } else { - throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); - } - } - - public void run_GetSupportedEncryption() throws Exception { - mCard.encryptionMode = Tangem_Card.EncryptionMode.None; - do { - CommandApdu rqApdu = StartPrepareCommand(INS.Read); - Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); - - ResponseApdu rspApdu = SendAndReceive(rqApdu, false); - - if (rspApdu.isStatus(SW.NEED_ENCRYPTION)) { - if (mCard.encryptionMode == Tangem_Card.EncryptionMode.None) { - mCard.encryptionMode = Tangem_Card.EncryptionMode.Fast; - } else if (mCard.encryptionMode == Tangem_Card.EncryptionMode.Fast) { - mCard.encryptionMode = Tangem_Card.EncryptionMode.Strong; - } else { - throw new Exception("Can't get supported encryption methods"); - } - } else if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { - Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); - readResult = rspApdu.getTLVs(); - mCard.setPIN(mPIN); - break; - } else { - break; - } - } while (true); - } - -} +package com.tangem.domain.cardReader; + +import android.content.Context; +import android.nfc.Tag; +import android.nfc.TagLostException; +import android.nfc.tech.IsoDep; +import android.util.Log; + +import com.tangem.wallet.CoinEngine; +import com.tangem.wallet.CoinEngineFactory; +import com.tangem.wallet.Issuer; +import com.tangem.wallet.Tangem_Card; +import com.tangem.wallet.Manufacturer; + +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; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.util.Calendar; + +import javax.crypto.KeyAgreement; + +/** + * Created by dvol on 14.07.2017. + */ + +public class CardProtocol { + + public interface Notifications { + void OnReadStart(CardProtocol cardProtocol); + + void OnReadProgress(CardProtocol cardProtocol, int progress); + + void OnReadFinish(CardProtocol cardProtocol); + + void OnReadCancel(); + + void OnReadWait(int msec); + + void OnReadBeforeRequest(int timeout); + + void OnReadAfterRequest(); + } + + public void setError(Exception error) { + mError = error; + } + + public Tangem_Card getCard() { + return mCard; + } + + public Exception getError() { + return mError; + } + + private static final String logTag = "CardProtocol"; + public static final int SW_PIN_ERROR = SW.INVALID_PARAMS; + + public static final String DefaultPIN = "000000"; + public static final String DefaultPIN2 = "000"; + + protected IsoDep mIsoDep; + + public Tag getTag() { + return mIsoDep.getTag(); + } + + protected String mPIN; + protected Notifications mNotifications; + + public void setPIN(String PIN) { + mPIN = PIN; + if (mCard != null) { + mCard.setPIN(PIN); + } + } + + protected Tangem_Card mCard; + protected Exception mError; + protected Context mContext; + + static { + Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1); + } + + public CardProtocol(Context context, IsoDep isoDep, Notifications notifications) { + mContext = context; + mIsoDep = isoDep; + mNotifications = notifications; + mPIN = null; + mCard = new Tangem_Card(Util.byteArrayToHexString(mIsoDep.getTag().getId())); + } + + public CardProtocol(Context context, IsoDep isoDep, Tangem_Card card, Notifications notifications) { + mContext = context; + mIsoDep = isoDep; + mNotifications = notifications; + mPIN = card.getPIN(); + mCard = card; + } + + public static class TangemException extends Exception { + public TangemException(String message) { + super(message); + } + } + + public static class TangemException_InvalidPIN extends TangemException { + public TangemException_InvalidPIN(String message) { + super(message); + } + } + + public static class TangemException_NeedPause extends TangemException { + public TangemException_NeedPause(String message) { + super(message); + } + } + + public static class TangemException_ExtendedLengthNotSupported extends TangemException { + public TangemException_ExtendedLengthNotSupported(String message) { + super(message); + } + } + + + public byte[] GetUID() { + if (mIsoDep == null || mIsoDep.getTag() == null) return null; + return mIsoDep.getTag().getId(); + } + + public int getTimeout() { + if (mIsoDep == null || mIsoDep.getTag() == null) return 60000; + return mIsoDep.getTimeout(); + } + + + protected byte[] protocolKey; + + public void resetProtocolKey() { + protocolKey = null; + } + + public void CreateProtocolKey() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException { + protocolKey = CardCrypto.pbkdf2(Util.calculateSHA256(mPIN), mIsoDep.getTag().getId(), 50); + //Log.e("Reader", String.format("PIN: %s, Protocol key: %s", mPIN, Util.bytesToHex(protocolKey))); + if (sessionKey != null) { + sessionKey = null; + } + } + + byte[] sessionKey = null; + + public void run_OpenSession(Tangem_Card.EncryptionMode encryptionMode) throws Exception { + sessionKey = null; + try { + CommandApdu cmdApdu = new CommandApdu(CommandApdu.ISO_CLA, INS.OpenSession.Code, 0, encryptionMode.getP()); + + switch (encryptionMode) { + case Fast: { + byte[] baMyChallenge = Util.generateRandomBytes(16); + + cmdApdu.addTLV(TLV.Tag.TAG_Session_Key_A, baMyChallenge); + Log.i(logTag, cmdApdu.getCommandName()); + ResponseApdu rspApdu = null; + + try { + if (mIsoDep == null) { + throw new TagLostException(); + } + byte[] cmdBytes = cmdApdu.toBytes(); + String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc()); + Log.v("NFC", String.format("<< [%s]: %s", cmdApdu.getCommandName(), cmdStr)); + + byte[] rsp = mIsoDep.transceive(cmdBytes); + rspApdu = new ResponseApdu(rsp); + + Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); + + if (rspApdu.isParsedWithError()) { + throw new Exception("Can't parse answer"); + } + } catch (Exception E) { + sessionKey = null; + throw E; + } + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + byte[] baTheirsChallenge = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Session_Key_B).Value; + if (protocolKey == null) CreateProtocolKey(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write(baMyChallenge); + outputStream.write(baTheirsChallenge); + outputStream.write(protocolKey); + sessionKey = Util.calculateSHA256(outputStream.toByteArray()); + //Log.i(logTag, String.format("Session key: %s", Util.bytesToHex(sessionKey))); + } else { + Log.e(logTag, String.format("Failed: %04X - %s", rspApdu.getSW1SW2(), rspApdu.getSW1SW2Description())); + throw new Exception(String.format("Can't open session: SW - %04X", rspApdu.getSW1SW2())); + } + } + break; + case Strong: { + KeyPairGenerator kpgen = KeyPairGenerator.getInstance("ECDH", "SC"); + kpgen.initialize(new ECGenParameterSpec("secp256k1"), new SecureRandom()); + KeyPair KP = kpgen.generateKeyPair(); + KeyAgreement ka = KeyAgreement.getInstance("ECDH", "SC"); + ka.init(KP.getPrivate()); + + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); + //return spec.getG().multiply(new BigInteger((ECPrivateKey) )).getEncoded(false); + ECPublicKey eckey = (ECPublicKey) KP.getPublic(); + byte[] baMyPublicKey = eckey.getQ().getEncoded(false); + + cmdApdu.addTLV(TLV.Tag.TAG_Session_Key_A, baMyPublicKey); + Log.i(logTag, cmdApdu.getCommandName()); + ResponseApdu rspApdu = null; + + try { + if (mIsoDep == null) { + throw new TagLostException(); + } + //mIsoDep.setTimeout(msTimeout); + + byte[] cmdBytes = cmdApdu.toBytes(); + String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc()); + Log.v("NFC", String.format("<< [%s]: %s", cmdApdu.getCommandName(), cmdStr)); + byte[] rsp = mIsoDep.transceive(cmdBytes); + rspApdu = new ResponseApdu(rsp); + Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); + + if (rspApdu.isParsedWithError()) { + throw new Exception("Can't parse answer"); + } + } catch (Exception E) { + sessionKey = null; + throw E; + } + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + byte[] baTheirsPublicKey = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Session_Key_B).Value; + ka.doPhase(CardCrypto.LoadPublicKey(baTheirsPublicKey), true); + if (protocolKey == null) CreateProtocolKey(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write(ka.generateSecret()); + outputStream.write(protocolKey); + sessionKey = Util.calculateSHA256(outputStream.toByteArray()); +// Log.i(logTag, String.format("Session key: %s", Util.bytesToHex(sessionKey))); + } else { + Log.i(logTag, String.format("Failed: %04X - %s", rspApdu.getSW1SW2(), rspApdu.getSW1SW2Description())); + throw new Exception(String.format("Can't open session: SW - %04X", rspApdu.getSW1SW2())); + } + } + break; + default: + throw new Exception("Unknown encryption mode"); + } + } catch (Exception e) { + e.printStackTrace(); + Log.e(logTag, String.format("Exception: %s", e.getMessage())); + throw new Exception("Can't open session: " + e.getMessage()); + } + } + + + // send command APDU, get response APDU, and display HEX data to user + private ResponseApdu SendAndReceive(CommandApdu cmdApdu, boolean breakOnNeedPause) throws Exception { + if (mCard.encryptionMode != Tangem_Card.EncryptionMode.None) { + if (sessionKey == null) { + run_OpenSession(mCard.encryptionMode); + } + cmdApdu.Crypt(sessionKey); + } + cmdApdu.setP1(mCard.encryptionMode.getP()); + byte[] cmdBytes = cmdApdu.toBytes(); + String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc()); + Log.v("NFC", String.format("<< [%s]: %s", cmdApdu.getCommandName(), cmdStr)); + byte[] rsp; + ResponseApdu rspApdu; + try { + do { + try { + mNotifications.OnReadBeforeRequest(mIsoDep.getTimeout()); + try { + rsp = mIsoDep.transceive(cmdBytes); + } finally { + mNotifications.OnReadAfterRequest(); + } + } catch (IOException e) { + if (e.getMessage().contains("length exceeds supported maximum") && mIsoDep.isExtendedLengthApduSupported()) { + throw new TangemException_ExtendedLengthNotSupported(e.getMessage()); + } + throw e; + } + if (mCard.encryptionMode != Tangem_Card.EncryptionMode.None) { + rspApdu = ResponseApdu.Decrypt(rsp, sessionKey); + } else { + rspApdu = new ResponseApdu(rsp); + } + + if (rspApdu.isParsedWithError()) { + Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); + throw new TangemException(rspApdu.getParseErroMessage()); + } else if (rspApdu.getSW1SW2() == SW.NEED_PAUSE && mNotifications != null) { + int remainingPause = rspApdu.getTLVs().getTagAsInt(TLV.Tag.TAG_Pause) * 10; + Log.v("NFC", String.format(">> Security delay, remaining %f s", remainingPause / 1000.0)); + if (breakOnNeedPause) { + break; + } else { + mNotifications.OnReadWait(remainingPause); + } + } else { + Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp))); + } + } while (rspApdu.getSW1SW2() == SW.NEED_PAUSE); + } finally { + mNotifications.OnReadWait(0); + } + + return rspApdu; + } + + private CommandApdu StartPrepareCommand(INS ins) throws NoSuchAlgorithmException { + CommandApdu Apdu = new CommandApdu(ins); + byte[] baPIN = Util.calculateSHA256(mPIN); + Apdu.addTLV(TLV.Tag.TAG_PIN, baPIN); + if (ins != INS.Read) { + Apdu.addTLV(TLV.Tag.TAG_CardID, mCard.getCID()); + } + return Apdu; + } + + public void run_Read() throws Exception { + CommandApdu rqApdu = StartPrepareCommand(INS.Read); + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + + + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + + + readResult = rspApdu.getTLVs(); + + parseReadResult(); + + run_ReadOrWriteIssuerDataAndDefineOfflineBalance(); + + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible PIN is invalid!\n", rspApdu.getSW1SW2())); + } else { + throw new TangemException(String.format("FAILED: [%04X]\n", rspApdu.getSW1SW2())); + } + } + + public void run_ReadOrWriteIssuerDataAndDefineOfflineBalance() 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_ReadIssuerData(); + } catch (Exception e) { + e.printStackTrace(); + tlvIssuerData = null; + } + } + if (mCard.getStatus() == Tangem_Card.Status.Loaded) { + // try read offline balance data + if (tlvIssuerData != null && tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination) != null && mCard.getMaxSignatures() == mCard.getRemainingSignatures()) { + mCard.setOfflineBalance(tlvIssuerData.getTLV(TLV.Tag.TAG_Denomination).Value); + } else { + mCard.clearOfflineBalance(); + } + } else { + mCard.clearOfflineBalance(); + } + } + + private TLVList readResult = null; + + public void clearReadResult() { + sessionKey = null; + readResult = null; + } + + public boolean haveReadResult() { + return readResult != null; + } + + public void parseReadResult() throws TangemException, NoSuchProviderException, NoSuchAlgorithmException { + TLV tlvStatus = readResult.getTLV(TLV.Tag.TAG_Status); + mCard.setStatus(Tangem_Card.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); + mCard.setHealth(readResult.getTLV(TLV.Tag.TAG_Health).getAsInt()); + + if (mCard.getStatus() != Tangem_Card.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); + + 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()); + + // this method has reflection TokenSymbol + // you mast call setBlockchainIDFromCard after calling setTokensDecimal + mCard.setBlockchainIDFromCard(tlvCardData.getTLV(TLV.Tag.TAG_Blockchain_ID).getAsString()); + 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 { + if (readResult.getTLV(TLV.Tag.TAG_Firmware) != null) { + mCard.setFirmwareVersion(readResult.getTLV(TLV.Tag.TAG_Firmware).getAsString()); + } else { + 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) { + mCard.setIssuer(Issuer.FindIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), readResult.getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value)); + } else { + mCard.setIssuer(Issuer.FindIssuer(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 { + mCard.setIssuer(Issuer.FindIssuer(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); + } + } + + 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"); + } + } + + + if (mCard.getStatus() == Tangem_Card.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); + + CoinEngine engineCoin = CoinEngineFactory.Create(mCard.getBlockchain()); + String wallet = engineCoin.calculateAddress(mCard, pkUncompressed); + mCard.setWallet(wallet); + //mCard.setWallet(Blockchain.calculateWalletAddress(mCard, pkUncompressed)); + + mCard.setRemainingSignatures(readResult.getTagAsInt(TLV.Tag.TAG_RemainingSignatures)); + + } else { + mCard.setWallet("N/A"); + } + } + + + public TLVList run_VerifyCard() throws Exception { + if (mCard.getCardPublicKey() == null || readResult == null) { + run_Read(); + } + if (mCard.getStatus() == Tangem_Card.Status.NotPersonalized) { + getCard().setManufacturer(Manufacturer.Unknown, false); + return null; + } + + if (mCard.getCardPublicKey() == null) { + throw new TangemException("Not all data read, can't verify card!"); + } + + CommandApdu rqApdu = StartPrepareCommand(INS.VerifyCard); + byte[] bChallenge = Util.generateRandomBytes(16); + rqApdu.addTLV(TLV.Tag.TAG_Challenge, bChallenge); + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + TLVList verifyResult = rspApdu.getTLVs(); + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + verifyResult.add(new TLV(TLV.Tag.TAG_Challenge, bChallenge)); + + TLV tlvSalt = verifyResult.getTLV(TLV.Tag.TAG_Salt); + TLV tlvCardSignature = verifyResult.getTLV(TLV.Tag.TAG_CardSignature); +// TLV tlvManufacturerSignature = verifyResult.getTLV(TLV.Tag.TAG_Manufacturer_Signature); + + if (tlvSalt == null || tlvCardSignature == null) { + throw new TangemException("Not all data read, can't verify card!"); + } + + try { + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + bs.write(bChallenge); + bs.write(tlvSalt.Value); + byte[] dataArray = bs.toByteArray(); + if (CardCrypto.VerifySignature(mCard.getCardPublicKey(), dataArray, tlvCardSignature.Value)) { + getCard().setCardPublicKeyValid(true); + Log.i(logTag, "Card signature verification OK"); + } else { + Log.e(logTag, "Card signature verification FAILED"); + getCard().setCardPublicKeyValid(false); + } + + //getCard().setManufacturer(Manufacturer.FindManufacturer(readResult.getTLV(TLV.Tag.TAG_Manufacture_ID).getAsString(), bChallenge, tlvSalt.Value, tlvManufacturerSignature.Value), true); + getCard().setManufacturer(Manufacturer.FindManufacturer(readResult.getTLV(TLV.Tag.TAG_Manufacture_ID).getAsString()), true); + } catch (Exception e) { + e.printStackTrace(); + getCard().setManufacturer(Manufacturer.Unknown, false); + } + return verifyResult; + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); + } else { + getCard().setManufacturer(Manufacturer.Unknown, false); + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + + } + + public void run_CreateWallet(String PIN2) throws Exception { + if (readResult == null) run_Read(); + 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(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(true); + } + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(false); + } + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + public TLVList run_CheckWallet() throws Exception { + CommandApdu rqApdu = StartPrepareCommand(INS.CheckWallet); + byte[] bChallenge = Util.generateRandomBytes(16); + rqApdu.addTLV(TLV.Tag.TAG_Challenge, bChallenge); + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + TLVList Result = rspApdu.getTLVs(); + Result.add(new TLV(TLV.Tag.TAG_Challenge, bChallenge)); + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + return Result; + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + public void run_CheckWalletWithSignatureVerify() throws Exception { + if (mCard.getCardPublicKey() == null || readResult == null) { + run_Read(); + } + if (mCard.getStatus() == Tangem_Card.Status.NotPersonalized) { + getCard().setManufacturer(Manufacturer.Unknown, false); + return; + } + + if (readResult.getTagAsInt(TLV.Tag.TAG_Status) != Tangem_Card.Status.Loaded.getCode()) { + throw new TangemException("Card must be loaded"); + } + TLVList checkResult = run_CheckWallet(); + if (checkResult == null) return; + + TLV tlvPublicKey = readResult.getTLV(TLV.Tag.TAG_Wallet_PublicKey); + TLV tlvChallenge = checkResult.getTLV(TLV.Tag.TAG_Challenge); + TLV tlvSalt = checkResult.getTLV(TLV.Tag.TAG_Salt); + TLV tlvSignature = checkResult.getTLV(TLV.Tag.TAG_Signature); + + if (tlvPublicKey == null || tlvChallenge == null || tlvSalt == null || tlvSignature == null) { + throw new TangemException("Not all data read, can't check signature!"); + } + + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + bs.write(tlvChallenge.Value); + bs.write(tlvSalt.Value); + byte[] dataArray = bs.toByteArray(); + + if (CardCrypto.VerifySignature(tlvPublicKey.Value, dataArray, tlvSignature.Value)) { + Log.i(logTag, "Signature verification OK"); + mCard.setWalletPublicKeyValid(true); + } else { + mCard.setWalletPublicKeyValid(false); + } + } + + public void run_PurgeWallet(String PIN2) throws Exception { + CommandApdu rqApdu = StartPrepareCommand(INS.PurgeWallet); + rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2)); + + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(true); + } + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(false); + } + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); + } else { + + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + public void run_SwapPIN(String PIN2, String newPin, String newPin2, boolean breakOnNeedPause) throws Exception { + CommandApdu rqApdu = StartPrepareCommand(INS.SwapPIN); + rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2)); + rqApdu.addTLV(TLV.Tag.TAG_NewPIN, Util.calculateSHA256(newPin)); + rqApdu.addTLV(TLV.Tag.TAG_NewPIN2, Util.calculateSHA256(newPin2)); + + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, breakOnNeedPause); + + if (rspApdu.isStatus(SW.PIN1_CHANGED) || rspApdu.isStatus(SW.PIN2_CHANGED) || rspApdu.isStatus(SW.PINS_CHANGED) || rspApdu.isStatus(SW.PINS_NOT_CHANGED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + if (newPin2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(true); + } else { + mCard.setUseDefaultPIN2(false); + } + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(false); + } + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Invalid PIN\n", rspApdu.getSW1SW2())); + } else if (breakOnNeedPause && rspApdu.isStatus(SW.NEED_PAUSE)) { + throw new TangemException_NeedPause(String.format("FAILED: [%04X] - Need pause\n", rspApdu.getSW1SW2())); + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + public void run_CheckPIN2isDefault() throws Exception { + if (mCard.isFirmwareNewer("1.19") || (mCard.isFirmwareNewer("1.12") && (mCard.getPauseBeforePIN2() == 0 || mCard.useSmartSecurityDelay()))) { + // can obtain SwapPIN(to default) answer without security delay - try check if PIN2 is default with card request + try { + run_SwapPIN(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); + } + } + + public TLVList run_SignHashes(String PIN2, byte[][] hashes, boolean UseIssuerValidation, byte[] issuerData, Issuer issuer) throws Exception { + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + if (hashes.length > 10) throw new Exception("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!"); + 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); + } + + + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + TLVList Result = rspApdu.getTLVs(); + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(true); + } + return Result; + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(false); + } + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible the PIN or PIN2 is invalid!\n", rspApdu.getSW1SW2())); + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + public TLVList run_SignRaw(String PIN2, byte[] bTxOutData) 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")); + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + TLVList Result = rspApdu.getTLVs(); + Result.add(new TLV(TLV.Tag.TAG_TrOut_Raw, bTxOutData)); + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(true); + } + return Result; + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(false); + } + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible the PIN or PIN2 is invalid!\n", rspApdu.getSW1SW2())); + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + private byte[] run_VerifyCode(String hashAlgID, int codePageAddress, int codePageCount, byte[] challenge) throws Exception { + if (readResult == null) run_Read(); + CommandApdu rqApdu = StartPrepareCommand(INS.VerifyCode); + rqApdu.addTLV(TLV.Tag.TAG_HashAlgID, hashAlgID.getBytes("US-ASCII")); + rqApdu.addTLV_U32(TLV.Tag.TAG_CodePageAddress, codePageAddress); + rqApdu.addTLV_U16(TLV.Tag.TAG_CodePageCount, codePageCount); + rqApdu.addTLV(TLV.Tag.TAG_Challenge, challenge); + + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + return rspApdu.getTLVs().getTLV(TLV.Tag.TAG_CodeHash).Value; + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + private void run_ValidateCard(String PIN2) throws Exception { + if (readResult == null) run_Read(); + CommandApdu rqApdu = StartPrepareCommand(INS.ValidateCard); + rqApdu.addTLV(TLV.Tag.TAG_PIN2, Util.calculateSHA256(PIN2)); + + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(true); + } + } else if (rspApdu.isStatus(SW_PIN_ERROR)) { + if (PIN2.equals(DefaultPIN2)) { + mCard.setUseDefaultPIN2(false); + } + throw new TangemException_InvalidPIN(String.format("FAILED: [%04X] - Possible the PIN or PIN2 is invalid!\n", rspApdu.getSW1SW2())); + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + private void run_WriteIssuerData(byte[] issuerData, byte[] issuerSignature) throws Exception { + run_Read(); + + CommandApdu rqApdu = StartPrepareCommand(INS.WriteIssuerData); + rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data, issuerData); + rqApdu.addTLV(TLV.Tag.TAG_Issuer_Data_Signature, issuerSignature); + + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + private TLVList run_ReadIssuerData() throws Exception { + CommandApdu rqApdu = StartPrepareCommand(INS.GetIssuerData); + + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + TLV issuerData = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Issuer_Data); + TLV issuerDataSignature = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Issuer_Data_Signature); + + if (issuerData == null || issuerDataSignature == null) + throw new TangemException("Invalid answer format (GetIssuerData)"); + + ByteArrayOutputStream bsDataToVerify = new ByteArrayOutputStream(); + bsDataToVerify.write(mCard.getCID()); + bsDataToVerify.write(issuerData.Value); + try { + if (CardCrypto.VerifySignature(mCard.getIssuer().getPublicDataKey(), bsDataToVerify.toByteArray(), issuerDataSignature.Value)) { + mCard.setIssuerData(issuerData.Value, issuerDataSignature.Value); + return TLVList.fromBytes(issuerData.Value); + } else { + throw new TangemException("Invalid issuer data read (signature verification failed)"); + } + } catch (Exception e) { + e.printStackTrace(); + throw new TangemException("Invalid issuer data read"); + } + } else { + throw new TangemException(String.format("Failed: %04X", rspApdu.getSW1SW2())); + } + } + + public void run_GetSupportedEncryption() throws Exception { + mCard.encryptionMode = Tangem_Card.EncryptionMode.None; + do { + CommandApdu rqApdu = StartPrepareCommand(INS.Read); + Log.i(logTag, String.format("[%s]\n%s", rqApdu.getCommandName(), rqApdu.getTLVs().getParsedTLVs(" "))); + + ResponseApdu rspApdu = SendAndReceive(rqApdu, false); + + if (rspApdu.isStatus(SW.NEED_ENCRYPTION)) { + if (mCard.encryptionMode == Tangem_Card.EncryptionMode.None) { + mCard.encryptionMode = Tangem_Card.EncryptionMode.Fast; + } else if (mCard.encryptionMode == Tangem_Card.EncryptionMode.Fast) { + mCard.encryptionMode = Tangem_Card.EncryptionMode.Strong; + } else { + throw new Exception("Can't get supported encryption methods"); + } + } else if (rspApdu.isStatus(SW.PROCESS_COMPLETED)) { + Log.i(logTag, String.format("OK: [%04X]\n%s", rspApdu.getSW1SW2(), rspApdu.getTLVs().getParsedTLVs(" "))); + readResult = rspApdu.getTLVs(); + mCard.setPIN(mPIN); + break; + } else { + break; + } + } while (true); + } + +} diff --git a/app/src/main/java/com/tangem/cardReader/CommandApdu.java b/app/src/main/java/com/tangem/domain/cardReader/CommandApdu.java similarity index 99% rename from app/src/main/java/com/tangem/cardReader/CommandApdu.java rename to app/src/main/java/com/tangem/domain/cardReader/CommandApdu.java index 3e552dc4dd..7d60037956 100644 --- a/app/src/main/java/com/tangem/cardReader/CommandApdu.java +++ b/app/src/main/java/com/tangem/domain/cardReader/CommandApdu.java @@ -1,4 +1,4 @@ -package com.tangem.cardReader; +package com.tangem.domain.cardReader; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/app/src/main/java/com/tangem/cardReader/CustomCardReader.java b/app/src/main/java/com/tangem/domain/cardReader/CustomCardReader.java similarity index 98% rename from app/src/main/java/com/tangem/cardReader/CustomCardReader.java rename to app/src/main/java/com/tangem/domain/cardReader/CustomCardReader.java index 9c2f9437b6..2d220ecd70 100644 --- a/app/src/main/java/com/tangem/cardReader/CustomCardReader.java +++ b/app/src/main/java/com/tangem/domain/cardReader/CustomCardReader.java @@ -1,4 +1,4 @@ -package com.tangem.cardReader; +package com.tangem.domain.cardReader; import android.content.Context; import android.nfc.TagLostException; diff --git a/app/src/main/java/com/tangem/cardReader/INS.java b/app/src/main/java/com/tangem/domain/cardReader/INS.java similarity index 91% rename from app/src/main/java/com/tangem/cardReader/INS.java rename to app/src/main/java/com/tangem/domain/cardReader/INS.java index c9b26ca5c0..0b653f775c 100644 --- a/app/src/main/java/com/tangem/cardReader/INS.java +++ b/app/src/main/java/com/tangem/domain/cardReader/INS.java @@ -1,43 +1,43 @@ -package com.tangem.cardReader; - -/** - * Created by dvol on 07.03.2018. - */ -public enum INS { - Unknown(0x00), - BootROM_SOS(0x40), - BootROM_Tangem(0xF0), - Personalize(0xF1), - Read(0xF2), - VerifyCard(0xF3), - ValidateCard(0xF4), - VerifyCode(0xF5), - WriteIssuerData(0xF6), - GetIssuerData(0xF7), - CreateWallet(0xF8), - CheckWallet(0xF9), - SwapPIN(0xFA), - Sign(0xFB), - PurgeWallet(0xFC), - Activate(0xFE), - OpenSession(0xFF), - ReadBlockedData(0xE4), - CreateTestWallet(0xE0), - ExtractWalletKey(0xE1), - Test(0xE2), - Depersonalize(0xE3); - - INS(int Code) { - this.Code = Code; - } - - public int Code; - - public static INS ByCode(int Code) { - INS[] allINS = INS.values(); - for (INS i : allINS) { - if (i.Code == Code) return i; - } - return Unknown; - } -} +package com.tangem.domain.cardReader; + +/** + * Created by dvol on 07.03.2018. + */ +public enum INS { + Unknown(0x00), + BootROM_SOS(0x40), + BootROM_Tangem(0xF0), + Personalize(0xF1), + Read(0xF2), + VerifyCard(0xF3), + ValidateCard(0xF4), + VerifyCode(0xF5), + WriteIssuerData(0xF6), + GetIssuerData(0xF7), + CreateWallet(0xF8), + CheckWallet(0xF9), + SwapPIN(0xFA), + Sign(0xFB), + PurgeWallet(0xFC), + Activate(0xFE), + OpenSession(0xFF), + ReadBlockedData(0xE4), + CreateTestWallet(0xE0), + ExtractWalletKey(0xE1), + Test(0xE2), + Depersonalize(0xE3); + + INS(int Code) { + this.Code = Code; + } + + public int Code; + + public static INS ByCode(int Code) { + INS[] allINS = INS.values(); + for (INS i : allINS) { + if (i.Code == Code) return i; + } + return Unknown; + } +} diff --git a/app/src/main/java/com/tangem/cardReader/NfcManager.java b/app/src/main/java/com/tangem/domain/cardReader/NfcManager.java similarity index 96% rename from app/src/main/java/com/tangem/cardReader/NfcManager.java rename to app/src/main/java/com/tangem/domain/cardReader/NfcManager.java index 17f819a329..378235ba73 100644 --- a/app/src/main/java/com/tangem/cardReader/NfcManager.java +++ b/app/src/main/java/com/tangem/domain/cardReader/NfcManager.java @@ -1,153 +1,155 @@ -package com.tangem.cardReader; - -import android.Manifest; -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.IsoDep; -import android.os.Build; -import android.os.Bundle; -import android.support.v4.app.ActivityCompat; -import android.util.Log; - -import java.io.IOException; - -public class NfcManager { - - private static final String TAG = "NfcManager"; - - - // reader mode flags: listen for type A (not B), skipping ndef check - private static final int READER_FLAGS = NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK | NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS; - - private NfcAdapter mNfcAdapter; - private NFCEnableDialog mEnableNfcDialog; - private Activity mActivity; - private NfcAdapter.ReaderCallback mReaderCallback; - - private boolean broadcomWorkaround = false; - private static final int DELAY_PRESENCE = 1500; - - public NfcManager(Activity activity, NfcAdapter.ReaderCallback readerCallback) { - mActivity = activity; - mReaderCallback = readerCallback; - mNfcAdapter = NfcAdapter.getDefaultAdapter(activity); - } - - public void onResume() { - // register broadcast receiver - IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); - mActivity.registerReceiver(mBroadcastReceiver, filter); - - if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { - ShowNFCEnableDialog(); - - } else { - enableReaderMode(); - } - } - - public void ShowNFCEnableDialog() { - mEnableNfcDialog=new NFCEnableDialog(); - mEnableNfcDialog.show(mActivity.getFragmentManager(),"NFCEnableDialog"); - } - - public void onPause() { - mActivity.unregisterReceiver(mBroadcastReceiver); - disableReaderMode(); - } - - public void onStop() { - if (mEnableNfcDialog != null) { - mEnableNfcDialog.dismiss(); - } - } - - public void IgnoreTag(Tag tag) throws IOException { -// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { -// mNfcAdapter.ignore(tag, 500, null, null); -// }else{ - IsoDep isoDep = IsoDep.get(tag); - if (isoDep != null) { - isoDep.close(); - } -// } - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @SuppressWarnings("deprecation") - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action == null) - return; - if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) { - int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, - NfcAdapter.STATE_ON); - if (state == NfcAdapter.STATE_ON - || state == NfcAdapter.STATE_TURNING_ON) { - Log.d(TAG, "state: " + state + " , dialog: " - + mEnableNfcDialog); - if (mEnableNfcDialog != null) { - mEnableNfcDialog.dismiss(); - } - if (state == NfcAdapter.STATE_ON) { - enableReaderMode(); - } - } else { - if (mEnableNfcDialog == null || !mEnableNfcDialog.isVisible()) { - ShowNFCEnableDialog(); - } - } - } - } - }; - - @TargetApi(Build.VERSION_CODES.KITKAT) - private void enableReaderMode() { - Bundle options = new Bundle(); - if (broadcomWorkaround) { - /* This is a work around for some Broadcom chipsets that does - * the presence check by sending commands that interrupt the - * processing of the ongoing command. - */ - options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, DELAY_PRESENCE); - } - mNfcAdapter.enableReaderMode(mActivity, mReaderCallback, READER_FLAGS, options); - } - - @TargetApi(Build.VERSION_CODES.KITKAT) - private void disableReaderMode() { - if (mNfcAdapter != null) { - mNfcAdapter.disableReaderMode(mActivity); - } - } - - private static final int REQUEST_NFC_PERMISSIONS = 1; - private static String[] PERMISSIONS_NFC = { - Manifest.permission.NFC - }; - - //Checks if the app has NFC permission - //If the app does not has permission then the user will be prompted to grant permissions - public static void verifyPermissions(Activity activity) { - // Check if we have write permission - int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.NFC); - - if (permission != PackageManager.PERMISSION_GRANTED) { - // We don't have permission so prompt the user - ActivityCompat.requestPermissions( - activity, - PERMISSIONS_NFC, - REQUEST_NFC_PERMISSIONS - ); - } - } -} - +package com.tangem.domain.cardReader; + +import android.Manifest; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.IsoDep; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.util.Log; + +import com.tangem.presentation.dialog.NFCEnableDialog; + +import java.io.IOException; + +public class NfcManager { + + private static final String TAG = "NfcManager"; + + + // reader mode flags: listen for type A (not B), skipping ndef check + private static final int READER_FLAGS = NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK | NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS; + + private NfcAdapter mNfcAdapter; + private NFCEnableDialog mEnableNfcDialog; + private Activity mActivity; + private NfcAdapter.ReaderCallback mReaderCallback; + + private boolean broadcomWorkaround = false; + private static final int DELAY_PRESENCE = 1500; + + public NfcManager(Activity activity, NfcAdapter.ReaderCallback readerCallback) { + mActivity = activity; + mReaderCallback = readerCallback; + mNfcAdapter = NfcAdapter.getDefaultAdapter(activity); + } + + public void onResume() { + // register broadcast receiver + IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + mActivity.registerReceiver(mBroadcastReceiver, filter); + + if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { + ShowNFCEnableDialog(); + + } else { + enableReaderMode(); + } + } + + public void ShowNFCEnableDialog() { + mEnableNfcDialog=new NFCEnableDialog(); + mEnableNfcDialog.show(mActivity.getFragmentManager(),"NFCEnableDialog"); + } + + public void onPause() { + mActivity.unregisterReceiver(mBroadcastReceiver); + disableReaderMode(); + } + + public void onStop() { + if (mEnableNfcDialog != null) { + mEnableNfcDialog.dismiss(); + } + } + + public void IgnoreTag(Tag tag) throws IOException { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { +// mNfcAdapter.ignore(tag, 500, null, null); +// }else{ + IsoDep isoDep = IsoDep.get(tag); + if (isoDep != null) { + isoDep.close(); + } +// } + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @SuppressWarnings("deprecation") + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action == null) + return; + if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) { + int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, + NfcAdapter.STATE_ON); + if (state == NfcAdapter.STATE_ON + || state == NfcAdapter.STATE_TURNING_ON) { + Log.d(TAG, "state: " + state + " , dialog: " + + mEnableNfcDialog); + if (mEnableNfcDialog != null) { + mEnableNfcDialog.dismiss(); + } + if (state == NfcAdapter.STATE_ON) { + enableReaderMode(); + } + } else { + if (mEnableNfcDialog == null || !mEnableNfcDialog.isVisible()) { + ShowNFCEnableDialog(); + } + } + } + } + }; + + @TargetApi(Build.VERSION_CODES.KITKAT) + private void enableReaderMode() { + Bundle options = new Bundle(); + if (broadcomWorkaround) { + /* This is a work around for some Broadcom chipsets that does + * the presence check by sending commands that interrupt the + * processing of the ongoing command. + */ + options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, DELAY_PRESENCE); + } + mNfcAdapter.enableReaderMode(mActivity, mReaderCallback, READER_FLAGS, options); + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + private void disableReaderMode() { + if (mNfcAdapter != null) { + mNfcAdapter.disableReaderMode(mActivity); + } + } + + private static final int REQUEST_NFC_PERMISSIONS = 1; + private static String[] PERMISSIONS_NFC = { + Manifest.permission.NFC + }; + + //Checks if the app has NFC permission + //If the app does not has permission then the user will be prompted to grant permissions + public static void verifyPermissions(Activity activity) { + // Check if we have write permission + int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.NFC); + + if (permission != PackageManager.PERMISSION_GRANTED) { + // We don't have permission so prompt the user + ActivityCompat.requestPermissions( + activity, + PERMISSIONS_NFC, + REQUEST_NFC_PERMISSIONS + ); + } + } +} + diff --git a/app/src/main/java/com/tangem/cardReader/PBKDF2.java b/app/src/main/java/com/tangem/domain/cardReader/PBKDF2.java similarity index 98% rename from app/src/main/java/com/tangem/cardReader/PBKDF2.java rename to app/src/main/java/com/tangem/domain/cardReader/PBKDF2.java index 0db1ddb69d..700648c6dd 100644 --- a/app/src/main/java/com/tangem/cardReader/PBKDF2.java +++ b/app/src/main/java/com/tangem/domain/cardReader/PBKDF2.java @@ -1,5 +1,5 @@ -package com.tangem.cardReader; +package com.tangem.domain.cardReader; import org.spongycastle.crypto.CipherParameters; import org.spongycastle.crypto.digests.SHA256Digest; diff --git a/app/src/main/java/com/tangem/cardReader/ResponseApdu.java b/app/src/main/java/com/tangem/domain/cardReader/ResponseApdu.java similarity index 98% rename from app/src/main/java/com/tangem/cardReader/ResponseApdu.java rename to app/src/main/java/com/tangem/domain/cardReader/ResponseApdu.java index 2058e4d054..a7bf0f4a48 100644 --- a/app/src/main/java/com/tangem/cardReader/ResponseApdu.java +++ b/app/src/main/java/com/tangem/domain/cardReader/ResponseApdu.java @@ -1,4 +1,4 @@ -package com.tangem.cardReader; +package com.tangem.domain.cardReader; import java.io.ByteArrayInputStream; import java.util.Arrays; diff --git a/app/src/main/java/com/tangem/cardReader/SW.java b/app/src/main/java/com/tangem/domain/cardReader/SW.java similarity index 95% rename from app/src/main/java/com/tangem/cardReader/SW.java rename to app/src/main/java/com/tangem/domain/cardReader/SW.java index 3765acbb74..cbc25c239a 100644 --- a/app/src/main/java/com/tangem/cardReader/SW.java +++ b/app/src/main/java/com/tangem/domain/cardReader/SW.java @@ -1,43 +1,43 @@ -package com.tangem.cardReader; - -/** - * Created by dvol on 07.03.2018. - */ - -public class SW { - public static final int PROCESS_COMPLETED = 0x9000; - public static final int INVALID_PARAMS = 0x6A86; - public static final int ERROR_PROCESSING_COMMAND = 0x6286; - public static final int INVALID_STATE = 0x6985; - public static final int PINS_NOT_CHANGED = PROCESS_COMPLETED; - public static final int PIN1_CHANGED = PROCESS_COMPLETED + 0x0001; - public static final int PIN2_CHANGED = PROCESS_COMPLETED + 0x0002; - public static final int PINS_CHANGED = PROCESS_COMPLETED + 0x0003; - public static final int INS_NOT_SUPPORTED = 0x6D00; - public static final int NEED_ENCRYPTION = 0x6982; - public static final int NEED_PAUSE = 0x9789; - - public static String getDescription(int sw) { - switch (sw) { - case ERROR_PROCESSING_COMMAND: - return "SW_ERROR_PROCESSING_COMMAND"; - case INVALID_PARAMS: - return "SW_INVALID_PARAMS"; - case INVALID_STATE: - return "SW_INVALID_STATE"; - case INS_NOT_SUPPORTED: - return "SW_INS_NOT_SUPPORTED"; - case NEED_ENCRYPTION: - return "SW_NEED_ENCRYPTION"; - case PIN1_CHANGED: - return "SW_PIN1_CHANGED"; - case PIN2_CHANGED: - return "SW_PIN2_CHANGED"; - case PINS_CHANGED: - return "SW_PINS_CHANGED"; - case PROCESS_COMPLETED: - return "SW_PROCESS_COMPLETED"; - } - return "???"; - } -} +package com.tangem.domain.cardReader; + +/** + * Created by dvol on 07.03.2018. + */ + +public class SW { + public static final int PROCESS_COMPLETED = 0x9000; + public static final int INVALID_PARAMS = 0x6A86; + public static final int ERROR_PROCESSING_COMMAND = 0x6286; + public static final int INVALID_STATE = 0x6985; + public static final int PINS_NOT_CHANGED = PROCESS_COMPLETED; + public static final int PIN1_CHANGED = PROCESS_COMPLETED + 0x0001; + public static final int PIN2_CHANGED = PROCESS_COMPLETED + 0x0002; + public static final int PINS_CHANGED = PROCESS_COMPLETED + 0x0003; + public static final int INS_NOT_SUPPORTED = 0x6D00; + public static final int NEED_ENCRYPTION = 0x6982; + public static final int NEED_PAUSE = 0x9789; + + public static String getDescription(int sw) { + switch (sw) { + case ERROR_PROCESSING_COMMAND: + return "SW_ERROR_PROCESSING_COMMAND"; + case INVALID_PARAMS: + return "SW_INVALID_PARAMS"; + case INVALID_STATE: + return "SW_INVALID_STATE"; + case INS_NOT_SUPPORTED: + return "SW_INS_NOT_SUPPORTED"; + case NEED_ENCRYPTION: + return "SW_NEED_ENCRYPTION"; + case PIN1_CHANGED: + return "SW_PIN1_CHANGED"; + case PIN2_CHANGED: + return "SW_PIN2_CHANGED"; + case PINS_CHANGED: + return "SW_PINS_CHANGED"; + case PROCESS_COMPLETED: + return "SW_PROCESS_COMPLETED"; + } + return "???"; + } +} diff --git a/app/src/main/java/com/tangem/cardReader/SettingsMask.java b/app/src/main/java/com/tangem/domain/cardReader/SettingsMask.java similarity index 93% rename from app/src/main/java/com/tangem/cardReader/SettingsMask.java rename to app/src/main/java/com/tangem/domain/cardReader/SettingsMask.java index b35815ab0e..f69a4a1cb3 100644 --- a/app/src/main/java/com/tangem/cardReader/SettingsMask.java +++ b/app/src/main/java/com/tangem/domain/cardReader/SettingsMask.java @@ -1,25 +1,25 @@ -package com.tangem.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; - -} +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; + +} diff --git a/app/src/main/java/com/tangem/cardReader/TLV.java b/app/src/main/java/com/tangem/domain/cardReader/TLV.java similarity index 96% rename from app/src/main/java/com/tangem/cardReader/TLV.java rename to app/src/main/java/com/tangem/domain/cardReader/TLV.java index 2bfe7751b8..0b8721a683 100644 --- a/app/src/main/java/com/tangem/cardReader/TLV.java +++ b/app/src/main/java/com/tangem/domain/cardReader/TLV.java @@ -1,222 +1,222 @@ -package com.tangem.cardReader; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Arrays; - -/** - * Created by dvol on 23.06.2017. - */ - -public class TLV { - public enum Tag { - TAG_Unknown(0x00), - TAG_CardID(0x01), - TAG_Status(0x02), - TAG_CardPublicKey(0x03), - TAG_CardSignature(0x04), - TAG_CurveID(0x05), - TAG_HashAlgID(0x06), - TAG_SigningMethod(0x07), - TAG_MaxSignatures(0x08), - TAG_PauseBeforePIN2(0x09), - TAG_SettingsMask(0x0A), - TAG_CardData(0x0C), - TAG_NDEFData(0x0D), - TAG_CreateWalletAtPersonalize(0x0E), - TAG_Health(0x0F), - - TAG_PIN(0x10), - TAG_PIN2(0x11), - TAG_NewPIN(0x12), - TAG_NewPIN2(0x13), - TAG_NewPIN_Hash(0x14), - TAG_NewPIN2_Hash(0x15), - TAG_Challenge(0x16), - TAG_Salt(0x17), - TAG_ValidationCounter(0x18), - TAG_CVC(0x19), - - TAG_Session_Key_A(0x1A), - TAG_Session_Key_B(0x1B), - TAG_Pause(0x1C), - - TAG_Manufacture_ID(0x20), - TAG_Manufacturer_Signature(0x21), - - TAG_Issuer_Data_PublicKey(0x30), - TAG_Issuer_Transaction_PublicKey(0x31), - TAG_Issuer_Data(0x32), - TAG_Issuer_Data_Signature(0x33), - TAG_Issuer_Transaction_Signature(0x34), - - TAG_IsActivated(0x3A), - TAG_ActivationSeed(0x3B), - TAG_ResetPIN(0x36), - - TAG_CodePageAddress(0x40), - TAG_CodePageCount(0x41), - TAG_CodeHash(0x42), - - TAG_TrOut_Hash(0x50), - TAG_TrOut_HashSize(0x51), - TAG_TrOut_Raw(0x52), - - TAG_Wallet_PublicKey(0x60), - TAG_Signature(0x61), - TAG_RemainingSignatures(0x62), - TAG_SignedHashes(0x63), - - TAG_Wallet_PrivateKey(0x70), - TAG_Card_PrivateKey(0x71), - TAG_Block_Reason(0x72), - - - TAG_Firmware(0x80), - TAG_Batch(0x81), - TAG_ManufactureDateTime(0x82), - TAG_Issuer_ID(0x83), - TAG_Blockchain_ID(0x84), - TAG_Manufacturer_PublicKey(0x85), - TAG_CardID_Manufacturer_Signature(0x86), - - TAG_Token_Symbol(0xA0), - TAG_Token_Contract_Address(0xA1), - TAG_Token_Decimal(0xA2), - TAG_Denomination(/*0xC0*/0xee), //TODO: quick fix - TAG_ValidatedBalance(0xC1), - TAG_LastSign_Date(0xC2); - - - Tag(int Code) { - this.Code = Code; - } - - public int getCode() { - return Code; - } - - private int Code; - - public static Tag ByCode(int Code) { - Tag[] allTags = Tag.values(); - for (Tag t : allTags) if (t.getCode() == Code) return t; - return TAG_Unknown; - } - } - - private Tag tag; - - public Tag getTag() { - return tag; - } - - public byte[] Value; - - public TLV(Tag tag, byte[] value) { - this.tag = tag; - this.Value = value; - } - - public void WriteToStream(ByteArrayOutputStream stream) throws IOException { - stream.write(tag.getCode()); - if (Value != null) { - if (Value.length > 0xFE) { - stream.write(0xFF); - stream.write((Value.length >> 8) & 0xFF); - stream.write(Value.length & 0xFF); - } else { - stream.write(Value.length & 0xFF); - } - stream.write(Value); - } else { - stream.write(0x00); - } - } - - public static TLV ReadFromStream(ByteArrayInputStream stream) throws IOException { - int code = stream.read(); - if (code == -1) return null; - int len = stream.read(); - if (len == -1) - throw new IOException("Can't read TLV"); - if (len == 0xFF) { - int lenH = stream.read(); - if (lenH == -1) - throw new IOException("Can't read TLV"); - len = stream.read(); - if (len == -1) - throw new IOException("Can't read TLV"); - len |= (lenH << 8); - } - byte[] value = new byte[len]; - if (len > 0) { - if (len != stream.read(value)) { - throw new IOException("Can't read TLV"); - } - } - Tag tag = Tag.ByCode(code); - TLV result = new TLV(tag, value); - return result; - } - - public int getAsInt() { - return Util.byteArrayToInt(Value); - } - - public String getAsHexString() { - return Util.bytesToHex(Value); - } - - public String getAsString() { - //String s=String.valueOf(Value); - if (Value[Value.length - 1] == 0) { - String s1 = new String(Arrays.copyOfRange(Value, 0, Value.length - 1), Charset.forName("utf-8")); - return s1.trim(); - } else { - String s1 = new String(Value, Charset.forName("utf-8")); - return s1.trim(); - - } - } - - @Override - public String toString() { - switch (tag) { - case TAG_CardData: - case TAG_Issuer_Data: { - try { - TLVList tlvSub = TLVList.fromBytes(Value); - return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), tlvSub.toString()); - } catch (TLVException e) { - e.printStackTrace(); - } - if (Value != null) { - return String.format("%s[%d]: %s (non TLV)", tag.name(), Value.length, Util.bytesToHex(Value)); - } else { - return String.format("%s[]: [[NULL]]", tag.name()); - } - } - case TAG_CurveID: - case TAG_HashAlgID: - case TAG_Blockchain_ID: - case TAG_Manufacture_ID: - case TAG_Firmware: - case TAG_Issuer_ID: - case TAG_Token_Symbol: - if (Value != null) { - return String.format("%s[%d]: %s(%s)", tag.name(), Value.length, Util.bytesToHex(Value), getAsString()); - } else { - return String.format("%s[]: [[NULL]]", tag.name()); - } - default: - if (Value != null) { - return String.format("%s[%d]: %s", tag.name(), Value.length, Util.bytesToHex(Value)); - } else { - return String.format("%s[]: [[NULL]]", tag.name()); - } - } - } -} +package com.tangem.domain.cardReader; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Arrays; + +/** + * Created by dvol on 23.06.2017. + */ + +public class TLV { + public enum Tag { + TAG_Unknown(0x00), + TAG_CardID(0x01), + TAG_Status(0x02), + TAG_CardPublicKey(0x03), + TAG_CardSignature(0x04), + TAG_CurveID(0x05), + TAG_HashAlgID(0x06), + TAG_SigningMethod(0x07), + TAG_MaxSignatures(0x08), + TAG_PauseBeforePIN2(0x09), + TAG_SettingsMask(0x0A), + TAG_CardData(0x0C), + TAG_NDEFData(0x0D), + TAG_CreateWalletAtPersonalize(0x0E), + TAG_Health(0x0F), + + TAG_PIN(0x10), + TAG_PIN2(0x11), + TAG_NewPIN(0x12), + TAG_NewPIN2(0x13), + TAG_NewPIN_Hash(0x14), + TAG_NewPIN2_Hash(0x15), + TAG_Challenge(0x16), + TAG_Salt(0x17), + TAG_ValidationCounter(0x18), + TAG_CVC(0x19), + + TAG_Session_Key_A(0x1A), + TAG_Session_Key_B(0x1B), + TAG_Pause(0x1C), + + TAG_Manufacture_ID(0x20), + TAG_Manufacturer_Signature(0x21), + + TAG_Issuer_Data_PublicKey(0x30), + TAG_Issuer_Transaction_PublicKey(0x31), + TAG_Issuer_Data(0x32), + TAG_Issuer_Data_Signature(0x33), + TAG_Issuer_Transaction_Signature(0x34), + + TAG_IsActivated(0x3A), + TAG_ActivationSeed(0x3B), + TAG_ResetPIN(0x36), + + TAG_CodePageAddress(0x40), + TAG_CodePageCount(0x41), + TAG_CodeHash(0x42), + + TAG_TrOut_Hash(0x50), + TAG_TrOut_HashSize(0x51), + TAG_TrOut_Raw(0x52), + + TAG_Wallet_PublicKey(0x60), + TAG_Signature(0x61), + TAG_RemainingSignatures(0x62), + TAG_SignedHashes(0x63), + + TAG_Wallet_PrivateKey(0x70), + TAG_Card_PrivateKey(0x71), + TAG_Block_Reason(0x72), + + + TAG_Firmware(0x80), + TAG_Batch(0x81), + TAG_ManufactureDateTime(0x82), + TAG_Issuer_ID(0x83), + TAG_Blockchain_ID(0x84), + TAG_Manufacturer_PublicKey(0x85), + TAG_CardID_Manufacturer_Signature(0x86), + + TAG_Token_Symbol(0xA0), + TAG_Token_Contract_Address(0xA1), + TAG_Token_Decimal(0xA2), + TAG_Denomination(/*0xC0*/0xee), //TODO: quick fix + TAG_ValidatedBalance(0xC1), + TAG_LastSign_Date(0xC2); + + + Tag(int Code) { + this.Code = Code; + } + + public int getCode() { + return Code; + } + + private int Code; + + public static Tag ByCode(int Code) { + Tag[] allTags = Tag.values(); + for (Tag t : allTags) if (t.getCode() == Code) return t; + return TAG_Unknown; + } + } + + private Tag tag; + + public Tag getTag() { + return tag; + } + + public byte[] Value; + + public TLV(Tag tag, byte[] value) { + this.tag = tag; + this.Value = value; + } + + public void WriteToStream(ByteArrayOutputStream stream) throws IOException { + stream.write(tag.getCode()); + if (Value != null) { + if (Value.length > 0xFE) { + stream.write(0xFF); + stream.write((Value.length >> 8) & 0xFF); + stream.write(Value.length & 0xFF); + } else { + stream.write(Value.length & 0xFF); + } + stream.write(Value); + } else { + stream.write(0x00); + } + } + + public static TLV ReadFromStream(ByteArrayInputStream stream) throws IOException { + int code = stream.read(); + if (code == -1) return null; + int len = stream.read(); + if (len == -1) + throw new IOException("Can't read TLV"); + if (len == 0xFF) { + int lenH = stream.read(); + if (lenH == -1) + throw new IOException("Can't read TLV"); + len = stream.read(); + if (len == -1) + throw new IOException("Can't read TLV"); + len |= (lenH << 8); + } + byte[] value = new byte[len]; + if (len > 0) { + if (len != stream.read(value)) { + throw new IOException("Can't read TLV"); + } + } + Tag tag = Tag.ByCode(code); + TLV result = new TLV(tag, value); + return result; + } + + public int getAsInt() { + return Util.byteArrayToInt(Value); + } + + public String getAsHexString() { + return Util.bytesToHex(Value); + } + + public String getAsString() { + //String s=String.valueOf(Value); + if (Value[Value.length - 1] == 0) { + String s1 = new String(Arrays.copyOfRange(Value, 0, Value.length - 1), Charset.forName("utf-8")); + return s1.trim(); + } else { + String s1 = new String(Value, Charset.forName("utf-8")); + return s1.trim(); + + } + } + + @Override + public String toString() { + switch (tag) { + case TAG_CardData: + case TAG_Issuer_Data: { + try { + TLVList tlvSub = TLVList.fromBytes(Value); + return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), tlvSub.toString()); + } catch (TLVException e) { + e.printStackTrace(); + } + if (Value != null) { + return String.format("%s[%d]: %s (non TLV)", tag.name(), Value.length, Util.bytesToHex(Value)); + } else { + return String.format("%s[]: [[NULL]]", tag.name()); + } + } + case TAG_CurveID: + case TAG_HashAlgID: + case TAG_Blockchain_ID: + case TAG_Manufacture_ID: + case TAG_Firmware: + case TAG_Issuer_ID: + case TAG_Token_Symbol: + if (Value != null) { + return String.format("%s[%d]: %s(%s)", tag.name(), Value.length, Util.bytesToHex(Value), getAsString()); + } else { + return String.format("%s[]: [[NULL]]", tag.name()); + } + default: + if (Value != null) { + return String.format("%s[%d]: %s", tag.name(), Value.length, Util.bytesToHex(Value)); + } else { + return String.format("%s[]: [[NULL]]", tag.name()); + } + } + } +} diff --git a/app/src/main/java/com/tangem/cardReader/TLVException.java b/app/src/main/java/com/tangem/domain/cardReader/TLVException.java similarity index 87% rename from app/src/main/java/com/tangem/cardReader/TLVException.java rename to app/src/main/java/com/tangem/domain/cardReader/TLVException.java index db5588dee1..6d69e73855 100644 --- a/app/src/main/java/com/tangem/cardReader/TLVException.java +++ b/app/src/main/java/com/tangem/domain/cardReader/TLVException.java @@ -1,18 +1,18 @@ -package com.tangem.cardReader; - -public class TLVException extends Exception { - - private static final long serialVersionUID = 1L; - - public TLVException(String message){ - super(message); - } - - public TLVException(String message, Throwable cause) { - super(message, cause); - } - - public TLVException(Throwable cause) { - super(cause); - } +package com.tangem.domain.cardReader; + +public class TLVException extends Exception { + + private static final long serialVersionUID = 1L; + + public TLVException(String message){ + super(message); + } + + public TLVException(String message, Throwable cause) { + super(message, cause); + } + + public TLVException(Throwable cause) { + super(cause); + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/cardReader/TLVList.java b/app/src/main/java/com/tangem/domain/cardReader/TLVList.java similarity index 94% rename from app/src/main/java/com/tangem/cardReader/TLVList.java rename to app/src/main/java/com/tangem/domain/cardReader/TLVList.java index ed9686de0a..3393a38756 100644 --- a/app/src/main/java/com/tangem/cardReader/TLVList.java +++ b/app/src/main/java/com/tangem/domain/cardReader/TLVList.java @@ -1,72 +1,72 @@ -package com.tangem.cardReader; - -/** - * Created by dvol on 23.06.2017. - */ - -import android.support.annotation.NonNull; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; - -public class TLVList extends ArrayList { - public String getParsedTLVs(String Prefix) { - String parsed = ""; - for (int i = 0; i < size(); i++) { - parsed += Prefix + this.get(i).toString() + (i < size() - 1 ? "\n" : ""); - } - return parsed;//.substring(0,parsed.length()-2); - } - - public TLVList() { - super(); - } - - public TLVList(@NonNull Collection c) { - super(c); - } - - public TLV getTLV(TLV.Tag tag) { - for (TLV tlv : this) { - if (tlv.getTag() == tag) return tlv; - } - return null; - } - - public int getTagAsInt(TLV.Tag tag) { - TLV tlv = getTLV(tag); - return Util.byteArrayToInt(tlv.Value); - } - - public byte[] toBytes() { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - for (TLV tlv : this) { - try { - tlv.WriteToStream(stream); - } catch (IOException e) { - e.printStackTrace(); - break; - } - } - return stream.toByteArray(); - } - - public static TLVList fromBytes(byte[] mData) throws TLVException { - TLVList tlvList = new TLVList(); - ByteArrayInputStream stream = new ByteArrayInputStream(mData); - TLV tlv = null; - do { - try { - tlv = TLV.ReadFromStream(stream); - if (tlv != null) tlvList.add(tlv); - } catch (IOException e) { - throw new TLVException("TLVError: " + e.getMessage()); - } - } - while (tlv != null); - return tlvList; - } -} +package com.tangem.domain.cardReader; + +/** + * Created by dvol on 23.06.2017. + */ + +import android.support.annotation.NonNull; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + +public class TLVList extends ArrayList { + public String getParsedTLVs(String Prefix) { + String parsed = ""; + for (int i = 0; i < size(); i++) { + parsed += Prefix + this.get(i).toString() + (i < size() - 1 ? "\n" : ""); + } + return parsed;//.substring(0,parsed.length()-2); + } + + public TLVList() { + super(); + } + + public TLVList(@NonNull Collection c) { + super(c); + } + + public TLV getTLV(TLV.Tag tag) { + for (TLV tlv : this) { + if (tlv.getTag() == tag) return tlv; + } + return null; + } + + public int getTagAsInt(TLV.Tag tag) { + TLV tlv = getTLV(tag); + return Util.byteArrayToInt(tlv.Value); + } + + public byte[] toBytes() { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + for (TLV tlv : this) { + try { + tlv.WriteToStream(stream); + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + return stream.toByteArray(); + } + + public static TLVList fromBytes(byte[] mData) throws TLVException { + TLVList tlvList = new TLVList(); + ByteArrayInputStream stream = new ByteArrayInputStream(mData); + TLV tlv = null; + do { + try { + tlv = TLV.ReadFromStream(stream); + if (tlv != null) tlvList.add(tlv); + } catch (IOException e) { + throw new TLVException("TLVError: " + e.getMessage()); + } + } + while (tlv != null); + return tlvList; + } +} diff --git a/app/src/main/java/com/tangem/cardReader/Util.java b/app/src/main/java/com/tangem/domain/cardReader/Util.java similarity index 99% rename from app/src/main/java/com/tangem/cardReader/Util.java rename to app/src/main/java/com/tangem/domain/cardReader/Util.java index 79a0205746..f03605a7f9 100644 --- a/app/src/main/java/com/tangem/cardReader/Util.java +++ b/app/src/main/java/com/tangem/domain/cardReader/Util.java @@ -1,4 +1,4 @@ -package com.tangem.cardReader; +package com.tangem.domain.cardReader; import android.text.format.DateUtils; @@ -18,7 +18,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; -import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.BitSet; import java.util.Date; diff --git a/app/src/main/java/com/tangem/presentation/Screen.java b/app/src/main/java/com/tangem/presentation/Screen.java deleted file mode 100644 index 4e389bb6b7..0000000000 --- a/app/src/main/java/com/tangem/presentation/Screen.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.tangem.presentation; - -public class Screen { -} diff --git a/app/src/main/java/com/tangem/presentation/activity/CardInfoActivity.java b/app/src/main/java/com/tangem/presentation/activity/CardInfoActivity.java index 9b10052280..067a3d8d61 100644 --- a/app/src/main/java/com/tangem/presentation/activity/CardInfoActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/CardInfoActivity.java @@ -12,7 +12,7 @@ import android.view.MenuItem; import com.tangem.wallet.R; import com.tangem.wallet.Tangem_Card; -import com.tangem.wallet.WalletInfoFragment; +import com.tangem.presentation.fragment.WalletInfoFragment; public class CardInfoActivity extends AppCompatActivity implements WalletInfoFragment.OnFragmentInteractionListener { diff --git a/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.java b/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.java index b28f9b915c..6b4bf0ac08 100644 --- a/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/ConfirmPaymentActivity.java @@ -22,20 +22,20 @@ import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; -import com.tangem.cardReader.NfcManager; -import com.tangem.cardReader.Util; +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.domain.cardReader.Util; import com.tangem.wallet.BTCUtils; import com.tangem.wallet.Blockchain; import com.tangem.wallet.CoinEngine; import com.tangem.wallet.CoinEngineFactory; import com.tangem.wallet.DerEncodingUtil; -import com.tangem.wallet.Electrum_Request; -import com.tangem.wallet.Electrum_Task; +import com.tangem.data.network.request.Electrum_Request; +import com.tangem.data.network.task.Electrum_Task; import com.tangem.wallet.Fee_Request; -import com.tangem.wallet.Fee_Task; +import com.tangem.data.network.task.Fee_Task; import com.tangem.wallet.FormatUtil; import com.tangem.wallet.Infura_Request; -import com.tangem.wallet.Infura_Task; +import com.tangem.data.network.task.Infura_Task; import com.tangem.wallet.R; import com.tangem.wallet.SharedData; import com.tangem.wallet.Tangem_Card; diff --git a/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.java b/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.java index 0aae506554..0699a29470 100644 --- a/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/CreateNewWalletActivity.java @@ -15,14 +15,14 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.NfcManager; -import com.tangem.cardReader.Util; -import com.tangem.wallet.NoExtendedLengthSupportDialog; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.domain.cardReader.Util; +import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog; import com.tangem.wallet.PINStorage; import com.tangem.wallet.R; import com.tangem.wallet.Tangem_Card; -import com.tangem.wallet.WaitSecurityDelayDialog; +import com.tangem.presentation.dialog.WaitSecurityDelayDialog; public class CreateNewWalletActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, CardProtocol.Notifications { diff --git a/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.java b/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.java index 5e27be5e8a..9e7c4f35e9 100644 --- a/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/EmptyWalletActivity.java @@ -17,14 +17,14 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.NfcManager; -import com.tangem.cardReader.Util; -import com.tangem.wallet.NoExtendedLengthSupportDialog; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.domain.cardReader.Util; +import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog; import com.tangem.wallet.R; import com.tangem.wallet.Tangem_Card; import com.tangem.wallet.VerifyCardTask; -import com.tangem.wallet.WaitSecurityDelayDialog; +import com.tangem.presentation.dialog.WaitSecurityDelayDialog; public class EmptyWalletActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, CardProtocol.Notifications { diff --git a/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.java b/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.java index b2c1f2c7dc..ae60bfb60b 100644 --- a/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/LoadedWalletActivity.java @@ -7,7 +7,7 @@ import android.nfc.Tag; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import com.tangem.wallet.LoadedWalletActivityFragment; +import com.tangem.presentation.fragment.LoadedWalletActivityFragment; import com.tangem.wallet.R; diff --git a/app/src/main/java/com/tangem/presentation/activity/MainActivity.java b/app/src/main/java/com/tangem/presentation/activity/MainActivity.java index 4bc9231baa..34fb4d16b8 100644 --- a/app/src/main/java/com/tangem/presentation/activity/MainActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/MainActivity.java @@ -35,7 +35,7 @@ import com.tangem.wallet.DeviceNFCAntennaLocation; import com.tangem.wallet.LastSignStorage; import com.tangem.wallet.LogFileProvider; import com.tangem.wallet.Logger; -import com.tangem.wallet.MainActivityFragment; +import com.tangem.presentation.fragment.MainActivityFragment; import com.tangem.wallet.PINStorage; import com.tangem.wallet.PhoneUtility; import com.tangem.wallet.R; diff --git a/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.java b/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.java index 8dd3e81dbe..cfc7d913bb 100644 --- a/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/PreparePaymentActivity.java @@ -17,7 +17,7 @@ import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; -import com.tangem.cardReader.NfcManager; +import com.tangem.domain.cardReader.NfcManager; import com.tangem.wallet.Blockchain; import com.tangem.wallet.CoinEngine; import com.tangem.wallet.CoinEngineFactory; diff --git a/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.java b/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.java index d6eb881845..a67dd5e36d 100644 --- a/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/PurgeActivity.java @@ -15,14 +15,14 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.NfcManager; -import com.tangem.cardReader.Util; -import com.tangem.wallet.NoExtendedLengthSupportDialog; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.domain.cardReader.Util; +import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog; import com.tangem.wallet.PINStorage; import com.tangem.wallet.R; import com.tangem.wallet.Tangem_Card; -import com.tangem.wallet.WaitSecurityDelayDialog; +import com.tangem.presentation.dialog.WaitSecurityDelayDialog; public class PurgeActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, CardProtocol.Notifications { diff --git a/app/src/main/java/com/tangem/presentation/activity/RequestPINActivity.java b/app/src/main/java/com/tangem/presentation/activity/RequestPINActivity.java index 9570babb18..e68938c105 100644 --- a/app/src/main/java/com/tangem/presentation/activity/RequestPINActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/RequestPINActivity.java @@ -26,7 +26,7 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; -import com.tangem.cardReader.NfcManager; +import com.tangem.domain.cardReader.NfcManager; import com.tangem.wallet.FingerprintHelper; import com.tangem.wallet.PINStorage; import com.tangem.wallet.R; diff --git a/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.java b/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.java index bec0ff1104..606b27315e 100644 --- a/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/SendTransactionActivity.java @@ -11,10 +11,10 @@ import android.widget.Toast; import com.tangem.wallet.Blockchain; import com.tangem.wallet.CoinEngine; import com.tangem.wallet.CoinEngineFactory; -import com.tangem.wallet.Electrum_Request; -import com.tangem.wallet.Electrum_Task; +import com.tangem.data.network.request.Electrum_Request; +import com.tangem.data.network.task.Electrum_Task; import com.tangem.wallet.Infura_Request; -import com.tangem.wallet.Infura_Task; +import com.tangem.data.network.task.Infura_Task; import com.tangem.wallet.LastSignStorage; import com.tangem.wallet.R; import com.tangem.wallet.SharedData; diff --git a/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.java b/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.java index d01ac47897..be424269a1 100644 --- a/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/SignPaymentActivity.java @@ -1 +1 @@ -package com.tangem.presentation.activity; import android.app.Activity; import android.content.Intent; import android.content.res.ColorStateList; import android.graphics.Color; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.IsoDep; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.tangem.cardReader.CardProtocol; import com.tangem.cardReader.NfcManager; import com.tangem.cardReader.Util; import com.tangem.wallet.BTCUtils; import com.tangem.wallet.Blockchain; import com.tangem.wallet.CoinEngine; import com.tangem.wallet.CoinEngineFactory; import com.tangem.wallet.LastSignStorage; import com.tangem.wallet.NoExtendedLengthSupportDialog; import com.tangem.wallet.R; import com.tangem.wallet.Tangem_Card; import com.tangem.wallet.WaitSecurityDelayDialog; public class SignPaymentActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, CardProtocol.Notifications { private static final int REQUEST_CODE_SEND_PAYMENT = 1; public static final int RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER; private Tangem_Card mCard; private TextView tvCardID; private NfcManager mNfcManager; private static final String logTag = "SignPayment"; private ProgressBar progressBar; private SignPaymentTask signPaymentTask; private String amountStr; private String feeStr; private String outAddressStr; private boolean lastReadSuccess = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_payment); MainActivity.commonInit(getApplicationContext()); mCard = new Tangem_Card(getIntent().getStringExtra("UID")); mCard.LoadFromBundle(getIntent().getExtras().getBundle("Card")); amountStr = getIntent().getStringExtra("Amount"); feeStr = getIntent().getStringExtra("Fee"); outAddressStr = getIntent().getStringExtra("Wallet"); tvCardID = findViewById(R.id.tvCardID); tvCardID.setText(mCard.getCIDDescription()); mNfcManager = new NfcManager(this, this); progressBar = findViewById(R.id.progressBar); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); } @Override public void onTagDiscovered(Tag tag) { try { // get IsoDep handle and run cardReader thread final IsoDep isoDep = IsoDep.get(tag); if (isoDep == null) { throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err)); } byte UID[] = tag.getId(); String sUID = Util.byteArrayToHexString(UID); Log.v(logTag, "UID: " + sUID); if (sUID.equals(mCard.getUID())) { if (lastReadSuccess) { isoDep.setTimeout(mCard.getPauseBeforePIN2() + 5000); } else { isoDep.setTimeout(mCard.getPauseBeforePIN2() + 65000); } signPaymentTask = new SignPaymentTask(isoDep, this, amountStr, feeStr, outAddressStr); signPaymentTask.start(); } else { Log.d(logTag, "Mismatch card UID (" + sUID + " instead of " + mCard.getUID() + ")"); mNfcManager.IgnoreTag(isoDep.getTag()); return; } } catch (Exception e) { e.printStackTrace(); } } @Override public void onResume() { super.onResume(); mNfcManager.onResume(); } @Override public void onPause() { mNfcManager.onPause(); if (signPaymentTask != null) { signPaymentTask.cancel(true); } super.onPause(); } @Override public void onStop() { // dismiss enable NFC dialog mNfcManager.onStop(); if (signPaymentTask != null) { signPaymentTask.cancel(true); } super.onStop(); } // @Override // public Dialog CreateNFCDialog(int id, AlertDialogWrapper.Builder builder, LayoutInflater li) { // return mNfcManager.onCreateDialog(id, builder, li); // } private class SignPaymentTask extends Thread { String txAmount = ""; String txFee = ""; public void SetTransactionValue(String amount, String fee) { txAmount = amount; txFee = fee; } private String txOutAddress; IsoDep mIsoDep; CardProtocol.Notifications mNotifications; private boolean isCancelled = false; public SignPaymentTask(IsoDep isoDep, CardProtocol.Notifications notifications, String amount, String fee, String outAddress) { mIsoDep = isoDep; mNotifications = notifications; txOutAddress = outAddress; SetTransactionValue(amount, fee); } @Override public void run() { if (mIsoDep == null) { return; } CardProtocol protocol = new CardProtocol(getBaseContext(), 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("SignPaymentTask", "[-- Start sign payment --]"); if (isCancelled) return; protocol.run_VerifyCard(); Log.i("SignPaymentTask", "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.Create(mCard.getBlockchain()); if (engine != null) { if (mCard.getPauseBeforePIN2() > 0) { mNotifications.OnReadWait(mCard.getPauseBeforePIN2()); } byte[] tx; // try { tx = engine.Sign(txFee, txAmount, txOutAddress, mCard, protocol); // } // finally { // mNotifications.OnReadWait(0); // } if (tx != null) { String txStr = BTCUtils.toHex(tx); if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet || mCard.getBlockchain() == Blockchain.Token) { txStr = String.format("0x%s", txStr); } LastSignStorage.setLastTX(mCard.getWallet(), txStr); Intent intent = new Intent(getBaseContext(), SendTransactionActivity.class); intent.putExtra("UID", mCard.getUID()); intent.putExtra("Card", mCard.getAsBundle()); intent.putExtra("TX", txStr); startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT); } } mNotifications.OnReadProgress(protocol, 100); if (isCancelled) return; } finally { mNfcManager.IgnoreTag(mIsoDep.getTag()); } } catch (CardProtocol.TangemException_InvalidPIN e) { e.printStackTrace(); protocol.setError(e); } catch (Exception e) { e.printStackTrace(); protocol.setError(e); } finally { Log.i("SignPaymentTask", "[-- Finish sign payment --]"); mNotifications.OnReadFinish(protocol); } } public void cancel(Boolean AllowInterrupt) { try { if (this.isAlive()) { isCancelled = true; join(500); } if (this.isAlive() && AllowInterrupt) { interrupt(); mNotifications.OnReadCancel(); } } catch (Exception e) { e.printStackTrace(); } } } public void OnReadStart(CardProtocol cardProtocol) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setVisibility(View.VISIBLE); progressBar.setProgress(5); } }); } public void OnReadFinish(final CardProtocol cardProtocol) { signPaymentTask = null; if (cardProtocol != null) { if (cardProtocol.getError() == null) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setProgress(100); progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); } }); } else { lastReadSuccess = false; if (cardProtocol.getError().getClass().equals(CardProtocol.TangemException_InvalidPIN.class)) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setProgress(100); progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); } }); progressBar.postDelayed(new Runnable() { @Override public void run() { try { progressBar.setProgress(0); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); Intent intent = new Intent(); intent.putExtra("message", "Cannot sign transaction. Make sure you enter correct PIN2!"); intent.putExtra("UID", cardProtocol.getCard().getUID()); intent.putExtra("Card", cardProtocol.getCard().getAsBundle()); setResult(RESULT_INVALID_PIN, intent); finish(); } catch (Exception e) { e.printStackTrace(); } } }, 500); return; } else { progressBar.post(new Runnable() { @Override public void run() { if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) { if (!NoExtendedLengthSupportDialog.allreadyShowed) { new NoExtendedLengthSupportDialog().show(getFragmentManager(), "NoExtendedLengthSupportDialog"); } } else { Toast.makeText(getBaseContext(), "Try to scan again", Toast.LENGTH_LONG).show(); } progressBar.setProgress(100); progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); } }); } } } progressBar.postDelayed(new Runnable() { @Override public void run() { try { progressBar.setProgress(0); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); } catch (Exception e) { e.printStackTrace(); } } }, 500); } public void OnReadProgress(CardProtocol protocol, final int progress) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setProgress(progress); } }); } public void OnReadCancel() { signPaymentTask = null; progressBar.postDelayed(new Runnable() { @Override public void run() { try { progressBar.setProgress(0); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); } catch (Exception e) { e.printStackTrace(); } } }, 500); } @Override public void OnReadWait(final int msec) { WaitSecurityDelayDialog.OnReadWait(this, msec); } @Override public void OnReadBeforeRequest(int timeout) { WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout); } @Override public void OnReadAfterRequest() { WaitSecurityDelayDialog.onReadAfterRequest(this); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: Intent intent = new Intent(); intent.putExtra("message", "Operation canceled by user"); setResult(Activity.RESULT_CANCELED, intent); finish(); return true; } return super.onKeyDown(keyCode, event); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_SEND_PAYMENT) { setResult(resultCode, data); finish(); return; } super.onActivityResult(requestCode, resultCode, data); } } \ No newline at end of file +package com.tangem.presentation.activity; import android.app.Activity; import android.content.Intent; import android.content.res.ColorStateList; import android.graphics.Color; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.IsoDep; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.tangem.domain.cardReader.CardProtocol; import com.tangem.domain.cardReader.NfcManager; import com.tangem.domain.cardReader.Util; import com.tangem.wallet.BTCUtils; import com.tangem.wallet.Blockchain; import com.tangem.wallet.CoinEngine; import com.tangem.wallet.CoinEngineFactory; import com.tangem.wallet.LastSignStorage; import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog; import com.tangem.wallet.R; import com.tangem.wallet.Tangem_Card; import com.tangem.presentation.dialog.WaitSecurityDelayDialog; public class SignPaymentActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, CardProtocol.Notifications { private static final int REQUEST_CODE_SEND_PAYMENT = 1; public static final int RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER; private Tangem_Card mCard; private TextView tvCardID; private NfcManager mNfcManager; private static final String logTag = "SignPayment"; private ProgressBar progressBar; private SignPaymentTask signPaymentTask; private String amountStr; private String feeStr; private String outAddressStr; private boolean lastReadSuccess = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_payment); MainActivity.commonInit(getApplicationContext()); mCard = new Tangem_Card(getIntent().getStringExtra("UID")); mCard.LoadFromBundle(getIntent().getExtras().getBundle("Card")); amountStr = getIntent().getStringExtra("Amount"); feeStr = getIntent().getStringExtra("Fee"); outAddressStr = getIntent().getStringExtra("Wallet"); tvCardID = findViewById(R.id.tvCardID); tvCardID.setText(mCard.getCIDDescription()); mNfcManager = new NfcManager(this, this); progressBar = findViewById(R.id.progressBar); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); } @Override public void onTagDiscovered(Tag tag) { try { // get IsoDep handle and run cardReader thread final IsoDep isoDep = IsoDep.get(tag); if (isoDep == null) { throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err)); } byte UID[] = tag.getId(); String sUID = Util.byteArrayToHexString(UID); Log.v(logTag, "UID: " + sUID); if (sUID.equals(mCard.getUID())) { if (lastReadSuccess) { isoDep.setTimeout(mCard.getPauseBeforePIN2() + 5000); } else { isoDep.setTimeout(mCard.getPauseBeforePIN2() + 65000); } signPaymentTask = new SignPaymentTask(isoDep, this, amountStr, feeStr, outAddressStr); signPaymentTask.start(); } else { Log.d(logTag, "Mismatch card UID (" + sUID + " instead of " + mCard.getUID() + ")"); mNfcManager.IgnoreTag(isoDep.getTag()); return; } } catch (Exception e) { e.printStackTrace(); } } @Override public void onResume() { super.onResume(); mNfcManager.onResume(); } @Override public void onPause() { mNfcManager.onPause(); if (signPaymentTask != null) { signPaymentTask.cancel(true); } super.onPause(); } @Override public void onStop() { // dismiss enable NFC dialog mNfcManager.onStop(); if (signPaymentTask != null) { signPaymentTask.cancel(true); } super.onStop(); } // @Override // public Dialog CreateNFCDialog(int id, AlertDialogWrapper.Builder builder, LayoutInflater li) { // return mNfcManager.onCreateDialog(id, builder, li); // } private class SignPaymentTask extends Thread { String txAmount = ""; String txFee = ""; public void SetTransactionValue(String amount, String fee) { txAmount = amount; txFee = fee; } private String txOutAddress; IsoDep mIsoDep; CardProtocol.Notifications mNotifications; private boolean isCancelled = false; public SignPaymentTask(IsoDep isoDep, CardProtocol.Notifications notifications, String amount, String fee, String outAddress) { mIsoDep = isoDep; mNotifications = notifications; txOutAddress = outAddress; SetTransactionValue(amount, fee); } @Override public void run() { if (mIsoDep == null) { return; } CardProtocol protocol = new CardProtocol(getBaseContext(), 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("SignPaymentTask", "[-- Start sign payment --]"); if (isCancelled) return; protocol.run_VerifyCard(); Log.i("SignPaymentTask", "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.Create(mCard.getBlockchain()); if (engine != null) { if (mCard.getPauseBeforePIN2() > 0) { mNotifications.OnReadWait(mCard.getPauseBeforePIN2()); } byte[] tx; // try { tx = engine.Sign(txFee, txAmount, txOutAddress, mCard, protocol); // } // finally { // mNotifications.OnReadWait(0); // } if (tx != null) { String txStr = BTCUtils.toHex(tx); if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet || mCard.getBlockchain() == Blockchain.Token) { txStr = String.format("0x%s", txStr); } LastSignStorage.setLastTX(mCard.getWallet(), txStr); Intent intent = new Intent(getBaseContext(), SendTransactionActivity.class); intent.putExtra("UID", mCard.getUID()); intent.putExtra("Card", mCard.getAsBundle()); intent.putExtra("TX", txStr); startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT); } } mNotifications.OnReadProgress(protocol, 100); if (isCancelled) return; } finally { mNfcManager.IgnoreTag(mIsoDep.getTag()); } } catch (CardProtocol.TangemException_InvalidPIN e) { e.printStackTrace(); protocol.setError(e); } catch (Exception e) { e.printStackTrace(); protocol.setError(e); } finally { Log.i("SignPaymentTask", "[-- Finish sign payment --]"); mNotifications.OnReadFinish(protocol); } } public void cancel(Boolean AllowInterrupt) { try { if (this.isAlive()) { isCancelled = true; join(500); } if (this.isAlive() && AllowInterrupt) { interrupt(); mNotifications.OnReadCancel(); } } catch (Exception e) { e.printStackTrace(); } } } public void OnReadStart(CardProtocol cardProtocol) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setVisibility(View.VISIBLE); progressBar.setProgress(5); } }); } public void OnReadFinish(final CardProtocol cardProtocol) { signPaymentTask = null; if (cardProtocol != null) { if (cardProtocol.getError() == null) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setProgress(100); progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); } }); } else { lastReadSuccess = false; if (cardProtocol.getError().getClass().equals(CardProtocol.TangemException_InvalidPIN.class)) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setProgress(100); progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); } }); progressBar.postDelayed(new Runnable() { @Override public void run() { try { progressBar.setProgress(0); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); Intent intent = new Intent(); intent.putExtra("message", "Cannot sign transaction. Make sure you enter correct PIN2!"); intent.putExtra("UID", cardProtocol.getCard().getUID()); intent.putExtra("Card", cardProtocol.getCard().getAsBundle()); setResult(RESULT_INVALID_PIN, intent); finish(); } catch (Exception e) { e.printStackTrace(); } } }, 500); return; } else { progressBar.post(new Runnable() { @Override public void run() { if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) { if (!NoExtendedLengthSupportDialog.allreadyShowed) { new NoExtendedLengthSupportDialog().show(getFragmentManager(), "NoExtendedLengthSupportDialog"); } } else { Toast.makeText(getBaseContext(), "Try to scan again", Toast.LENGTH_LONG).show(); } progressBar.setProgress(100); progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); } }); } } } progressBar.postDelayed(new Runnable() { @Override public void run() { try { progressBar.setProgress(0); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); } catch (Exception e) { e.printStackTrace(); } } }, 500); } public void OnReadProgress(CardProtocol protocol, final int progress) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setProgress(progress); } }); } public void OnReadCancel() { signPaymentTask = null; progressBar.postDelayed(new Runnable() { @Override public void run() { try { progressBar.setProgress(0); progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); progressBar.setVisibility(View.INVISIBLE); } catch (Exception e) { e.printStackTrace(); } } }, 500); } @Override public void OnReadWait(final int msec) { WaitSecurityDelayDialog.OnReadWait(this, msec); } @Override public void OnReadBeforeRequest(int timeout) { WaitSecurityDelayDialog.onReadBeforeRequest(this, timeout); } @Override public void OnReadAfterRequest() { WaitSecurityDelayDialog.onReadAfterRequest(this); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: Intent intent = new Intent(); intent.putExtra("message", "Operation canceled by user"); setResult(Activity.RESULT_CANCELED, intent); finish(); return true; } return super.onKeyDown(keyCode, event); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_SEND_PAYMENT) { setResult(resultCode, data); finish(); return; } super.onActivityResult(requestCode, resultCode, data); } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/presentation/activity/SwapPINActivity.java b/app/src/main/java/com/tangem/presentation/activity/SwapPINActivity.java index 32a16c9739..25e0c243b3 100644 --- a/app/src/main/java/com/tangem/presentation/activity/SwapPINActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/SwapPINActivity.java @@ -15,14 +15,14 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.NfcManager; -import com.tangem.cardReader.Util; -import com.tangem.wallet.NoExtendedLengthSupportDialog; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.domain.cardReader.Util; +import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog; import com.tangem.wallet.PINStorage; import com.tangem.wallet.R; import com.tangem.wallet.Tangem_Card; -import com.tangem.wallet.WaitSecurityDelayDialog; +import com.tangem.presentation.dialog.WaitSecurityDelayDialog; public class SwapPINActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, CardProtocol.Notifications { diff --git a/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.java b/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.java index 7af9846019..e3e3821430 100644 --- a/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/VerifyCardActivity.java @@ -6,7 +6,7 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import com.tangem.wallet.R; -import com.tangem.wallet.VerifyCardActivityFragment; +import com.tangem.presentation.fragment.VerifyCardActivityFragment; public class VerifyCardActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/tangem/wallet/CardListAdapter.java b/app/src/main/java/com/tangem/presentation/adapter/CardListAdapter.java similarity index 99% rename from app/src/main/java/com/tangem/wallet/CardListAdapter.java rename to app/src/main/java/com/tangem/presentation/adapter/CardListAdapter.java index bc3668bb3c..6a0b3be3e7 100644 --- a/app/src/main/java/com/tangem/wallet/CardListAdapter.java +++ b/app/src/main/java/com/tangem/presentation/adapter/CardListAdapter.java @@ -1,4 +1,4 @@ -package com.tangem.wallet; +package com.tangem.presentation.adapter; import android.content.Context; import android.graphics.Color; @@ -10,9 +10,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.RelativeLayout; import android.widget.TextView; +import com.tangem.wallet.Blockchain; +import com.tangem.wallet.CoinEngine; +import com.tangem.wallet.CoinEngineFactory; +import com.tangem.wallet.R; +import com.tangem.wallet.Tangem_Card; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; diff --git a/app/src/main/java/com/tangem/wallet/CardUnspentListAdapter.java b/app/src/main/java/com/tangem/presentation/adapter/CardUnspentListAdapter.java similarity index 95% rename from app/src/main/java/com/tangem/wallet/CardUnspentListAdapter.java rename to app/src/main/java/com/tangem/presentation/adapter/CardUnspentListAdapter.java index 19d57e41ff..488711706b 100644 --- a/app/src/main/java/com/tangem/wallet/CardUnspentListAdapter.java +++ b/app/src/main/java/com/tangem/presentation/adapter/CardUnspentListAdapter.java @@ -1,83 +1,86 @@ -package com.tangem.wallet; - -import android.content.Context; -import android.os.Build; -import android.text.Html; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import static android.text.Html.FROM_HTML_MODE_COMPACT; - -/** - * Created by dvol on 17.07.2017. - */ - -public class CardUnspentListAdapter extends BaseAdapter { - private LayoutInflater mLayoutInflater; - private Context mContext; - private Tangem_Card mCard; - - public CardUnspentListAdapter(LayoutInflater layoutInflater, Tangem_Card card) { - mLayoutInflater = layoutInflater; - mContext = layoutInflater.getContext(); - mCard = card; - } - - @Override - public int getCount() { - if (mCard != null && mCard.getUnspentTransactions() != null) - return mCard.getUnspentTransactions().size(); - return 0; - } - - @Override - public Object getItem(int i) { - if (mCard != null && mCard.getUnspentTransactions() != null) - return mCard.getUnspentTransactions().get(i); - return null; - } - - @Override - public long getItemId(int i) { - if (mCard != null && mCard.getUnspentTransactions() != null) - return mCard.getUnspentTransactions().get(i).txID.hashCode(); - return 0; - } - - @Override - public View getView(int position, View convertView, ViewGroup viewGroup) { - if (convertView == null) { - convertView = mLayoutInflater.inflate(R.layout.card_unspent_list_item, viewGroup, - false); - } - TextView tvItem = (TextView) convertView.findViewById(R.id.tvItem); - - Tangem_Card.UnspentTransaction unspentTransaction = (Tangem_Card.UnspentTransaction) getItem(position); - - String html=String.format("%d mBTC
%s", unspentTransaction.Amount, unspentTransaction.txID); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - tvItem.setText(Html.fromHtml(html, FROM_HTML_MODE_COMPACT)); - } else { - tvItem.setText(Html.fromHtml(html.toString())); - } - return convertView; - } - - public void Clear() { - mCard.getUnspentTransactions().clear(); - notifyDataSetChanged(); - } - - public void UpdateUnspent(String tx_hash, int value, int height) { - Tangem_Card.UnspentTransaction newUT=new Tangem_Card.UnspentTransaction(); - newUT.txID=tx_hash; - newUT.Amount=value; - newUT.Height=height; - mCard.getUnspentTransactions().add(newUT); - notifyDataSetChanged(); - } -} +package com.tangem.presentation.adapter; + +import android.content.Context; +import android.os.Build; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.tangem.wallet.R; +import com.tangem.wallet.Tangem_Card; + +import static android.text.Html.FROM_HTML_MODE_COMPACT; + +/** + * Created by dvol on 17.07.2017. + */ + +public class CardUnspentListAdapter extends BaseAdapter { + private LayoutInflater mLayoutInflater; + private Context mContext; + private Tangem_Card mCard; + + public CardUnspentListAdapter(LayoutInflater layoutInflater, Tangem_Card card) { + mLayoutInflater = layoutInflater; + mContext = layoutInflater.getContext(); + mCard = card; + } + + @Override + public int getCount() { + if (mCard != null && mCard.getUnspentTransactions() != null) + return mCard.getUnspentTransactions().size(); + return 0; + } + + @Override + public Object getItem(int i) { + if (mCard != null && mCard.getUnspentTransactions() != null) + return mCard.getUnspentTransactions().get(i); + return null; + } + + @Override + public long getItemId(int i) { + if (mCard != null && mCard.getUnspentTransactions() != null) + return mCard.getUnspentTransactions().get(i).txID.hashCode(); + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup viewGroup) { + if (convertView == null) { + convertView = mLayoutInflater.inflate(R.layout.card_unspent_list_item, viewGroup, + false); + } + TextView tvItem = (TextView) convertView.findViewById(R.id.tvItem); + + Tangem_Card.UnspentTransaction unspentTransaction = (Tangem_Card.UnspentTransaction) getItem(position); + + String html=String.format("%d mBTC
%s", unspentTransaction.Amount, unspentTransaction.txID); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + tvItem.setText(Html.fromHtml(html, FROM_HTML_MODE_COMPACT)); + } else { + tvItem.setText(Html.fromHtml(html.toString())); + } + return convertView; + } + + public void Clear() { + mCard.getUnspentTransactions().clear(); + notifyDataSetChanged(); + } + + public void UpdateUnspent(String tx_hash, int value, int height) { + Tangem_Card.UnspentTransaction newUT=new Tangem_Card.UnspentTransaction(); + newUT.txID=tx_hash; + newUT.Amount=value; + newUT.Height=height; + mCard.getUnspentTransactions().add(newUT); + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/com/tangem/cardReader/NFCEnableDialog.java b/app/src/main/java/com/tangem/presentation/dialog/NFCEnableDialog.java similarity index 95% rename from app/src/main/java/com/tangem/cardReader/NFCEnableDialog.java rename to app/src/main/java/com/tangem/presentation/dialog/NFCEnableDialog.java index d970fd1b9e..caca5b59cb 100644 --- a/app/src/main/java/com/tangem/cardReader/NFCEnableDialog.java +++ b/app/src/main/java/com/tangem/presentation/dialog/NFCEnableDialog.java @@ -1,45 +1,45 @@ -package com.tangem.cardReader; - -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.provider.Settings; -import android.support.v7.app.AlertDialog; - -import com.tangem.wallet.R; - -/** - * Created by dvol on 18.02.2018. - */ - -public class NFCEnableDialog extends DialogFragment { - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setCancelable(false) - .setIcon(R.drawable.ic_action_nfc_gray) - .setTitle(R.string.nfc_disabled) - .setMessage(R.string.enable_nfc) - .setPositiveButton(R.string.dialog_ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int id) { - // take user to wireless settings - getActivity().startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS)); - } - }) - .setNegativeButton(R.string.dialog_quit, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int id) { - dialog.cancel(); - getActivity().finish(); - } - }); - return builder.create(); - } -} +package com.tangem.presentation.dialog; + +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.provider.Settings; +import android.support.v7.app.AlertDialog; + +import com.tangem.wallet.R; + +/** + * Created by dvol on 18.02.2018. + */ + +public class NFCEnableDialog extends DialogFragment { + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setCancelable(false) + .setIcon(R.drawable.ic_action_nfc_gray) + .setTitle(R.string.nfc_disabled) + .setMessage(R.string.enable_nfc) + .setPositiveButton(R.string.dialog_ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int id) { + // take user to wireless settings + getActivity().startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS)); + } + }) + .setNegativeButton(R.string.dialog_quit, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int id) { + dialog.cancel(); + getActivity().finish(); + } + }); + return builder.create(); + } +} diff --git a/app/src/main/java/com/tangem/wallet/NoExtendedLengthSupportDialog.java b/app/src/main/java/com/tangem/presentation/dialog/NoExtendedLengthSupportDialog.java similarity index 94% rename from app/src/main/java/com/tangem/wallet/NoExtendedLengthSupportDialog.java rename to app/src/main/java/com/tangem/presentation/dialog/NoExtendedLengthSupportDialog.java index a3c9337086..62a1552dcc 100644 --- a/app/src/main/java/com/tangem/wallet/NoExtendedLengthSupportDialog.java +++ b/app/src/main/java/com/tangem/presentation/dialog/NoExtendedLengthSupportDialog.java @@ -1,34 +1,36 @@ -package com.tangem.wallet; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; - -public class NoExtendedLengthSupportDialog extends DialogFragment { - - public static boolean allreadyShowed=false; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - return new AlertDialog.Builder(getActivity()) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle("Warning") - .setMessage("The NFC adapter of the device does not support extended length APDU, it's possible that some functions will not work!") - .setPositiveButton("Got it", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - NoExtendedLengthSupportDialog.allreadyShowed=true; - } - } - ) - .create(); - } - - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - } -} +package com.tangem.presentation.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; + +import com.tangem.wallet.R; + +public class NoExtendedLengthSupportDialog extends DialogFragment { + + public static boolean allreadyShowed=false; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + return new AlertDialog.Builder(getActivity()) + .setIcon(R.drawable.tangem_logo_small_new) + .setTitle("Warning") + .setMessage("The NFC adapter of the device does not support extended length APDU, it's possible that some functions will not work!") + .setPositiveButton("Got it", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + NoExtendedLengthSupportDialog.allreadyShowed=true; + } + } + ) + .create(); + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + } +} diff --git a/app/src/main/java/com/tangem/wallet/WaitSecurityDelayDialog.java b/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialog.java similarity index 96% rename from app/src/main/java/com/tangem/wallet/WaitSecurityDelayDialog.java rename to app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialog.java index e22fa55b07..b7184c9444 100644 --- a/app/src/main/java/com/tangem/wallet/WaitSecurityDelayDialog.java +++ b/app/src/main/java/com/tangem/presentation/dialog/WaitSecurityDelayDialog.java @@ -1,166 +1,168 @@ -package com.tangem.wallet; - -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.view.LayoutInflater; -import android.view.View; -import android.widget.ProgressBar; - -import java.util.Timer; -import java.util.TimerTask; - -/** - * Created by dvol on 06.03.2018. - */ -public class WaitSecurityDelayDialog extends DialogFragment { - ProgressBar progressBar; - int msTimeout = 60000, msProgress = 0; - Timer timer; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - LayoutInflater inflater = getActivity().getLayoutInflater(); - - // Inflate and set the layout for the dialog - // Pass null as the parent view because its going in the dialog layout - View v = inflater.inflate(R.layout.dialog_wait_pin2, null); - - progressBar = v.findViewById(R.id.progressBar); - progressBar.setMax(msTimeout); - progressBar.setProgress(msProgress); - - timer = new Timer(); - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - progressBar.post(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("Security delay") - .setView(v) - .setCancelable(false) - .create(); - } - - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - } - - public void setup(int msTimeout, int msProgress) { - this.msTimeout = msTimeout; - this.msProgress = msProgress; - } - - public void setRemainingTimeout(final int msec) { - 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); - } - } - } - }); - } - - static Timer timerToShowDelayDialog = null; - static WaitSecurityDelayDialog instance = null; - - public static WaitSecurityDelayDialog getInstance() { - if (instance == null) { - instance = new WaitSecurityDelayDialog(); - } - return instance; - } - - private final static int MinRemainingDelayToShowDialog=1000; - private final static int DelayBeforeShowDialog=5000; - - public static void onReadBeforeRequest(final Activity activity, final int timeout) { - 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(new Runnable() { - @Override - public void run() { - if (timerToShowDelayDialog == null) return; - timerToShowDelayDialog.cancel(); - timerToShowDelayDialog = null; - } - }); - } - - 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); - } - } - }); - } -} +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.view.LayoutInflater; +import android.view.View; +import android.widget.ProgressBar; + +import com.tangem.wallet.R; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * Created by dvol on 06.03.2018. + */ +public class WaitSecurityDelayDialog extends DialogFragment { + ProgressBar progressBar; + int msTimeout = 60000, msProgress = 0; + Timer timer; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + LayoutInflater inflater = getActivity().getLayoutInflater(); + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + View v = inflater.inflate(R.layout.dialog_wait_pin2, null); + + progressBar = v.findViewById(R.id.progressBar); + progressBar.setMax(msTimeout); + progressBar.setProgress(msProgress); + + timer = new Timer(); + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + progressBar.post(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("Security delay") + .setView(v) + .setCancelable(false) + .create(); + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + } + + public void setup(int msTimeout, int msProgress) { + this.msTimeout = msTimeout; + this.msProgress = msProgress; + } + + public void setRemainingTimeout(final int msec) { + 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); + } + } + } + }); + } + + static Timer timerToShowDelayDialog = null; + static WaitSecurityDelayDialog instance = null; + + public static WaitSecurityDelayDialog getInstance() { + if (instance == null) { + instance = new WaitSecurityDelayDialog(); + } + return instance; + } + + private final static int MinRemainingDelayToShowDialog=1000; + private final static int DelayBeforeShowDialog=5000; + + public static void onReadBeforeRequest(final Activity activity, final int timeout) { + 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(new Runnable() { + @Override + public void run() { + if (timerToShowDelayDialog == null) return; + timerToShowDelayDialog.cancel(); + timerToShowDelayDialog = null; + } + }); + } + + 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/wallet/LoadedWalletActivityFragment.java b/app/src/main/java/com/tangem/presentation/fragment/LoadedWalletActivityFragment.java similarity index 97% rename from app/src/main/java/com/tangem/wallet/LoadedWalletActivityFragment.java rename to app/src/main/java/com/tangem/presentation/fragment/LoadedWalletActivityFragment.java index 5d1c32bcb8..be5a020de2 100644 --- a/app/src/main/java/com/tangem/wallet/LoadedWalletActivityFragment.java +++ b/app/src/main/java/com/tangem/presentation/fragment/LoadedWalletActivityFragment.java @@ -1,1605 +1,1624 @@ -package com.tangem.wallet; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.ColorStateList; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.IsoDep; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.widget.SwipeRefreshLayout; -import android.text.Html; -import android.text.Spanned; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.PopupMenu; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.EncodeHintType; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.qrcode.QRCodeWriter; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.NfcManager; -import com.tangem.cardReader.Util; -import com.tangem.presentation.activity.CreateNewWalletActivity; -import com.tangem.presentation.activity.PreparePaymentActivity; -import com.tangem.presentation.activity.PurgeActivity; -import com.tangem.presentation.activity.RequestPINActivity; -import com.tangem.presentation.activity.SwapPINActivity; -import com.tangem.presentation.activity.VerifyCardActivity; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -import static android.content.Context.CLIPBOARD_SERVICE; - -/** - * A placeholder fragment containing a simple view. - */ -public class LoadedWalletActivityFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, NfcAdapter.ReaderCallback, CardProtocol.Notifications { - - - private static final int REQUEST_CODE_SEND_PAYMENT = 1; - private static final int REQUEST_CODE_PURGE = 2; - private static final int REQUEST_CODE_REQUEST_PIN2_FOR_PURGE = 3; - private static final int REQUEST_CODE_VERIFY_CARD = 4; - private static final int REQUEST_CODE_ENTER_NEW_PIN = 5; - private static final int REQUEST_CODE_ENTER_NEW_PIN2 = 6; - private static final int REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = 7; - private static final int REQUEST_CODE_SWAP_PIN = 8; - Tangem_Card mCard; - TextView tvCardID, tvBalance, tvOffline, tvBalanceEquivalent, tvWallet, tvInputs, lbInputs, tvOutputs, tvSend, tvPurge, tvError, tvMessage, tvIssuer, tvIssuerData, tvBlockchain, tvLastInput, tvLastOutput, lbLastOutput, tvValidationNode; - TextView tvHeader, tvCaution; - ImageView imgLookup; - TextView tvLookup; - ProgressBar progressBar; - ImageView ivBlockchain, ivPIN, ivPIN2orSecurityDelay, ivDeveloperVersion, ivQR; - SwipeRefreshLayout mSwipeRefreshLayout; - List updateTasks = new ArrayList<>(); - private NfcManager mNfcManager; - private final String logTag = "LoadedWalletFragment"; - private boolean lastReadSuccess = true; - private VerifyCardTask verifyCardTask = null; - private int requestPIN2Count = 0; - - public LoadedWalletActivityFragment() { - - } - - public void onRefresh() { - //Update - // Showing refresh animation before making http call - if (updateTasks.size() > 0) return; - ; - mSwipeRefreshLayout.setRefreshing(true); - mCard.clearInfo(); - mCard.setError(null); - mCard.setMessage(null); - - boolean needResendTX = LastSignStorage.getNeedTxSend(mCard.getWallet()); - - UpdateViews(); - - CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); - - if (mCard.getBlockchain() == Blockchain.Bitcoin || mCard.getBlockchain() == Blockchain.BitcoinTestNet) { - SharedData data = new SharedData(SharedData.COUNT_REQUEST); - for (int i = 0; i < data.allRequest; ++i) { - String nodeAddress = engine.GetNextNode(mCard); - int nodePort = engine.GetNextNodePort(mCard); - UpdateWalletInfoTask connectTaskEx = new UpdateWalletInfoTask(nodeAddress, nodePort, data); - connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(mCard.getWallet())); - } - - String nodeAddress = engine.GetNode(mCard); - int nodePort = engine.GetNodePort(mCard); - UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort, data); - updateTasks.add(updateWalletInfoTask); - updateWalletInfoTask.execute(Electrum_Request.ListUnspent(mCard.getWallet()), Electrum_Request.ListHistory(mCard.getWallet())); - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "bitcoin", "bitcoin"); - taskRate.execute(rate); - - - } else if (mCard.getBlockchain() == Blockchain.BitcoinCash || mCard.getBlockchain() == Blockchain.BitcoinCashTestNet) { - SharedData data = new SharedData(SharedData.COUNT_REQUEST); - for (int i = 0; i < data.allRequest; ++i) { - String nodeAddress = engine.GetNextNode(mCard); - int nodePort = engine.GetNextNodePort(mCard); - UpdateWalletInfoTask connectTaskEx = new UpdateWalletInfoTask(nodeAddress, nodePort, data); - connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(mCard.getWallet())); - } - - String nodeAddress = engine.GetNode(mCard); - int nodePort = engine.GetNodePort(mCard); - UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort, data); - - updateTasks.add(updateWalletInfoTask); - updateWalletInfoTask.execute(Electrum_Request.ListUnspent(mCard.getWallet()), Electrum_Request.ListHistory(mCard.getWallet())); - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "bitcoin-cash", "bitcoin-cash"); - taskRate.execute(rate); - - - } - else if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet) { - ETHRequestTask updateETH = new ETHRequestTask(mCard.getBlockchain()); - Infura_Request reqETH = Infura_Request.GetBalance(mCard.getWallet()); - reqETH.setID(67); - reqETH.setBlockchain(mCard.getBlockchain()); - - Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(mCard.getWallet()); - reqNonce.setID(67); - reqNonce.setBlockchain(mCard.getBlockchain()); - - updateETH.execute(reqETH, reqNonce); - - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "ethereum", "ethereum"); - taskRate.execute(rate); - - } else if (mCard.getBlockchain() == Blockchain.Token) { - ETHRequestTask updateETH = new ETHRequestTask(mCard.getBlockchain()); - Infura_Request reqETH = Infura_Request.GetTokenBalance(mCard.getWallet(), engine.GetContractAddress(mCard), engine.GetTokenDecimals(mCard)); - reqETH.setID(67); - reqETH.setBlockchain(mCard.getBlockchain()); - - Infura_Request reqBalance = Infura_Request.GetBalance(mCard.getWallet()); - reqBalance.setID(67); - reqBalance.setBlockchain(mCard.getBlockchain()); - - Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(mCard.getWallet()); - reqNonce.setID(67); - reqNonce.setBlockchain(mCard.getBlockchain()); - updateETH.execute(reqETH, reqNonce, reqBalance); - - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "basic-attention-token", "ethereum"); - taskRate.execute(rate); - } - - if (needResendTX) { - SendTransaction(LastSignStorage.getTxForSend(mCard.getWallet())); - } - } - - void doShareWallet(boolean useURI) { - if (useURI) { - String txtShare = CoinEngineFactory.Create(mCard.getBlockchain()).getShareWalletURI(mCard).toString(); - //String txtShare = Blockchain.getShareWalletURI(mCard).toString(); - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - intent.putExtra(Intent.EXTRA_SUBJECT, "Wallet address"); - intent.putExtra(Intent.EXTRA_TEXT, txtShare); - - PackageManager packageManager = getActivity().getPackageManager(); - List activities = packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL); - boolean isIntentSafe = activities.size() > 0; - - if (isIntentSafe) { - String title = "Share wallet address with:"; - // Create intent to show chooser - Intent chooser = Intent.createChooser(intent, title); - // Verify the intent will resolve to at least one activity - if (intent.resolveActivity(getActivity().getPackageManager()) != null) { - startActivity(chooser); - } - } else { - ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE); - clipboard.setPrimaryClip(ClipData.newPlainText(txtShare, txtShare)); - Toast.makeText(getContext(), "Copied to clipboard", Toast.LENGTH_LONG).show(); - } - } else { - String txtShare = mCard.getWallet(); - ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE); - clipboard.setPrimaryClip(ClipData.newPlainText(txtShare, txtShare)); - Toast.makeText(getContext(), "Copied to clipboard", Toast.LENGTH_LONG).show(); - } - - - } - - @Override - public View onCreateView(final LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_loaded_wallet, container, false); - - mNfcManager = new NfcManager(this.getActivity(), this); - - - // SwipeRefreshLayout - mSwipeRefreshLayout = v.findViewById(R.id.swipe_container); - mSwipeRefreshLayout.setOnRefreshListener(this); - - mCard = new Tangem_Card(getActivity().getIntent().getStringExtra("UID")); - mCard.LoadFromBundle(getActivity().getIntent().getExtras().getBundle("Card")); - tvCardID = v.findViewById(R.id.tvCardID); - - tvBalance = v.findViewById(R.id.tvBalance); - tvOffline = v.findViewById(R.id.tvOffline); - - if (mCard.getBlockchain() == Blockchain.Token) { - //tvBalance.setLines(2); - tvBalance.setSingleLine(false); - } - - tvBalanceEquivalent = v.findViewById(R.id.tvBalanceEquivalent); - - tvWallet = v.findViewById(R.id.tvWallet); - tvWallet.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - doShareWallet(false); - } - }); - - tvInputs = v.findViewById(R.id.tvInputs); - lbInputs = v.findViewById(R.id.lbInputs); - - tvLastOutput = v.findViewById(R.id.tvLastOutput); - lbLastOutput = v.findViewById(R.id.lbLastOutput); - - final CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); - - boolean visibleFlag = engine != null ? engine.InOutPutVisible() : true; - int visibleIOPuts = visibleFlag ? View.VISIBLE : View.GONE; - if (tvInputs != null) { - tvInputs.setVisibility(visibleIOPuts); - } - - if (lbInputs != null) { - lbInputs.setVisibility(visibleIOPuts); - } - - if (tvLastOutput != null) { - tvLastOutput.setVisibility(visibleIOPuts); - } - - if (lbLastOutput != null) { - lbLastOutput.setVisibility(visibleIOPuts); - } - - tvValidationNode = v.findViewById(R.id.tvValidationNode); - - progressBar = v.findViewById(R.id.progressBar); - - tvBlockchain = v.findViewById(R.id.tvBlockchain); - ivBlockchain = v.findViewById(R.id.imgBlockchain); - ivPIN = v.findViewById(R.id.imgPIN); - ivPIN2orSecurityDelay = v.findViewById(R.id.imgPIN2orSecurityDelay); - ivDeveloperVersion = v.findViewById(R.id.imgDeveloperVersion); - - ivQR = v.findViewById(R.id.qrWallet); - - - try { - ivQR.setImageBitmap(generateQrCode(engine.getShareWalletURI(mCard).toString())); - } catch (WriterException e) { - e.printStackTrace(); - } - ivQR.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - doShareWallet(true); - } - }); - - tvError = v.findViewById(R.id.tvError); - tvMessage = v.findViewById(R.id.tvMessage); - - tvIssuer = v.findViewById(R.id.tvIssuer); - tvIssuerData = v.findViewById(R.id.tvIssuerData); - - tvHeader = v.findViewById(R.id.tvHeader); - tvCaution = v.findViewById(R.id.tvCaution); - - tvSend = v.findViewById(R.id.tvSend); - - imgLookup = v.findViewById(R.id.imgLookup); - - if (imgLookup != null) { - - imgLookup.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!mCard.hasBalanceInfo()) { - return; - } - CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain()); - - Intent browserIntent = new Intent(Intent.ACTION_VIEW, engineClick.getShareWalletURIExplorer(mCard)); - startActivity(browserIntent); - } - }); - - } - - tvLookup = v.findViewById(R.id.tvLookup); - - if (tvLookup != null) { - - tvLookup.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!mCard.hasBalanceInfo()) { - return; - } - CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain()); - - Intent browserIntent = new Intent(Intent.ACTION_VIEW, engineClick.getShareWalletURIExplorer(mCard)); - startActivity(browserIntent); - } - }); - } - - if (tvSend != null) { - tvSend.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!mCard.hasBalanceInfo()) { - return; - } else if (!engine.IsBalanceNotZero(mCard)) { - Toast.makeText(getContext(), "The wallet is empty", Toast.LENGTH_LONG).show(); - return; - } else if (!engine.IsBalanceAlterNotZero(mCard)) { - Toast.makeText(getContext(), "Not enough funds for transaction fee (gas)!", Toast.LENGTH_LONG).show(); - return; - } else if (engine.AwaitingConfirmation(mCard)) { - Toast.makeText(getContext(), "Please wait while previous transaction is confirmed in blockchain", Toast.LENGTH_LONG).show(); - return; - } else if (!engine.CheckUnspentTransaction(mCard)) { - Toast.makeText(getContext(), "Please wait for confirmation of incoming transaction!", Toast.LENGTH_LONG).show(); - return; - } else if (mCard.getRemainingSignatures() == 0) { - Toast.makeText(getContext(), "Card hasn't remaining signature!", Toast.LENGTH_LONG).show(); - return; - } - - Intent intent = new Intent(getContext(), PreparePaymentActivity.class); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT); - } - }); - } - - tvPurge = v.findViewById(R.id.tvPurge); - if (tvPurge != null) { - tvPurge.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showMenu(tvPurge); - } - } - ); - } - UpdateViews(); - - if (!mCard.hasBalanceInfo()) { - mSwipeRefreshLayout.setRefreshing(true); - mSwipeRefreshLayout.postDelayed(new Runnable() { - @Override - public void run() { - onRefresh(); - } - }, 1000); - } - return v; - } - - public void showMenu(View v) { - final PopupMenu popup = new PopupMenu(getActivity(), v); - MenuInflater inflater = popup.getMenuInflater(); - inflater.inflate(R.menu.menu_loaded_wallet, popup.getMenu()); - - popup.getMenu().findItem(R.id.action_set_PIN1).setVisible(mCard.allowSwapPIN()); - popup.getMenu().findItem(R.id.action_reset_PIN1).setVisible(mCard.allowSwapPIN() && !mCard.useDefaultPIN1()); - popup.getMenu().findItem(R.id.action_set_PIN2).setVisible(mCard.allowSwapPIN2()); - popup.getMenu().findItem(R.id.action_reset_PIN2).setVisible(mCard.allowSwapPIN2() && !mCard.useDefaultPIN2()); - popup.getMenu().findItem(R.id.action_reset_PINs).setVisible(mCard.allowSwapPIN() && mCard.allowSwapPIN2() && !mCard.useDefaultPIN1() && !mCard.useDefaultPIN2()); - - popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - - int id = item.getItemId(); - switch (id) { - case R.id.action_set_PIN1: - doSetPin(); - return true; - case R.id.action_reset_PIN1: - doResetPin(); - return true; - case R.id.action_set_PIN2: - doSetPin2(); - return true; - case R.id.action_reset_PIN2: - doResetPin2(); - return true; - case R.id.action_reset_PINs: - doResetPins(); - return true; - case R.id.action_purge: - doPurge(); - return true; - default: - return false; - } - } - }); - popup.show(); - } - - String newPIN = "", newPIN2 = ""; - - void doSetPin() { - requestPIN2Count = 0; - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestNewPIN.toString()); - newPIN = ""; - newPIN2 = ""; - startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN); - } - - void doResetPin() { - requestPIN2Count = 0; - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - newPIN = PINStorage.getDefaultPIN(); - newPIN2 = ""; - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); - } - - void doResetPin2() { - requestPIN2Count = 0; - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - newPIN = ""; - newPIN2 = PINStorage.getDefaultPIN2(); - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); - } - - void doResetPins() { - requestPIN2Count = 0; - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - newPIN = PINStorage.getDefaultPIN(); - newPIN2 = PINStorage.getDefaultPIN2(); - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); - } - - - void doSetPin2() { - requestPIN2Count = 0; - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestNewPIN2.toString()); - newPIN = ""; - newPIN2 = ""; - startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN2); - } - - void doPurge() { - requestPIN2Count = 0; - final CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); - if (!mCard.hasBalanceInfo()) { - return; - } else if (engine.IsBalanceNotZero(mCard)) { - Toast.makeText(getContext(), "Cannot erase wallet with non-zero balance", Toast.LENGTH_LONG).show(); - return; - } - - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_PURGE); - } - - void UpdateViews() { - try { - if (timerHideErrorAndMessage != null) { - timerHideErrorAndMessage.cancel(); - timerHideErrorAndMessage = null; - } - tvCardID.setText(mCard.getCIDDescription()); - - if ((mCard.getError() == null || mCard.getError().isEmpty())) { - tvError.setVisibility(View.GONE); - tvError.setText(""); - } else { - tvError.setVisibility(View.VISIBLE); - tvError.setText(mCard.getError()); - } - - boolean needResendTX = LastSignStorage.getNeedTxSend(mCard.getWallet()); - - if ((mCard.getMessage() == null || mCard.getMessage().isEmpty()) && !needResendTX) { - tvMessage.setText(""); - tvMessage.setVisibility(View.GONE); - } else { - if (needResendTX) { - tvMessage.setText("Sending cached transaction..."); - } else { - tvMessage.setText(mCard.getMessage()); - } - tvMessage.setVisibility(View.VISIBLE); - - } - - - CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); - - if (engine.HasBalanceInfo(mCard) || mCard.getOfflineBalance() == null) { - if (mCard.getBlockchain() == Blockchain.Token) { - Spanned html = Html.fromHtml(engine.GetBalanceWithAlter(mCard)); - tvBalance.setText(html); - } else { - tvBalance.setText(engine.GetBalanceWithAlter(mCard)); - } - - tvBalanceEquivalent.setText(engine.GetBalanceEquivalent(mCard)); - tvOffline.setVisibility(View.INVISIBLE); - } else { - String offlineAmount = engine.ConvertByteArrayToAmount(mCard, mCard.getOfflineBalance()); - if (mCard.getBlockchain() == Blockchain.Token) { - tvBalance.setText("NOT IMPLEMENTED"); - } else { - tvBalance.setText(engine.GetAmountDescription(mCard, offlineAmount)); - } - - tvBalanceEquivalent.setText(engine.GetAmountEqualentDescriptor(mCard, offlineAmount)); - tvOffline.setVisibility(View.VISIBLE); - } - - if (!mCard.getAmountEquivalentDescriptionAvailable()) { - //tvBalanceEquivalent.setError("Service unavailable"); - } else { - tvBalanceEquivalent.setError(null); - } - - tvWallet.setText(mCard.getWallet()); - - tvInputs.setText(mCard.getInputsDescription()); - if (mCard.getLastInputDescription().contains("awaiting")) { - tvInputs.setTextColor(getContext().getResources().getColor(R.color.not_confirmed, getContext().getTheme())); - } else if (mCard.getLastInputDescription().contains("None")) { - tvInputs.setTextColor(getContext().getResources().getColor(R.color.primary_dark, getContext().getTheme())); - } else { - tvInputs.setTextColor(getContext().getResources().getColor(R.color.confirmed, getContext().getTheme())); - } - - if (tvOutputs != null) { - tvOutputs.setText(mCard.getOutputsDescription()); - } - - if (tvLastInput != null) { - tvLastInput.setText(mCard.getLastInputDescription()); - } - if (tvLastOutput != null) { - tvLastOutput.setText(mCard.getLastOutputDescription()); - } - - tvBlockchain.setText(mCard.getBlockchainName()); - ivBlockchain.setImageResource(mCard.getBlockchain().getImageResource(this.getContext(), mCard.getTokenSymbol())); - - if (tvValidationNode != null) { - tvValidationNode.setText(mCard.getValidationNodeDescription()); - } - - if (mCard.useDefaultPIN1()) { - ivPIN.setImageResource(R.drawable.unlock_pin1); - ivPIN.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by default PIN1 code", Toast.LENGTH_LONG).show(); - } - }); - } else { - ivPIN.setImageResource(R.drawable.lock_pin1); - ivPIN.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by user's PIN1 code", Toast.LENGTH_LONG).show(); - } - }); - } - - if (mCard.getPauseBeforePIN2() > 0 && (mCard.useDefaultPIN2() || !mCard.useSmartSecurityDelay())) { - ivPIN2orSecurityDelay.setImageResource(R.drawable.timer); - ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), String.format("This banknote will enforce %.0f seconds security delay for all operations requiring PIN2 code", mCard.getPauseBeforePIN2() / 1000.0), Toast.LENGTH_LONG).show(); - } - }); - - } else if (mCard.useDefaultPIN2()) { - ivPIN2orSecurityDelay.setImageResource(R.drawable.unlock_pin2); - ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by default PIN2 code", Toast.LENGTH_LONG).show(); - } - }); - } else { - ivPIN2orSecurityDelay.setImageResource(R.drawable.lock_pin2); - ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by user's PIN2 code", Toast.LENGTH_LONG).show(); - } - }); - } - - - if (mCard.useDevelopersFirmware()) { - ivDeveloperVersion.setImageResource(R.drawable.ic_developer_version); - ivDeveloperVersion.setVisibility(View.VISIBLE); - ivDeveloperVersion.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "Unlocked banknote, only for development use", Toast.LENGTH_LONG).show(); - } - }); - } else { - ivDeveloperVersion.setVisibility(View.INVISIBLE); - } - - if (tvSend != null) { - if (mCard.hasBalanceInfo()) { - tvSend.setEnabled(true); - } else { - tvSend.setEnabled(false); - } - } - - if (tvPurge != null) { - if (mCard.hasBalanceInfo()) { - tvPurge.setEnabled(true); - } else { - tvPurge.setEnabled(false); - } - } - - tvIssuer.setText(mCard.getIssuerDescription()); - - timerHideErrorAndMessage = new Timer(); - - - timerHideErrorAndMessage.schedule(new TimerTask() { - @Override - public void run() { - tvError.post(new Runnable() { - @Override - public void run() { - tvMessage.setVisibility(View.GONE); - tvError.setVisibility(View.GONE); - mCard.setError(null); - mCard.setMessage(null); - } - }); - } - }, 5000); - - if (mCard.isReusable()) { - tvHeader.setText("REUSABLE WALLET"); - tvCaution.setVisibility(View.GONE); - } else { - if (mCard.getMaxSignatures() == mCard.getRemainingSignatures()) { - tvHeader.setText("BANKNOTE"); - tvCaution.setVisibility(View.GONE); - } else { - tvHeader.setText("NON-TRANSFERABLE BANKNOTE"); - tvCaution.setVisibility(View.VISIBLE); - } - } - - if (mCard.useDevelopersFirmware()) { - tvHeader.setText("DEVELOPER KIT"); - tvCaution.setVisibility(View.VISIBLE); - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - - Timer timerHideErrorAndMessage = null; - - public Intent prepareResultIntent() { - Intent data = new Intent(); - data.putExtra("UID", mCard.getUID()); - data.putExtra("Card", mCard.getAsBundle()); - return data; - } - - private void SendTransaction(String tx) { - CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); - if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet || mCard.getBlockchain() == Blockchain.Token) { - ETHRequestTask task = new ETHRequestTask(mCard.getBlockchain()); - Infura_Request req = Infura_Request.SendTransaction(mCard.getWallet(), tx); - req.setID(67); - req.setBlockchain(mCard.getBlockchain()); - task.execute(req); - } else if (mCard.getBlockchain() == Blockchain.Bitcoin ||mCard.getBlockchain() == Blockchain.BitcoinTestNet) { - String nodeAddress = engine.GetNode(mCard); - int nodePort = engine.GetNodePort(mCard); - - UpdateWalletInfoTask connectTask = new UpdateWalletInfoTask(nodeAddress, nodePort); - connectTask.execute(Electrum_Request.Broadcast(mCard.getWallet(), tx)); - } - else if (mCard.getBlockchain() == Blockchain.BitcoinCash ||mCard.getBlockchain() == Blockchain.BitcoinCashTestNet) { - String nodeAddress = engine.GetNode(mCard); - int nodePort = engine.GetNodePort(mCard); - - UpdateWalletInfoTask connectTask = new UpdateWalletInfoTask(nodeAddress, nodePort); - connectTask.execute(Electrum_Request.Broadcast(mCard.getWallet(), tx)); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - switch (requestCode) { - case REQUEST_CODE_ENTER_NEW_PIN: - if (resultCode == Activity.RESULT_OK) { - if (data != null) { - if (data.getExtras().containsKey("confirmPIN")) { - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - newPIN = data.getStringExtra("newPIN"); - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); - } else { - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("newPIN", data.getStringExtra("newPIN")); - intent.putExtra("mode", RequestPINActivity.Mode.ConfirmNewPIN.toString()); - startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN); - } - } - } - break; - case REQUEST_CODE_ENTER_NEW_PIN2: - if (resultCode == Activity.RESULT_OK) { - if (data != null) { - if (data.getExtras().containsKey("confirmPIN2")) { - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - newPIN2 = data.getStringExtra("newPIN2"); - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); - } else { - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("newPIN2", data.getStringExtra("newPIN2")); - intent.putExtra("mode", RequestPINActivity.Mode.ConfirmNewPIN2.toString()); - startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN2); - } - } - } - break; - case REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN: - if (resultCode == Activity.RESULT_OK) { - if (newPIN.equals("")) { - newPIN = mCard.getPIN(); - } - if (newPIN2.equals("")) { - newPIN2 = PINStorage.getPIN2(); - } - - PINSwapWarningDialog dialog = (new PINSwapWarningDialog()); - dialog.activityFragment = this; - if (!PINStorage.isDefaultPIN(newPIN) || !PINStorage.isDefaultPIN2(newPIN2)) { - dialog.message = "If you forget your new PIN you will lose your money forever!"; - } else { - dialog.message = "If you use default PIN someone can steal your money!"; - } - dialog.show(getActivity().getFragmentManager(), "PINSwapWarningDialog"); - } - break; - - case REQUEST_CODE_SWAP_PIN: - if (resultCode == Activity.RESULT_OK) { - if (data == null) { - data = new Intent(); - - data.putExtra("UID", mCard.getUID()); - data.putExtra("Card", mCard.getAsBundle()); - data.putExtra("modification", "delete"); - } else { - data.putExtra("modification", "update"); - } - getActivity().setResult(Activity.RESULT_OK, data); - getActivity().finish(); - } else { - if (data != null && data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) { - Tangem_Card updatedCard = new Tangem_Card(data.getStringExtra("UID")); - updatedCard.LoadFromBundle(data.getBundleExtra("Card")); - mCard = updatedCard; - } - if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) { - requestPIN2Count++; - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); - return; - } else { - if (data != null && data.getExtras().containsKey("message")) { - mCard.setError(data.getStringExtra("message")); - } - } - } - break; - case REQUEST_CODE_REQUEST_PIN2_FOR_PURGE: - if (resultCode == Activity.RESULT_OK) { - Intent intent = new Intent(getContext(), PurgeActivity.class); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - startActivityForResult(intent, REQUEST_CODE_PURGE); - } - break; - case REQUEST_CODE_PURGE: - if (resultCode == Activity.RESULT_OK) { - if (data == null) { - data = new Intent(); - - data.putExtra("UID", mCard.getUID()); - data.putExtra("Card", mCard.getAsBundle()); - data.putExtra("modification", "delete"); - } else { - data.putExtra("modification", "update"); - } - getActivity().setResult(Activity.RESULT_OK, data); - getActivity().finish(); - } else { - if (data != null && data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) { - Tangem_Card updatedCard = new Tangem_Card(data.getStringExtra("UID")); - updatedCard.LoadFromBundle(data.getBundleExtra("Card")); - mCard = updatedCard; - } - if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) { - requestPIN2Count++; - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_PURGE); - return; - } else { - if (data != null && data.getExtras().containsKey("message")) { - mCard.setError(data.getStringExtra("message")); - } - } - UpdateViews(); - } - break; - case REQUEST_CODE_SEND_PAYMENT: - if (resultCode == Activity.RESULT_OK) { - mSwipeRefreshLayout.postDelayed(new Runnable() { - @Override - public void run() { - onRefresh(); - } - }, 10000); - mSwipeRefreshLayout.setRefreshing(true); - mCard.clearInfo(); - UpdateViews(); - } - - if (data != null) { - if (data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) { - Tangem_Card updatedCard = new Tangem_Card(data.getStringExtra("UID")); - updatedCard.LoadFromBundle(data.getBundleExtra("Card")); - mCard = updatedCard; - } - if (data.getExtras().containsKey("message")) { - if (resultCode == Activity.RESULT_OK) { - mCard.setMessage(data.getStringExtra("message")); - } else { - mCard.setError(data.getStringExtra("message")); - } - } - UpdateViews(); - } - - break; - } - - } - - private void startSwapPINActivity() { - Intent intent = new Intent(getContext(), SwapPINActivity.class); - intent.putExtra("UID", mCard.getUID()); - intent.putExtra("Card", mCard.getAsBundle()); - intent.putExtra("newPIN", newPIN); - intent.putExtra("newPIN2", newPIN2); - startActivityForResult(intent, REQUEST_CODE_SWAP_PIN); - } - - public static Bitmap generateQrCode(String myCodeText) throws WriterException { - Hashtable hintMap = new Hashtable(); - hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // H = 30% damage - - QRCodeWriter qrCodeWriter = new QRCodeWriter(); - - int size = 256; - - BitMatrix bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hintMap); - int width = bitMatrix.getWidth(); - Bitmap bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565); - for (int x = 0; x < width; x++) { - for (int y = 0; y < width; y++) { - bmp.setPixel(y, x, bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE); - } - } - return bmp; - } - - - @Override - public void onResume() { - super.onResume(); - mNfcManager.onResume(); - } - - @Override - public void onPause() { - super.onPause(); - mNfcManager.onPause(); - } - - @Override - public void onStop() { - super.onStop(); - for (UpdateWalletInfoTask ut : updateTasks) { - ut.cancel(true); - } - mNfcManager.onStop(); - } - - @Override - public void onTagDiscovered(Tag tag) { - try { - final IsoDep isoDep = IsoDep.get(tag); - if (isoDep == null) { - throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err)); - } - byte UID[] = tag.getId(); - String sUID = Util.byteArrayToHexString(UID); - if (!mCard.getUID().equals(sUID)) { - Log.d(logTag, "Invalid UID: " + sUID); - mNfcManager.IgnoreTag(isoDep.getTag()); - return; - } else { - Log.v(logTag, "UID: " + sUID); - } - - if (lastReadSuccess) { - isoDep.setTimeout(1000); - } else { - isoDep.setTimeout(65000); - } - //lastTag = tag; - verifyCardTask = new VerifyCardTask(getContext(), mCard, mNfcManager, isoDep, this); - verifyCardTask.start(); - - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void ErrorOnUpdate(String message) { - mCard.setError("Cannot obtain data from blockchain"); - UpdateViews(); - } - - private class ETHRequestTask extends Infura_Task { - ETHRequestTask(Blockchain blockchain) { - super(blockchain); - } - - @Override - protected void onPostExecute(List requests) { - super.onPostExecute(requests); - for (Infura_Request request : requests) { - try { - if (request.error == null) { - - if (request.isMethod(Infura_Request.METHOD_ETH_GetBalance)) { - try { - String balanceCap = request.getResultString(); - balanceCap = balanceCap.substring(2); - BigInteger l = new BigInteger(balanceCap, 16); - BigInteger d = l.divide(new BigInteger("1000000000000000000", 10)); - Long balance = d.longValue(); - - mCard.setBalanceConfirmed(balance); - mCard.setBalanceUnconfirmed(0L); - if (mCard.getBlockchain() != Blockchain.Token) - mCard.setDecimalBalance(l.toString(10)); - mCard.setDecimalBalanceAlter(l.toString(10)); - - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - } - } else if (request.isMethod(Infura_Request.METHOD_ETH_Call)) { - try { - String balanceCap = request.getResultString(); - balanceCap = balanceCap.substring(2); - BigInteger l = new BigInteger(balanceCap, 16); - Long balance = l.longValue(); - - if (l.compareTo(BigInteger.ZERO) == 0) { - mCard.setBlockchainID(Blockchain.Ethereum.getID()); - mCard.addTokenToBlockchainName(); - mSwipeRefreshLayout.setRefreshing(false); - onRefresh(); - return; - } - - mCard.setBalanceConfirmed(balance); - mCard.setBalanceUnconfirmed(0L); - mCard.setDecimalBalance(l.toString(10)); - - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - } - } else if (request.isMethod(Infura_Request.METHOD_ETH_GetOutTransactionCount)) { - try { - String nonce = request.getResultString(); - nonce = nonce.substring(2); - BigInteger count = new BigInteger(nonce, 16); - - mCard.SetConfirmTXCount(count); - } catch (JSONException e) { - e.printStackTrace(); - } - } else if (request.isMethod(Infura_Request.METHOD_ETH_SendRawTransaction)) { - try { - String hashTX = ""; - - try { - String tmp = request.getResultString(); - hashTX = tmp; - } catch (JSONException e) { - JSONObject msg = request.getAnswer(); - JSONObject err = msg.getJSONObject("error"); - hashTX = err.getString("message"); - LastSignStorage.setLastMessage(mCard.getWallet(), hashTX); - ErrorOnUpdate("Failed to send transaction. Try again"); - return; - } - - if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) { - hashTX = hashTX.substring(2); - } - BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ - LastSignStorage.setTxWasSend(mCard.getWallet()); - LastSignStorage.setLastMessage(mCard.getWallet(), ""); - Log.e("TX_RESULT", hashTX); - - - BigInteger nonce = mCard.GetConfirmTXCount(); - nonce.add(BigInteger.valueOf(1)); - mCard.SetConfirmTXCount(nonce); - Log.e("TX_RESULT", hashTX); - - } catch (Exception e) { - e.printStackTrace(); - ErrorOnUpdate("Failed to send transaction. Try again"); - } - } - UpdateViews(); - } else { - ErrorOnUpdate(request.error); - } - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - } - } - - if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); - } - } - - public void OnReadStart(CardProtocol cardProtocol) { - progressBar.post(new Runnable() { - @Override - public void run() { - progressBar.setVisibility(View.VISIBLE); - progressBar.setProgress(5); - } - }); - } - - public void OnReadFinish(final CardProtocol cardProtocol) { - - verifyCardTask = null; - - if (cardProtocol != null) { - if (cardProtocol.getError() == null) { - progressBar.post(new Runnable() { - @Override - public void run() { - progressBar.setProgress(100); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); - Intent intent = new Intent(getContext(), VerifyCardActivity.class); - // TODO обновить карту mCard - intent.putExtra("UID", cardProtocol.getCard().getUID()); - intent.putExtra("Card", cardProtocol.getCard().getAsBundle()); - startActivityForResult(intent, REQUEST_CODE_VERIFY_CARD); - //addCard(cardProtocol.getCard()); - } - }); - } else { - // remove last UIDs because of error and no card read - progressBar.post(new Runnable() { - @Override - public void run() { - lastReadSuccess = false; - if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allreadyShowed) { - new NoExtendedLengthSupportDialog().show(getActivity().getFragmentManager(), "NoExtendedLengthSupportDialog"); - } - } else { - Toast.makeText(getContext(), "Try to scan again", Toast.LENGTH_LONG).show(); - } - progressBar.setProgress(100); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); - } - }); - } - } - - progressBar.postDelayed(new Runnable() { - @Override - public void run() { - try { - progressBar.setProgress(0); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); - progressBar.setVisibility(View.INVISIBLE); - } catch (Exception e) { - e.printStackTrace(); - } - } - }, 500); - } - - public void OnReadProgress(CardProtocol protocol, final int progress) { - progressBar.post(new Runnable() { - @Override - public void run() { - progressBar.setProgress(progress); - } - }); - } - - public void OnReadCancel() { - - verifyCardTask = null; - - progressBar.postDelayed(new Runnable() { - @Override - public void run() { - try { - progressBar.setProgress(0); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); - progressBar.setVisibility(View.INVISIBLE); - } catch (Exception e) { - e.printStackTrace(); - } - } - }, 500); - } - - public void OnReadWait(int msec) { - WaitSecurityDelayDialog.OnReadWait(getActivity(), msec); - } - - @Override - public void OnReadBeforeRequest(int timeout) { - WaitSecurityDelayDialog.onReadBeforeRequest(getActivity(), timeout); - } - - @Override - public void OnReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(getActivity()); - } - - - private class RateInfoTask extends ExchangeTask { - protected void onPostExecute(List requests) { - super.onPostExecute(requests); - for (ExchangeRequest request : requests) { - if (request.error == null) { - try { - - JSONArray arr = request.getAnswerList(); - for (int i = 0; i < arr.length(); ++i) { - JSONObject obj = arr.getJSONObject(i); - String currency = obj.getString("id"); - - boolean stop = false; - boolean stopAlter = false; - if (currency.equals(request.currency)) { - String usd = obj.getString("price_usd"); - - Float rate = Float.valueOf(usd); - mCard.setRate(rate); - UpdateViews(); - stop = true; - } - - if (currency.equals(request.currencyAlter)) { - String usd = obj.getString("price_usd"); - - Float rate = Float.valueOf(usd); - mCard.setRateAlter(rate); - UpdateViews(); - stopAlter = true; - } - - if (stop && stopAlter) { - break; - } - - } - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - } - } - - private class UpdateWalletInfoTask extends Electrum_Task { - public UpdateWalletInfoTask(String host, int port) { - super(host, port); - } - - - public UpdateWalletInfoTask(String host, int port, SharedData sharedData) { - super(host, port, sharedData); - } - - @Override - protected void onProgressUpdate(Integer... values) { - super.onProgressUpdate(values); - } - - @Override - protected void onCancelled() { - super.onCancelled(); - updateTasks.remove(this); - if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); - } - - @Override - protected void onPostExecute(List requests) { - super.onPostExecute(requests); - Log.i("RequestWalletInfoTask", "onPostExecute[" + String.valueOf(updateTasks.size()) + "]"); - updateTasks.remove(this); - - CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); - - for (Electrum_Request request : requests) { - try { - if (request.error == null) { - if (request.isMethod(Electrum_Request.METHOD_GetBalance)) { - try { - String mWalletAddress = request.getParams().getString(0); - Long confBalance = request.getResult().getLong("confirmed"); - Long unconf = request.getResult().getLong("unconfirmed"); - if (sharedCounter != null) { - int counter = sharedCounter.requestCounter.incrementAndGet(); - if (counter != 1) { - continue; - } - } - - mCard.setBalanceConfirmed(confBalance); - mCard.setBalanceUnconfirmed(unconf); - mCard.setDecimalBalance(String.valueOf(confBalance)); - mCard.setValidationNodeDescription(getValidationNodeDescription()); - } catch (JSONException e) { - if (sharedCounter != null) { - int errCounter = sharedCounter.errorRequest.incrementAndGet(); - if (errCounter >= sharedCounter.allRequest) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - } - } else { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - } - } - } else if (request.isMethod(Electrum_Request.METHOD_SendTransaction)) { - try { - String hashTX = request.getResultString(); - - try { - LastSignStorage.setLastMessage(mCard.getWallet(), hashTX); - if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) { - hashTX = hashTX.substring(2); - } - BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ - LastSignStorage.setTxWasSend(mCard.getWallet()); - LastSignStorage.setLastMessage(mCard.getWallet(), ""); - Log.e("TX_RESULT", hashTX); - - } catch (Exception e) { - engine.SwitchNode(mCard); - ErrorOnUpdate("Failed to send transaction. Try again."); - } - - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate("Failed to send transaction. Try again."); - engine.SwitchNode(mCard); - } - } else if (request.isMethod(Electrum_Request.METHOD_ListUnspent)) { - try { - String mWalletAddress = request.getParams().getString(0); - - JSONArray jsUnspentArray = request.getResultArray(); - try { - mCard.getUnspentTransactions().clear(); - for (int i = 0; i < jsUnspentArray.length(); i++) { - JSONObject jsUnspent = jsUnspentArray.getJSONObject(i); - Tangem_Card.UnspentTransaction trUnspent = new Tangem_Card.UnspentTransaction(); - trUnspent.txID = jsUnspent.getString("tx_hash"); - trUnspent.Amount = jsUnspent.getInt("value"); - trUnspent.Height = jsUnspent.getInt("height"); - mCard.getUnspentTransactions().add(trUnspent); - } - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - } - - 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) { - String nodeAddress = engine.GetNextNode(mCard); - int nodePort = engine.GetNextNodePort(mCard); - UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort); - - updateTasks.add(updateWalletInfoTask); - - updateWalletInfoTask.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), - Electrum_Request.GetTransaction(mWalletAddress, hash)); - } - } - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - } - } else if (request.isMethod(Electrum_Request.METHOD_GetHistory)) { - try { - String mWalletAddress = request.getParams().getString(0); - - JSONArray jsHistoryArray = request.getResultArray(); - try { - mCard.getHistoryTransactions().clear(); - for (int i = 0; i < jsHistoryArray.length(); i++) { - JSONObject jsUnspent = jsHistoryArray.getJSONObject(i); - Tangem_Card.HistoryTransaction trHistory = new Tangem_Card.HistoryTransaction(); - trHistory.txID = jsUnspent.getString("tx_hash"); - trHistory.Height = jsUnspent.getInt("height"); - mCard.getHistoryTransactions().add(trHistory); - } - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - } - - for (int i = 0; i < jsHistoryArray.length(); i++) { - JSONObject jsUnspent = jsHistoryArray.getJSONObject(i); - Integer height = jsUnspent.getInt("height"); - String hash = jsUnspent.getString("tx_hash"); - if (height != -1) { - - String nodeAddress = engine.GetNode(mCard); - int nodePort = engine.GetNodePort(mCard); - UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort); - updateTasks.add(updateWalletInfoTask); - - updateWalletInfoTask.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), - Electrum_Request.GetTransaction(mWalletAddress, hash)); - } - - } - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - } - } else if (request.isMethod(Electrum_Request.METHOD_GetHeader)) { - try { - JSONObject jsHeader = request.getResult(); - try { - mCard.getHaedersInfo(); - mCard.UpdateHeaderInfo(new Tangem_Card.HeaderInfo( - jsHeader.getInt("block_height"), - jsHeader.getInt("timestamp"))); - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - - } - - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - - } - } else if (request.isMethod(Electrum_Request.METHOD_GetTransaction)) { - try { - - String txHash = request.TxHash; - String raw = request.getResultString(); - - List listTx = mCard.getUnspentTransactions(); - for (Tangem_Card.UnspentTransaction tx : listTx) { - if (tx.txID.equals(txHash)) { - tx.Raw = raw; - } - } - - List listHTx = mCard.getHistoryTransactions(); - for (Tangem_Card.HistoryTransaction tx : listHTx) { - if (tx.txID.equals(txHash)) { - tx.Raw = raw; - try { - ArrayList prevHashes = BTCUtils.getPrevTX(raw); - - boolean isOur = false; - for (byte[] hash : prevHashes) { - String checkID = BTCUtils.toHex(hash); - for (Tangem_Card.HistoryTransaction txForCheck : listHTx) { - if (txForCheck.txID == checkID) { - isOur = true; - } - } - } - - tx.isInput = !isOur; - } catch (BitcoinException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - } - Log.e("TX", raw); - } - } - - } catch (JSONException e) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - engine.SwitchNode(mCard); - } - } - UpdateViews(); - } else { - if (sharedCounter != null) { - int errCounter = sharedCounter.errorRequest.incrementAndGet(); - if (errCounter >= sharedCounter.allRequest) { - ErrorOnUpdate(request.error); - engine.SwitchNode(mCard); - - } - } else { - ErrorOnUpdate(request.error); - engine.SwitchNode(mCard); - - } - - } - } catch (JSONException e) { - if (sharedCounter != null) { - int errCounter = sharedCounter.errorRequest.incrementAndGet(); - if (errCounter >= sharedCounter.allRequest) { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - } - } else { - e.printStackTrace(); - ErrorOnUpdate(e.toString()); - } - } - } - if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); - - } - } - - public static class PINSwapWarningDialog extends DialogFragment { - - LoadedWalletActivityFragment activityFragment = null; - String message; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - return new AlertDialog.Builder(getActivity()) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle("Your money is at risk!") - .setMessage(message) - .setCancelable(true) - .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - PINSwapWarningDialog.this.dismiss(); - } - }) - .setPositiveButton("Continue", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - if (activityFragment != null) - activityFragment.startSwapPINActivity(); - } - } - ) - .create(); - } - - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - } - } - -} +package com.tangem.presentation.fragment; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.ColorStateList; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.IsoDep; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.text.Html; +import android.text.Spanned; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.PopupMenu; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.domain.cardReader.Util; +import com.tangem.presentation.activity.CreateNewWalletActivity; +import com.tangem.presentation.activity.PreparePaymentActivity; +import com.tangem.presentation.activity.PurgeActivity; +import com.tangem.presentation.activity.RequestPINActivity; +import com.tangem.presentation.activity.SwapPINActivity; +import com.tangem.presentation.activity.VerifyCardActivity; +import com.tangem.wallet.BTCUtils; +import com.tangem.wallet.BitcoinException; +import com.tangem.wallet.Blockchain; +import com.tangem.wallet.CoinEngine; +import com.tangem.wallet.CoinEngineFactory; +import com.tangem.data.network.request.Electrum_Request; +import com.tangem.data.network.task.Electrum_Task; +import com.tangem.data.network.request.ExchangeRequest; +import com.tangem.data.network.task.ExchangeTask; +import com.tangem.wallet.Infura_Request; +import com.tangem.data.network.task.Infura_Task; +import com.tangem.wallet.LastSignStorage; +import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog; +import com.tangem.wallet.PINStorage; +import com.tangem.wallet.R; +import com.tangem.wallet.SharedData; +import com.tangem.wallet.Tangem_Card; +import com.tangem.wallet.VerifyCardTask; +import com.tangem.presentation.dialog.WaitSecurityDelayDialog; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import static android.content.Context.CLIPBOARD_SERVICE; + +/** + * A placeholder fragment containing a simple view. + */ +public class LoadedWalletActivityFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, NfcAdapter.ReaderCallback, CardProtocol.Notifications { + + + private static final int REQUEST_CODE_SEND_PAYMENT = 1; + private static final int REQUEST_CODE_PURGE = 2; + private static final int REQUEST_CODE_REQUEST_PIN2_FOR_PURGE = 3; + private static final int REQUEST_CODE_VERIFY_CARD = 4; + private static final int REQUEST_CODE_ENTER_NEW_PIN = 5; + private static final int REQUEST_CODE_ENTER_NEW_PIN2 = 6; + private static final int REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = 7; + private static final int REQUEST_CODE_SWAP_PIN = 8; + Tangem_Card mCard; + TextView tvCardID, tvBalance, tvOffline, tvBalanceEquivalent, tvWallet, tvInputs, lbInputs, tvOutputs, tvSend, tvPurge, tvError, tvMessage, tvIssuer, tvIssuerData, tvBlockchain, tvLastInput, tvLastOutput, lbLastOutput, tvValidationNode; + TextView tvHeader, tvCaution; + ImageView imgLookup; + TextView tvLookup; + ProgressBar progressBar; + ImageView ivBlockchain, ivPIN, ivPIN2orSecurityDelay, ivDeveloperVersion, ivQR; + SwipeRefreshLayout mSwipeRefreshLayout; + List updateTasks = new ArrayList<>(); + private NfcManager mNfcManager; + private final String logTag = "LoadedWalletFragment"; + private boolean lastReadSuccess = true; + private VerifyCardTask verifyCardTask = null; + private int requestPIN2Count = 0; + + public LoadedWalletActivityFragment() { + + } + + public void onRefresh() { + //Update + // Showing refresh animation before making http call + if (updateTasks.size() > 0) return; + ; + mSwipeRefreshLayout.setRefreshing(true); + mCard.clearInfo(); + mCard.setError(null); + mCard.setMessage(null); + + boolean needResendTX = LastSignStorage.getNeedTxSend(mCard.getWallet()); + + UpdateViews(); + + CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); + + if (mCard.getBlockchain() == Blockchain.Bitcoin || mCard.getBlockchain() == Blockchain.BitcoinTestNet) { + SharedData data = new SharedData(SharedData.COUNT_REQUEST); + for (int i = 0; i < data.allRequest; ++i) { + String nodeAddress = engine.GetNextNode(mCard); + int nodePort = engine.GetNextNodePort(mCard); + UpdateWalletInfoTask connectTaskEx = new UpdateWalletInfoTask(nodeAddress, nodePort, data); + connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(mCard.getWallet())); + } + + String nodeAddress = engine.GetNode(mCard); + int nodePort = engine.GetNodePort(mCard); + UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort, data); + updateTasks.add(updateWalletInfoTask); + updateWalletInfoTask.execute(Electrum_Request.ListUnspent(mCard.getWallet()), Electrum_Request.ListHistory(mCard.getWallet())); + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "bitcoin", "bitcoin"); + taskRate.execute(rate); + + + } else if (mCard.getBlockchain() == Blockchain.BitcoinCash || mCard.getBlockchain() == Blockchain.BitcoinCashTestNet) { + SharedData data = new SharedData(SharedData.COUNT_REQUEST); + for (int i = 0; i < data.allRequest; ++i) { + String nodeAddress = engine.GetNextNode(mCard); + int nodePort = engine.GetNextNodePort(mCard); + UpdateWalletInfoTask connectTaskEx = new UpdateWalletInfoTask(nodeAddress, nodePort, data); + connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(mCard.getWallet())); + } + + String nodeAddress = engine.GetNode(mCard); + int nodePort = engine.GetNodePort(mCard); + UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort, data); + + updateTasks.add(updateWalletInfoTask); + updateWalletInfoTask.execute(Electrum_Request.ListUnspent(mCard.getWallet()), Electrum_Request.ListHistory(mCard.getWallet())); + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "bitcoin-cash", "bitcoin-cash"); + taskRate.execute(rate); + + + } + else if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet) { + ETHRequestTask updateETH = new ETHRequestTask(mCard.getBlockchain()); + Infura_Request reqETH = Infura_Request.GetBalance(mCard.getWallet()); + reqETH.setID(67); + reqETH.setBlockchain(mCard.getBlockchain()); + + Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(mCard.getWallet()); + reqNonce.setID(67); + reqNonce.setBlockchain(mCard.getBlockchain()); + + updateETH.execute(reqETH, reqNonce); + + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "ethereum", "ethereum"); + taskRate.execute(rate); + + } else if (mCard.getBlockchain() == Blockchain.Token) { + ETHRequestTask updateETH = new ETHRequestTask(mCard.getBlockchain()); + Infura_Request reqETH = Infura_Request.GetTokenBalance(mCard.getWallet(), engine.GetContractAddress(mCard), engine.GetTokenDecimals(mCard)); + reqETH.setID(67); + reqETH.setBlockchain(mCard.getBlockchain()); + + Infura_Request reqBalance = Infura_Request.GetBalance(mCard.getWallet()); + reqBalance.setID(67); + reqBalance.setBlockchain(mCard.getBlockchain()); + + Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(mCard.getWallet()); + reqNonce.setID(67); + reqNonce.setBlockchain(mCard.getBlockchain()); + updateETH.execute(reqETH, reqNonce, reqBalance); + + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(mCard.getWallet(), "basic-attention-token", "ethereum"); + taskRate.execute(rate); + } + + if (needResendTX) { + SendTransaction(LastSignStorage.getTxForSend(mCard.getWallet())); + } + } + + void doShareWallet(boolean useURI) { + if (useURI) { + String txtShare = CoinEngineFactory.Create(mCard.getBlockchain()).getShareWalletURI(mCard).toString(); + //String txtShare = Blockchain.getShareWalletURI(mCard).toString(); + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, "Wallet address"); + intent.putExtra(Intent.EXTRA_TEXT, txtShare); + + PackageManager packageManager = getActivity().getPackageManager(); + List activities = packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL); + boolean isIntentSafe = activities.size() > 0; + + if (isIntentSafe) { + String title = "Share wallet address with:"; + // Create intent to show chooser + Intent chooser = Intent.createChooser(intent, title); + // Verify the intent will resolve to at least one activity + if (intent.resolveActivity(getActivity().getPackageManager()) != null) { + startActivity(chooser); + } + } else { + ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE); + clipboard.setPrimaryClip(ClipData.newPlainText(txtShare, txtShare)); + Toast.makeText(getContext(), "Copied to clipboard", Toast.LENGTH_LONG).show(); + } + } else { + String txtShare = mCard.getWallet(); + ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE); + clipboard.setPrimaryClip(ClipData.newPlainText(txtShare, txtShare)); + Toast.makeText(getContext(), "Copied to clipboard", Toast.LENGTH_LONG).show(); + } + + + } + + @Override + public View onCreateView(final LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_loaded_wallet, container, false); + + mNfcManager = new NfcManager(this.getActivity(), this); + + + // SwipeRefreshLayout + mSwipeRefreshLayout = v.findViewById(R.id.swipe_container); + mSwipeRefreshLayout.setOnRefreshListener(this); + + mCard = new Tangem_Card(getActivity().getIntent().getStringExtra("UID")); + mCard.LoadFromBundle(getActivity().getIntent().getExtras().getBundle("Card")); + tvCardID = v.findViewById(R.id.tvCardID); + + tvBalance = v.findViewById(R.id.tvBalance); + tvOffline = v.findViewById(R.id.tvOffline); + + if (mCard.getBlockchain() == Blockchain.Token) { + //tvBalance.setLines(2); + tvBalance.setSingleLine(false); + } + + tvBalanceEquivalent = v.findViewById(R.id.tvBalanceEquivalent); + + tvWallet = v.findViewById(R.id.tvWallet); + tvWallet.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doShareWallet(false); + } + }); + + tvInputs = v.findViewById(R.id.tvInputs); + lbInputs = v.findViewById(R.id.lbInputs); + + tvLastOutput = v.findViewById(R.id.tvLastOutput); + lbLastOutput = v.findViewById(R.id.lbLastOutput); + + final CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); + + boolean visibleFlag = engine != null ? engine.InOutPutVisible() : true; + int visibleIOPuts = visibleFlag ? View.VISIBLE : View.GONE; + if (tvInputs != null) { + tvInputs.setVisibility(visibleIOPuts); + } + + if (lbInputs != null) { + lbInputs.setVisibility(visibleIOPuts); + } + + if (tvLastOutput != null) { + tvLastOutput.setVisibility(visibleIOPuts); + } + + if (lbLastOutput != null) { + lbLastOutput.setVisibility(visibleIOPuts); + } + + tvValidationNode = v.findViewById(R.id.tvValidationNode); + + progressBar = v.findViewById(R.id.progressBar); + + tvBlockchain = v.findViewById(R.id.tvBlockchain); + ivBlockchain = v.findViewById(R.id.imgBlockchain); + ivPIN = v.findViewById(R.id.imgPIN); + ivPIN2orSecurityDelay = v.findViewById(R.id.imgPIN2orSecurityDelay); + ivDeveloperVersion = v.findViewById(R.id.imgDeveloperVersion); + + ivQR = v.findViewById(R.id.qrWallet); + + + try { + ivQR.setImageBitmap(generateQrCode(engine.getShareWalletURI(mCard).toString())); + } catch (WriterException e) { + e.printStackTrace(); + } + ivQR.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doShareWallet(true); + } + }); + + tvError = v.findViewById(R.id.tvError); + tvMessage = v.findViewById(R.id.tvMessage); + + tvIssuer = v.findViewById(R.id.tvIssuer); + tvIssuerData = v.findViewById(R.id.tvIssuerData); + + tvHeader = v.findViewById(R.id.tvHeader); + tvCaution = v.findViewById(R.id.tvCaution); + + tvSend = v.findViewById(R.id.tvSend); + + imgLookup = v.findViewById(R.id.imgLookup); + + if (imgLookup != null) { + + imgLookup.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!mCard.hasBalanceInfo()) { + return; + } + CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain()); + + Intent browserIntent = new Intent(Intent.ACTION_VIEW, engineClick.getShareWalletURIExplorer(mCard)); + startActivity(browserIntent); + } + }); + + } + + tvLookup = v.findViewById(R.id.tvLookup); + + if (tvLookup != null) { + + tvLookup.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!mCard.hasBalanceInfo()) { + return; + } + CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain()); + + Intent browserIntent = new Intent(Intent.ACTION_VIEW, engineClick.getShareWalletURIExplorer(mCard)); + startActivity(browserIntent); + } + }); + } + + if (tvSend != null) { + tvSend.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!mCard.hasBalanceInfo()) { + return; + } else if (!engine.IsBalanceNotZero(mCard)) { + Toast.makeText(getContext(), "The wallet is empty", Toast.LENGTH_LONG).show(); + return; + } else if (!engine.IsBalanceAlterNotZero(mCard)) { + Toast.makeText(getContext(), "Not enough funds for transaction fee (gas)!", Toast.LENGTH_LONG).show(); + return; + } else if (engine.AwaitingConfirmation(mCard)) { + Toast.makeText(getContext(), "Please wait while previous transaction is confirmed in blockchain", Toast.LENGTH_LONG).show(); + return; + } else if (!engine.CheckUnspentTransaction(mCard)) { + Toast.makeText(getContext(), "Please wait for confirmation of incoming transaction!", Toast.LENGTH_LONG).show(); + return; + } else if (mCard.getRemainingSignatures() == 0) { + Toast.makeText(getContext(), "Card hasn't remaining signature!", Toast.LENGTH_LONG).show(); + return; + } + + Intent intent = new Intent(getContext(), PreparePaymentActivity.class); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT); + } + }); + } + + tvPurge = v.findViewById(R.id.tvPurge); + if (tvPurge != null) { + tvPurge.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showMenu(tvPurge); + } + } + ); + } + UpdateViews(); + + if (!mCard.hasBalanceInfo()) { + mSwipeRefreshLayout.setRefreshing(true); + mSwipeRefreshLayout.postDelayed(new Runnable() { + @Override + public void run() { + onRefresh(); + } + }, 1000); + } + return v; + } + + public void showMenu(View v) { + final PopupMenu popup = new PopupMenu(getActivity(), v); + MenuInflater inflater = popup.getMenuInflater(); + inflater.inflate(R.menu.menu_loaded_wallet, popup.getMenu()); + + popup.getMenu().findItem(R.id.action_set_PIN1).setVisible(mCard.allowSwapPIN()); + popup.getMenu().findItem(R.id.action_reset_PIN1).setVisible(mCard.allowSwapPIN() && !mCard.useDefaultPIN1()); + popup.getMenu().findItem(R.id.action_set_PIN2).setVisible(mCard.allowSwapPIN2()); + popup.getMenu().findItem(R.id.action_reset_PIN2).setVisible(mCard.allowSwapPIN2() && !mCard.useDefaultPIN2()); + popup.getMenu().findItem(R.id.action_reset_PINs).setVisible(mCard.allowSwapPIN() && mCard.allowSwapPIN2() && !mCard.useDefaultPIN1() && !mCard.useDefaultPIN2()); + + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + + int id = item.getItemId(); + switch (id) { + case R.id.action_set_PIN1: + doSetPin(); + return true; + case R.id.action_reset_PIN1: + doResetPin(); + return true; + case R.id.action_set_PIN2: + doSetPin2(); + return true; + case R.id.action_reset_PIN2: + doResetPin2(); + return true; + case R.id.action_reset_PINs: + doResetPins(); + return true; + case R.id.action_purge: + doPurge(); + return true; + default: + return false; + } + } + }); + popup.show(); + } + + String newPIN = "", newPIN2 = ""; + + void doSetPin() { + requestPIN2Count = 0; + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestNewPIN.toString()); + newPIN = ""; + newPIN2 = ""; + startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN); + } + + void doResetPin() { + requestPIN2Count = 0; + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + newPIN = PINStorage.getDefaultPIN(); + newPIN2 = ""; + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); + } + + void doResetPin2() { + requestPIN2Count = 0; + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + newPIN = ""; + newPIN2 = PINStorage.getDefaultPIN2(); + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); + } + + void doResetPins() { + requestPIN2Count = 0; + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + newPIN = PINStorage.getDefaultPIN(); + newPIN2 = PINStorage.getDefaultPIN2(); + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); + } + + + void doSetPin2() { + requestPIN2Count = 0; + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestNewPIN2.toString()); + newPIN = ""; + newPIN2 = ""; + startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN2); + } + + void doPurge() { + requestPIN2Count = 0; + final CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); + if (!mCard.hasBalanceInfo()) { + return; + } else if (engine.IsBalanceNotZero(mCard)) { + Toast.makeText(getContext(), "Cannot erase wallet with non-zero balance", Toast.LENGTH_LONG).show(); + return; + } + + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_PURGE); + } + + void UpdateViews() { + try { + if (timerHideErrorAndMessage != null) { + timerHideErrorAndMessage.cancel(); + timerHideErrorAndMessage = null; + } + tvCardID.setText(mCard.getCIDDescription()); + + if ((mCard.getError() == null || mCard.getError().isEmpty())) { + tvError.setVisibility(View.GONE); + tvError.setText(""); + } else { + tvError.setVisibility(View.VISIBLE); + tvError.setText(mCard.getError()); + } + + boolean needResendTX = LastSignStorage.getNeedTxSend(mCard.getWallet()); + + if ((mCard.getMessage() == null || mCard.getMessage().isEmpty()) && !needResendTX) { + tvMessage.setText(""); + tvMessage.setVisibility(View.GONE); + } else { + if (needResendTX) { + tvMessage.setText("Sending cached transaction..."); + } else { + tvMessage.setText(mCard.getMessage()); + } + tvMessage.setVisibility(View.VISIBLE); + + } + + + CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); + + if (engine.HasBalanceInfo(mCard) || mCard.getOfflineBalance() == null) { + if (mCard.getBlockchain() == Blockchain.Token) { + Spanned html = Html.fromHtml(engine.GetBalanceWithAlter(mCard)); + tvBalance.setText(html); + } else { + tvBalance.setText(engine.GetBalanceWithAlter(mCard)); + } + + tvBalanceEquivalent.setText(engine.GetBalanceEquivalent(mCard)); + tvOffline.setVisibility(View.INVISIBLE); + } else { + String offlineAmount = engine.ConvertByteArrayToAmount(mCard, mCard.getOfflineBalance()); + if (mCard.getBlockchain() == Blockchain.Token) { + tvBalance.setText("NOT IMPLEMENTED"); + } else { + tvBalance.setText(engine.GetAmountDescription(mCard, offlineAmount)); + } + + tvBalanceEquivalent.setText(engine.GetAmountEqualentDescriptor(mCard, offlineAmount)); + tvOffline.setVisibility(View.VISIBLE); + } + + if (!mCard.getAmountEquivalentDescriptionAvailable()) { + //tvBalanceEquivalent.setError("Service unavailable"); + } else { + tvBalanceEquivalent.setError(null); + } + + tvWallet.setText(mCard.getWallet()); + + tvInputs.setText(mCard.getInputsDescription()); + if (mCard.getLastInputDescription().contains("awaiting")) { + tvInputs.setTextColor(getContext().getResources().getColor(R.color.not_confirmed, getContext().getTheme())); + } else if (mCard.getLastInputDescription().contains("None")) { + tvInputs.setTextColor(getContext().getResources().getColor(R.color.primary_dark, getContext().getTheme())); + } else { + tvInputs.setTextColor(getContext().getResources().getColor(R.color.confirmed, getContext().getTheme())); + } + + if (tvOutputs != null) { + tvOutputs.setText(mCard.getOutputsDescription()); + } + + if (tvLastInput != null) { + tvLastInput.setText(mCard.getLastInputDescription()); + } + if (tvLastOutput != null) { + tvLastOutput.setText(mCard.getLastOutputDescription()); + } + + tvBlockchain.setText(mCard.getBlockchainName()); + ivBlockchain.setImageResource(mCard.getBlockchain().getImageResource(this.getContext(), mCard.getTokenSymbol())); + + if (tvValidationNode != null) { + tvValidationNode.setText(mCard.getValidationNodeDescription()); + } + + if (mCard.useDefaultPIN1()) { + ivPIN.setImageResource(R.drawable.unlock_pin1); + ivPIN.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by default PIN1 code", Toast.LENGTH_LONG).show(); + } + }); + } else { + ivPIN.setImageResource(R.drawable.lock_pin1); + ivPIN.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by user's PIN1 code", Toast.LENGTH_LONG).show(); + } + }); + } + + if (mCard.getPauseBeforePIN2() > 0 && (mCard.useDefaultPIN2() || !mCard.useSmartSecurityDelay())) { + ivPIN2orSecurityDelay.setImageResource(R.drawable.timer); + ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), String.format("This banknote will enforce %.0f seconds security delay for all operations requiring PIN2 code", mCard.getPauseBeforePIN2() / 1000.0), Toast.LENGTH_LONG).show(); + } + }); + + } else if (mCard.useDefaultPIN2()) { + ivPIN2orSecurityDelay.setImageResource(R.drawable.unlock_pin2); + ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by default PIN2 code", Toast.LENGTH_LONG).show(); + } + }); + } else { + ivPIN2orSecurityDelay.setImageResource(R.drawable.lock_pin2); + ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by user's PIN2 code", Toast.LENGTH_LONG).show(); + } + }); + } + + + if (mCard.useDevelopersFirmware()) { + ivDeveloperVersion.setImageResource(R.drawable.ic_developer_version); + ivDeveloperVersion.setVisibility(View.VISIBLE); + ivDeveloperVersion.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "Unlocked banknote, only for development use", Toast.LENGTH_LONG).show(); + } + }); + } else { + ivDeveloperVersion.setVisibility(View.INVISIBLE); + } + + if (tvSend != null) { + if (mCard.hasBalanceInfo()) { + tvSend.setEnabled(true); + } else { + tvSend.setEnabled(false); + } + } + + if (tvPurge != null) { + if (mCard.hasBalanceInfo()) { + tvPurge.setEnabled(true); + } else { + tvPurge.setEnabled(false); + } + } + + tvIssuer.setText(mCard.getIssuerDescription()); + + timerHideErrorAndMessage = new Timer(); + + + timerHideErrorAndMessage.schedule(new TimerTask() { + @Override + public void run() { + tvError.post(new Runnable() { + @Override + public void run() { + tvMessage.setVisibility(View.GONE); + tvError.setVisibility(View.GONE); + mCard.setError(null); + mCard.setMessage(null); + } + }); + } + }, 5000); + + if (mCard.isReusable()) { + tvHeader.setText("REUSABLE WALLET"); + tvCaution.setVisibility(View.GONE); + } else { + if (mCard.getMaxSignatures() == mCard.getRemainingSignatures()) { + tvHeader.setText("BANKNOTE"); + tvCaution.setVisibility(View.GONE); + } else { + tvHeader.setText("NON-TRANSFERABLE BANKNOTE"); + tvCaution.setVisibility(View.VISIBLE); + } + } + + if (mCard.useDevelopersFirmware()) { + tvHeader.setText("DEVELOPER KIT"); + tvCaution.setVisibility(View.VISIBLE); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + Timer timerHideErrorAndMessage = null; + + public Intent prepareResultIntent() { + Intent data = new Intent(); + data.putExtra("UID", mCard.getUID()); + data.putExtra("Card", mCard.getAsBundle()); + return data; + } + + private void SendTransaction(String tx) { + CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); + if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet || mCard.getBlockchain() == Blockchain.Token) { + ETHRequestTask task = new ETHRequestTask(mCard.getBlockchain()); + Infura_Request req = Infura_Request.SendTransaction(mCard.getWallet(), tx); + req.setID(67); + req.setBlockchain(mCard.getBlockchain()); + task.execute(req); + } else if (mCard.getBlockchain() == Blockchain.Bitcoin ||mCard.getBlockchain() == Blockchain.BitcoinTestNet) { + String nodeAddress = engine.GetNode(mCard); + int nodePort = engine.GetNodePort(mCard); + + UpdateWalletInfoTask connectTask = new UpdateWalletInfoTask(nodeAddress, nodePort); + connectTask.execute(Electrum_Request.Broadcast(mCard.getWallet(), tx)); + } + else if (mCard.getBlockchain() == Blockchain.BitcoinCash ||mCard.getBlockchain() == Blockchain.BitcoinCashTestNet) { + String nodeAddress = engine.GetNode(mCard); + int nodePort = engine.GetNodePort(mCard); + + UpdateWalletInfoTask connectTask = new UpdateWalletInfoTask(nodeAddress, nodePort); + connectTask.execute(Electrum_Request.Broadcast(mCard.getWallet(), tx)); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (requestCode) { + case REQUEST_CODE_ENTER_NEW_PIN: + if (resultCode == Activity.RESULT_OK) { + if (data != null) { + if (data.getExtras().containsKey("confirmPIN")) { + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + newPIN = data.getStringExtra("newPIN"); + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); + } else { + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("newPIN", data.getStringExtra("newPIN")); + intent.putExtra("mode", RequestPINActivity.Mode.ConfirmNewPIN.toString()); + startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN); + } + } + } + break; + case REQUEST_CODE_ENTER_NEW_PIN2: + if (resultCode == Activity.RESULT_OK) { + if (data != null) { + if (data.getExtras().containsKey("confirmPIN2")) { + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + newPIN2 = data.getStringExtra("newPIN2"); + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); + } else { + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("newPIN2", data.getStringExtra("newPIN2")); + intent.putExtra("mode", RequestPINActivity.Mode.ConfirmNewPIN2.toString()); + startActivityForResult(intent, REQUEST_CODE_ENTER_NEW_PIN2); + } + } + } + break; + case REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN: + if (resultCode == Activity.RESULT_OK) { + if (newPIN.equals("")) { + newPIN = mCard.getPIN(); + } + if (newPIN2.equals("")) { + newPIN2 = PINStorage.getPIN2(); + } + + PINSwapWarningDialog dialog = (new PINSwapWarningDialog()); + dialog.activityFragment = this; + if (!PINStorage.isDefaultPIN(newPIN) || !PINStorage.isDefaultPIN2(newPIN2)) { + dialog.message = "If you forget your new PIN you will lose your money forever!"; + } else { + dialog.message = "If you use default PIN someone can steal your money!"; + } + dialog.show(getActivity().getFragmentManager(), "PINSwapWarningDialog"); + } + break; + + case REQUEST_CODE_SWAP_PIN: + if (resultCode == Activity.RESULT_OK) { + if (data == null) { + data = new Intent(); + + data.putExtra("UID", mCard.getUID()); + data.putExtra("Card", mCard.getAsBundle()); + data.putExtra("modification", "delete"); + } else { + data.putExtra("modification", "update"); + } + getActivity().setResult(Activity.RESULT_OK, data); + getActivity().finish(); + } else { + if (data != null && data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) { + Tangem_Card updatedCard = new Tangem_Card(data.getStringExtra("UID")); + updatedCard.LoadFromBundle(data.getBundleExtra("Card")); + mCard = updatedCard; + } + if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) { + requestPIN2Count++; + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN); + return; + } else { + if (data != null && data.getExtras().containsKey("message")) { + mCard.setError(data.getStringExtra("message")); + } + } + } + break; + case REQUEST_CODE_REQUEST_PIN2_FOR_PURGE: + if (resultCode == Activity.RESULT_OK) { + Intent intent = new Intent(getContext(), PurgeActivity.class); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + startActivityForResult(intent, REQUEST_CODE_PURGE); + } + break; + case REQUEST_CODE_PURGE: + if (resultCode == Activity.RESULT_OK) { + if (data == null) { + data = new Intent(); + + data.putExtra("UID", mCard.getUID()); + data.putExtra("Card", mCard.getAsBundle()); + data.putExtra("modification", "delete"); + } else { + data.putExtra("modification", "update"); + } + getActivity().setResult(Activity.RESULT_OK, data); + getActivity().finish(); + } else { + if (data != null && data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) { + Tangem_Card updatedCard = new Tangem_Card(data.getStringExtra("UID")); + updatedCard.LoadFromBundle(data.getBundleExtra("Card")); + mCard = updatedCard; + } + if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) { + requestPIN2Count++; + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString()); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2_FOR_PURGE); + return; + } else { + if (data != null && data.getExtras().containsKey("message")) { + mCard.setError(data.getStringExtra("message")); + } + } + UpdateViews(); + } + break; + case REQUEST_CODE_SEND_PAYMENT: + if (resultCode == Activity.RESULT_OK) { + mSwipeRefreshLayout.postDelayed(new Runnable() { + @Override + public void run() { + onRefresh(); + } + }, 10000); + mSwipeRefreshLayout.setRefreshing(true); + mCard.clearInfo(); + UpdateViews(); + } + + if (data != null) { + if (data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) { + Tangem_Card updatedCard = new Tangem_Card(data.getStringExtra("UID")); + updatedCard.LoadFromBundle(data.getBundleExtra("Card")); + mCard = updatedCard; + } + if (data.getExtras().containsKey("message")) { + if (resultCode == Activity.RESULT_OK) { + mCard.setMessage(data.getStringExtra("message")); + } else { + mCard.setError(data.getStringExtra("message")); + } + } + UpdateViews(); + } + + break; + } + + } + + private void startSwapPINActivity() { + Intent intent = new Intent(getContext(), SwapPINActivity.class); + intent.putExtra("UID", mCard.getUID()); + intent.putExtra("Card", mCard.getAsBundle()); + intent.putExtra("newPIN", newPIN); + intent.putExtra("newPIN2", newPIN2); + startActivityForResult(intent, REQUEST_CODE_SWAP_PIN); + } + + public static Bitmap generateQrCode(String myCodeText) throws WriterException { + Hashtable hintMap = new Hashtable(); + hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // H = 30% damage + + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + + int size = 256; + + BitMatrix bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hintMap); + int width = bitMatrix.getWidth(); + Bitmap bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565); + for (int x = 0; x < width; x++) { + for (int y = 0; y < width; y++) { + bmp.setPixel(y, x, bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE); + } + } + return bmp; + } + + + @Override + public void onResume() { + super.onResume(); + mNfcManager.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + mNfcManager.onPause(); + } + + @Override + public void onStop() { + super.onStop(); + for (UpdateWalletInfoTask ut : updateTasks) { + ut.cancel(true); + } + mNfcManager.onStop(); + } + + @Override + public void onTagDiscovered(Tag tag) { + try { + final IsoDep isoDep = IsoDep.get(tag); + if (isoDep == null) { + throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err)); + } + byte UID[] = tag.getId(); + String sUID = Util.byteArrayToHexString(UID); + if (!mCard.getUID().equals(sUID)) { + Log.d(logTag, "Invalid UID: " + sUID); + mNfcManager.IgnoreTag(isoDep.getTag()); + return; + } else { + Log.v(logTag, "UID: " + sUID); + } + + if (lastReadSuccess) { + isoDep.setTimeout(1000); + } else { + isoDep.setTimeout(65000); + } + //lastTag = tag; + verifyCardTask = new VerifyCardTask(getContext(), mCard, mNfcManager, isoDep, this); + verifyCardTask.start(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void ErrorOnUpdate(String message) { + mCard.setError("Cannot obtain data from blockchain"); + UpdateViews(); + } + + private class ETHRequestTask extends Infura_Task { + ETHRequestTask(Blockchain blockchain) { + super(blockchain); + } + + @Override + protected void onPostExecute(List requests) { + super.onPostExecute(requests); + for (Infura_Request request : requests) { + try { + if (request.error == null) { + + if (request.isMethod(Infura_Request.METHOD_ETH_GetBalance)) { + try { + String balanceCap = request.getResultString(); + balanceCap = balanceCap.substring(2); + BigInteger l = new BigInteger(balanceCap, 16); + BigInteger d = l.divide(new BigInteger("1000000000000000000", 10)); + Long balance = d.longValue(); + + mCard.setBalanceConfirmed(balance); + mCard.setBalanceUnconfirmed(0L); + if (mCard.getBlockchain() != Blockchain.Token) + mCard.setDecimalBalance(l.toString(10)); + mCard.setDecimalBalanceAlter(l.toString(10)); + + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + } + } else if (request.isMethod(Infura_Request.METHOD_ETH_Call)) { + try { + String balanceCap = request.getResultString(); + balanceCap = balanceCap.substring(2); + BigInteger l = new BigInteger(balanceCap, 16); + Long balance = l.longValue(); + + if (l.compareTo(BigInteger.ZERO) == 0) { + mCard.setBlockchainID(Blockchain.Ethereum.getID()); + mCard.addTokenToBlockchainName(); + mSwipeRefreshLayout.setRefreshing(false); + onRefresh(); + return; + } + + mCard.setBalanceConfirmed(balance); + mCard.setBalanceUnconfirmed(0L); + mCard.setDecimalBalance(l.toString(10)); + + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + } + } else if (request.isMethod(Infura_Request.METHOD_ETH_GetOutTransactionCount)) { + try { + String nonce = request.getResultString(); + nonce = nonce.substring(2); + BigInteger count = new BigInteger(nonce, 16); + + mCard.SetConfirmTXCount(count); + } catch (JSONException e) { + e.printStackTrace(); + } + } else if (request.isMethod(Infura_Request.METHOD_ETH_SendRawTransaction)) { + try { + String hashTX = ""; + + try { + String tmp = request.getResultString(); + hashTX = tmp; + } catch (JSONException e) { + JSONObject msg = request.getAnswer(); + JSONObject err = msg.getJSONObject("error"); + hashTX = err.getString("message"); + LastSignStorage.setLastMessage(mCard.getWallet(), hashTX); + ErrorOnUpdate("Failed to send transaction. Try again"); + return; + } + + if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) { + hashTX = hashTX.substring(2); + } + BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ + LastSignStorage.setTxWasSend(mCard.getWallet()); + LastSignStorage.setLastMessage(mCard.getWallet(), ""); + Log.e("TX_RESULT", hashTX); + + + BigInteger nonce = mCard.GetConfirmTXCount(); + nonce.add(BigInteger.valueOf(1)); + mCard.SetConfirmTXCount(nonce); + Log.e("TX_RESULT", hashTX); + + } catch (Exception e) { + e.printStackTrace(); + ErrorOnUpdate("Failed to send transaction. Try again"); + } + } + UpdateViews(); + } else { + ErrorOnUpdate(request.error); + } + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + } + } + + if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); + } + } + + public void OnReadStart(CardProtocol cardProtocol) { + progressBar.post(new Runnable() { + @Override + public void run() { + progressBar.setVisibility(View.VISIBLE); + progressBar.setProgress(5); + } + }); + } + + public void OnReadFinish(final CardProtocol cardProtocol) { + + verifyCardTask = null; + + if (cardProtocol != null) { + if (cardProtocol.getError() == null) { + progressBar.post(new Runnable() { + @Override + public void run() { + progressBar.setProgress(100); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); + Intent intent = new Intent(getContext(), VerifyCardActivity.class); + // TODO обновить карту mCard + intent.putExtra("UID", cardProtocol.getCard().getUID()); + intent.putExtra("Card", cardProtocol.getCard().getAsBundle()); + startActivityForResult(intent, REQUEST_CODE_VERIFY_CARD); + //addCard(cardProtocol.getCard()); + } + }); + } else { + // remove last UIDs because of error and no card read + progressBar.post(new Runnable() { + @Override + public void run() { + lastReadSuccess = false; + if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) { + if (!NoExtendedLengthSupportDialog.allreadyShowed) { + new NoExtendedLengthSupportDialog().show(getActivity().getFragmentManager(), "NoExtendedLengthSupportDialog"); + } + } else { + Toast.makeText(getContext(), "Try to scan again", Toast.LENGTH_LONG).show(); + } + progressBar.setProgress(100); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); + } + }); + } + } + + progressBar.postDelayed(new Runnable() { + @Override + public void run() { + try { + progressBar.setProgress(0); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); + progressBar.setVisibility(View.INVISIBLE); + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 500); + } + + public void OnReadProgress(CardProtocol protocol, final int progress) { + progressBar.post(new Runnable() { + @Override + public void run() { + progressBar.setProgress(progress); + } + }); + } + + public void OnReadCancel() { + + verifyCardTask = null; + + progressBar.postDelayed(new Runnable() { + @Override + public void run() { + try { + progressBar.setProgress(0); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); + progressBar.setVisibility(View.INVISIBLE); + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 500); + } + + public void OnReadWait(int msec) { + WaitSecurityDelayDialog.OnReadWait(getActivity(), msec); + } + + @Override + public void OnReadBeforeRequest(int timeout) { + WaitSecurityDelayDialog.onReadBeforeRequest(getActivity(), timeout); + } + + @Override + public void OnReadAfterRequest() { + WaitSecurityDelayDialog.onReadAfterRequest(getActivity()); + } + + + private class RateInfoTask extends ExchangeTask { + protected void onPostExecute(List requests) { + super.onPostExecute(requests); + for (ExchangeRequest request : requests) { + if (request.error == null) { + try { + + JSONArray arr = request.getAnswerList(); + for (int i = 0; i < arr.length(); ++i) { + JSONObject obj = arr.getJSONObject(i); + String currency = obj.getString("id"); + + boolean stop = false; + boolean stopAlter = false; + if (currency.equals(request.currency)) { + String usd = obj.getString("price_usd"); + + Float rate = Float.valueOf(usd); + mCard.setRate(rate); + UpdateViews(); + stop = true; + } + + if (currency.equals(request.currencyAlter)) { + String usd = obj.getString("price_usd"); + + Float rate = Float.valueOf(usd); + mCard.setRateAlter(rate); + UpdateViews(); + stopAlter = true; + } + + if (stop && stopAlter) { + break; + } + + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + } + + private class UpdateWalletInfoTask extends Electrum_Task { + public UpdateWalletInfoTask(String host, int port) { + super(host, port); + } + + + public UpdateWalletInfoTask(String host, int port, SharedData sharedData) { + super(host, port, sharedData); + } + + @Override + protected void onProgressUpdate(Integer... values) { + super.onProgressUpdate(values); + } + + @Override + protected void onCancelled() { + super.onCancelled(); + updateTasks.remove(this); + if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); + } + + @Override + protected void onPostExecute(List requests) { + super.onPostExecute(requests); + Log.i("RequestWalletInfoTask", "onPostExecute[" + String.valueOf(updateTasks.size()) + "]"); + updateTasks.remove(this); + + CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain()); + + for (Electrum_Request request : requests) { + try { + if (request.error == null) { + if (request.isMethod(Electrum_Request.METHOD_GetBalance)) { + try { + String mWalletAddress = request.getParams().getString(0); + Long confBalance = request.getResult().getLong("confirmed"); + Long unconf = request.getResult().getLong("unconfirmed"); + if (sharedCounter != null) { + int counter = sharedCounter.requestCounter.incrementAndGet(); + if (counter != 1) { + continue; + } + } + + mCard.setBalanceConfirmed(confBalance); + mCard.setBalanceUnconfirmed(unconf); + mCard.setDecimalBalance(String.valueOf(confBalance)); + mCard.setValidationNodeDescription(getValidationNodeDescription()); + } catch (JSONException e) { + if (sharedCounter != null) { + int errCounter = sharedCounter.errorRequest.incrementAndGet(); + if (errCounter >= sharedCounter.allRequest) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + } + } else { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + } + } + } else if (request.isMethod(Electrum_Request.METHOD_SendTransaction)) { + try { + String hashTX = request.getResultString(); + + try { + LastSignStorage.setLastMessage(mCard.getWallet(), hashTX); + if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) { + hashTX = hashTX.substring(2); + } + BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ + LastSignStorage.setTxWasSend(mCard.getWallet()); + LastSignStorage.setLastMessage(mCard.getWallet(), ""); + Log.e("TX_RESULT", hashTX); + + } catch (Exception e) { + engine.SwitchNode(mCard); + ErrorOnUpdate("Failed to send transaction. Try again."); + } + + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate("Failed to send transaction. Try again."); + engine.SwitchNode(mCard); + } + } else if (request.isMethod(Electrum_Request.METHOD_ListUnspent)) { + try { + String mWalletAddress = request.getParams().getString(0); + + JSONArray jsUnspentArray = request.getResultArray(); + try { + mCard.getUnspentTransactions().clear(); + for (int i = 0; i < jsUnspentArray.length(); i++) { + JSONObject jsUnspent = jsUnspentArray.getJSONObject(i); + Tangem_Card.UnspentTransaction trUnspent = new Tangem_Card.UnspentTransaction(); + trUnspent.txID = jsUnspent.getString("tx_hash"); + trUnspent.Amount = jsUnspent.getInt("value"); + trUnspent.Height = jsUnspent.getInt("height"); + mCard.getUnspentTransactions().add(trUnspent); + } + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + } + + 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) { + String nodeAddress = engine.GetNextNode(mCard); + int nodePort = engine.GetNextNodePort(mCard); + UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort); + + updateTasks.add(updateWalletInfoTask); + + updateWalletInfoTask.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), + Electrum_Request.GetTransaction(mWalletAddress, hash)); + } + } + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + } + } else if (request.isMethod(Electrum_Request.METHOD_GetHistory)) { + try { + String mWalletAddress = request.getParams().getString(0); + + JSONArray jsHistoryArray = request.getResultArray(); + try { + mCard.getHistoryTransactions().clear(); + for (int i = 0; i < jsHistoryArray.length(); i++) { + JSONObject jsUnspent = jsHistoryArray.getJSONObject(i); + Tangem_Card.HistoryTransaction trHistory = new Tangem_Card.HistoryTransaction(); + trHistory.txID = jsUnspent.getString("tx_hash"); + trHistory.Height = jsUnspent.getInt("height"); + mCard.getHistoryTransactions().add(trHistory); + } + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + } + + for (int i = 0; i < jsHistoryArray.length(); i++) { + JSONObject jsUnspent = jsHistoryArray.getJSONObject(i); + Integer height = jsUnspent.getInt("height"); + String hash = jsUnspent.getString("tx_hash"); + if (height != -1) { + + String nodeAddress = engine.GetNode(mCard); + int nodePort = engine.GetNodePort(mCard); + UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(nodeAddress, nodePort); + updateTasks.add(updateWalletInfoTask); + + updateWalletInfoTask.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), + Electrum_Request.GetTransaction(mWalletAddress, hash)); + } + + } + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + } + } else if (request.isMethod(Electrum_Request.METHOD_GetHeader)) { + try { + JSONObject jsHeader = request.getResult(); + try { + mCard.getHaedersInfo(); + mCard.UpdateHeaderInfo(new Tangem_Card.HeaderInfo( + jsHeader.getInt("block_height"), + jsHeader.getInt("timestamp"))); + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + + } + + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + + } + } else if (request.isMethod(Electrum_Request.METHOD_GetTransaction)) { + try { + + String txHash = request.TxHash; + String raw = request.getResultString(); + + List listTx = mCard.getUnspentTransactions(); + for (Tangem_Card.UnspentTransaction tx : listTx) { + if (tx.txID.equals(txHash)) { + tx.Raw = raw; + } + } + + List listHTx = mCard.getHistoryTransactions(); + for (Tangem_Card.HistoryTransaction tx : listHTx) { + if (tx.txID.equals(txHash)) { + tx.Raw = raw; + try { + ArrayList prevHashes = BTCUtils.getPrevTX(raw); + + boolean isOur = false; + for (byte[] hash : prevHashes) { + String checkID = BTCUtils.toHex(hash); + for (Tangem_Card.HistoryTransaction txForCheck : listHTx) { + if (txForCheck.txID == checkID) { + isOur = true; + } + } + } + + tx.isInput = !isOur; + } catch (BitcoinException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + } + Log.e("TX", raw); + } + } + + } catch (JSONException e) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + engine.SwitchNode(mCard); + } + } + UpdateViews(); + } else { + if (sharedCounter != null) { + int errCounter = sharedCounter.errorRequest.incrementAndGet(); + if (errCounter >= sharedCounter.allRequest) { + ErrorOnUpdate(request.error); + engine.SwitchNode(mCard); + + } + } else { + ErrorOnUpdate(request.error); + engine.SwitchNode(mCard); + + } + + } + } catch (JSONException e) { + if (sharedCounter != null) { + int errCounter = sharedCounter.errorRequest.incrementAndGet(); + if (errCounter >= sharedCounter.allRequest) { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + } + } else { + e.printStackTrace(); + ErrorOnUpdate(e.toString()); + } + } + } + if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); + + } + } + + public static class PINSwapWarningDialog extends DialogFragment { + + LoadedWalletActivityFragment activityFragment = null; + String message; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + return new AlertDialog.Builder(getActivity()) + .setIcon(R.drawable.tangem_logo_small_new) + .setTitle("Your money is at risk!") + .setMessage(message) + .setCancelable(true) + .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + PINSwapWarningDialog.this.dismiss(); + } + }) + .setPositiveButton("Continue", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + if (activityFragment != null) + activityFragment.startSwapPINActivity(); + } + } + ) + .create(); + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + } + } + +} diff --git a/app/src/main/java/com/tangem/wallet/MainActivityFragment.java b/app/src/main/java/com/tangem/presentation/fragment/MainActivityFragment.java similarity index 97% rename from app/src/main/java/com/tangem/wallet/MainActivityFragment.java rename to app/src/main/java/com/tangem/presentation/fragment/MainActivityFragment.java index 4bf58483a0..043d931616 100644 --- a/app/src/main/java/com/tangem/wallet/MainActivityFragment.java +++ b/app/src/main/java/com/tangem/presentation/fragment/MainActivityFragment.java @@ -1,1042 +1,1058 @@ -package com.tangem.wallet; - -import android.Manifest; -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.IsoDep; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.Fragment; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.Toast; - -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.NfcManager; -import com.tangem.cardReader.Util; -import com.tangem.presentation.activity.EmptyWalletActivity; -import com.tangem.presentation.activity.LoadedWalletActivity; -import com.tangem.presentation.activity.MainActivity; -import com.tangem.presentation.activity.RequestPINActivity; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - - -/** - * A placeholder fragment containing a simple view. - */ -public class MainActivityFragment extends Fragment implements NfcAdapter.ReaderCallback, CardListAdapter.UiCallbacks, CardProtocol.Notifications, MainActivity.OnCardsClean { - - private static final int REQUEST_CODE_SHOW_CARD_ACTIVITY = 1; - private static final int REQUEST_CODE_ENTER_PIN_ACTIVITY = 2; - private static final int REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS = 3; - private NfcManager mNfcManager; - private ArrayList slCardUIDs = new ArrayList<>(); - private static final String logTag = "MainActivityFragment"; - private ProgressBar progressBar; - - private CardListAdapter mCardListAdapter; - - public CardListAdapter getCardListAdapter() { - return mCardListAdapter; - } - - private ReadCardInfoTask readCardInfoTask; - private SwipeRefreshLayout mSwipeRefreshLayout; //TODO: tmp - List requestTasks = new ArrayList<>(); - - public MainActivityFragment() { - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mCardListAdapter.onSaveInstanceState(outState); - outState.putStringArrayList("slCardUIDs", slCardUIDs); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View result = inflater.inflate(R.layout.fragment_main, container, false); - - mNfcManager = new NfcManager(this.getActivity(), this); - verifyPermissions(); - - progressBar = result.findViewById(R.id.progressBar); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); - RecyclerView rvCards = result.findViewById(R.id.lvCards); - rvCards.setLayoutManager(new LinearLayoutManager(getContext())); - mCardListAdapter = new CardListAdapter(getActivity().getLayoutInflater(), savedInstanceState, this); - rvCards.setAdapter(mCardListAdapter); - if (savedInstanceState != null && savedInstanceState.containsKey("slCardUIDs")) { - slCardUIDs = savedInstanceState.getStringArrayList("slCardUIDs"); - } - - // SwipeRefreshLayout - mSwipeRefreshLayout = result.findViewById(R.id.swipe_container); //TODO: tmp - - if( mSwipeRefreshLayout!=null ) { - SwipeRefreshLayout.OnRefreshListener onRefreshListener = new SwipeRefreshLayout.OnRefreshListener() { - - @Override - public void onRefresh() { - //Update - // Showing refresh animation before making http call - - if (requestTasks.size() > 0) return; - - if (requestTasks.size() > 0) { //TODO: tmp - mSwipeRefreshLayout.setRefreshing(true); - } else { - mSwipeRefreshLayout.setRefreshing(false); - } - } - }; - mSwipeRefreshLayout.setOnRefreshListener(onRefreshListener); //TODO: tmp - } - - ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { - @Override - public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { - return false; - } - - @Override - public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { - //Remove swiped item from list and notify the RecyclerView - int cardIndex = viewHolder.getAdapterPosition(); - if (cardIndex < 0 || cardIndex >= mCardListAdapter.getItemCount()) return; - slCardUIDs.remove(mCardListAdapter.getCard(cardIndex).getUID()); - if (mCardListAdapter.getCard(cardIndex).getUID() == lastRead_UID) { - lastRead_UID = ""; - } - mCardListAdapter.removeCard(cardIndex); - if (mCardListAdapter.getItemCount() == 0 && getActivity().getClass() == MainActivity.class) { - ((MainActivity) getActivity()).hideCleanButton(); - } - } - }); - - itemTouchHelper.attachToRecyclerView(rvCards); - - if (getActivity() instanceof MainActivity) { - ((MainActivity) getActivity()).setOnCardsClean(this); -// ((MainActivity) getActivity()).setOnCreateNFCDialog(this); - ((MainActivity) getActivity()).setNfcAdapterReaderCallback(this); - } - - return result; - } - - private void verifyPermissions() { - NfcManager.verifyPermissions(getActivity()); - if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { - Log.e("QRScanActivity", "User hasn't granted permission to use camera"); - ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS); - } - } - - int unsuccessReadCount = 0; - Tag lastTag = null; - - @Override - public void onTagDiscovered(Tag tag) { - try { - // get IsoDep handle and run cardReader thread - final IsoDep isoDep = IsoDep.get(tag); - if (isoDep == null) { - throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err)); - } - - byte UID[] = tag.getId(); - String sUID = Util.byteArrayToHexString(UID); - if (slCardUIDs.indexOf(sUID) != -1) { - Log.d(logTag, "Repeat UID: " + sUID); - mNfcManager.IgnoreTag(isoDep.getTag()); - return; - } else { - Log.v(logTag, "UID: " + sUID); - } - -// Log.e(logTag,"setTimeout("+String.valueOf(1000 + 3000 * unsuccessReadCount)+")"); - if (unsuccessReadCount < 2) { - isoDep.setTimeout(2000 + 5000 * unsuccessReadCount); - } else { - isoDep.setTimeout(90000); - } - lastTag = tag; - - readCardInfoTask = new ReadCardInfoTask(isoDep, this); - readCardInfoTask.start(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void onResume() { - super.onResume(); - - mNfcManager.onResume(); - } - - @Override - public void onPause() { - mNfcManager.onPause(); - if (readCardInfoTask != null) { - readCardInfoTask.cancel(true); - } - super.onPause(); - } - - @Override - public void onStop() { - // dismiss enable NFC dialog - mNfcManager.onStop(); - if (readCardInfoTask != null) { - readCardInfoTask.cancel(true); - } - for (RequestWalletInfoTask rt : requestTasks) { - rt.cancel(true); - } - super.onStop(); - } - - public void refreshCard(Tangem_Card card) { - CoinEngine engine = CoinEngineFactory.Create(card.getBlockchain()); - if (card.getBlockchain() == Blockchain.Ethereum || card.getBlockchain() == Blockchain.EthereumTestNet) { - ETHRequestTask task = new ETHRequestTask(card.getBlockchain()); - Infura_Request req = Infura_Request.GetBalance(card.getWallet()); - req.setID(67); - req.setBlockchain(card.getBlockchain()); - Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); - reqNonce.setID(67); - reqNonce.setBlockchain(card.getBlockchain()); - - task.execute(req, reqNonce); - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "ethereum", "ethereum"); - taskRate.execute(rate); - - } else if (card.getBlockchain() == Blockchain.BitcoinTestNet || card.getBlockchain() == Blockchain.Bitcoin) { - SharedData data = new SharedData(SharedData.COUNT_REQUEST); - for (int i = 0; i < data.allRequest; ++i) { - - String nodeAddress = engine.GetNextNode(card); - int nodePort = engine.GetNextNodePort(card); - RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); - connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); - } - - String nodeAddress = engine.GetNode(card); - int nodePort = engine.GetNodePort(card); - RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); - if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp - requestTasks.add(task); - task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin", "bitcoin"); - taskRate.execute(rate); - - } - else if (card.getBlockchain() == Blockchain.BitcoinCashTestNet || card.getBlockchain() == Blockchain.BitcoinCash) { - SharedData data = new SharedData(SharedData.COUNT_REQUEST); - for (int i = 0; i < data.allRequest; ++i) { - - String nodeAddress = engine.GetNextNode(card); - int nodePort = engine.GetNextNodePort(card); - RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); - connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); - } - - String nodeAddress = engine.GetNode(card); - int nodePort = engine.GetNodePort(card); - RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); - if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp - requestTasks.add(task); - task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin-cash", "bitcoin-cash"); - taskRate.execute(rate); - - }else if (card.getBlockchain() == Blockchain.Token) { - ETHRequestTask updateETH = new ETHRequestTask(card.getBlockchain()); - Infura_Request reqETH = Infura_Request.GetTokenBalance(card.getWallet(), engine.GetContractAddress(card), engine.GetTokenDecimals(card)); - reqETH.setID(67); - reqETH.setBlockchain(card.getBlockchain()); - - - Infura_Request reqBalance = Infura_Request.GetBalance(card.getWallet()); - reqBalance.setID(67); - reqBalance.setBlockchain(card.getBlockchain()); - - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "basic-attention-token", "ethereum"); - taskRate.execute(rate); - - Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); - reqNonce.setID(67); - reqNonce.setBlockchain(card.getBlockchain()); - - updateETH.execute(reqETH, reqNonce, reqBalance); - } - } - - public void addCard(final Tangem_Card card) { - if (mCardListAdapter != null) { - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - unsuccessReadCount = 0; - slCardUIDs.add(0, card.getUID()); - mCardListAdapter.addCard(card); - - CoinEngine engine = CoinEngineFactory.Create(card.getBlockchain()); - - if (card.getStatus() == Tangem_Card.Status.Loaded) { - - if (card.getBlockchain() == Blockchain.Ethereum || card.getBlockchain() == Blockchain.EthereumTestNet) { - ETHRequestTask task = new ETHRequestTask(card.getBlockchain()); - Infura_Request req = Infura_Request.GetBalance(card.getWallet()); - req.setID(67); - req.setBlockchain(card.getBlockchain()); - Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); - reqNonce.setID(67); - reqNonce.setBlockchain(card.getBlockchain()); - - task.execute(req, reqNonce); - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "ethereum", "ethereum"); - taskRate.execute(rate); - - } else if (card.getBlockchain() == Blockchain.BitcoinTestNet || card.getBlockchain() == Blockchain.Bitcoin) { - SharedData data = new SharedData(SharedData.COUNT_REQUEST); - - for (int i = 0; i < data.allRequest; ++i) { - String nodeAddress = engine.GetNextNode(card); - int nodePort = engine.GetNextNodePort(card); - - RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); - connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); - } - - String nodeAddress = engine.GetNode(card); - int nodePort = engine.GetNodePort(card); - - RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); - if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp - - requestTasks.add(task); - task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin", "bitcoin"); - taskRate.execute(rate); - - }else if (card.getBlockchain() == Blockchain.BitcoinCashTestNet || card.getBlockchain() == Blockchain.BitcoinCash) { - SharedData data = new SharedData(SharedData.COUNT_REQUEST); - - for (int i = 0; i < data.allRequest; ++i) { - String nodeAddress = engine.GetNextNode(card); - int nodePort = engine.GetNextNodePort(card); - - RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); - connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); - } - - String nodeAddress = engine.GetNode(card); - int nodePort = engine.GetNodePort(card); - - RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); - if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp - - requestTasks.add(task); - task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin-cash", "bitcoin-cash"); - taskRate.execute(rate); - - } - else if (card.getBlockchain() == Blockchain.Token) { - ETHRequestTask updateETH = new ETHRequestTask(card.getBlockchain()); - Infura_Request reqETH = Infura_Request.GetTokenBalance(card.getWallet(), engine.GetContractAddress(card), engine.GetTokenDecimals(card)); - reqETH.setID(67); - reqETH.setBlockchain(card.getBlockchain()); - - - Infura_Request reqBalance = Infura_Request.GetBalance(card.getWallet()); - reqBalance.setID(67); - reqBalance.setBlockchain(card.getBlockchain()); - - - RateInfoTask taskRate = new RateInfoTask(); - ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "basic-attention-token", "ethereum"); - taskRate.execute(rate); - - Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); - reqNonce.setID(67); - reqNonce.setBlockchain(card.getBlockchain()); - - updateETH.execute(reqETH, reqNonce, reqBalance); - } - } - if (getActivity().getClass() == MainActivity.class) { - ((MainActivity) getActivity()).showCleanButton(); - } - } - }); - } - } - - @Override - public void onViewCard(Bundle cardInfo) { - - if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(false); //TODO: tmp - - String UID = cardInfo.getString("UID"); - Tangem_Card card = new Tangem_Card(UID); - card.LoadFromBundle(cardInfo.getBundle("Card")); - - - Intent intent; - - if (card.getStatus() == Tangem_Card.Status.Empty) { - intent = new Intent(getActivity(), EmptyWalletActivity.class); - } else if (card.getStatus() == Tangem_Card.Status.Loaded) { - intent = new Intent(getActivity(), LoadedWalletActivity.class); - } else if (card.getStatus() == Tangem_Card.Status.NotPersonalized || card.getStatus() == Tangem_Card.Status.Purged) { - return; - } else { - intent = new Intent(getActivity(), LoadedWalletActivity.class); - } - - intent.putExtras(cardInfo); - startActivityForResult(intent, REQUEST_CODE_SHOW_CARD_ACTIVITY); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - Log.d(logTag, "ActivityResult: requestCode = " + requestCode + ", resultCode = " + resultCode); - // если пришло ОК - if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_SHOW_CARD_ACTIVITY) { - if (data != null && data.getExtras().containsKey("UID")) { - final Tangem_Card card = new Tangem_Card(data.getStringExtra("UID")); - card.LoadFromBundle(data.getBundleExtra("Card")); - if (data.getStringExtra("modification").equals("delete")) { - mCardListAdapter.removeCard(card); - for (int i = 0; i < slCardUIDs.size(); i++) { - if (slCardUIDs.get(i).equals(card.getUID())) { - slCardUIDs.remove(i); - break; - } - } - if (mCardListAdapter.getItemCount() == 0 && getActivity().getClass() == MainActivity.class) { - ((MainActivity) getActivity()).hideCleanButton(); - } - } else if (data.getStringExtra("modification").equals("update")) { - mCardListAdapter.updateCard(card); - } else if (data.getStringExtra("modification").equals("updateAndViewCard")) { - mCardListAdapter.updateCard(card); - onViewCard(data.getExtras()); - } - - } - } else if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_ENTER_PIN_ACTIVITY) { - if (lastTag != null) onTagDiscovered(lastTag); - } - } - - @Override - public void doClean() { - mCardListAdapter.clearCards(); - slCardUIDs.clear(); - for (RequestWalletInfoTask rt : requestTasks) { - rt.cancel(true); - } - lastRead_UID = ""; - } - - public void doEnterPIN() { - Intent intent = new Intent(getContext(), RequestPINActivity.class); - intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN.toString()); - startActivityForResult(intent, REQUEST_CODE_ENTER_PIN_ACTIVITY); - } - - private static String lastRead_UID = ""; - private static ArrayList lastRead_UnsuccessfullPINs = new ArrayList<>(); - private static Tangem_Card.EncryptionMode lastRead_Encryption = null; - - private class ReadCardInfoTask extends Thread { - - - IsoDep mIsoDep; - CardProtocol.Notifications mNotifications; - private boolean isCancelled = false; - - ReadCardInfoTask(IsoDep isoDep, CardProtocol.Notifications notifications) { - mIsoDep = isoDep; - mNotifications = notifications; - } - - @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(getContext(), 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)) { - lastRead_UID = sUID; - lastRead_UnsuccessfullPINs.clear(); - lastRead_Encryption = null; - } - - Log.i("ReadCardInfoTask", "[-- Start read card info --]"); - - if (isCancelled) return; - - protocol.setPIN(PINStorage.getDefaultPIN()); - protocol.clearReadResult(); - - if (lastRead_Encryption == null) { - Log.i("ReadCardInfoTask", "Try get supported encryption mode"); - protocol.run_GetSupportedEncryption(); - } else { - Log.i("ReadCardInfoTask", "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_ReadOrWriteIssuerDataAndDefineOfflineBalance(); - 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 == Tangem_Card.EncryptionMode.None) { - // default pin not accepted - lastRead_UnsuccessfullPINs.add(PINStorage.getDefaultPIN()); - } - } - - boolean pinFound = false; - for (String PIN : PINStorage.getPINs()) { - Log.e("ReadCardInfoTask", "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("ReadCardInfoTask", "Skip PIN - already checked before"); - continue; - } - - try { - protocol.setPIN(PIN); - if (protocol.getCard().encryptionMode != Tangem_Card.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(logTag, 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("ReadCardInfoTask", "[-- Finish read card info --]"); - mNotifications.OnReadFinish(protocol); - } - } finally { - mNfcManager.IgnoreTag(mIsoDep.getTag()); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - void cancel(Boolean AllowInterrupt) { - try { - if (this.isAlive()) { - isCancelled = true; - join(500); - } - if (this.isAlive() && AllowInterrupt) { - interrupt(); - mNotifications.OnReadCancel(); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - } - - public void OnReadStart(CardProtocol cardProtocol) { - progressBar.post(new Runnable() { - @Override - public void run() { - progressBar.setVisibility(View.VISIBLE); - progressBar.setProgress(5); - } - }); - } - - public void OnReadFinish(final CardProtocol cardProtocol) { - - readCardInfoTask = null; - - if (cardProtocol != null) { - if (cardProtocol.getError() == null) { - progressBar.post(new Runnable() { - @Override - public void run() { - progressBar.setProgress(100); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); - addCard(cardProtocol.getCard()); - } - }); - } else { - // remove last UIDs because of error and no card read - progressBar.post(new Runnable() { - @Override - public void run() { - Toast.makeText(getContext(), "Try to scan again", Toast.LENGTH_LONG).show(); - unsuccessReadCount++; - progressBar.setProgress(100); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); - slCardUIDs.remove(cardProtocol.getCard().getUID()); - if (cardProtocol.getError() instanceof CardProtocol.TangemException_InvalidPIN) { - doEnterPIN(); - } else if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) { - if (!NoExtendedLengthSupportDialog.allreadyShowed) { - new NoExtendedLengthSupportDialog().show(getActivity().getFragmentManager(), "NoExtendedLengthSupportDialog"); - } - } else { - lastTag = null; - } - } - }); - } - } - - progressBar.postDelayed(new Runnable() { - @Override - public void run() { - try { - progressBar.setProgress(0); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); - progressBar.setVisibility(View.INVISIBLE); - } catch (Exception e) { - e.printStackTrace(); - } - } - }, 500); - } - - public void OnReadProgress(CardProtocol protocol, final int progress) { - progressBar.post(new Runnable() { - @Override - public void run() { - progressBar.setProgress(progress); - } - }); - } - - public void OnReadCancel() { - - readCardInfoTask = null; - - progressBar.postDelayed(new Runnable() { - @Override - public void run() { - try { - progressBar.setProgress(0); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); - progressBar.setVisibility(View.INVISIBLE); - } catch (Exception e) { - e.printStackTrace(); - } - } - }, 500); - } - - - public void OnReadWait(final int msec) { - WaitSecurityDelayDialog.OnReadWait(getActivity(), msec); - } - - @Override - public void OnReadBeforeRequest(int timeout) { - WaitSecurityDelayDialog.onReadBeforeRequest(getActivity(), timeout); - } - - @Override - public void OnReadAfterRequest() { - WaitSecurityDelayDialog.onReadAfterRequest(getActivity()); - } - - private class RequestWalletInfoTask extends Electrum_Task { - public RequestWalletInfoTask(String host, int port) { - super(host, port); - } - - - public RequestWalletInfoTask(String host, int port, SharedData sharedData) { - super(host, port, sharedData); - } - - @Override - protected void onProgressUpdate(Integer... values) { - super.onProgressUpdate(values); - } - - @Override - protected void onCancelled() { - super.onCancelled(); - requestTasks.remove(this); - if ( mSwipeRefreshLayout!=null && requestTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); //TODO: tmp - - } - - void FinishWithError(String wallet, String message) { - mCardListAdapter.UpdateWalletError(wallet, "Cannot obtain data from blockchain"); - } - - @Override - protected void onPostExecute(List requests) { - super.onPostExecute(requests); - requestTasks.remove(this); - Log.i("RequestWalletInfoTask", "onPostExecute[" + String.valueOf(requests.size()) + "]"); - - CoinEngine engine = CoinEngineFactory.Create(Blockchain.Bitcoin); - - for (Electrum_Request request : requests) { - try { - - if (request.error == null) { - if (request.isMethod(Electrum_Request.METHOD_GetBalance)) { - try { - Long conf = request.getResult().getLong("confirmed"); - Long unconf = request.getResult().getLong("unconfirmed"); - if (sharedCounter != null) { - int counter = sharedCounter.requestCounter.incrementAndGet(); - if (counter != 1) { - continue; - } - } - String mWalletAddress = request.getParams().getString(0); - mCardListAdapter.UpdateWalletBalance(mWalletAddress, conf, unconf, getValidationNodeDescription()); - } catch (JSONException e) { - if (sharedCounter != null) { - int errCounter = sharedCounter.errorRequest.incrementAndGet(); - if (errCounter == sharedCounter.allRequest) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - engine.SwitchNode(null); - } - } else { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - engine.SwitchNode(null); - } - } - } else if (request.isMethod(Electrum_Request.METHOD_ListUnspent)) { - try { - String mWalletAddress = request.getParams().getString(0); - mCardListAdapter.UpdateWalletUnspent(mWalletAddress, request.getResultArray()); - - JSONArray unspentList = request.getResultArray(); - - for (int i = 0; i < unspentList.length(); i++) { - JSONObject jsUnspent = unspentList.getJSONObject(i); - Integer height = jsUnspent.getInt("height"); - String hash = jsUnspent.getString("tx_hash"); - if (height != -1) { - RequestWalletInfoTask task = new RequestWalletInfoTask(request.Host, request.Port); - requestTasks.add(task); - task.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), - Electrum_Request.GetTransaction(mWalletAddress, hash)); - } - } - } catch (JSONException e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - engine.SwitchNode(null); - } - } else if (request.isMethod(Electrum_Request.METHOD_GetHistory)) { - try { - String mWalletAddress = request.getParams().getString(0); - mCardListAdapter.UpdateWalletHistory(mWalletAddress, request.getResultArray()); - - JSONArray historyList = request.getResultArray(); - - for (int i = 0; i < historyList.length(); i++) { - JSONObject jsUnspent = historyList.getJSONObject(i); - Integer height = jsUnspent.getInt("height"); - String hash = jsUnspent.getString("tx_hash"); - if (height != -1) { - RequestWalletInfoTask task = new RequestWalletInfoTask(request.Host, request.Port); - requestTasks.add(task); - - task.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), - Electrum_Request.GetTransaction(mWalletAddress, hash)); - } - } - } catch (JSONException e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - engine.SwitchNode(null); - } - } else if (request.isMethod(Electrum_Request.METHOD_GetHeader)) { - try { - String mWalletAddress = request.WalletAddress; - - mCardListAdapter.UpdateWalletHeader(mWalletAddress, request.getResult()); - - } catch (JSONException e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - engine.SwitchNode(null); - } - } else if (request.isMethod(Electrum_Request.METHOD_GetTransaction)) { - try { - Log.e("MainActivityFragment_TX", request.TxHash); - String mWalletAddress = request.WalletAddress; - String tx = request.TxHash; - String raw = request.getResultString(); - Log.e("MainActivityFragment_R", raw); - mCardListAdapter.UpdateTransaction(mWalletAddress, tx, raw); - - } catch (JSONException e) { - e.printStackTrace(); - mCardListAdapter.UpdateWalletError(request.WalletAddress, "Cannot obtain data from blockchain"); - FinishWithError(request.WalletAddress, e.toString()); - engine.SwitchNode(null); - } - } - } else { - if (sharedCounter != null) { - int errCounter = sharedCounter.errorRequest.incrementAndGet(); - if (errCounter >= sharedCounter.allRequest) { - FinishWithError(request.WalletAddress, request.error); - engine.SwitchNode(null); - } - } else { - FinishWithError(request.WalletAddress, request.error); - engine.SwitchNode(null); - } - - } - } catch (JSONException e) { - if (sharedCounter != null) { - int errCounter = sharedCounter.errorRequest.incrementAndGet(); - if (errCounter >= sharedCounter.allRequest) { - e.printStackTrace(); - mCardListAdapter.UpdateWalletError(request.WalletAddress, "Cannot obtain data from blockchain"); - engine.SwitchNode(null); - } - } else { - e.printStackTrace(); - mCardListAdapter.UpdateWalletError(request.WalletAddress, "Cannot obtain data from blockchain"); - engine.SwitchNode(null); - } - - } - } - - if ( mSwipeRefreshLayout!=null && requestTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); //TODO: tmp - } - - } - - private class ETHRequestTask extends Infura_Task { - ETHRequestTask(Blockchain blockchain) { - super(blockchain); - } - - void FinishWithError(String wallet, String message) { - mCardListAdapter.UpdateWalletError(wallet, "Cannot obtain data from blockchain"); - } - - @Override - protected void onPostExecute(List requests) { - super.onPostExecute(requests); - for (Infura_Request request : requests) { - try { - if (request.error == null) { - - if (request.isMethod(Infura_Request.METHOD_ETH_GetBalance)) { - try { - String mWalletAddress = request.getParams().getString(0); - - String balanceCap = request.getResultString(); - balanceCap = balanceCap.substring(2); - BigInteger l = new BigInteger(balanceCap, 16); - BigInteger d = l.divide(new BigInteger("1000000000000000000", 10)); - Long balance = d.longValue(); - if (request.getBlockchain() != Blockchain.Token) - mCardListAdapter.UpdateWalletBalance(mWalletAddress, balance, l.toString(10), getValidationNodeDescription()); - mCardListAdapter.UpdateWalletBalanceOnlyAlter(mWalletAddress, l.toString(10)); - } catch (JSONException e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - } - } else if (request.isMethod(Infura_Request.METHOD_ETH_Call)) { - try { - String mWalletAddress = request.WalletAddress; - - String balanceCap = request.getResultString(); - balanceCap = balanceCap.substring(2); - BigInteger l = new BigInteger(balanceCap, 16); - Long balance = l.longValue(); - if (l.compareTo(BigInteger.ZERO) == 0) { - mCardListAdapter.UpdateWalletBlockchain(mWalletAddress, Blockchain.Ethereum); - mCardListAdapter.AddWalletBlockchainNameToken(mWalletAddress); - Tangem_Card card = mCardListAdapter.getCardByWallet(request.WalletAddress); - if (card != null) { - refreshCard(card); - } - return; - } - mCardListAdapter.UpdateWalletBalance(mWalletAddress, balance, l.toString(10), getValidationNodeDescription()); - } catch (JSONException e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - } catch (Exception e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - } - } else if (request.isMethod(Infura_Request.METHOD_ETH_GetOutTransactionCount)) { - try { - String mWalletAddress = request.getParams().getString(0); - - String nonce = request.getResultString(); - nonce = nonce.substring(2); - BigInteger count = new BigInteger(nonce, 16); - - mCardListAdapter.UpdateWalletCoutConfirmTx(mWalletAddress, count); - } catch (JSONException e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - } - } - } else { - FinishWithError(request.WalletAddress, request.error); - } - } catch (JSONException e) { - e.printStackTrace(); - FinishWithError(request.WalletAddress, e.toString()); - } - } - } - - } - - private class RateInfoTask extends ExchangeTask { - protected void onPostExecute(List requests) { - super.onPostExecute(requests); - for (ExchangeRequest request : requests) { - if (request.error == null) { - try { - - JSONArray arr = request.getAnswerList(); - for (int i = 0; i < arr.length(); ++i) { - JSONObject obj = arr.getJSONObject(i); - String currency = obj.getString("id"); - - boolean stop = false; - boolean stopAlter = false; - if (currency.equals(request.currency)) { - String usd = obj.getString("price_usd"); - - Float rate = Float.valueOf(usd); - mCardListAdapter.UpdateRate(request.WalletAddress, rate); - stop = true; - } - - if (currency.equals(request.currencyAlter)) { - String usd = obj.getString("price_usd"); - - Float rate = Float.valueOf(usd); - mCardListAdapter.UpdateRateAlter(request.WalletAddress, rate); - stopAlter = true; - } - - if (stop && stopAlter) { - break; - } - } - - - //mCardListAdapter.UpdateWalletBalance(mWalletAddress, balance, l.toString(10)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - } - } - - -} +package com.tangem.presentation.fragment; + +import android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.IsoDep; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.Toast; + +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.domain.cardReader.Util; +import com.tangem.presentation.activity.EmptyWalletActivity; +import com.tangem.presentation.activity.LoadedWalletActivity; +import com.tangem.presentation.activity.MainActivity; +import com.tangem.presentation.activity.RequestPINActivity; +import com.tangem.wallet.Blockchain; +import com.tangem.presentation.adapter.CardListAdapter; +import com.tangem.wallet.CoinEngine; +import com.tangem.wallet.CoinEngineFactory; +import com.tangem.data.network.request.Electrum_Request; +import com.tangem.data.network.task.Electrum_Task; +import com.tangem.data.network.request.ExchangeRequest; +import com.tangem.data.network.task.ExchangeTask; +import com.tangem.wallet.Infura_Request; +import com.tangem.data.network.task.Infura_Task; +import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog; +import com.tangem.wallet.PINStorage; +import com.tangem.wallet.R; +import com.tangem.wallet.SharedData; +import com.tangem.wallet.Tangem_Card; +import com.tangem.presentation.dialog.WaitSecurityDelayDialog; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + + +/** + * A placeholder fragment containing a simple view. + */ +public class MainActivityFragment extends Fragment implements NfcAdapter.ReaderCallback, CardListAdapter.UiCallbacks, CardProtocol.Notifications, MainActivity.OnCardsClean { + + private static final int REQUEST_CODE_SHOW_CARD_ACTIVITY = 1; + private static final int REQUEST_CODE_ENTER_PIN_ACTIVITY = 2; + private static final int REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS = 3; + private NfcManager mNfcManager; + private ArrayList slCardUIDs = new ArrayList<>(); + private static final String logTag = "MainActivityFragment"; + private ProgressBar progressBar; + + private CardListAdapter mCardListAdapter; + + public CardListAdapter getCardListAdapter() { + return mCardListAdapter; + } + + private ReadCardInfoTask readCardInfoTask; + private SwipeRefreshLayout mSwipeRefreshLayout; //TODO: tmp + List requestTasks = new ArrayList<>(); + + public MainActivityFragment() { + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mCardListAdapter.onSaveInstanceState(outState); + outState.putStringArrayList("slCardUIDs", slCardUIDs); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View result = inflater.inflate(R.layout.fragment_main, container, false); + + mNfcManager = new NfcManager(this.getActivity(), this); + verifyPermissions(); + + progressBar = result.findViewById(R.id.progressBar); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); + RecyclerView rvCards = result.findViewById(R.id.lvCards); + rvCards.setLayoutManager(new LinearLayoutManager(getContext())); + mCardListAdapter = new CardListAdapter(getActivity().getLayoutInflater(), savedInstanceState, this); + rvCards.setAdapter(mCardListAdapter); + if (savedInstanceState != null && savedInstanceState.containsKey("slCardUIDs")) { + slCardUIDs = savedInstanceState.getStringArrayList("slCardUIDs"); + } + + // SwipeRefreshLayout + mSwipeRefreshLayout = result.findViewById(R.id.swipe_container); //TODO: tmp + + if( mSwipeRefreshLayout!=null ) { + SwipeRefreshLayout.OnRefreshListener onRefreshListener = new SwipeRefreshLayout.OnRefreshListener() { + + @Override + public void onRefresh() { + //Update + // Showing refresh animation before making http call + + if (requestTasks.size() > 0) return; + + if (requestTasks.size() > 0) { //TODO: tmp + mSwipeRefreshLayout.setRefreshing(true); + } else { + mSwipeRefreshLayout.setRefreshing(false); + } + } + }; + mSwipeRefreshLayout.setOnRefreshListener(onRefreshListener); //TODO: tmp + } + + ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { + return false; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { + //Remove swiped item from list and notify the RecyclerView + int cardIndex = viewHolder.getAdapterPosition(); + if (cardIndex < 0 || cardIndex >= mCardListAdapter.getItemCount()) return; + slCardUIDs.remove(mCardListAdapter.getCard(cardIndex).getUID()); + if (mCardListAdapter.getCard(cardIndex).getUID() == lastRead_UID) { + lastRead_UID = ""; + } + mCardListAdapter.removeCard(cardIndex); + if (mCardListAdapter.getItemCount() == 0 && getActivity().getClass() == MainActivity.class) { + ((MainActivity) getActivity()).hideCleanButton(); + } + } + }); + + itemTouchHelper.attachToRecyclerView(rvCards); + + if (getActivity() instanceof MainActivity) { + ((MainActivity) getActivity()).setOnCardsClean(this); +// ((MainActivity) getActivity()).setOnCreateNFCDialog(this); + ((MainActivity) getActivity()).setNfcAdapterReaderCallback(this); + } + + return result; + } + + private void verifyPermissions() { + NfcManager.verifyPermissions(getActivity()); + if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + Log.e("QRScanActivity", "User hasn't granted permission to use camera"); + ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS); + } + } + + int unsuccessReadCount = 0; + Tag lastTag = null; + + @Override + public void onTagDiscovered(Tag tag) { + try { + // get IsoDep handle and run cardReader thread + final IsoDep isoDep = IsoDep.get(tag); + if (isoDep == null) { + throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err)); + } + + byte UID[] = tag.getId(); + String sUID = Util.byteArrayToHexString(UID); + if (slCardUIDs.indexOf(sUID) != -1) { + Log.d(logTag, "Repeat UID: " + sUID); + mNfcManager.IgnoreTag(isoDep.getTag()); + return; + } else { + Log.v(logTag, "UID: " + sUID); + } + +// Log.e(logTag,"setTimeout("+String.valueOf(1000 + 3000 * unsuccessReadCount)+")"); + if (unsuccessReadCount < 2) { + isoDep.setTimeout(2000 + 5000 * unsuccessReadCount); + } else { + isoDep.setTimeout(90000); + } + lastTag = tag; + + readCardInfoTask = new ReadCardInfoTask(isoDep, this); + readCardInfoTask.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onResume() { + super.onResume(); + + mNfcManager.onResume(); + } + + @Override + public void onPause() { + mNfcManager.onPause(); + if (readCardInfoTask != null) { + readCardInfoTask.cancel(true); + } + super.onPause(); + } + + @Override + public void onStop() { + // dismiss enable NFC dialog + mNfcManager.onStop(); + if (readCardInfoTask != null) { + readCardInfoTask.cancel(true); + } + for (RequestWalletInfoTask rt : requestTasks) { + rt.cancel(true); + } + super.onStop(); + } + + public void refreshCard(Tangem_Card card) { + CoinEngine engine = CoinEngineFactory.Create(card.getBlockchain()); + if (card.getBlockchain() == Blockchain.Ethereum || card.getBlockchain() == Blockchain.EthereumTestNet) { + ETHRequestTask task = new ETHRequestTask(card.getBlockchain()); + Infura_Request req = Infura_Request.GetBalance(card.getWallet()); + req.setID(67); + req.setBlockchain(card.getBlockchain()); + Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); + reqNonce.setID(67); + reqNonce.setBlockchain(card.getBlockchain()); + + task.execute(req, reqNonce); + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "ethereum", "ethereum"); + taskRate.execute(rate); + + } else if (card.getBlockchain() == Blockchain.BitcoinTestNet || card.getBlockchain() == Blockchain.Bitcoin) { + SharedData data = new SharedData(SharedData.COUNT_REQUEST); + for (int i = 0; i < data.allRequest; ++i) { + + String nodeAddress = engine.GetNextNode(card); + int nodePort = engine.GetNextNodePort(card); + RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); + connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); + } + + String nodeAddress = engine.GetNode(card); + int nodePort = engine.GetNodePort(card); + RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); + if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp + requestTasks.add(task); + task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin", "bitcoin"); + taskRate.execute(rate); + + } + else if (card.getBlockchain() == Blockchain.BitcoinCashTestNet || card.getBlockchain() == Blockchain.BitcoinCash) { + SharedData data = new SharedData(SharedData.COUNT_REQUEST); + for (int i = 0; i < data.allRequest; ++i) { + + String nodeAddress = engine.GetNextNode(card); + int nodePort = engine.GetNextNodePort(card); + RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); + connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); + } + + String nodeAddress = engine.GetNode(card); + int nodePort = engine.GetNodePort(card); + RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); + if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp + requestTasks.add(task); + task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin-cash", "bitcoin-cash"); + taskRate.execute(rate); + + }else if (card.getBlockchain() == Blockchain.Token) { + ETHRequestTask updateETH = new ETHRequestTask(card.getBlockchain()); + Infura_Request reqETH = Infura_Request.GetTokenBalance(card.getWallet(), engine.GetContractAddress(card), engine.GetTokenDecimals(card)); + reqETH.setID(67); + reqETH.setBlockchain(card.getBlockchain()); + + + Infura_Request reqBalance = Infura_Request.GetBalance(card.getWallet()); + reqBalance.setID(67); + reqBalance.setBlockchain(card.getBlockchain()); + + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "basic-attention-token", "ethereum"); + taskRate.execute(rate); + + Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); + reqNonce.setID(67); + reqNonce.setBlockchain(card.getBlockchain()); + + updateETH.execute(reqETH, reqNonce, reqBalance); + } + } + + public void addCard(final Tangem_Card card) { + if (mCardListAdapter != null) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + unsuccessReadCount = 0; + slCardUIDs.add(0, card.getUID()); + mCardListAdapter.addCard(card); + + CoinEngine engine = CoinEngineFactory.Create(card.getBlockchain()); + + if (card.getStatus() == Tangem_Card.Status.Loaded) { + + if (card.getBlockchain() == Blockchain.Ethereum || card.getBlockchain() == Blockchain.EthereumTestNet) { + ETHRequestTask task = new ETHRequestTask(card.getBlockchain()); + Infura_Request req = Infura_Request.GetBalance(card.getWallet()); + req.setID(67); + req.setBlockchain(card.getBlockchain()); + Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); + reqNonce.setID(67); + reqNonce.setBlockchain(card.getBlockchain()); + + task.execute(req, reqNonce); + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "ethereum", "ethereum"); + taskRate.execute(rate); + + } else if (card.getBlockchain() == Blockchain.BitcoinTestNet || card.getBlockchain() == Blockchain.Bitcoin) { + SharedData data = new SharedData(SharedData.COUNT_REQUEST); + + for (int i = 0; i < data.allRequest; ++i) { + String nodeAddress = engine.GetNextNode(card); + int nodePort = engine.GetNextNodePort(card); + + RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); + connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); + } + + String nodeAddress = engine.GetNode(card); + int nodePort = engine.GetNodePort(card); + + RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); + if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp + + requestTasks.add(task); + task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin", "bitcoin"); + taskRate.execute(rate); + + }else if (card.getBlockchain() == Blockchain.BitcoinCashTestNet || card.getBlockchain() == Blockchain.BitcoinCash) { + SharedData data = new SharedData(SharedData.COUNT_REQUEST); + + for (int i = 0; i < data.allRequest; ++i) { + String nodeAddress = engine.GetNextNode(card); + int nodePort = engine.GetNextNodePort(card); + + RequestWalletInfoTask connectTaskEx = new RequestWalletInfoTask(nodeAddress, nodePort, data); + connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Electrum_Request.CheckBalance(card.getWallet())); + } + + String nodeAddress = engine.GetNode(card); + int nodePort = engine.GetNodePort(card); + + RequestWalletInfoTask task = new RequestWalletInfoTask(nodeAddress, nodePort); + if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(true); //TODO: tmp + + requestTasks.add(task); + task.execute(Electrum_Request.ListUnspent(card.getWallet()), Electrum_Request.ListHistory(card.getWallet())); + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "bitcoin-cash", "bitcoin-cash"); + taskRate.execute(rate); + + } + else if (card.getBlockchain() == Blockchain.Token) { + ETHRequestTask updateETH = new ETHRequestTask(card.getBlockchain()); + Infura_Request reqETH = Infura_Request.GetTokenBalance(card.getWallet(), engine.GetContractAddress(card), engine.GetTokenDecimals(card)); + reqETH.setID(67); + reqETH.setBlockchain(card.getBlockchain()); + + + Infura_Request reqBalance = Infura_Request.GetBalance(card.getWallet()); + reqBalance.setID(67); + reqBalance.setBlockchain(card.getBlockchain()); + + + RateInfoTask taskRate = new RateInfoTask(); + ExchangeRequest rate = ExchangeRequest.GetRate(card.getWallet(), "basic-attention-token", "ethereum"); + taskRate.execute(rate); + + Infura_Request reqNonce = Infura_Request.GetOutTransactionCount(card.getWallet()); + reqNonce.setID(67); + reqNonce.setBlockchain(card.getBlockchain()); + + updateETH.execute(reqETH, reqNonce, reqBalance); + } + } + if (getActivity().getClass() == MainActivity.class) { + ((MainActivity) getActivity()).showCleanButton(); + } + } + }); + } + } + + @Override + public void onViewCard(Bundle cardInfo) { + + if( mSwipeRefreshLayout!=null ) mSwipeRefreshLayout.setRefreshing(false); //TODO: tmp + + String UID = cardInfo.getString("UID"); + Tangem_Card card = new Tangem_Card(UID); + card.LoadFromBundle(cardInfo.getBundle("Card")); + + + Intent intent; + + if (card.getStatus() == Tangem_Card.Status.Empty) { + intent = new Intent(getActivity(), EmptyWalletActivity.class); + } else if (card.getStatus() == Tangem_Card.Status.Loaded) { + intent = new Intent(getActivity(), LoadedWalletActivity.class); + } else if (card.getStatus() == Tangem_Card.Status.NotPersonalized || card.getStatus() == Tangem_Card.Status.Purged) { + return; + } else { + intent = new Intent(getActivity(), LoadedWalletActivity.class); + } + + intent.putExtras(cardInfo); + startActivityForResult(intent, REQUEST_CODE_SHOW_CARD_ACTIVITY); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.d(logTag, "ActivityResult: requestCode = " + requestCode + ", resultCode = " + resultCode); + // если пришло ОК + if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_SHOW_CARD_ACTIVITY) { + if (data != null && data.getExtras().containsKey("UID")) { + final Tangem_Card card = new Tangem_Card(data.getStringExtra("UID")); + card.LoadFromBundle(data.getBundleExtra("Card")); + if (data.getStringExtra("modification").equals("delete")) { + mCardListAdapter.removeCard(card); + for (int i = 0; i < slCardUIDs.size(); i++) { + if (slCardUIDs.get(i).equals(card.getUID())) { + slCardUIDs.remove(i); + break; + } + } + if (mCardListAdapter.getItemCount() == 0 && getActivity().getClass() == MainActivity.class) { + ((MainActivity) getActivity()).hideCleanButton(); + } + } else if (data.getStringExtra("modification").equals("update")) { + mCardListAdapter.updateCard(card); + } else if (data.getStringExtra("modification").equals("updateAndViewCard")) { + mCardListAdapter.updateCard(card); + onViewCard(data.getExtras()); + } + + } + } else if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_ENTER_PIN_ACTIVITY) { + if (lastTag != null) onTagDiscovered(lastTag); + } + } + + @Override + public void doClean() { + mCardListAdapter.clearCards(); + slCardUIDs.clear(); + for (RequestWalletInfoTask rt : requestTasks) { + rt.cancel(true); + } + lastRead_UID = ""; + } + + public void doEnterPIN() { + Intent intent = new Intent(getContext(), RequestPINActivity.class); + intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN.toString()); + startActivityForResult(intent, REQUEST_CODE_ENTER_PIN_ACTIVITY); + } + + private static String lastRead_UID = ""; + private static ArrayList lastRead_UnsuccessfullPINs = new ArrayList<>(); + private static Tangem_Card.EncryptionMode lastRead_Encryption = null; + + private class ReadCardInfoTask extends Thread { + + + IsoDep mIsoDep; + CardProtocol.Notifications mNotifications; + private boolean isCancelled = false; + + ReadCardInfoTask(IsoDep isoDep, CardProtocol.Notifications notifications) { + mIsoDep = isoDep; + mNotifications = notifications; + } + + @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(getContext(), 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)) { + lastRead_UID = sUID; + lastRead_UnsuccessfullPINs.clear(); + lastRead_Encryption = null; + } + + Log.i("ReadCardInfoTask", "[-- Start read card info --]"); + + if (isCancelled) return; + + protocol.setPIN(PINStorage.getDefaultPIN()); + protocol.clearReadResult(); + + if (lastRead_Encryption == null) { + Log.i("ReadCardInfoTask", "Try get supported encryption mode"); + protocol.run_GetSupportedEncryption(); + } else { + Log.i("ReadCardInfoTask", "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_ReadOrWriteIssuerDataAndDefineOfflineBalance(); + 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 == Tangem_Card.EncryptionMode.None) { + // default pin not accepted + lastRead_UnsuccessfullPINs.add(PINStorage.getDefaultPIN()); + } + } + + boolean pinFound = false; + for (String PIN : PINStorage.getPINs()) { + Log.e("ReadCardInfoTask", "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("ReadCardInfoTask", "Skip PIN - already checked before"); + continue; + } + + try { + protocol.setPIN(PIN); + if (protocol.getCard().encryptionMode != Tangem_Card.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(logTag, 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("ReadCardInfoTask", "[-- Finish read card info --]"); + mNotifications.OnReadFinish(protocol); + } + } finally { + mNfcManager.IgnoreTag(mIsoDep.getTag()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + void cancel(Boolean AllowInterrupt) { + try { + if (this.isAlive()) { + isCancelled = true; + join(500); + } + if (this.isAlive() && AllowInterrupt) { + interrupt(); + mNotifications.OnReadCancel(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + + public void OnReadStart(CardProtocol cardProtocol) { + progressBar.post(new Runnable() { + @Override + public void run() { + progressBar.setVisibility(View.VISIBLE); + progressBar.setProgress(5); + } + }); + } + + public void OnReadFinish(final CardProtocol cardProtocol) { + + readCardInfoTask = null; + + if (cardProtocol != null) { + if (cardProtocol.getError() == null) { + progressBar.post(new Runnable() { + @Override + public void run() { + progressBar.setProgress(100); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); + addCard(cardProtocol.getCard()); + } + }); + } else { + // remove last UIDs because of error and no card read + progressBar.post(new Runnable() { + @Override + public void run() { + Toast.makeText(getContext(), "Try to scan again", Toast.LENGTH_LONG).show(); + unsuccessReadCount++; + progressBar.setProgress(100); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); + slCardUIDs.remove(cardProtocol.getCard().getUID()); + if (cardProtocol.getError() instanceof CardProtocol.TangemException_InvalidPIN) { + doEnterPIN(); + } else if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) { + if (!NoExtendedLengthSupportDialog.allreadyShowed) { + new NoExtendedLengthSupportDialog().show(getActivity().getFragmentManager(), "NoExtendedLengthSupportDialog"); + } + } else { + lastTag = null; + } + } + }); + } + } + + progressBar.postDelayed(new Runnable() { + @Override + public void run() { + try { + progressBar.setProgress(0); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); + progressBar.setVisibility(View.INVISIBLE); + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 500); + } + + public void OnReadProgress(CardProtocol protocol, final int progress) { + progressBar.post(new Runnable() { + @Override + public void run() { + progressBar.setProgress(progress); + } + }); + } + + public void OnReadCancel() { + + readCardInfoTask = null; + + progressBar.postDelayed(new Runnable() { + @Override + public void run() { + try { + progressBar.setProgress(0); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); + progressBar.setVisibility(View.INVISIBLE); + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 500); + } + + + public void OnReadWait(final int msec) { + WaitSecurityDelayDialog.OnReadWait(getActivity(), msec); + } + + @Override + public void OnReadBeforeRequest(int timeout) { + WaitSecurityDelayDialog.onReadBeforeRequest(getActivity(), timeout); + } + + @Override + public void OnReadAfterRequest() { + WaitSecurityDelayDialog.onReadAfterRequest(getActivity()); + } + + private class RequestWalletInfoTask extends Electrum_Task { + public RequestWalletInfoTask(String host, int port) { + super(host, port); + } + + + public RequestWalletInfoTask(String host, int port, SharedData sharedData) { + super(host, port, sharedData); + } + + @Override + protected void onProgressUpdate(Integer... values) { + super.onProgressUpdate(values); + } + + @Override + protected void onCancelled() { + super.onCancelled(); + requestTasks.remove(this); + if ( mSwipeRefreshLayout!=null && requestTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); //TODO: tmp + + } + + void FinishWithError(String wallet, String message) { + mCardListAdapter.UpdateWalletError(wallet, "Cannot obtain data from blockchain"); + } + + @Override + protected void onPostExecute(List requests) { + super.onPostExecute(requests); + requestTasks.remove(this); + Log.i("RequestWalletInfoTask", "onPostExecute[" + String.valueOf(requests.size()) + "]"); + + CoinEngine engine = CoinEngineFactory.Create(Blockchain.Bitcoin); + + for (Electrum_Request request : requests) { + try { + + if (request.error == null) { + if (request.isMethod(Electrum_Request.METHOD_GetBalance)) { + try { + Long conf = request.getResult().getLong("confirmed"); + Long unconf = request.getResult().getLong("unconfirmed"); + if (sharedCounter != null) { + int counter = sharedCounter.requestCounter.incrementAndGet(); + if (counter != 1) { + continue; + } + } + String mWalletAddress = request.getParams().getString(0); + mCardListAdapter.UpdateWalletBalance(mWalletAddress, conf, unconf, getValidationNodeDescription()); + } catch (JSONException e) { + if (sharedCounter != null) { + int errCounter = sharedCounter.errorRequest.incrementAndGet(); + if (errCounter == sharedCounter.allRequest) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + engine.SwitchNode(null); + } + } else { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + engine.SwitchNode(null); + } + } + } else if (request.isMethod(Electrum_Request.METHOD_ListUnspent)) { + try { + String mWalletAddress = request.getParams().getString(0); + mCardListAdapter.UpdateWalletUnspent(mWalletAddress, request.getResultArray()); + + JSONArray unspentList = request.getResultArray(); + + for (int i = 0; i < unspentList.length(); i++) { + JSONObject jsUnspent = unspentList.getJSONObject(i); + Integer height = jsUnspent.getInt("height"); + String hash = jsUnspent.getString("tx_hash"); + if (height != -1) { + RequestWalletInfoTask task = new RequestWalletInfoTask(request.Host, request.Port); + requestTasks.add(task); + task.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), + Electrum_Request.GetTransaction(mWalletAddress, hash)); + } + } + } catch (JSONException e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + engine.SwitchNode(null); + } + } else if (request.isMethod(Electrum_Request.METHOD_GetHistory)) { + try { + String mWalletAddress = request.getParams().getString(0); + mCardListAdapter.UpdateWalletHistory(mWalletAddress, request.getResultArray()); + + JSONArray historyList = request.getResultArray(); + + for (int i = 0; i < historyList.length(); i++) { + JSONObject jsUnspent = historyList.getJSONObject(i); + Integer height = jsUnspent.getInt("height"); + String hash = jsUnspent.getString("tx_hash"); + if (height != -1) { + RequestWalletInfoTask task = new RequestWalletInfoTask(request.Host, request.Port); + requestTasks.add(task); + + task.execute(Electrum_Request.GetHeader(mWalletAddress, String.valueOf(height)), + Electrum_Request.GetTransaction(mWalletAddress, hash)); + } + } + } catch (JSONException e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + engine.SwitchNode(null); + } + } else if (request.isMethod(Electrum_Request.METHOD_GetHeader)) { + try { + String mWalletAddress = request.WalletAddress; + + mCardListAdapter.UpdateWalletHeader(mWalletAddress, request.getResult()); + + } catch (JSONException e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + engine.SwitchNode(null); + } + } else if (request.isMethod(Electrum_Request.METHOD_GetTransaction)) { + try { + Log.e("MainActivityFragment_TX", request.TxHash); + String mWalletAddress = request.WalletAddress; + String tx = request.TxHash; + String raw = request.getResultString(); + Log.e("MainActivityFragment_R", raw); + mCardListAdapter.UpdateTransaction(mWalletAddress, tx, raw); + + } catch (JSONException e) { + e.printStackTrace(); + mCardListAdapter.UpdateWalletError(request.WalletAddress, "Cannot obtain data from blockchain"); + FinishWithError(request.WalletAddress, e.toString()); + engine.SwitchNode(null); + } + } + } else { + if (sharedCounter != null) { + int errCounter = sharedCounter.errorRequest.incrementAndGet(); + if (errCounter >= sharedCounter.allRequest) { + FinishWithError(request.WalletAddress, request.error); + engine.SwitchNode(null); + } + } else { + FinishWithError(request.WalletAddress, request.error); + engine.SwitchNode(null); + } + + } + } catch (JSONException e) { + if (sharedCounter != null) { + int errCounter = sharedCounter.errorRequest.incrementAndGet(); + if (errCounter >= sharedCounter.allRequest) { + e.printStackTrace(); + mCardListAdapter.UpdateWalletError(request.WalletAddress, "Cannot obtain data from blockchain"); + engine.SwitchNode(null); + } + } else { + e.printStackTrace(); + mCardListAdapter.UpdateWalletError(request.WalletAddress, "Cannot obtain data from blockchain"); + engine.SwitchNode(null); + } + + } + } + + if ( mSwipeRefreshLayout!=null && requestTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false); //TODO: tmp + } + + } + + private class ETHRequestTask extends Infura_Task { + ETHRequestTask(Blockchain blockchain) { + super(blockchain); + } + + void FinishWithError(String wallet, String message) { + mCardListAdapter.UpdateWalletError(wallet, "Cannot obtain data from blockchain"); + } + + @Override + protected void onPostExecute(List requests) { + super.onPostExecute(requests); + for (Infura_Request request : requests) { + try { + if (request.error == null) { + + if (request.isMethod(Infura_Request.METHOD_ETH_GetBalance)) { + try { + String mWalletAddress = request.getParams().getString(0); + + String balanceCap = request.getResultString(); + balanceCap = balanceCap.substring(2); + BigInteger l = new BigInteger(balanceCap, 16); + BigInteger d = l.divide(new BigInteger("1000000000000000000", 10)); + Long balance = d.longValue(); + if (request.getBlockchain() != Blockchain.Token) + mCardListAdapter.UpdateWalletBalance(mWalletAddress, balance, l.toString(10), getValidationNodeDescription()); + mCardListAdapter.UpdateWalletBalanceOnlyAlter(mWalletAddress, l.toString(10)); + } catch (JSONException e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + } + } else if (request.isMethod(Infura_Request.METHOD_ETH_Call)) { + try { + String mWalletAddress = request.WalletAddress; + + String balanceCap = request.getResultString(); + balanceCap = balanceCap.substring(2); + BigInteger l = new BigInteger(balanceCap, 16); + Long balance = l.longValue(); + if (l.compareTo(BigInteger.ZERO) == 0) { + mCardListAdapter.UpdateWalletBlockchain(mWalletAddress, Blockchain.Ethereum); + mCardListAdapter.AddWalletBlockchainNameToken(mWalletAddress); + Tangem_Card card = mCardListAdapter.getCardByWallet(request.WalletAddress); + if (card != null) { + refreshCard(card); + } + return; + } + mCardListAdapter.UpdateWalletBalance(mWalletAddress, balance, l.toString(10), getValidationNodeDescription()); + } catch (JSONException e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + } catch (Exception e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + } + } else if (request.isMethod(Infura_Request.METHOD_ETH_GetOutTransactionCount)) { + try { + String mWalletAddress = request.getParams().getString(0); + + String nonce = request.getResultString(); + nonce = nonce.substring(2); + BigInteger count = new BigInteger(nonce, 16); + + mCardListAdapter.UpdateWalletCoutConfirmTx(mWalletAddress, count); + } catch (JSONException e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + } + } + } else { + FinishWithError(request.WalletAddress, request.error); + } + } catch (JSONException e) { + e.printStackTrace(); + FinishWithError(request.WalletAddress, e.toString()); + } + } + } + + } + + private class RateInfoTask extends ExchangeTask { + protected void onPostExecute(List requests) { + super.onPostExecute(requests); + for (ExchangeRequest request : requests) { + if (request.error == null) { + try { + + JSONArray arr = request.getAnswerList(); + for (int i = 0; i < arr.length(); ++i) { + JSONObject obj = arr.getJSONObject(i); + String currency = obj.getString("id"); + + boolean stop = false; + boolean stopAlter = false; + if (currency.equals(request.currency)) { + String usd = obj.getString("price_usd"); + + Float rate = Float.valueOf(usd); + mCardListAdapter.UpdateRate(request.WalletAddress, rate); + stop = true; + } + + if (currency.equals(request.currencyAlter)) { + String usd = obj.getString("price_usd"); + + Float rate = Float.valueOf(usd); + mCardListAdapter.UpdateRateAlter(request.WalletAddress, rate); + stopAlter = true; + } + + if (stop && stopAlter) { + break; + } + } + + + //mCardListAdapter.UpdateWalletBalance(mWalletAddress, balance, l.toString(10)); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + } + + +} diff --git a/app/src/main/java/com/tangem/wallet/VerifyCardActivityFragment.java b/app/src/main/java/com/tangem/presentation/fragment/VerifyCardActivityFragment.java similarity index 97% rename from app/src/main/java/com/tangem/wallet/VerifyCardActivityFragment.java rename to app/src/main/java/com/tangem/presentation/fragment/VerifyCardActivityFragment.java index c04b7912a0..15a2d5b091 100644 --- a/app/src/main/java/com/tangem/wallet/VerifyCardActivityFragment.java +++ b/app/src/main/java/com/tangem/presentation/fragment/VerifyCardActivityFragment.java @@ -1,360 +1,362 @@ -package com.tangem.wallet; - -import android.app.Activity; -import android.content.Intent; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.widget.SwipeRefreshLayout; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import com.tangem.cardReader.NfcManager; - -import java.io.IOException; -import java.util.Timer; -import java.util.TimerTask; - -public class VerifyCardActivityFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, NfcAdapter.ReaderCallback { - - Tangem_Card mCard; - TextView tvCardID, tvManufacturer, tvRegistrationDate, tvCardIdentity, tvLastSigned, tvRemainingSignatures, tvReusable, tvOk, tvError, tvMessage, - tvIssuer, tvIssuerData, tvFeatures, tvBlockchain, tvSignedTx, tvSigningMethod, tvFirmware, tvWalletIdentity, tvWallet; - ImageView ivBlockchain, ivPIN, ivPIN2orSecurityDelay, ivDeveloperVersion; - SwipeRefreshLayout mSwipeRefreshLayout; - private NfcManager mNfcManager; - - public VerifyCardActivityFragment() { - - } - - public void onRefresh() { - mSwipeRefreshLayout.setRefreshing(false); - } - - @Override - public View onCreateView(final LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - View v = inflater.inflate(R.layout.fragment_verify_card, container, false); - - mNfcManager = new NfcManager(this.getActivity(), this); - - - // SwipeRefreshLayout - mSwipeRefreshLayout = v.findViewById(R.id.swipe_container); - mSwipeRefreshLayout.setOnRefreshListener(this); - - mCard = new Tangem_Card(getActivity().getIntent().getStringExtra("UID")); - mCard.LoadFromBundle(getActivity().getIntent().getExtras().getBundle("Card")); - tvCardID = v.findViewById(R.id.tvCardID); - - tvLastSigned = v.findViewById(R.id.tvLastSigned); - tvRemainingSignatures = v.findViewById(R.id.tvRemainingSignatures); - - tvReusable = v.findViewById(R.id.tvReusable); - - tvManufacturer = v.findViewById(R.id.tvManufacturerInfo); - - tvCardIdentity = v.findViewById(R.id.tvCardIdentity); - - tvRegistrationDate = v.findViewById(R.id.tvCardRegistredDate); - - ivBlockchain = v.findViewById(R.id.imgBlockchain); - ivPIN = v.findViewById(R.id.imgPIN); - ivPIN2orSecurityDelay = v.findViewById(R.id.imgPIN2orSecurityDelay); - ivDeveloperVersion = v.findViewById(R.id.imgDeveloperVersion); - - tvError = v.findViewById(R.id.tvError); - tvMessage = v.findViewById(R.id.tvMessage); - - tvIssuer = v.findViewById(R.id.tvIssuer); - tvIssuerData = v.findViewById(R.id.tvIssuerData); - - tvFirmware = v.findViewById(R.id.tvFirmware); - tvFeatures = v.findViewById(R.id.tvFeatures); - tvBlockchain = v.findViewById(R.id.tvBlockchain); - - tvSignedTx = v.findViewById(R.id.tvSignedTx); - tvSigningMethod = v.findViewById(R.id.tvSigningMethod); - - tvOk = v.findViewById(R.id.tvOk); - if (tvOk != null) { - tvOk.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent data = prepareResultIntent(); - data.putExtra("modification", "update"); - getActivity().setResult(Activity.RESULT_OK, data); - getActivity().finish(); - } - }); - } - - tvWallet = v.findViewById(R.id.tvWallet); - tvWalletIdentity = v.findViewById(R.id.tvWalletIdentity); - - UpdateViews(); - -// if (NeedUpdate) { -// mSwipeRefreshLayout.setRefreshing(true); -// mSwipeRefreshLayout.postDelayed(new Runnable() { -// @Override -// public void run() { -// onRefresh(); -// } -// }, 1000); -// } - return v; - } - - void UpdateViews() { - try { - if (timerHideErrorAndMessage != null) { - timerHideErrorAndMessage.cancel(); - timerHideErrorAndMessage = null; - } - tvCardID.setText(mCard.getCIDDescription()); - - if (mCard.getError() == null || mCard.getError().isEmpty()) { - tvError.setVisibility(View.GONE); - tvError.setText(""); - } else { - tvError.setVisibility(View.VISIBLE); - tvError.setText(mCard.getError()); - } - if (mCard.getMessage() == null || mCard.getMessage().isEmpty()) { - tvMessage.setVisibility(View.GONE); - tvMessage.setText(""); - } else { - tvMessage.setVisibility(View.VISIBLE); - tvMessage.setText(mCard.getMessage()); - } - - tvManufacturer.setText(mCard.getManufacturer().getOfficialName()); - - if (mCard.isManufacturerConfirmed() && mCard.isCardPublicKeyValid()) { - tvCardIdentity.setText("Attested"); - tvCardIdentity.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); - } else { - tvCardIdentity.setText("Not confirmed"); - tvCardIdentity.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); - } - - tvIssuer.setText(mCard.getIssuerDescription()); - tvIssuerData.setText(mCard.getIssuerDataDescription()); - - tvRegistrationDate.setText(mCard.getPersonalizationDateTimeDescription()); - - //tvBlockchain.setText(mCard.getBlockchain().getOfficialName()); - tvBlockchain.setText(mCard.getBlockchainName()); - ivBlockchain.setImageResource(mCard.getBlockchain().getImageResource(this.getContext(), mCard.getTokenSymbol())); - - if (mCard.isReusable()) { - tvReusable.setText("Reusable"); - } else { - tvReusable.setText("One-off banknote"); - } - - tvSigningMethod.setText(mCard.getSigningMethod().getDescription()); - - if (mCard.getStatus() == Tangem_Card.Status.Loaded || mCard.getStatus() == Tangem_Card.Status.Purged) { - - tvLastSigned.setText(mCard.getLastSignedDescription()); - if (mCard.getRemainingSignatures() == 0) { - tvRemainingSignatures.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); - tvRemainingSignatures.setText("None"); - } else if (mCard.getRemainingSignatures() == 1) { - tvRemainingSignatures.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); - tvRemainingSignatures.setText("Last one!"); - } else if (mCard.getRemainingSignatures() > 1000) { - tvRemainingSignatures.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); - tvRemainingSignatures.setText("Unlimited"); - } else { - tvRemainingSignatures.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); - tvRemainingSignatures.setText(String.valueOf(mCard.getRemainingSignatures())); - } - tvSignedTx.setText(String.valueOf(mCard.getMaxSignatures() - mCard.getRemainingSignatures())); - } else { - tvLastSigned.setText(""); - tvRemainingSignatures.setText(""); - tvSignedTx.setText(""); - } - - tvFirmware.setText(mCard.getFirmwareVersion()); - - String features = ""; - - if (mCard.allowSwapPIN() && mCard.allowSwapPIN2()) { - features += "Allows change PIN1 and PIN2\n"; - } else if (mCard.allowSwapPIN()) { - features += "Allows change PIN1\n"; - } else if (mCard.allowSwapPIN2()) { - features += "Allows change PIN2\n"; - } else { - features += "Fixed PIN1 and PIN2\n"; - } - - if (mCard.needCVC()) { - features += "Requires CVC\n"; - } - - if (mCard.supportDynamicNDEF()) { - features += "Dynamic NDEF for iOS\n"; - } else if (mCard.supportNDEF()) { - features += "NDEF\n"; - } - - if (mCard.supportBlock()) { - features += "Blockable\n"; - } - - if (mCard.supportOnlyOneCommandAtTime()) { - features += "Atomic command mode"; - } - - if (features.endsWith("\n")) { - features = features.substring(0, features.length() - 1); - } - tvFeatures.setText(features); - - if (mCard.useDefaultPIN1()) { - ivPIN.setImageResource(R.drawable.unlock_pin1); - ivPIN.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by default PIN1 code", Toast.LENGTH_LONG).show(); - } - }); - } else { - ivPIN.setImageResource(R.drawable.lock_pin1); - ivPIN.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by user's PIN1 code", Toast.LENGTH_LONG).show(); - } - }); - } - - if (mCard.getPauseBeforePIN2() > 0 && (mCard.useDefaultPIN2() || !mCard.useSmartSecurityDelay())) { - ivPIN2orSecurityDelay.setImageResource(R.drawable.timer); - ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), String.format("This banknote will enforce %.0f seconds security delay for all operations requiring PIN2 code", mCard.getPauseBeforePIN2() / 1000.0), Toast.LENGTH_LONG).show(); - } - }); - - } else if (mCard.useDefaultPIN2()) { - ivPIN2orSecurityDelay.setImageResource(R.drawable.unlock_pin2); - ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by default PIN2 code", Toast.LENGTH_LONG).show(); - } - }); - } else { - ivPIN2orSecurityDelay.setImageResource(R.drawable.lock_pin2); - ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "This banknote is protected by user's PIN2 code", Toast.LENGTH_LONG).show(); - } - }); - } - - - if (mCard.useDevelopersFirmware()) { - ivDeveloperVersion.setImageResource(R.drawable.ic_developer_version); - ivDeveloperVersion.setVisibility(View.VISIBLE); - ivDeveloperVersion.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Toast.makeText(getContext(), "Unlocked banknote, only for development use", Toast.LENGTH_LONG).show(); - } - }); - } else { - ivDeveloperVersion.setVisibility(View.INVISIBLE); - } - - if (mCard.getStatus() == Tangem_Card.Status.Loaded) { - tvWallet.setText(mCard.getShortWalletString()); - if (mCard.isWalletPublicKeyValid()) { - tvWalletIdentity.setText("Possession proved"); - tvWalletIdentity.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); - } else { - tvWalletIdentity.setText("Possession NOT proved"); - tvWalletIdentity.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); - } - } else { - tvWallet.setText("not available"); - tvWalletIdentity.setText("-- -- --"); - } - - timerHideErrorAndMessage = new Timer(); - timerHideErrorAndMessage.schedule(new TimerTask() { - @Override - public void run() { - tvError.post(new Runnable() { - @Override - public void run() { - tvMessage.setVisibility(View.GONE); - tvError.setVisibility(View.GONE); - mCard.setError(null); - mCard.setMessage(null); - } - }); - } - }, 5000); - - - } catch (Exception e) { - e.printStackTrace(); - } - } - - Timer timerHideErrorAndMessage = null; - - public Intent prepareResultIntent() { - Intent data = new Intent(); - data.putExtra("UID", mCard.getUID()); - data.putExtra("Card", mCard.getAsBundle()); - return data; - } - - - @Override - public void onResume() { - super.onResume(); - mNfcManager.onResume(); - } - - @Override - public void onPause() { - super.onPause(); - mNfcManager.onPause(); - } - - @Override - public void onStop() { - super.onStop(); - mNfcManager.onStop(); - } - - @Override - public void onTagDiscovered(Tag tag) { - try { - Log.w(getClass().getName(), "Ignore discovered tag!"); - mNfcManager.IgnoreTag(tag); - } catch (IOException e) { - e.printStackTrace(); - } - } - -} +package com.tangem.presentation.fragment; + +import android.app.Activity; +import android.content.Intent; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.tangem.domain.cardReader.NfcManager; +import com.tangem.wallet.R; +import com.tangem.wallet.Tangem_Card; + +import java.io.IOException; +import java.util.Timer; +import java.util.TimerTask; + +public class VerifyCardActivityFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, NfcAdapter.ReaderCallback { + + Tangem_Card mCard; + TextView tvCardID, tvManufacturer, tvRegistrationDate, tvCardIdentity, tvLastSigned, tvRemainingSignatures, tvReusable, tvOk, tvError, tvMessage, + tvIssuer, tvIssuerData, tvFeatures, tvBlockchain, tvSignedTx, tvSigningMethod, tvFirmware, tvWalletIdentity, tvWallet; + ImageView ivBlockchain, ivPIN, ivPIN2orSecurityDelay, ivDeveloperVersion; + SwipeRefreshLayout mSwipeRefreshLayout; + private NfcManager mNfcManager; + + public VerifyCardActivityFragment() { + + } + + public void onRefresh() { + mSwipeRefreshLayout.setRefreshing(false); + } + + @Override + public View onCreateView(final LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View v = inflater.inflate(R.layout.fragment_verify_card, container, false); + + mNfcManager = new NfcManager(this.getActivity(), this); + + + // SwipeRefreshLayout + mSwipeRefreshLayout = v.findViewById(R.id.swipe_container); + mSwipeRefreshLayout.setOnRefreshListener(this); + + mCard = new Tangem_Card(getActivity().getIntent().getStringExtra("UID")); + mCard.LoadFromBundle(getActivity().getIntent().getExtras().getBundle("Card")); + tvCardID = v.findViewById(R.id.tvCardID); + + tvLastSigned = v.findViewById(R.id.tvLastSigned); + tvRemainingSignatures = v.findViewById(R.id.tvRemainingSignatures); + + tvReusable = v.findViewById(R.id.tvReusable); + + tvManufacturer = v.findViewById(R.id.tvManufacturerInfo); + + tvCardIdentity = v.findViewById(R.id.tvCardIdentity); + + tvRegistrationDate = v.findViewById(R.id.tvCardRegistredDate); + + ivBlockchain = v.findViewById(R.id.imgBlockchain); + ivPIN = v.findViewById(R.id.imgPIN); + ivPIN2orSecurityDelay = v.findViewById(R.id.imgPIN2orSecurityDelay); + ivDeveloperVersion = v.findViewById(R.id.imgDeveloperVersion); + + tvError = v.findViewById(R.id.tvError); + tvMessage = v.findViewById(R.id.tvMessage); + + tvIssuer = v.findViewById(R.id.tvIssuer); + tvIssuerData = v.findViewById(R.id.tvIssuerData); + + tvFirmware = v.findViewById(R.id.tvFirmware); + tvFeatures = v.findViewById(R.id.tvFeatures); + tvBlockchain = v.findViewById(R.id.tvBlockchain); + + tvSignedTx = v.findViewById(R.id.tvSignedTx); + tvSigningMethod = v.findViewById(R.id.tvSigningMethod); + + tvOk = v.findViewById(R.id.tvOk); + if (tvOk != null) { + tvOk.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent data = prepareResultIntent(); + data.putExtra("modification", "update"); + getActivity().setResult(Activity.RESULT_OK, data); + getActivity().finish(); + } + }); + } + + tvWallet = v.findViewById(R.id.tvWallet); + tvWalletIdentity = v.findViewById(R.id.tvWalletIdentity); + + UpdateViews(); + +// if (NeedUpdate) { +// mSwipeRefreshLayout.setRefreshing(true); +// mSwipeRefreshLayout.postDelayed(new Runnable() { +// @Override +// public void run() { +// onRefresh(); +// } +// }, 1000); +// } + return v; + } + + void UpdateViews() { + try { + if (timerHideErrorAndMessage != null) { + timerHideErrorAndMessage.cancel(); + timerHideErrorAndMessage = null; + } + tvCardID.setText(mCard.getCIDDescription()); + + if (mCard.getError() == null || mCard.getError().isEmpty()) { + tvError.setVisibility(View.GONE); + tvError.setText(""); + } else { + tvError.setVisibility(View.VISIBLE); + tvError.setText(mCard.getError()); + } + if (mCard.getMessage() == null || mCard.getMessage().isEmpty()) { + tvMessage.setVisibility(View.GONE); + tvMessage.setText(""); + } else { + tvMessage.setVisibility(View.VISIBLE); + tvMessage.setText(mCard.getMessage()); + } + + tvManufacturer.setText(mCard.getManufacturer().getOfficialName()); + + if (mCard.isManufacturerConfirmed() && mCard.isCardPublicKeyValid()) { + tvCardIdentity.setText("Attested"); + tvCardIdentity.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); + } else { + tvCardIdentity.setText("Not confirmed"); + tvCardIdentity.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); + } + + tvIssuer.setText(mCard.getIssuerDescription()); + tvIssuerData.setText(mCard.getIssuerDataDescription()); + + tvRegistrationDate.setText(mCard.getPersonalizationDateTimeDescription()); + + //tvBlockchain.setText(mCard.getBlockchain().getOfficialName()); + tvBlockchain.setText(mCard.getBlockchainName()); + ivBlockchain.setImageResource(mCard.getBlockchain().getImageResource(this.getContext(), mCard.getTokenSymbol())); + + if (mCard.isReusable()) { + tvReusable.setText("Reusable"); + } else { + tvReusable.setText("One-off banknote"); + } + + tvSigningMethod.setText(mCard.getSigningMethod().getDescription()); + + if (mCard.getStatus() == Tangem_Card.Status.Loaded || mCard.getStatus() == Tangem_Card.Status.Purged) { + + tvLastSigned.setText(mCard.getLastSignedDescription()); + if (mCard.getRemainingSignatures() == 0) { + tvRemainingSignatures.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); + tvRemainingSignatures.setText("None"); + } else if (mCard.getRemainingSignatures() == 1) { + tvRemainingSignatures.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); + tvRemainingSignatures.setText("Last one!"); + } else if (mCard.getRemainingSignatures() > 1000) { + tvRemainingSignatures.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); + tvRemainingSignatures.setText("Unlimited"); + } else { + tvRemainingSignatures.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); + tvRemainingSignatures.setText(String.valueOf(mCard.getRemainingSignatures())); + } + tvSignedTx.setText(String.valueOf(mCard.getMaxSignatures() - mCard.getRemainingSignatures())); + } else { + tvLastSigned.setText(""); + tvRemainingSignatures.setText(""); + tvSignedTx.setText(""); + } + + tvFirmware.setText(mCard.getFirmwareVersion()); + + String features = ""; + + if (mCard.allowSwapPIN() && mCard.allowSwapPIN2()) { + features += "Allows change PIN1 and PIN2\n"; + } else if (mCard.allowSwapPIN()) { + features += "Allows change PIN1\n"; + } else if (mCard.allowSwapPIN2()) { + features += "Allows change PIN2\n"; + } else { + features += "Fixed PIN1 and PIN2\n"; + } + + if (mCard.needCVC()) { + features += "Requires CVC\n"; + } + + if (mCard.supportDynamicNDEF()) { + features += "Dynamic NDEF for iOS\n"; + } else if (mCard.supportNDEF()) { + features += "NDEF\n"; + } + + if (mCard.supportBlock()) { + features += "Blockable\n"; + } + + if (mCard.supportOnlyOneCommandAtTime()) { + features += "Atomic command mode"; + } + + if (features.endsWith("\n")) { + features = features.substring(0, features.length() - 1); + } + tvFeatures.setText(features); + + if (mCard.useDefaultPIN1()) { + ivPIN.setImageResource(R.drawable.unlock_pin1); + ivPIN.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by default PIN1 code", Toast.LENGTH_LONG).show(); + } + }); + } else { + ivPIN.setImageResource(R.drawable.lock_pin1); + ivPIN.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by user's PIN1 code", Toast.LENGTH_LONG).show(); + } + }); + } + + if (mCard.getPauseBeforePIN2() > 0 && (mCard.useDefaultPIN2() || !mCard.useSmartSecurityDelay())) { + ivPIN2orSecurityDelay.setImageResource(R.drawable.timer); + ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), String.format("This banknote will enforce %.0f seconds security delay for all operations requiring PIN2 code", mCard.getPauseBeforePIN2() / 1000.0), Toast.LENGTH_LONG).show(); + } + }); + + } else if (mCard.useDefaultPIN2()) { + ivPIN2orSecurityDelay.setImageResource(R.drawable.unlock_pin2); + ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by default PIN2 code", Toast.LENGTH_LONG).show(); + } + }); + } else { + ivPIN2orSecurityDelay.setImageResource(R.drawable.lock_pin2); + ivPIN2orSecurityDelay.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "This banknote is protected by user's PIN2 code", Toast.LENGTH_LONG).show(); + } + }); + } + + + if (mCard.useDevelopersFirmware()) { + ivDeveloperVersion.setImageResource(R.drawable.ic_developer_version); + ivDeveloperVersion.setVisibility(View.VISIBLE); + ivDeveloperVersion.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(getContext(), "Unlocked banknote, only for development use", Toast.LENGTH_LONG).show(); + } + }); + } else { + ivDeveloperVersion.setVisibility(View.INVISIBLE); + } + + if (mCard.getStatus() == Tangem_Card.Status.Loaded) { + tvWallet.setText(mCard.getShortWalletString()); + if (mCard.isWalletPublicKeyValid()) { + tvWalletIdentity.setText("Possession proved"); + tvWalletIdentity.setTextColor(getResources().getColor(R.color.confirmed, getActivity().getTheme())); + } else { + tvWalletIdentity.setText("Possession NOT proved"); + tvWalletIdentity.setTextColor(getResources().getColor(R.color.not_confirmed, getActivity().getTheme())); + } + } else { + tvWallet.setText("not available"); + tvWalletIdentity.setText("-- -- --"); + } + + timerHideErrorAndMessage = new Timer(); + timerHideErrorAndMessage.schedule(new TimerTask() { + @Override + public void run() { + tvError.post(new Runnable() { + @Override + public void run() { + tvMessage.setVisibility(View.GONE); + tvError.setVisibility(View.GONE); + mCard.setError(null); + mCard.setMessage(null); + } + }); + } + }, 5000); + + + } catch (Exception e) { + e.printStackTrace(); + } + } + + Timer timerHideErrorAndMessage = null; + + public Intent prepareResultIntent() { + Intent data = new Intent(); + data.putExtra("UID", mCard.getUID()); + data.putExtra("Card", mCard.getAsBundle()); + return data; + } + + + @Override + public void onResume() { + super.onResume(); + mNfcManager.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + mNfcManager.onPause(); + } + + @Override + public void onStop() { + super.onStop(); + mNfcManager.onStop(); + } + + @Override + public void onTagDiscovered(Tag tag) { + try { + Log.w(getClass().getName(), "Ignore discovered tag!"); + mNfcManager.IgnoreTag(tag); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/com/tangem/wallet/WalletInfoFragment.java b/app/src/main/java/com/tangem/presentation/fragment/WalletInfoFragment.java similarity index 96% rename from app/src/main/java/com/tangem/wallet/WalletInfoFragment.java rename to app/src/main/java/com/tangem/presentation/fragment/WalletInfoFragment.java index 183b5c9171..77237e7356 100644 --- a/app/src/main/java/com/tangem/wallet/WalletInfoFragment.java +++ b/app/src/main/java/com/tangem/presentation/fragment/WalletInfoFragment.java @@ -1,150 +1,152 @@ -package com.tangem.wallet; - -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.EncodeHintType; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.qrcode.QRCodeWriter; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; - -import java.util.Hashtable; - -import static android.content.Context.CLIPBOARD_SERVICE; - -/** - * A simple {@link Fragment} subclass. - * Activities that contain this fragment must implement the - * {@link OnFragmentInteractionListener} interface - * to handle interaction events. - * Use the {@link WalletInfoFragment#newInstance} factory method to - * create an instance of this fragment. - */ -public class WalletInfoFragment extends Fragment { - - // TODO: Rename and change types of parameters - private Tangem_Card mCard; - - private OnFragmentInteractionListener mListener; - - public WalletInfoFragment() { - // Required empty public constructor - } - - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @return A new instance of fragment WalletInfoFragment. - */ - // TODO: Rename and change types and number of parameters - public static WalletInfoFragment newInstance(Tangem_Card card) { - WalletInfoFragment fragment = new WalletInfoFragment(); - Bundle args = new Bundle(); - args.putString("UID",card.getUID()); - card.SaveToBundle(args); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - mCard = new Tangem_Card(getArguments().getString("UID")); - mCard.LoadFromBundle(getArguments()); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - // Inflate the layout for this fragment - View result=inflater.inflate(R.layout.fragment_wallet_info, container, false); - - ImageView mImage= (ImageView)result.findViewById(R.id.qrWallet); - try { - mImage.setImageBitmap(generateQrCode(mCard.getWallet())); - } catch (WriterException e) { - e.printStackTrace(); - } - TextView mText=(TextView)result.findViewById(R.id.strWallet); - mText.setText(mCard.getWallet()); - - mText.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - TextView mText = (TextView) view; - ClipboardManager clipboard = (ClipboardManager)getActivity().getSystemService(CLIPBOARD_SERVICE); - clipboard.setPrimaryClip(ClipData.newPlainText(mText.getText(), mText.getText())); - Toast.makeText(getContext(),"Copied to clipboard",Toast.LENGTH_LONG).show(); - } - }); - return result; - } - - public static Bitmap generateQrCode(String myCodeText) throws WriterException { - Hashtable hintMap = new Hashtable(); - hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // H = 30% damage - - QRCodeWriter qrCodeWriter = new QRCodeWriter(); - - int size = 256; - - BitMatrix bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hintMap); - int width = bitMatrix.getWidth(); - Bitmap bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565); - for (int x = 0; x < width; x++) { - for (int y = 0; y < width; y++) { - bmp.setPixel(y, x, bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE); - } - } - return bmp; - } - - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnFragmentInteractionListener) { - mListener = (OnFragmentInteractionListener) context; - } else { - throw new RuntimeException(context.toString() - + " must implement OnFragmentInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - /** - * This interface must be implemented by activities that contain this - * fragment to allow an interaction in this fragment to be communicated - * to the activity and potentially other fragments contained in that - * activity. - *

- * See the Android Training lesson Communicating with Other Fragments for more information. - */ - public interface OnFragmentInteractionListener { - // TODO: Update argument type and name -// void onFragmentInteraction(Uri uri); - } -} +package com.tangem.presentation.fragment; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import com.tangem.wallet.R; +import com.tangem.wallet.Tangem_Card; + +import java.util.Hashtable; + +import static android.content.Context.CLIPBOARD_SERVICE; + +/** + * A simple {@link Fragment} subclass. + * Activities that contain this fragment must implement the + * {@link OnFragmentInteractionListener} interface + * to handle interaction events. + * Use the {@link WalletInfoFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class WalletInfoFragment extends Fragment { + + // TODO: Rename and change types of parameters + private Tangem_Card mCard; + + private OnFragmentInteractionListener mListener; + + public WalletInfoFragment() { + // Required empty public constructor + } + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @return A new instance of fragment WalletInfoFragment. + */ + // TODO: Rename and change types and number of parameters + public static WalletInfoFragment newInstance(Tangem_Card card) { + WalletInfoFragment fragment = new WalletInfoFragment(); + Bundle args = new Bundle(); + args.putString("UID",card.getUID()); + card.SaveToBundle(args); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mCard = new Tangem_Card(getArguments().getString("UID")); + mCard.LoadFromBundle(getArguments()); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View result=inflater.inflate(R.layout.fragment_wallet_info, container, false); + + ImageView mImage= (ImageView)result.findViewById(R.id.qrWallet); + try { + mImage.setImageBitmap(generateQrCode(mCard.getWallet())); + } catch (WriterException e) { + e.printStackTrace(); + } + TextView mText=(TextView)result.findViewById(R.id.strWallet); + mText.setText(mCard.getWallet()); + + mText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + TextView mText = (TextView) view; + ClipboardManager clipboard = (ClipboardManager)getActivity().getSystemService(CLIPBOARD_SERVICE); + clipboard.setPrimaryClip(ClipData.newPlainText(mText.getText(), mText.getText())); + Toast.makeText(getContext(),"Copied to clipboard",Toast.LENGTH_LONG).show(); + } + }); + return result; + } + + public static Bitmap generateQrCode(String myCodeText) throws WriterException { + Hashtable hintMap = new Hashtable(); + hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // H = 30% damage + + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + + int size = 256; + + BitMatrix bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hintMap); + int width = bitMatrix.getWidth(); + Bitmap bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565); + for (int x = 0; x < width; x++) { + for (int y = 0; y < width; y++) { + bmp.setPixel(y, x, bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE); + } + } + return bmp; + } + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof OnFragmentInteractionListener) { + mListener = (OnFragmentInteractionListener) context; + } else { + throw new RuntimeException(context.toString() + + " must implement OnFragmentInteractionListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + /** + * This interface must be implemented by activities that contain this + * fragment to allow an interaction in this fragment to be communicated + * to the activity and potentially other fragments contained in that + * activity. + *

+ * See the Android Training lesson Communicating with Other Fragments for more information. + */ + public interface OnFragmentInteractionListener { + // TODO: Update argument type and name +// void onFragmentInteraction(Uri uri); + } +} diff --git a/app/src/main/java/com/tangem/wallet/BTCUtils.java b/app/src/main/java/com/tangem/wallet/BTCUtils.java index 1f298fe57b..39f2ad8884 100644 --- a/app/src/main/java/com/tangem/wallet/BTCUtils.java +++ b/app/src/main/java/com/tangem/wallet/BTCUtils.java @@ -6,49 +6,18 @@ package com.tangem.wallet; import android.util.Log; -import com.tangem.cardReader.Util; - -import org.spongycastle.asn1.ASN1EncodableVector; -import org.spongycastle.asn1.ASN1Integer; -import org.spongycastle.asn1.DERSequence; -import org.spongycastle.asn1.DERSequenceGenerator; -import org.spongycastle.asn1.sec.SECNamedCurves; -import org.spongycastle.asn1.x9.X9ECParameters; -import org.spongycastle.asn1.x9.X9IntegerConverter; -import org.spongycastle.crypto.params.ECDomainParameters; -import org.spongycastle.crypto.params.ECPrivateKeyParameters; -import org.spongycastle.crypto.params.ECPublicKeyParameters; -import org.spongycastle.crypto.signers.ECDSASigner; -import org.spongycastle.jce.ECNamedCurveTable; -import org.spongycastle.jce.spec.ECNamedCurveParameterSpec; -import org.spongycastle.jce.spec.ECPrivateKeySpec; -import org.spongycastle.jce.spec.ECPublicKeySpec; -import org.spongycastle.math.ec.ECAlgorithms; -import org.spongycastle.math.ec.ECCurve; -import org.spongycastle.math.ec.ECPoint; +import com.tangem.domain.cardReader.Util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyFactory; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.text.Format; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Stack; -import java.util.regex.Pattern; - -import static org.bitcoinj.core.ECKey.CURVE; -import static org.bitcoinj.core.ECKey.HALF_CURVE_ORDER; @SuppressWarnings({"WeakerAccess", "TryWithIdenticalCatches", "unused"}) public final class BTCUtils { diff --git a/app/src/main/java/com/tangem/wallet/Blockchain.java b/app/src/main/java/com/tangem/wallet/Blockchain.java index 53960c684c..b92f1339c0 100644 --- a/app/src/main/java/com/tangem/wallet/Blockchain.java +++ b/app/src/main/java/com/tangem/wallet/Blockchain.java @@ -1,19 +1,6 @@ package com.tangem.wallet; -import android.net.Uri; - import com.google.common.base.Strings; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.Util; - -import org.bitcoinj.core.Base58; - -import java.nio.ByteBuffer; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; /** * Created by dvol on 06.08.2017. diff --git a/app/src/main/java/com/tangem/wallet/BtcCashEngine.java b/app/src/main/java/com/tangem/wallet/BtcCashEngine.java index bf8850105a..b0b3fdaa56 100644 --- a/app/src/main/java/com/tangem/wallet/BtcCashEngine.java +++ b/app/src/main/java/com/tangem/wallet/BtcCashEngine.java @@ -2,9 +2,9 @@ package com.tangem.wallet; import android.net.Uri; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.TLV; -import com.tangem.cardReader.Util; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.TLV; +import com.tangem.domain.cardReader.Util; import java.io.ByteArrayOutputStream; import java.math.BigDecimal; diff --git a/app/src/main/java/com/tangem/wallet/BtcEngine.java b/app/src/main/java/com/tangem/wallet/BtcEngine.java index 1181f2e6db..2e6a4a1029 100644 --- a/app/src/main/java/com/tangem/wallet/BtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/BtcEngine.java @@ -2,9 +2,9 @@ package com.tangem.wallet; import android.net.Uri; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.TLV; -import com.tangem.cardReader.Util; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.TLV; +import com.tangem.domain.cardReader.Util; import java.io.ByteArrayOutputStream; import java.math.BigDecimal; diff --git a/app/src/main/java/com/tangem/wallet/CoinEngine.java b/app/src/main/java/com/tangem/wallet/CoinEngine.java index 9796775fcb..cdb6688911 100644 --- a/app/src/main/java/com/tangem/wallet/CoinEngine.java +++ b/app/src/main/java/com/tangem/wallet/CoinEngine.java @@ -2,7 +2,7 @@ package com.tangem.wallet; import android.net.Uri; -import com.tangem.cardReader.CardProtocol; +import com.tangem.domain.cardReader.CardProtocol; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; diff --git a/app/src/main/java/com/tangem/wallet/CoinEngineFactory.java b/app/src/main/java/com/tangem/wallet/CoinEngineFactory.java index ba8a649112..e1d7f8ca90 100644 --- a/app/src/main/java/com/tangem/wallet/CoinEngineFactory.java +++ b/app/src/main/java/com/tangem/wallet/CoinEngineFactory.java @@ -5,16 +5,14 @@ package com.tangem.wallet; */ public class CoinEngineFactory { - public static CoinEngine Create(Blockchain chain) - { - if(Blockchain.BitcoinCash == chain || Blockchain.BitcoinCashTestNet == chain) { + public static CoinEngine Create(Blockchain chain) { + if (Blockchain.BitcoinCash == chain || Blockchain.BitcoinCashTestNet == chain) { return new BtcCashEngine(); - }else if(Blockchain.Bitcoin == chain || Blockchain.BitcoinTestNet == chain) { + } else if (Blockchain.Bitcoin == chain || Blockchain.BitcoinTestNet == chain) { return new BtcEngine(); //TODO: ВРЕМЕНГГО!!!! - }else if(Blockchain.Ethereum == chain || Blockchain.EthereumTestNet == chain) { + } else if (Blockchain.Ethereum == chain || Blockchain.EthereumTestNet == chain) { return new EthEngine(); - } - else if(Blockchain.Token == chain) { + } else if (Blockchain.Token == chain) { return new TokenEngine(); } else { return null; diff --git a/app/src/main/java/com/tangem/wallet/CryptoUtil.java b/app/src/main/java/com/tangem/wallet/CryptoUtil.java index 6500a6f7ed..bc09335f4c 100644 --- a/app/src/main/java/com/tangem/wallet/CryptoUtil.java +++ b/app/src/main/java/com/tangem/wallet/CryptoUtil.java @@ -2,7 +2,7 @@ package com.tangem.wallet; import android.util.Log; -import com.tangem.cardReader.Util; +import com.tangem.domain.cardReader.Util; import org.spongycastle.asn1.ASN1EncodableVector; import org.spongycastle.asn1.ASN1Integer; diff --git a/app/src/main/java/com/tangem/wallet/EthEngine.java b/app/src/main/java/com/tangem/wallet/EthEngine.java index 780339247f..46f0e9acab 100644 --- a/app/src/main/java/com/tangem/wallet/EthEngine.java +++ b/app/src/main/java/com/tangem/wallet/EthEngine.java @@ -3,8 +3,8 @@ package com.tangem.wallet; import android.net.Uri; import android.util.Log; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.TLV; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.TLV; import org.bitcoinj.core.ECKey; diff --git a/app/src/main/java/com/tangem/wallet/Issuer.java b/app/src/main/java/com/tangem/wallet/Issuer.java index 39d55271e5..a6dd2539c2 100644 --- a/app/src/main/java/com/tangem/wallet/Issuer.java +++ b/app/src/main/java/com/tangem/wallet/Issuer.java @@ -1,15 +1,9 @@ package com.tangem.wallet; -import com.tangem.cardReader.CardCrypto; +import com.tangem.domain.cardReader.CardCrypto; -import org.spongycastle.jce.ECNamedCurveTable; -import org.spongycastle.jce.spec.ECNamedCurveParameterSpec; - -import java.math.BigInteger; import java.util.Arrays; -import static com.tangem.cardReader.CardCrypto.*; - /** * Created by dvol on 14.11.2017. */ diff --git a/app/src/main/java/com/tangem/wallet/Logger.java b/app/src/main/java/com/tangem/wallet/Logger.java index daf5c146a6..559356ebd8 100644 --- a/app/src/main/java/com/tangem/wallet/Logger.java +++ b/app/src/main/java/com/tangem/wallet/Logger.java @@ -3,7 +3,7 @@ package com.tangem.wallet; import android.content.Context; import android.util.Log; -import com.tangem.cardReader.Util; +import com.tangem.domain.cardReader.Util; import java.io.BufferedReader; import java.io.BufferedWriter; diff --git a/app/src/main/java/com/tangem/wallet/PINStorage.java b/app/src/main/java/com/tangem/wallet/PINStorage.java index bd4c9836e4..04b4878d7c 100644 --- a/app/src/main/java/com/tangem/wallet/PINStorage.java +++ b/app/src/main/java/com/tangem/wallet/PINStorage.java @@ -5,7 +5,7 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.util.Base64; -import com.tangem.cardReader.CardProtocol; +import com.tangem.domain.cardReader.CardProtocol; import java.util.ArrayList; import java.util.List; @@ -31,7 +31,7 @@ public class PINStorage { } - static List getPINs() { + public static List getPINs() { ArrayList result = new ArrayList<>(); if (mLastUsedPIN != null) result.add(mLastUsedPIN); if (mEncryptedPIN != null && !result.contains(mEncryptedPIN)) result.add(mEncryptedPIN); @@ -41,7 +41,7 @@ public class PINStorage { return result; } - static void setLastUsedPIN(String PIN) { + public static void setLastUsedPIN(String PIN) { mLastUsedPIN = PIN; } diff --git a/app/src/main/java/com/tangem/wallet/Tangem_Card.java b/app/src/main/java/com/tangem/wallet/Tangem_Card.java index 589761a3ae..b18187d8a2 100644 --- a/app/src/main/java/com/tangem/wallet/Tangem_Card.java +++ b/app/src/main/java/com/tangem/wallet/Tangem_Card.java @@ -1,21 +1,16 @@ package com.tangem.wallet; import android.os.Bundle; -import android.util.Log; import com.google.common.base.Strings; -import com.tangem.cardReader.SettingsMask; -import com.tangem.cardReader.Util; +import com.tangem.domain.cardReader.SettingsMask; +import com.tangem.domain.cardReader.Util; -import java.math.BigDecimal; import java.math.BigInteger; -import java.math.RoundingMode; -import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; -import java.util.StringJoiner; /** * Created by dvol on 16.07.2017. diff --git a/app/src/main/java/com/tangem/wallet/TokenEngine.java b/app/src/main/java/com/tangem/wallet/TokenEngine.java index 6faad29a6a..79c92b1d6e 100644 --- a/app/src/main/java/com/tangem/wallet/TokenEngine.java +++ b/app/src/main/java/com/tangem/wallet/TokenEngine.java @@ -4,8 +4,8 @@ import android.net.Uri; import android.util.Log; import com.google.common.base.Strings; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.TLV; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.TLV; import org.bitcoinj.core.ECKey; @@ -24,51 +24,46 @@ import static com.tangem.wallet.FormatUtil.GetDecimalFormat; * Created by Ilia on 20.03.2018. */ -public class TokenEngine extends CoinEngine{ - public String GetNextNode(Tangem_Card mCard) - { +public class TokenEngine extends CoinEngine { + public String GetNextNode(Tangem_Card mCard) { return "abc1.hsmiths.com"; } - public int GetNextNodePort(Tangem_Card mCard) - { + + public int GetNextNodePort(Tangem_Card mCard) { return 60001; } - public String GetNode(Tangem_Card mCard) - { + + public String GetNode(Tangem_Card mCard) { return "abc1.hsmiths.com"; } - public int GetNodePort(Tangem_Card mCard) - { + + public int GetNodePort(Tangem_Card mCard) { return 60001; } - public void SwitchNode(Tangem_Card mCard) - { + + public void SwitchNode(Tangem_Card mCard) { } - public boolean AwaitingConfirmation(Tangem_Card card) - { + + public boolean AwaitingConfirmation(Tangem_Card card) { return false; } - public boolean InOutPutVisible() - { + public boolean InOutPutVisible() { return false; } - public String GetBalanceCurrency(Tangem_Card card) - { + public String GetBalanceCurrency(Tangem_Card card) { String currency = card.getTokenSymbol(); - if(Strings.isNullOrEmpty(currency)) + if (Strings.isNullOrEmpty(currency)) return "NoN"; return currency; } - public String GetFeeCurrency() - { + public String GetFeeCurrency() { return "Gwei"; } - BigDecimal convertToEth(String value) - { + BigDecimal convertToEth(String value) { BigInteger m = new BigInteger(value, 10); BigDecimal n = new BigDecimal(m); BigDecimal d = n.divide(new BigDecimal("1000000000000000000")); @@ -77,17 +72,15 @@ public class TokenEngine extends CoinEngine{ } - public int GetTokenDecimals(Tangem_Card card) - { + public int GetTokenDecimals(Tangem_Card card) { return card.getTokensDecimal(); } - public String GetContractAddress(Tangem_Card card) - { + public String GetContractAddress(Tangem_Card card) { return card.getContractAddress(); } - public boolean IsNeedCheckNode() - { + + public boolean IsNeedCheckNode() { return false; } @@ -96,21 +89,18 @@ public class TokenEngine extends CoinEngine{ return false; } - if(!address.startsWith("0x")&&!address.startsWith("0X")) - { + if (!address.startsWith("0x") && !address.startsWith("0X")) { return false; } - if(address.length()!=42) - { + if (address.length() != 42) { return false; } return true; } - public String GetBalanceAlterValue(Tangem_Card mCard) - { + public String GetBalanceAlterValue(Tangem_Card mCard) { String dec = mCard.getDecimalBalanceAlter(); BigDecimal d = convertToEth(dec); String s = d.toString(); @@ -121,9 +111,8 @@ public class TokenEngine extends CoinEngine{ return output; } - public String GetBalanceValue(Tangem_Card mCard) - { - if(!HasBalanceInfo(mCard)) + public String GetBalanceValue(Tangem_Card mCard) { + if (!HasBalanceInfo(mCard)) return "-- -- -- " + GetBalanceCurrency(mCard); String dec = mCard.getDecimalBalance(); @@ -138,28 +127,24 @@ public class TokenEngine extends CoinEngine{ return output; } - public boolean CheckAmount(Tangem_Card card, String amount) throws Exception - { + public boolean CheckAmount(Tangem_Card card, String amount) throws Exception { DecimalFormat decimalFormat = GetDecimalFormat(); BigDecimal amountValue = (BigDecimal) decimalFormat.parse(amount); //new BigDecimal(strAmount); BigDecimal maxValue = new BigDecimal(GetBalanceValue(card)); - if(amountValue.compareTo(maxValue) > 0 ) - { + if (amountValue.compareTo(maxValue) > 0) { return false; } return true; } - public Long GetBalanceLong(Tangem_Card mCard) - { + public Long GetBalanceLong(Tangem_Card mCard) { return mCard.getBalance(); } - public boolean IsBalanceAlterNotZero(Tangem_Card card) - { + public boolean IsBalanceAlterNotZero(Tangem_Card card) { String balance = card.getDecimalBalanceAlter(); - if(balance == null || balance == "") + if (balance == null || balance == "") return false; BigDecimal bi = new BigDecimal(balance); @@ -170,10 +155,9 @@ public class TokenEngine extends CoinEngine{ return true; } - public boolean IsBalanceNotZero(Tangem_Card card) - { + public boolean IsBalanceNotZero(Tangem_Card card) { String balance = card.getDecimalBalance(); - if(balance == null || balance == "") + if (balance == null || balance == "") return false; BigDecimal bi = new BigDecimal(balance); @@ -184,21 +168,20 @@ public class TokenEngine extends CoinEngine{ return true; } - public boolean HasBalanceInfo(Tangem_Card card) - { + public boolean HasBalanceInfo(Tangem_Card card) { String balance = card.getDecimalBalance(); - if(balance == null || balance == "") + if (balance == null || balance == "") return false; String balanceEx = card.getDecimalBalanceAlter(); - if(balanceEx == null || balanceEx == "") + if (balanceEx == null || balanceEx == "") return false; return true; } @Override public String GetBalanceEquivalent(Tangem_Card mCard) { - if(!HasBalanceInfo(mCard)){ + if (!HasBalanceInfo(mCard)) { return "-- -- -- "; } String dec = mCard.getDecimalBalance(); @@ -208,7 +191,7 @@ public class TokenEngine extends CoinEngine{ @Override public String GetBalance(Tangem_Card mCard) { - if(!HasBalanceInfo(mCard)){ + if (!HasBalanceInfo(mCard)) { return "-- -- -- " + GetBalanceCurrency(mCard); } @@ -218,15 +201,12 @@ public class TokenEngine extends CoinEngine{ } - - - public String GetBalanceWithAlter(Tangem_Card mCard) - { + public String GetBalanceWithAlter(Tangem_Card mCard) { //return GetBalance(mCard) + "\n(" + GetBalanceAlterValue(mCard) + " ETH)"; return " " + GetBalance(mCard) + "
+ " + GetBalanceAlterValue(mCard) + " ETH for gas"; } - public String calculateAddress(Tangem_Card mCard, byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException { + public String calculateAddress(Tangem_Card mCard, byte[] pkUncompressed) throws NoSuchProviderException, NoSuchAlgorithmException { Keccak256 kec = new Keccak256(); int lenPk = pkUncompressed.length; if (lenPk < 2) { @@ -262,35 +242,29 @@ public class TokenEngine extends CoinEngine{ } - public String GetAmountEqualentDescriptor(Tangem_Card mCard, String value) - { + public String GetAmountEqualentDescriptor(Tangem_Card mCard, String value) { BigDecimal d = new BigDecimal(value); return EthEngine.getAmountEquivalentDescriptionETH(d, mCard.getRate()); } - public String GetFeeEqualentDescriptor(Tangem_Card mCard, String value) - { + public String GetFeeEqualentDescriptor(Tangem_Card mCard, String value) { BigDecimal d = new BigDecimal(value); return EthEngine.getAmountEquivalentDescriptionETH(d, mCard.getRateAlter()); } - public Uri getShareWalletURIExplorer(Tangem_Card mCard) - { - return Uri.parse("https://etherscan.io/token/"+GetContractAddress(mCard)+"?a=" + mCard.getWallet()); + public Uri getShareWalletURIExplorer(Tangem_Card mCard) { + return Uri.parse("https://etherscan.io/token/" + GetContractAddress(mCard) + "?a=" + mCard.getWallet()); } - public Uri getShareWalletURI(Tangem_Card mCard) - { + public Uri getShareWalletURI(Tangem_Card mCard) { return Uri.parse("" + mCard.getWallet()); } - public boolean CheckUnspentTransaction(Tangem_Card mCard) - { + public boolean CheckUnspentTransaction(Tangem_Card mCard) { return true; } - public boolean CheckAmountValie(Tangem_Card mCard, String amountValue, String feeValue, Long minFeeInInternalUnits) - { + public boolean CheckAmountValie(Tangem_Card mCard, String amountValue, String feeValue, Long minFeeInInternalUnits) { Long fee = null; BigDecimal amount = null; try { @@ -301,14 +275,14 @@ public class TokenEngine extends CoinEngine{ return false; } - if(fee == null || amount == null) + if (fee == null || amount == null) return false; - if(fee == 0 || amount.compareTo(BigDecimal.ZERO) == 0) + if (fee == 0 || amount.compareTo(BigDecimal.ZERO) == 0) return false; - if(fee < minFeeInInternalUnits) + if (fee < minFeeInInternalUnits) return false; @@ -322,8 +296,7 @@ public class TokenEngine extends CoinEngine{ return true; } - public String EvaluteFeeEquivalent(Tangem_Card mCard, String fee) - { + public String EvaluteFeeEquivalent(Tangem_Card mCard, String fee) { BigDecimal gweFee = new BigDecimal(fee); gweFee = gweFee.divide(new BigDecimal("1000000000")); gweFee = gweFee.setScale(18, RoundingMode.DOWN); @@ -334,7 +307,7 @@ public class TokenEngine extends CoinEngine{ BigInteger nonceValue = mCard.GetConfirmTXCount(); byte[] pbKey = mCard.getWalletPublicKey(); - boolean flag = (mCard.getSigningMethod()== Tangem_Card.SigningMethod.Sign_Hash_Validated_By_Issuer); + boolean flag = (mCard.getSigningMethod() == Tangem_Card.SigningMethod.Sign_Hash_Validated_By_Issuer); Issuer issuer = mCard.getIssuer(); @@ -353,8 +326,6 @@ public class TokenEngine extends CoinEngine{ BigInteger amount = amountDec.toBigInteger(); //new BigInteger(amountValue, 10); - - //amount = amount.subtract(fee); BigInteger nonce = nonceValue; @@ -384,12 +355,11 @@ public class TokenEngine extends CoinEngine{ amountLeadZero = amountLeadZero.substring(2); } - while(amountLeadZero.length() < 64) - { + while (amountLeadZero.length() < 64) { amountLeadZero = "0" + amountLeadZero; } - String cmd = "a9059cbb000000000000000000000000"+to+amountLeadZero; //TODO only for BAT + String cmd = "a9059cbb000000000000000000000000" + to + amountLeadZero; //TODO only for BAT byte[] data = BTCUtils.fromHex(cmd); @@ -416,8 +386,7 @@ public class TokenEngine extends CoinEngine{ boolean f = ECKey.verify(for_hash, new ECKey.ECDSASignature(r, s), pbKey); - if(!f) - { + if (!f) { Log.e("ETH-CHECK", "Sign Failed."); } diff --git a/app/src/main/java/com/tangem/wallet/VerifyCardTask.java b/app/src/main/java/com/tangem/wallet/VerifyCardTask.java index 3b827b4419..b11e4c8566 100644 --- a/app/src/main/java/com/tangem/wallet/VerifyCardTask.java +++ b/app/src/main/java/com/tangem/wallet/VerifyCardTask.java @@ -4,8 +4,8 @@ import android.content.Context; import android.nfc.tech.IsoDep; import android.util.Log; -import com.tangem.cardReader.CardProtocol; -import com.tangem.cardReader.NfcManager; +import com.tangem.domain.cardReader.CardProtocol; +import com.tangem.domain.cardReader.NfcManager; /** * Created by dvol on 04.02.2018. diff --git a/app/src/main/java/com/tangem/wallet/VerticalTextView.java b/app/src/main/java/com/tangem/wallet/VerticalTextView.java deleted file mode 100644 index d63b26cdb2..0000000000 --- a/app/src/main/java/com/tangem/wallet/VerticalTextView.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.tangem.wallet; - -import android.content.Context; -import android.graphics.Canvas; -import android.text.TextPaint; -import android.util.AttributeSet; -import android.view.Gravity; -import android.widget.TextView; - -public class VerticalTextView extends TextView -{ - final boolean topDown; - - public VerticalTextView( Context context, - AttributeSet attrs ) - { - super( context, attrs ); - final int gravity = getGravity(); - if ( Gravity.isVertical( gravity ) - && ( gravity & Gravity.VERTICAL_GRAVITY_MASK ) - == Gravity.BOTTOM ) - { - setGravity( - ( gravity & Gravity.HORIZONTAL_GRAVITY_MASK ) - | Gravity.TOP ); - topDown = false; - } - else - { - topDown = true; - } - } - - @Override - protected void onMeasure( int widthMeasureSpec, - int heightMeasureSpec ) - { - super.onMeasure( heightMeasureSpec, - widthMeasureSpec ); - setMeasuredDimension( getMeasuredHeight(), - getMeasuredWidth() ); - } - - @Override - protected void onDraw( Canvas canvas ) - { - TextPaint textPaint = getPaint(); - textPaint.setColor( getCurrentTextColor() ); - textPaint.drawableState = getDrawableState(); - - canvas.save(); - - if ( topDown ) - { - canvas.translate( getWidth(), 0 ); - canvas.rotate( 90 ); - } - else - { - canvas.translate( 0, getHeight() ); - canvas.rotate( -90 ); - } - - canvas.translate( getCompoundPaddingLeft(), - getExtendedPaddingTop() ); - - getLayout().draw( canvas ); - canvas.restore(); - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/card_list_item.xml b/app/src/main/res/layout/card_list_item.xml index bf9708244b..1c99e02a76 100644 --- a/app/src/main/res/layout/card_list_item.xml +++ b/app/src/main/res/layout/card_list_item.xml @@ -56,7 +56,7 @@ android:alpha="0.5" android:background="@color/white" /> - diff --git a/app/src/main/res/layout/fragment_verify_card.xml b/app/src/main/res/layout/fragment_verify_card.xml index b1f7dbfbb7..e565ca8726 100644 --- a/app/src/main/res/layout/fragment_verify_card.xml +++ b/app/src/main/res/layout/fragment_verify_card.xml @@ -7,7 +7,7 @@ android:background="@color/white" android:orientation="vertical" android:padding="0dp" - tools:context="com.tangem.wallet.VerifyCardActivityFragment" + tools:context="com.tangem.wallet.com.tangem.presentation.fragment.VerifyCardActivityFragment" tools:showIn="@layout/activity_verify_card"> + tools:context="com.tangem.wallet.com.tangem.presentation.fragment.WalletInfoFragment">