From cd00923ebc79ccbc9a0d67215147e974be78f805 Mon Sep 17 00:00:00 2001 From: hvarona Date: Tue, 23 Oct 2018 23:28:53 -0400 Subject: [PATCH 1/6] Added Get Next Bitcoin and Bitcoin like coins request and manager --- .../apigenerator/InsightApiGenerator.java | 4 +- .../crystalwallet/dao/BitcoinAddressDao.java | 3 + .../manager/GeneralAccountManager.java | 68 ++++++++++----- .../requestmanagers/BitcoinSendRequest.java | 2 + .../GeneralAccountSendRequest.java | 85 ------------------- .../NextBitcoinAccountAddressRequest.java | 10 +++ 6 files changed, 65 insertions(+), 107 deletions(-) delete mode 100644 app/src/main/java/cy/agorise/crystalwallet/requestmanagers/GeneralAccountSendRequest.java diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java index 7a5505f..d6229c9 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java @@ -18,11 +18,9 @@ public class InsightApiGenerator { * Fecth all the transaciton for a giving address * @param cryptoCoin the crypto net of the address * @param address The address String - * @param request the request api to response * @param subscribe If needs to follow the address (Real time) */ - public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, - ApiRequest request, boolean subscribe){ + public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, boolean subscribe){ if(!transactionGetters.containsKey(cryptoCoin)){ transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet()))); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java b/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java index 5260595..51088c6 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java +++ b/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java @@ -31,6 +31,9 @@ public interface BitcoinAddressDao { @Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'true' ") long getLastChangeAddress(long accountId); + @Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'false' ") + long getLastExternalAddress(long accountId); + @Insert(onConflict = OnConflictStrategy.REPLACE) public long[] insertBitcoinAddresses(BitcoinAddress... addresses); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java index 3895f73..01ad0e6 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java @@ -1,6 +1,5 @@ package cy.agorise.crystalwallet.manager; -import android.accounts.Account; import android.content.Context; import org.bitcoinj.core.Address; @@ -26,7 +25,6 @@ import cy.agorise.crystalwallet.apigenerator.InsightApiGenerator; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout; -import cy.agorise.crystalwallet.application.CrystalApplication; import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.enums.CryptoCoin; import cy.agorise.crystalwallet.models.AccountSeed; @@ -37,11 +35,11 @@ import cy.agorise.crystalwallet.models.CryptoCoinBalance; import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoNetAccount; -import cy.agorise.crystalwallet.models.GTxIO; -import cy.agorise.crystalwallet.models.GeneralCoinAddress; +import cy.agorise.crystalwallet.requestmanagers.BitcoinSendRequest; +import cy.agorise.crystalwallet.requestmanagers.CreateBitcoinAccountRequest; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestsListener; -import cy.agorise.crystalwallet.requestmanagers.GeneralAccountSendRequest; +import cy.agorise.crystalwallet.requestmanagers.NextBitcoinAccountAddressRequest; import cy.agorise.graphenej.Util; public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener { @@ -85,9 +83,14 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf @Override public void onNewRequest(CryptoNetInfoRequest request) { - if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){ - if(request instanceof GeneralAccountSendRequest){ - this.send((GeneralAccountSendRequest)request); + //if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){ + if(request.getCoin().equals(this.cryptoCoin)){ + if(request instanceof BitcoinSendRequest) { + this.send((BitcoinSendRequest) request); + }else if(request instanceof CreateBitcoinAccountRequest){ + + }else if(request instanceof NextBitcoinAccountAddressRequest){ + this.getNextAddress((NextBitcoinAccountAddressRequest) request); }else{ System.out.println("Invalid " +this.cryptoCoin.getLabel() + " request "); } @@ -255,7 +258,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance); } - public void send(final GeneralAccountSendRequest request){ + public void send(final BitcoinSendRequest request){ //TODO check server connection //TODO validate to address @@ -271,19 +274,19 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); db.bitcoinTransactionDao(); - List utxos = getUtxos(request.getAccount().getId(),db); + List utxos = getUtxos(request.getSourceAccount().getId(),db); if(currentAmount< request.getAmount() + fee){ - request.setStatus(GeneralAccountSendRequest.StatusCode.NO_BALANCE); + request.setStatus(BitcoinSendRequest.StatusCode.NO_BALANCE); return; } - AccountSeed seed = db.accountSeedDao().findById(request.getAccount().getSeedId()); + AccountSeed seed = db.accountSeedDao().findById(request.getSourceAccount().getSeedId()); DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(), new ChildNumber(44, true)); DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey, new ChildNumber(cryptoCoin.getCoinNumber(), true)); DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey, - new ChildNumber(request.getAccount().getAccountIndex(), true)); + new ChildNumber(request.getSourceAccount().getAccountIndex(), true)); DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, new ChildNumber(0, false)); DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey, @@ -309,7 +312,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf //Change address long remain = currentAmount - request.getAmount() - fee; if( remain > 0 ) { - long index = db.bitcoinAddressDao().getLastChangeAddress(request.getAccount().getId()); + long index = db.bitcoinAddressDao().getLastChangeAddress(request.getSourceAccount().getId()); BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index); Address changeAddr; if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){ @@ -323,7 +326,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf } btAddress = new BitcoinAddress(); btAddress.setIndex(index); - btAddress.setAccountId(request.getAccount().getId()); + btAddress.setAccountId(request.getSourceAccount().getId()); btAddress.setChange(true); btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString()); db.bitcoinAddressDao().insertBitcoinAddresses(btAddress); @@ -342,7 +345,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf if(btAddress.isChange()){ addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)); }else{ - addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), true)); + addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) btAddress.getIndex(), true)); } tx.addSignedInput(outPoint, script, addrKey, Transaction.SigHash.ALL, true); } @@ -350,24 +353,51 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf InsightApiGenerator.broadcastTransaction(cryptoCoin,Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() { @Override public void success(Object answer, int idPetition) { - request.setStatus(GeneralAccountSendRequest.StatusCode.SUCCEEDED); + request.setStatus(BitcoinSendRequest.StatusCode.SUCCEEDED); } @Override public void fail(int idPetition) { - request.setStatus(GeneralAccountSendRequest.StatusCode.PETITION_FAILED); + request.setStatus(BitcoinSendRequest.StatusCode.PETITION_FAILED); } })); } @Override public void fail(int idPetition) { - request.setStatus(GeneralAccountSendRequest.StatusCode.NO_FEE); + request.setStatus(BitcoinSendRequest.StatusCode.NO_FEE); } })); } + private void getNextAddress(NextBitcoinAccountAddressRequest request){ + CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); + long index = db.bitcoinAddressDao().getLastExternalAddress(request.getAccount().getId()); + index++; + AccountSeed seed = db.accountSeedDao().findById(request.getAccount().getSeedId()); + DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(), + new ChildNumber(44, true)); + DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey, + new ChildNumber(cryptoCoin.getCoinNumber(), true)); + DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey, + new ChildNumber(request.getAccount().getAccountIndex(), true)); + DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, + new ChildNumber(0, false)); + ECKey addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) index, true)); + BitcoinAddress address = new BitcoinAddress(); + address.setChange(false); + address.setAccountId(request.getAccount().getId()); + address.setIndex(index); + String addressString =addrKey.toAddress(this.cryptoCoin.getParameters()).toString(); + address.setAddress(addressString); + db.bitcoinAddressDao().insertBitcoinAddresses(address); + InsightApiGenerator.getTransactionFromAddress(this.cryptoCoin,addressString,true); + + request.setAddress(addressString); + request.setStatus(NextBitcoinAccountAddressRequest.StatusCode.SUCCEEDED); + } + private List getUtxos(long accountId, CrystalDatabase db){ List answer = new ArrayList<>(); List bTGTxI = new ArrayList<>(); diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java index b104c78..762d107 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java +++ b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java @@ -21,6 +21,8 @@ public class BitcoinSendRequest extends CryptoNetInfoRequest { SUCCEEDED, NO_INTERNET, NO_SERVER_CONNECTION, + NO_BALANCE, + NO_FEE, PETITION_FAILED } diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/GeneralAccountSendRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/GeneralAccountSendRequest.java deleted file mode 100644 index de98bb5..0000000 --- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/GeneralAccountSendRequest.java +++ /dev/null @@ -1,85 +0,0 @@ -package cy.agorise.crystalwallet.requestmanagers; - -import android.content.Context; - -import cy.agorise.crystalwallet.enums.CryptoCoin; -import cy.agorise.crystalwallet.models.CryptoNetAccount; - -public class GeneralAccountSendRequest extends CryptoNetInfoRequest { - /** - * The status code of this request - */ - public enum StatusCode{ - NOT_STARTED, - SUCCEEDED, - NO_INTERNET, - NO_SERVER_CONNECTION, - BAD_TO_ADDRESS, - NO_FEE, - NO_BALANCE, - PETITION_FAILED - } - - // The app context - private Context mContext; - //The soruce Account - private CryptoNetAccount mAccount; - // The destination account address - private String mToAccount; - // The amount of the transaction - private long mAmount; - // The memo, can be null - private String mMemo; - // The state of this request - private StatusCode status = StatusCode.NOT_STARTED; - - public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount, String memo) { - super(coin); - this.mContext = context; - this.mAccount = account; - this.mToAccount = toAccount; - this.mAmount = amount; - this.mMemo = memo; - } - - public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount) { - this(coin,context,account,toAccount,amount,null); - - } - - public Context getContext() { - return mContext; - } - - public CryptoNetAccount getAccount() { - return mAccount; - } - - public String getToAccount() { - return mToAccount; - } - - public long getAmount() { - return mAmount; - } - - public String getMemo() { - return mMemo; - } - - public void validate(){ - if ((this.status != StatusCode.NOT_STARTED)){ - this._fireOnCarryOutEvent(); - } - } - - public void setStatus(StatusCode code){ - this.status = code; - this._fireOnCarryOutEvent(); - } - - public StatusCode getStatus() { - return status; - } - -} diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java index fa55102..f7fdbd0 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java +++ b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java @@ -19,6 +19,8 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest { private CryptoCoin cryptoCoin; private Context context; + private String address = null; + /** * The status code of this request */ @@ -62,4 +64,12 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest { public StatusCode getStatus() { return status; } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } } From 41a3b1c17227b500e5ca2f0c2c3ed8fb309c051f Mon Sep 17 00:00:00 2001 From: dtvv Date: Wed, 24 Oct 2018 02:01:44 -0500 Subject: [PATCH 2/6] In the create seed activity when the user types it validates with the server each time, this has to be done til the user touches the CREATE WALLET button for performance --- .../activities/CreateSeedActivity.kt | 47 +------------------ .../BitsharesAccountNameValidation.kt | 1 + 2 files changed, 2 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt b/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt index 4b5f6fc..776dc4c 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt @@ -259,52 +259,7 @@ class CreateSeedActivity : CustomActivity() { * */ if (result) { - /* - * Show the dialog for connection with the server - * */ - val creatingAccountMaterialDialog = CrystalDialog(globalActivity) - creatingAccountMaterialDialog.setText(globalActivity.resources.getString(R.string.window_create_seed_Server_validation)) - creatingAccountMaterialDialog.progress() - creatingAccountMaterialDialog.show() - - /* - * Validate the account does not exists - * */ - val request = ValidateExistBitsharesAccountRequest(tietAccountName?.text.toString()) - request.setListener { - - /* - * Dismiss the dialog of loading - * */ - creatingAccountMaterialDialog.dismiss() - - if (request.accountExists) { - - /* - * The account exists and is not valid - * */ - tietAccountName.fieldValidatorModel.setInvalid() - tietAccountName.fieldValidatorModel.message = tietAccountName.resources.getString(R.string.account_name_already_exist) - - /* - * Disaible button create - * */ - disableCreate() - - } else { - - /* - * Passed all validations - * */ - tietAccountName.fieldValidatorModel.setValid() - - /* - * Enable button create - * */ - enableCreate() - } - } - CryptoNetInfoRequests.getInstance().addRequest(request) + enableCreate() } else { diff --git a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/customImpl/validationFields/BitsharesAccountNameValidation.kt b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/customImpl/validationFields/BitsharesAccountNameValidation.kt index 2f6f002..1b52c8b 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/customImpl/validationFields/BitsharesAccountNameValidation.kt +++ b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/validators/customImpl/validationFields/BitsharesAccountNameValidation.kt @@ -101,6 +101,7 @@ class BitsharesAccountNameValidation : CustomValidationField, UIValidator { result = false accountNameField.fieldValidatorModel.setInvalid() accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_at_least_one_character) + } else { /* From c3c6677faaea90dc12953621f5af293d1296ca7d Mon Sep 17 00:00:00 2001 From: dtvv Date: Wed, 24 Oct 2018 02:38:48 -0500 Subject: [PATCH 3/6] -In the import seed activity add all the fixed strings to android string resources -In the import seed window remove the first service connection that validates the seed, it seems that in the second service it does it too -In the import seed activity adjust the new error strings to the new error show model -In the import seed activity onlye enable the CREATE WALLET button if all the fields are correctly validate, specially the PIN mismatch error --- .../activities/ImportSeedActivity.java | 125 +++++++++++++----- app/src/main/res/values/strings.xml | 6 + 2 files changed, 97 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java index 954b06c..7ac8255 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java @@ -3,7 +3,6 @@ package cy.agorise.crystalwallet.activities; import android.app.Activity; import android.arch.lifecycle.ViewModelProviders; import android.content.Intent; -import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.Editable; @@ -12,7 +11,6 @@ import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; -import android.widget.Toast; import com.thekhaeng.pushdownanim.PushDownAnim; @@ -23,7 +21,6 @@ import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnTextChanged; import cy.agorise.crystalwallet.R; -import cy.agorise.crystalwallet.application.CrystalSecurityMonitor; import cy.agorise.crystalwallet.dialogs.material.CrystalLoading; import cy.agorise.crystalwallet.dialogs.material.DialogMaterial; import cy.agorise.crystalwallet.dialogs.material.NegativeResponse; @@ -77,6 +74,11 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator final Activity activity = this; + /* + * Flag to check correct PIN equality + * */ + private boolean pinsOK = false; + @@ -127,20 +129,20 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator @Override public void afterTextChanged(Editable s) { + /* + * Validate that PINs are equals + * */ + validatePINS(); + /* * If all is ready to continue enable the button, contrarie case disable it * */ - if(allFieldsAreFill()){ + if(allFieldsAreOK()){ enableCreate(); } else{ disableCreate(); } - - /* - * Validate that PINs are equals - * */ - validatePINS(); } }); etPinConfirmation.addTextChangedListener(new TextWatcher() { @@ -157,20 +159,20 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator @Override public void afterTextChanged(Editable s) { + /* + * Validate that PINs are equals + * */ + validatePINS(); + /* * If all is ready to continue enable the button, contrarie case disable it * */ - if(allFieldsAreFill()){ + if(allFieldsAreOK()){ enableCreate(); } else{ disableCreate(); } - - /* - * Validate that PINs are equals - * */ - validatePINS(); } }); etSeedWords.addTextChangedListener(new TextWatcher() { @@ -187,10 +189,15 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator @Override public void afterTextChanged(Editable s) { + /* + * Validate that PINs are equals + * */ + validatePINS(); + /* * If all is ready to continue enable the button, contrarie case disable it * */ - if(allFieldsAreFill()){ + if(allFieldsAreOK()){ enableCreate(); } else{ @@ -200,7 +207,7 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator /* * Hide error field * */ - txtErrorAccount.setVisibility(View.INVISIBLE); + clearErrors(); } }); etAccountName.addTextChangedListener(new TextWatcher() { @@ -217,10 +224,15 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator @Override public void afterTextChanged(Editable s) { + /* + * Validate that PINs are equals + * */ + validatePINS(); + /* * If all is ready to continue enable the button, contrarie case disable it * */ - if(allFieldsAreFill()){ + if(allFieldsAreOK()){ enableCreate(); } else{ @@ -234,6 +246,13 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator importSeedValidator.setListener(this); } + + private void clearErrors(){ + txtErrorPIN.setVisibility(View.INVISIBLE); + txtErrorAccount.setVisibility(View.INVISIBLE); + } + + /* * Validate that PINs are equals * */ @@ -243,29 +262,34 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator final String confirmoPIN = etPinConfirmation.getText().toString().trim(); if(!pin.isEmpty() && !confirmoPIN.isEmpty()){ if(pin.compareTo(confirmoPIN)!=0){ + pinsOK = false; txtErrorPIN.setVisibility(View.VISIBLE); } else{ - txtErrorPIN.setVisibility(View.INVISIBLE); + pinsOK = true; + clearErrors(); } } else{ - txtErrorPIN.setVisibility(View.INVISIBLE); + pinsOK = false; + clearErrors(); } } /* - * Method to validate if all the fields are fill + * Method to validate if all the fields are fill and correctly * */ - private boolean allFieldsAreFill(){ + private boolean allFieldsAreOK(){ boolean complete = false; if( etPin.getText().toString().trim().compareTo("")!=0 && etPinConfirmation.getText().toString().trim().compareTo("")!=0 && etSeedWords.getText().toString().trim().compareTo("")!=0 && etAccountName.getText().toString().trim().compareTo("")!=0){ - complete = true; + if(pinsOK){ + complete = true; + } } return complete; } @@ -324,10 +348,15 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator final CrystalLoading crystalLoading = new CrystalLoading(activity); crystalLoading.show(); + /* + * Final service connection + * */ + finalStep(crystalLoading); + /* * Validate mnemonic with the server * */ - final ValidateImportBitsharesAccountRequest request = new ValidateImportBitsharesAccountRequest(etAccountName.getText().toString().trim(),etSeedWords.getText().toString().trim(),activity); + /*final ValidateImportBitsharesAccountRequest request = new ValidateImportBitsharesAccountRequest(etAccountName.getText().toString().trim(),etSeedWords.getText().toString().trim(),activity); request.setListener(new CryptoNetInfoRequestListener() { @Override public void onCarryOut() { @@ -335,9 +364,6 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator //Correct - /* - * Final service connection - * */ finalStep(crystalLoading); } @@ -350,7 +376,7 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator } } }); - CryptoNetInfoRequests.getInstance().addRequest(request); + CryptoNetInfoRequests.getInstance().addRequest(request);*/ } }); @@ -378,26 +404,57 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator crystalLoading.dismiss(); if (!validatorRequest.getStatus().equals(ValidateImportBitsharesAccountRequest.StatusCode.SUCCEEDED)) { - String errorText = "An error ocurred attempting to import the account"; switch (validatorRequest.getStatus()){ case PETITION_FAILED: case NO_INTERNET: case NO_SERVER_CONNECTION: - errorText = "There was an error with the connection. Try again later"; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + txtErrorAccount.setText(activity.getResources().getString(R.string.NO_SERVER_CONNECTION)); + } + }); break; case ACCOUNT_DOESNT_EXIST: - errorText = "The account doesn't exists"; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + txtErrorAccount.setText(activity.getResources().getString(R.string.ACCOUNT_DOESNT_EXIST)); + } + }); break; case BAD_SEED: - errorText = "The seed is not valid"; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + txtErrorAccount.setText(activity.getResources().getString(R.string.BAD_SEED)); + } + }); break; case NO_ACCOUNT_DATA: - errorText = "The account doesn't have any data"; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + txtErrorAccount.setText(activity.getResources().getString(R.string.NO_ACCOUNT_DATA)); + } + }); break; + + default: + txtErrorAccount.setText(activity.getResources().getString(R.string.ERROR_UNRECOGNIZABLE)); + } - Toast.makeText(thisActivity.getApplicationContext(),errorText,Toast.LENGTH_LONG).show(); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + txtErrorAccount.setVisibility(View.VISIBLE); + } + }); + + //Toast.makeText(thisActivity.getApplicationContext(),errorText,Toast.LENGTH_LONG).show(); + } else { Intent intent = new Intent(thisActivity, BoardActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 719f5cd..fc1bd08 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,6 +91,12 @@ SAVE NEXT + An error ocurred attempting to import the account + The account does not have any data + The seed is not valid + The account does not exists + There was an error with the connection. Try again later + A permission need to be granted before to continue Please enter brainkey From b3a267fb47f69bef697e9daa014b26ad7126e1c0 Mon Sep 17 00:00:00 2001 From: dtvv Date: Wed, 24 Oct 2018 02:59:42 -0500 Subject: [PATCH 4/6] When the PATTERN is typed 4 wrong times, it has to block 15 seconds before make new tries --- .../activities/PatternRequestActivity.java | 74 ++++++++++++++++++- .../fragments/PatternSecurityFragment.java | 6 +- .../res/layout/activity_pattern_request.xml | 11 +++ app/src/main/res/values/strings.xml | 2 +- 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java index ec51e2f..56ec8b1 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/PatternRequestActivity.java @@ -36,6 +36,19 @@ public class PatternRequestActivity extends AppCompatActivity { @BindView(R.id.tvPatternText) TextView tvPatternText; + @BindView(R.id.txtBadtry) + TextView txtBadtry; + + /* + * Contains the bad tries + * */ + private int tries = 0; + + /* + * Seconds counter + * */ + private int seconds = 15; + @@ -111,10 +124,69 @@ public class PatternRequestActivity extends AppCompatActivity { private void incorrect(){ + /* + * One more bad try + * */ + ++tries; + + final Activity activity = this; + + /* + * User can not go more up to 5 bad tries + * */ + if(tries==4) { + tries = 0; + + patternLockView.setEnabled(false); + txtBadtry.setVisibility(View.VISIBLE); + txtBadtry.setText(txtBadtry.getText().toString().replace("%%",String.valueOf(seconds))); + + final Timer t = new Timer(); + //Set the schedule function and rate + t.scheduleAtFixedRate(new TimerTask() { + + @Override + public void run() { + + --seconds; + + if(seconds==0){ + t.cancel(); + + seconds = 15; + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + patternLockView.setEnabled(true); + txtBadtry.setVisibility(View.INVISIBLE); + patternLockView.clearPattern(); + patternLockView.requestFocus(); + } + }); + } + else{ + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + txtBadtry.setText(activity.getResources().getString(R.string.wrong_pin_wait).replace("%%",String.valueOf(seconds))); + } + }); + } + } + + }, + //Set how long before to start calling the TimerTask (in milliseconds) + 1000, + //Set the amount of time between each execution (in milliseconds) + 1000); + + return; + } + /* * Show error * */ - final Activity activity = this; tvPatternText.setText(activity.getResources().getString(R.string.Incorrect_pattern)); tvPatternText.setTextColor(Color.RED); tvPatternText.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java index 070b1b8..e98d883 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java @@ -193,8 +193,8 @@ public class PatternSecurityFragment extends Fragment { * */ tvPatternText.setText(getActivity().getResources().getString(R.string.Pattern_set_correctly)); tvPatternText.setTextColor(Color.GREEN); - final Timer t = new Timer(); - t.scheduleAtFixedRate(new TimerTask() { + final Timer t_ = new Timer(); + t_.scheduleAtFixedRate(new TimerTask() { @Override public void run() { @@ -203,7 +203,7 @@ public class PatternSecurityFragment extends Fragment { @Override public void run() { - t.cancel(); + t_.cancel(); showNewPatternUI(); } }); diff --git a/app/src/main/res/layout/activity_pattern_request.xml b/app/src/main/res/layout/activity_pattern_request.xml index 1bd30ed..1f9e119 100644 --- a/app/src/main/res/layout/activity_pattern_request.xml +++ b/app/src/main/res/layout/activity_pattern_request.xml @@ -21,4 +21,15 @@ android:layout_centerInParent="true" android:background="@drawable/gradient"/> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fc1bd08..02263a8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -220,7 +220,7 @@ Fee OK - Wrong PIN you have to wait %% seconds ... + Wrong match you have to wait %% seconds ... Loading... Pay to From 4ba629982275441c3d5ac31ae4296a269dbce1b4 Mon Sep 17 00:00:00 2001 From: dtvv Date: Wed, 24 Oct 2018 03:56:21 -0500 Subject: [PATCH 5/6] -Search solution for the viewpager crashes actions when try to define a pattern horisontally -In the ChildViewPager of security settings disable swipe horisontally and navigation now it is by tabs -In the ChildViewPager modify the class so it can control when the swipe touch event is bloqued or not correctly --- .../fragments/PatternSecurityFragment.java | 15 ++++++- .../fragments/SecuritySettingsFragment.java | 5 ++- .../crystalwallet/util/ChildViewPager.java | 45 ++++++++++++------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java index e98d883..63e15d7 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java @@ -28,6 +28,7 @@ import butterknife.OnTextChanged; import cy.agorise.crystalwallet.R; import cy.agorise.crystalwallet.application.CrystalSecurityMonitor; import cy.agorise.crystalwallet.models.GeneralSetting; +import cy.agorise.crystalwallet.util.ChildViewPager; import cy.agorise.crystalwallet.util.PasswordManager; import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel; import cy.agorise.crystalwallet.viewmodels.validators.PinSecurityValidator; @@ -45,9 +46,17 @@ public class PatternSecurityFragment extends Fragment { @BindView(R.id.tvPatternText) TextView tvPatternText; + /* + * Contains the ChildViewPager to block the viewpager when the user is using the pattern control + * */ + private ChildViewPager childViewPager; + private PatternLockViewListener actualPatternListener; private String patternEntered; + + + public PatternSecurityFragment() { // Required empty public constructor } @@ -80,6 +89,11 @@ public class PatternSecurityFragment extends Fragment { return patternString; } + public void setChildViewPager(ChildViewPager childViewPager) { + this.childViewPager = childViewPager; + } + + public void removePatternListener(){ if (actualPatternListener != null){ patternLockView.removePatternLockListener(actualPatternListener); @@ -96,7 +110,6 @@ public class PatternSecurityFragment extends Fragment { actualPatternListener = new PatternLockViewListener() { @Override public void onStarted() { - } @Override diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java index 7b5ee8c..a61d330 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java @@ -96,7 +96,6 @@ public class SecuritySettingsFragment extends Fragment { default: mPager.setCurrentItem(0); } - mPager.setSwipeLocked(true); TabLayout tabLayout = v.findViewById(R.id.tabs); @@ -134,7 +133,9 @@ public class SecuritySettingsFragment extends Fragment { case 1: return new PinSecurityFragment(); case 2: - return new PatternSecurityFragment(); + final PatternSecurityFragment patternSecurityFragment = new PatternSecurityFragment(); + patternSecurityFragment.setChildViewPager(mPager); + return patternSecurityFragment; } return null; //new OnConstructionFragment(); diff --git a/app/src/main/java/cy/agorise/crystalwallet/util/ChildViewPager.java b/app/src/main/java/cy/agorise/crystalwallet/util/ChildViewPager.java index fbac369..34f6417 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/util/ChildViewPager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/util/ChildViewPager.java @@ -4,6 +4,10 @@ import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; +import android.view.animation.DecelerateInterpolator; +import android.widget.Scroller; + +import java.lang.reflect.Field; /** * Created by xd on 1/18/18. @@ -14,36 +18,47 @@ import android.view.MotionEvent; public class ChildViewPager extends ViewPager { - private boolean swipeLocked; - public ChildViewPager(Context context) { super(context); + + setMyScroller(); } public ChildViewPager(Context context, AttributeSet attrs) { super(context, attrs); } - public boolean getSwipeLocked() { - return swipeLocked; - } - - public void setSwipeLocked(boolean swipeLocked) { - this.swipeLocked = swipeLocked; - } - @Override public boolean onTouchEvent(MotionEvent event) { - return !swipeLocked && super.onTouchEvent(event); + // stop swipe + return false; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { - return !swipeLocked && super.onInterceptTouchEvent(event); + // stop switching pages + return false; } - @Override - public boolean canScrollHorizontally(int direction) { - return !swipeLocked && super.canScrollHorizontally(direction); + private void setMyScroller() { + try { + Class viewpager = ViewPager.class; + Field scroller = viewpager.getDeclaredField("mScroller"); + scroller.setAccessible(true); + scroller.set(this, new MyScroller(getContext())); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public class MyScroller extends Scroller { + public MyScroller(Context context) { + super(context, new DecelerateInterpolator()); + } + + @Override + public void startScroll(int startX, int startY, int dx, int dy, int duration) { + super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/); + } } } \ No newline at end of file From 418749ea6a9ff75f94e290366352dfc5c8e3d05b Mon Sep 17 00:00:00 2001 From: dtvv Date: Wed, 24 Oct 2018 16:18:01 -0500 Subject: [PATCH 6/6] Pocket security functionality disable for now --- .../crystalwallet/fragments/SecuritySettingsFragment.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java index a61d330..d3ed69a 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java @@ -83,6 +83,11 @@ public class SecuritySettingsFragment extends Fragment { View v = inflater.inflate(R.layout.fragment_security_settings, container, false); ButterKnife.bind(this, v); + /* + * For now this will not be implemented + * */ + sPocketSecurity.setEnabled(false); + securityPagerAdapter = new SecurityPagerAdapter(getChildFragmentManager()); mPager.setAdapter(securityPagerAdapter);